1 #include "win32\win32guts.h"
2 #ifndef _APRICOT_H_
3 #include "apricot.h"
4 #endif
5 #include "guts.h"
6 #include "Window.h"
7 #include "Icon.h"
8 #include "DeviceBitmap.h"
9
10 #ifdef __cplusplus
11 extern "C" {
12 #endif
13
14
15 #define sys (( PDrawableData)(( PComponent) self)-> sysData)->
16 #define dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
17 #define var (( PWidget) self)->
18 #define HANDLE sys handle
19 #define DHANDLE(x) dsys(x) handle
20
21 static Bool
create_gdip_surface(Handle self)22 create_gdip_surface(Handle self)
23 {
24 HRGN rgn;
25
26 /* force null region as it lingers in GDI+ space somehow */
27 rgn = CreateRectRgn(0,0,0,0);
28 if ( GetClipRgn( sys ps, rgn ) > 0 )
29 SelectClipRgn( sys ps, NULL);
30 else
31 rgn = NULL;
32
33 GPCALL GdipCreateFromHDC(sys ps, &sys graphics);
34 apiGPErrCheckRet(false);
35
36 if ( rgn ) {
37 SelectClipRgn( sys ps, rgn);
38 GPCALL GdipSetClipHrgn(sys graphics, rgn, CombineModeReplace);
39 apiGPErrCheck;
40 DeleteObject( rgn);
41 }
42
43 return true;
44 }
45
46 #define CREATE_GDIP_SURFACE (( sys ps && sys graphics == NULL ) ? create_gdip_surface(self) : true)
47
48 Bool
apc_gp_set_alpha(Handle self,int alpha)49 apc_gp_set_alpha( Handle self, int alpha)
50 {
51 if (
52 ( is_apt(aptDeviceBitmap) && ((PDeviceBitmap)self)->type == dbtBitmap) ||
53 ( is_apt(aptImage) && ((PImage)self)-> type == imBW )
54 )
55 alpha = 255;
56
57 sys alpha = alpha;
58
59 if ( alpha < 255 ) {
60 if ( !CREATE_GDIP_SURFACE) {
61 sys alpha = 255;
62 return false;
63 }
64 }
65
66 if ( sys ps && sys graphics )
67 stylus_change( self);
68
69 if ( sys alphaArenaPalette ) {
70 free(sys alphaArenaPalette);
71 sys alphaArenaPalette = NULL;
72 }
73
74 return true;
75 }
76
77 Bool
apc_gp_set_antialias(Handle self,Bool aa)78 apc_gp_set_antialias( Handle self, Bool aa)
79 {
80 if ( aa ) {
81 if (
82 ( is_apt(aptDeviceBitmap) && ((PDeviceBitmap)self)->type == dbtBitmap) ||
83 ( is_apt(aptImage) && ((PImage)self)-> type == imBW )
84 )
85 return false;
86 if ( !CREATE_GDIP_SURFACE)
87 return false;
88 apt_set(aptGDIPlus);
89 GdipSetSmoothingMode(sys graphics, SmoothingModeAntiAlias);
90 GdipSetPixelOffsetMode(sys graphics, PixelOffsetModeHalf);
91 } else {
92 apt_clear(aptGDIPlus);
93 GdipSetSmoothingMode(sys graphics, SmoothingModeNone);
94 GdipSetPixelOffsetMode(sys graphics, PixelOffsetModeNone);
95 }
96 return true;
97 }
98
99 int
apc_gp_get_alpha(Handle self)100 apc_gp_get_alpha( Handle self)
101 {
102 return sys alpha;
103 }
104
105 Bool
apc_gp_get_antialias(Handle self)106 apc_gp_get_antialias( Handle self)
107 {
108 return is_apt(aptGDIPlus);
109 }
110
111
112 Bool
apc_gp_aa_fill_poly(Handle self,int numPts,NPoint * points)113 apc_gp_aa_fill_poly( Handle self, int numPts, NPoint * points)
114 {
115 int i;
116 double dy = sys lastSize. y;
117 Point t = sys gp_transform;
118 GpPointF *p;
119 objCheck false;
120
121 if ((p = malloc( sizeof(GpPointF) * numPts)) == NULL)
122 return false;
123
124 for ( i = 0; i < numPts; i++) {
125 p[i].X = t.x + points[i].x;
126 p[i].Y = t.y + dy - points[i].y;
127 }
128
129 STYLUS_USE_GP_BRUSH;
130 GPCALL GdipFillPolygon(
131 sys graphics,
132 sys stylusGPResource-> brush,
133 p, numPts,
134 ((sys psFillMode & fmWinding) == fmAlternate) ?
135 FillModeAlternate : FillModeWinding
136 );
137 apiGPErrCheckRet(false);
138
139 return true;
140 }
141
142 /* emulate alpha text */
143
144 #define GRAD 57.29577951
145
146 void
aa_free_arena(Handle self,Bool for_reuse)147 aa_free_arena(Handle self, Bool for_reuse)
148 {
149 if ( !for_reuse && sys alphaArenaPalette ) {
150 free(sys alphaArenaPalette);
151 sys alphaArenaPalette = NULL;
152 }
153
154 if ( !sys alphaArenaDC)
155 return;
156
157 if (sys alphaArenaStockFont)
158 SelectObject( sys alphaArenaDC, sys alphaArenaStockFont);
159 SelectObject( sys alphaArenaDC, sys alphaArenaStockBitmap);
160 DeleteObject( sys alphaArenaBitmap );
161 sys alphaArenaBitmap = NULL;
162 sys alphaArenaStockFont = NULL;
163 sys alphaArenaStockBitmap = NULL;
164 if ( !for_reuse ) {
165 DeleteDC(sys alphaArenaDC);
166 sys alphaArenaDC = NULL;
167 }
168
169 }
170
171 static Bool
aa_make_arena(Handle self)172 aa_make_arena(Handle self)
173 {
174 int w,h;
175 w = var font. maximalWidth;
176 h = var font. height;
177 if ( w < h ) w = h;
178
179 if ( var font. direction != 0) {
180 if ( sys font_sin == sys font_cos && sys font_sin == 0.0 ) {
181 sys font_sin = sin( var font. direction / GRAD);
182 sys font_cos = cos( var font. direction / GRAD);
183 }
184 }
185
186 if ( w < sys alphaArenaSize.x || h < sys alphaArenaSize.y || !sys alphaArenaDC ) {
187 HDC dc;
188 if ( sys alphaArenaBitmap ) {
189 aa_free_arena(self, true);
190 } else {
191 if (!( sys alphaArenaDC = CreateCompatibleDC(0)))
192 return false;
193 SetTextAlign(sys alphaArenaDC, TA_BOTTOM);
194 SetBkMode( sys alphaArenaDC, TRANSPARENT);
195 SetTextColor( sys alphaArenaDC, 0xffffff);
196 }
197
198 sys alphaArenaSize.x = sys alphaArenaSize.y = w * 4;
199
200 dc = dc_alloc();
201 if ( !( sys alphaArenaBitmap = image_create_argb_dib_section(
202 dc, sys alphaArenaSize.x, sys alphaArenaSize.y, &sys alphaArenaPtr
203 ))) {
204 dc_free();
205 return false;
206 }
207 dc_free();
208
209 sys alphaArenaStockBitmap = SelectObject( sys alphaArenaDC, sys alphaArenaBitmap);
210 sys alphaArenaStockFont = NULL;
211 sys alphaArenaFontChanged = true;
212 }
213
214 if ( sys alphaArenaFontChanged || !sys alphaArenaStockFont) {
215 HFONT f;
216 f = SelectObject( sys alphaArenaDC, sys fontResource-> hfont );
217 if ( !sys alphaArenaStockFont )
218 sys alphaArenaStockFont = f;
219 sys alphaArenaFontChanged = false;
220 }
221
222 return true;
223 }
224
225 static Bool
aa_render(Handle self,int x,int y,NPoint * delta,ABCFLOAT * abc,int advance,int dx,int dy)226 aa_render( Handle self, int x, int y, NPoint* delta, ABCFLOAT * abc, int advance, int dx, int dy)
227 {
228 BLENDFUNCTION bf;
229 float xx, yy, shift;
230 register uint32_t * p, * palette;
231 int i, j, miny, maxy, maxx, minx;
232 Point sz;
233
234 /* replace white to our color + alpha, calculate minimal affected box */
235 p = sys alphaArenaPtr;
236 palette = sys alphaArenaPalette;
237 for (
238 i = maxy = maxx = 0,
239 minx = sys alphaArenaSize.x - 1,
240 miny = sys alphaArenaSize.y - 1;
241 i < sys alphaArenaSize.y;
242 i++
243 ) {
244 Bool match = false;
245 for ( j = 0; j < sys alphaArenaSize.x; j++, p++) {
246 if (1 || *p != 0) {
247 register Byte *argb = (Byte*) p;
248 *p = palette[argb[0] + argb[1] + argb[2]];
249 if ( minx > j ) minx = j;
250 if ( maxx < j ) maxx = j;
251 match = true;
252 }
253 }
254 if ( match ) {
255 if ( miny > i ) miny = i;
256 if ( maxy < i ) maxy = i;
257 }
258 }
259 if ( maxy < miny ) return true;
260
261 /* calculate advance for the next glyph and the position, if needed, for this one */
262 if ( advance >= 0 ) {
263 shift = advance;
264 if ( var font.direction != 0 ) {
265 xx = (dx * sys font_cos) - (dy * sys font_sin);
266 yy = (dx * sys font_sin) + (dy * sys font_cos);
267 } else {
268 xx = dx;
269 yy = dy;
270 }
271 } else {
272 shift = abc->abcfA + abc->abcfB + abc->abcfC;
273 xx = yy = 0.0;
274 }
275 x += round(delta->x + xx);
276 y += round(delta->y - yy);
277
278 if ( var font.direction != 0 ) {
279 delta->x += shift * sys font_cos;
280 delta->y -= shift * sys font_sin;
281 } else {
282 delta->x += shift;
283 }
284
285 /* calculate the aperture */
286 sz = sys alphaArenaSize;
287 x -= sz.x/2;
288 y -= sz.y/2;
289 if ( is_apt( aptTextOutBaseline)) {
290 if ( var font. direction != 0 ) {
291 float d = var font. descent;
292 x += d * sys font_sin + .5;
293 y += d * sys font_cos + .5;
294 } else
295 y += var font. descent;
296 }
297
298 /* minimize the blit rectangle */
299 {
300 int m, n;
301 m = sys alphaArenaSize.y - maxy - 1;
302 n = sys alphaArenaSize.y - miny - 1;
303 miny = m;
304 maxy = n;
305 }
306 sz.x = maxx - minx + 1;
307 sz.y = maxy - miny + 1;
308
309 /* blend */
310 bf.BlendOp = AC_SRC_OVER;
311 bf.BlendFlags = 0;
312 bf.SourceConstantAlpha = 0xff;
313 bf.AlphaFormat = AC_SRC_ALPHA;
314 return AlphaBlend(
315 sys ps, x + minx, y + miny, sz.x, sz.y,
316 sys alphaArenaDC, minx, miny, sz.x, sz.y,
317 bf);
318 }
319
320 /* precalculate alpha map */
321 Bool
aa_fill_palette(Handle self)322 aa_fill_palette(Handle self)
323 {
324 int i,j,r,g,b;
325 PStylus s = & sys stylus;
326
327 if ( sys alphaArenaPalette )
328 return true;
329
330 if ( !( sys alphaArenaPalette = malloc(4 * 256 * 3)))
331 return false;
332
333 b = (s->pen.lopnColor >> 16) & 0xff;
334 g = (s->pen.lopnColor & 0xff00) >> 8;
335 r = s->pen.lopnColor & 0xff;
336
337 for ( i = j = 0; i < 256; i++) {
338 uint32_t a = sys alpha * i / 255;
339 a =
340 (a << 24) |
341 ((r * a / 255 ) << 16) |
342 ((g * a / 255 ) << 8) |
343 ( b * a / 255 )
344 ;
345 sys alphaArenaPalette[j++] = a;
346 sys alphaArenaPalette[j++] = a;
347 sys alphaArenaPalette[j++] = a;
348 }
349
350 return true;
351 }
352
353 Bool
aa_text_out(Handle self,int x,int y,void * text,int len,Bool wide)354 aa_text_out( Handle self, int x, int y, void * text, int len, Bool wide)
355 {
356 int i;
357 NPoint delta = { 0, 0 };
358
359 if ( !(aa_fill_palette(self) && aa_make_arena(self)))
360 return false;
361
362 for ( i = 0; i < len; i++) {
363 ABCFLOAT abc;
364 memset(sys alphaArenaPtr, 0, sys alphaArenaSize.x * sys alphaArenaSize.y * 4);
365 if ( wide ) {
366 if (!GetCharABCWidthsFloatW( sys ps, ((WCHAR*)text)[i], ((WCHAR*)text)[i], &abc)) apiErrRet;
367 } else {
368 if (!GetCharABCWidthsFloatA( sys ps, ((char *)text)[i], ((char *)text)[i], &abc)) apiErrRet;
369 }
370 if ( wide ) {
371 if (!TextOutW( sys alphaArenaDC, sys alphaArenaSize.x/2, sys alphaArenaSize.y/2, ((WCHAR*)text) + i, 1)) apiErrRet;
372 } else {
373 if (!TextOutA( sys alphaArenaDC, sys alphaArenaSize.x/2, sys alphaArenaSize.y/2, ((char *)text) + i, 1)) apiErrRet;
374 }
375 if ( !aa_render(self, x, y, &delta, &abc, -1, 0, 0))
376 return false;
377 }
378 return true;
379 }
380
381 Bool
aa_glyphs_out(Handle self,PGlyphsOutRec t,int x,int y,int * text_advance,HFONT font)382 aa_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance, HFONT font)
383 {
384 int i;
385 NPoint delta = { 0, 0 };
386 uint16_t *advances = t->advances;
387 int16_t *positions = t->positions;
388 HFONT f;
389
390 if ( !(aa_fill_palette(self) && aa_make_arena(self)))
391 return false;
392
393 if ( text_advance )
394 *text_advance = 0;
395
396 f = SelectObject( sys alphaArenaDC, font );
397 if ( !sys alphaArenaStockFont )
398 sys alphaArenaStockFont = f;
399 sys alphaArenaFontChanged = false;
400
401 for ( i = 0; i < t->len; i++) {
402 ABCFLOAT abc, *pabc;
403 int adv, dx, dy;
404 memset(sys alphaArenaPtr, 0, sys alphaArenaSize.x * sys alphaArenaSize.y * 4);
405 if ( !ExtTextOutW(sys alphaArenaDC,
406 sys alphaArenaSize.x/2, sys alphaArenaSize.y/2,
407 ETO_GLYPH_INDEX, NULL, (LPCWSTR)(t->glyphs) + i, 1,
408 NULL
409 ))
410 apiErrRet;
411
412 if ( advances ) {
413 adv = *(advances++);
414 if ( text_advance )
415 *text_advance += *advances;
416 pabc = NULL;
417 dx = *(positions++);
418 dy = *(positions++);
419 } else {
420 ABC abci;
421 adv = -1;
422 pabc = &abc;
423 dx = dy = 0;
424 if (!GetCharABCWidthsI( sys ps, ((WCHAR*)(t->glyphs))[i], 1, NULL, &abci)) apiErr;
425 if ( text_advance )
426 *text_advance += abci.abcA + abci.abcB + abci.abcC;
427 abc.abcfA = abci.abcA;
428 abc.abcfB = abci.abcB;
429 abc.abcfC = abci.abcC;
430 }
431
432 if ( !aa_render(self, x, y, &delta, pabc, adv, dx, dy))
433 return false;
434 }
435 return false;
436 }
437
438 #ifdef __cplusplus
439 }
440 #endif
441