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