1 #ifndef _APRICOT_H_
2 #include "apricot.h"
3 #endif
4 #include <usp10.h>
5 #include "guts.h"
6 #include "win32\win32guts.h"
7 #include "Widget.h"
8 
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12 
13 
14 #define  sys (( PDrawableData)(( PComponent) self)-> sysData)->
15 #define  dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
16 #define var (( PWidget) self)->
17 #define HANDLE sys handle
18 #define DHANDLE(x) dsys(x) handle
19 
20 #define GRAD 57.29577951
21 
22 typedef struct {
23 	HDC dc;
24 	int i, len, stop;
25 	Handle self;
26 	HFONT orig, saved, curr;
27 	PDCFont nondefault_font;
28 	uint32_t nondefault_fid;
29 	uint16_t *fonts;
30 } FontContext;
31 
32 static void
font_context_init(FontContext * fc,Handle self,PGlyphsOutRec t)33 font_context_init( FontContext * fc, Handle self, PGlyphsOutRec t)
34 {
35 	bzero(fc, sizeof(FontContext));
36 	fc->self  = self;
37 	fc->orig  = sys fontResource->hfont;
38 	fc->fonts = t->fonts;
39 	fc->len   = t->len;
40 	fc->dc    = sys ps;
41 }
42 
43 static void
font_context_done(FontContext * fc)44 font_context_done( FontContext * fc )
45 {
46 	if ( fc-> nondefault_font )
47 		font_free(fc-> nondefault_font, false);
48 	if ( fc-> saved )
49 		SelectObject(fc->dc, fc->saved);
50 }
51 
52 static void
font_context_rewind(FontContext * fc,int index)53 font_context_rewind( FontContext * fc, int index )
54 {
55 	fc-> i = index;
56 	fc-> stop = fc-> i >= fc-> len;
57 }
58 
59 static int
font_context_next(FontContext * fc)60 font_context_next( FontContext * fc )
61 {
62 	Font *_src, src, dst;
63 	uint16_t nfid;
64 	int start, len;
65 	HFONT hfont, selected;
66 
67 	if ( fc-> stop ) return 0;
68 
69 	if ( !fc-> fonts ) {
70 		start = fc-> i;
71 		fc-> i = fc-> len;
72 		fc-> stop = true;
73 		return fc-> i - start;
74 	}
75 
76 	for (
77 		len = 0, start = fc->i, nfid = fc->fonts[fc->i];
78 		fc->i <= fc->len;
79 		fc->i++
80 	) {
81 		if (
82 			fc->i >= fc->len || fc->fonts[fc->i] != nfid
83 		) {
84 			len = fc->i - start;
85 			break;
86 		}
87 	}
88 	fc-> stop = fc-> i >= fc-> len;
89 	if ( len == 0 ) return 0;
90 
91 	if ( nfid == 0 ) {
92 		hfont = fc->orig;
93 	} else if ( nfid == fc->nondefault_fid ) {
94 		hfont = fc->nondefault_font->hfont;
95 	} else if ( !( _src = prima_font_mapper_get_font(nfid))) {
96 		hfont = fc->orig;
97 	} else {
98 		dst = (( PWidget) fc->self)-> font;
99 		src = *_src;
100 #define CP(x) src.x = dst.x; src.undef.x = 0;
101 		CP(size)
102 		CP(direction)
103 #undef CP
104 		src.direction = dst.direction;
105 		apc_font_pick(fc->self, &src, &dst);
106 		if ( strcmp(src.name, dst.name) == 0) {
107 			if ( fc-> nondefault_font )
108 				font_free(fc-> nondefault_font, false);
109 			fc->nondefault_font = font_alloc(&dst);
110 			fc->nondefault_fid  = nfid;
111 			hfont = fc->nondefault_font->hfont;
112 		} else {
113 			hfont = fc->orig;
114 		}
115 	}
116 
117 	fc->curr = hfont;
118 	selected = SelectObject(fc->dc, fc->curr);
119 	if ( !fc->saved ) fc->saved = selected;
120 
121 	return len;
122 }
123 
124 /* emulate underscore and strikeout because ExtTextOutW with ETO_PDY underlines each glyph separately */
125 static void
underscore_font(Handle self,int x,int y,int width,Bool use_alpha)126 underscore_font( Handle self, int x, int y, int width, Bool use_alpha)
127 {
128 	Stylus ss;
129 	HPEN old = NULL;
130 	HDC dc = sys ps;
131 	PDCStylus dcs;
132 	float c, s;
133 	GpPen * gppen = NULL;
134 
135 	bzero(&ss, sizeof(ss));
136 	ss.pen.lopnStyle   = PS_SOLID;
137 	ss.pen.lopnWidth.x = 1;
138 	ss.pen.lopnColor   = sys stylus.pen.lopnColor;
139 
140 	if ( var font. direction != 0) {
141 		if ( sys font_sin == sys font_cos && sys font_sin == 0.0 ) {
142 			sys font_sin = sin( var font. direction / GRAD);
143 			sys font_cos = cos( var font. direction / GRAD);
144 		}
145 		c = sys font_cos;
146 		s = sys font_sin;
147 	} else {
148 		s = 0.0;
149 		c = 1.0;
150 	}
151 
152 	if ( var font. style & fsUnderlined ) {
153 		int i, Y = 0;
154 		Point pt[2];
155 
156 		if ( !is_apt( aptTextOutBaseline))
157 			Y -= var font. descent;
158 		if (sys otmsUnderscoreSize > 0) {
159 			Y -= sys otmsUnderscorePosition;
160 			ss.pen.lopnWidth.x = sys otmsUnderscoreSize;
161 		} else
162 			Y += var font. descent - 1;
163 
164 		pt[0].x = 0;
165 		pt[0].y = -Y;
166 		pt[1].x = width;
167 		pt[1].y = -Y;
168 		if ( var font. direction != 0) {
169 			for ( i = 0; i < 2; i++) {
170 				float x = pt[i].x * c - pt[i].y * s;
171 				float y = pt[i].x * s + pt[i].y * c;
172 				pt[i].x = x + (( x > 0) ? 0.5 : -0.5);
173 				pt[i].y = y + (( y > 0) ? 0.5 : -0.5);
174 			}
175 		}
176 
177 		if ( use_alpha ) {
178 			gppen = stylus_gp_get_pen(ss.pen.lopnWidth.x,
179 				( sys alpha << 24) |
180 				(ss.pen.lopnColor >> 16) |
181 				(ss.pen.lopnColor & 0xff00) |
182 				((ss.pen.lopnColor & 0xff) << 16)
183 			);
184 			GdipDrawLineI(sys graphics, gppen, x + pt[0].x, y - pt[0].y, x + pt[1].x, y - pt[1].y);
185 		} else {
186 			dcs = stylus_alloc(&ss);
187 			old = SelectObject( dc, dcs-> hpen );
188 
189 			MoveToEx( dc, x + pt[0].x, y - pt[0].y, NULL);
190 			LineTo( dc, x + pt[1].x, y - pt[1].y);
191 		}
192 	}
193 
194 	if ( var font. style & fsStruckOut ) {
195 		int i, Y = 0;
196 		Point pt[2];
197 
198 		if ( !is_apt( aptTextOutBaseline))
199 			Y -= var font. descent;
200 		if (sys otmsStrikeoutSize > 0) {
201 			Y -= sys otmsStrikeoutPosition;
202 			if ( ss.pen.lopnWidth.x != sys otmsStrikeoutSize ) {
203 				if ( use_alpha && gppen == NULL ) {
204 					gppen = stylus_gp_get_pen(ss.pen.lopnWidth.x,
205 						( sys alpha << 24) |
206 						(ss.pen.lopnColor >> 16) |
207 						(ss.pen.lopnColor & 0xff00) |
208 						((ss.pen.lopnColor & 0xff) << 16)
209 					);
210 				} else if ( !use_alpha && old == NULL ) {
211 					HPEN curr;
212 					ss.pen.lopnWidth.x = sys otmsStrikeoutSize;
213 					dcs = stylus_alloc(&ss);
214 					curr = SelectObject( dc, dcs-> hpen );
215 					if ( old == NULL ) old = curr;
216 				}
217 			}
218 		} else
219 			Y -= var font. ascent / 2;
220 
221 		pt[0].x = 0;
222 		pt[0].y = -Y;
223 		pt[1].x = width;
224 		pt[1].y = -Y;
225 		if ( var font. direction != 0) {
226 			for ( i = 0; i < 2; i++) {
227 				float x = pt[i].x * c - pt[i].y * s;
228 				float y = pt[i].x * s + pt[i].y * c;
229 				pt[i].x = x + (( x > 0) ? 0.5 : -0.5);
230 				pt[i].y = y + (( y > 0) ? 0.5 : -0.5);
231 			}
232 		}
233 
234 		if ( use_alpha ) {
235 			GdipDrawLineI(sys graphics, gppen, x + pt[0].x, y - pt[0].y, x + pt[1].x, y - pt[1].y);
236 		} else {
237 			MoveToEx( dc, x + pt[0].x, y - pt[0].y, NULL);
238 			LineTo( dc, x + pt[1].x, y - pt[1].y);
239 		}
240 	}
241 
242 	if ( !use_alpha )
243 		SelectObject( dc, old );
244 }
245 
246 void
gp_get_text_widths(Handle self,const char * text,int len,int flags,ABC * extents)247 gp_get_text_widths( Handle self, const char* text, int len, int flags, ABC * extents)
248 {
249 	SIZE  sz;
250 	int   div, offset = 0, ret = 0;
251 
252 	objCheck;
253 	memset(extents, 0, sizeof(ABC));
254 	if ( len == 0) return;
255 
256 	/* width more that 32K returned incorrectly by Win32 core */
257 	if (( div = 32768L / ( var font. maximalWidth ? var font. maximalWidth : 1)) == 0)
258 		div = 1;
259 
260 	while ( offset < len) {
261 		int chunk_len = ( offset + div > len) ? ( len - offset) : div;
262 		if ( flags & toGlyphs) {
263 			if ( !GetTextExtentPointI( sys ps, ( WCHAR*) text + offset, chunk_len, &sz)) apiErr;
264 		} else if ( flags & toUnicode) {
265 			if ( !GetTextExtentPoint32W( sys ps, ( WCHAR*) text + offset, chunk_len, &sz)) apiErr;
266 		} else {
267 			if ( !GetTextExtentPoint32( sys ps, text + offset, chunk_len, &sz)) apiErr;
268 		}
269 		ret += sz. cx;
270 		offset += div;
271 	}
272 	extents->abcB = ret;
273 
274 	if ( flags & toAddOverhangs) {
275 		if ( sys tmPitchAndFamily & TMPF_TRUETYPE) {
276 			ABC abc[2];
277 			if ( flags & toGlyphs) {
278 				WCHAR * t = (WCHAR*) text;
279 				GetCharABCWidthsI( sys ps, *t, 1, NULL, &abc[0]);
280 				GetCharABCWidthsI( sys ps, t[len-1], 1, NULL, &abc[1]);
281 			} else if ( flags & toUnicode) {
282 				WCHAR * t = (WCHAR*) text;
283 				if ( guts. utf8_prepend_0x202D ) {
284 					/* the 1st character is 0x202D, skip it */
285 					t++;
286 					len--;
287 				}
288 				GetCharABCWidthsW( sys ps, *t, *t, &abc[0]);
289 				GetCharABCWidthsW( sys ps, t[len-1], t[len-1], &abc[1]);
290 			} else {
291 				GetCharABCWidths( sys ps, text[ 0    ], text[ 0    ], &abc[0]);
292 				GetCharABCWidths( sys ps, text[ len-1], text[ len-1], &abc[1]);
293 			}
294 			extents->abcA = abc[0].abcA;
295 			extents->abcC = abc[1].abcC;
296 		}
297 	}
298 }
299 
300 static void
gp_get_polyfont_widths(Handle self,const PGlyphsOutRec t,int flags,ABC * extents)301 gp_get_polyfont_widths( Handle self, const PGlyphsOutRec t, int flags, ABC * extents)
302 {
303 	int div, len, offset = 0;
304 	FontContext fc;
305 
306 	objCheck;
307 	memset(extents, 0, sizeof(ABC));
308 	if ( t->len == 0) return;
309 
310 	font_context_init(&fc, self, t);
311 
312 	if ( t->advances ) {
313 		int i;
314 		ABC abc;
315 		for ( i = 0; i < t->len; i++)
316 			extents->abcB += t->advances[i];
317 		GetCharABCWidthsI( sys ps, t->glyphs[0], 1, NULL, &abc);
318 		extents->abcA = abc.abcA;
319 		if ( t->fonts[0] != t->fonts[t->len - 1] ) {
320 			font_context_rewind(&fc, t->len - 1);
321 			font_context_next(&fc);
322 		}
323 		GetCharABCWidthsI( sys ps, t->glyphs[t->len-1], 1, NULL, &abc);
324 		extents->abcC = abc.abcC;
325 		font_context_done(&fc);
326 		return;
327 	}
328 
329 	/* width more that 32K returned incorrectly by Win32 core */
330 	if (( div = 32768L / ( var font. maximalWidth ? var font. maximalWidth : 1)) == 0)
331 		div = 1;
332 
333 	while (( len = font_context_next(&fc)) > 0 ) {
334 		ABC abc;
335 		SIZE sz;
336 		int local_offset = offset;
337 		while ( local_offset < len) {
338 			int chunk_len = ( local_offset + div > len) ? ( len - local_offset) : div;
339 			if ( !GetTextExtentPointI( sys ps, ( WCHAR*) t->glyphs + local_offset, chunk_len, &sz)) apiErr;
340 			local_offset += div;
341 			extents-> abcB += sz.cx;
342 		}
343 		if ( offset == 0 ) {
344 			GetCharABCWidthsI( sys ps, t->glyphs[0], 1, NULL, &abc);
345 			extents->abcA = abc.abcA;
346 		} else if ( fc.stop ) {
347 			GetCharABCWidthsI( sys ps, t->glyphs[len-1], 1, NULL, &abc);
348 			extents->abcC = abc.abcC;
349 		}
350 		offset += len;
351 	}
352 	font_context_done(&fc);
353 }
354 
355 static int
gp_get_text_width(Handle self,const char * text,int len,int flags)356 gp_get_text_width( Handle self, const char* text, int len, int flags)
357 {
358 	ABC abc;
359 	gp_get_text_widths(self,text,len,flags,&abc);
360 	if ( flags & toAddOverhangs ) {
361 		if ( abc.abcA < 0) abc.abcB -= abc.abcA;
362 		if ( abc.abcC < 0) abc.abcB -= abc.abcC;
363 	}
364 	return abc.abcB;
365 }
366 
367 static int
gp_get_glyphs_width(Handle self,PGlyphsOutRec t,int flags)368 gp_get_glyphs_width( Handle self, PGlyphsOutRec t, int flags)
369 {
370 	ABC abc;
371 	if ( t-> fonts )
372 		gp_get_polyfont_widths(self,t,flags,&abc);
373 	else
374 		gp_get_text_widths( self, (const char*)t->glyphs, t->len, t->flags | toGlyphs, &abc);
375 	if ( abc.abcA < 0) abc.abcB -= abc.abcA;
376 	if ( abc.abcC < 0) abc.abcB -= abc.abcC;
377 	return abc.abcB;
378 }
379 
380 static void
paint_text_background(Handle self,const char * text,int x,int y,int len,int flags)381 paint_text_background( Handle self, const char * text, int x, int y, int len, int flags)
382 {
383 	int i, rop, color;
384 	Point p[5];
385 	FillPattern fp;
386 	ABC abc;
387 	uint32_t *palette;
388 
389 	palette = sys alphaArenaPalette;
390 	sys alphaArenaPalette = NULL;
391 	memcpy( &fp, apc_gp_get_fill_pattern( self), sizeof( FillPattern));
392 	if ( flags & toGlyphs) {
393 		PGlyphsOutRec t = (PGlyphsOutRec) text;
394 		if ( t-> fonts )
395 			gp_get_polyfont_widths(self,t,toAddOverhangs,&abc);
396 		else
397 			gp_get_text_widths( self, (const char*)t->glyphs, t->len, t->flags | toGlyphs | toAddOverhangs, &abc);
398 	} else {
399 		gp_get_text_widths(self, text, len, flags | toAddOverhangs, &abc);
400 	}
401 	gp_get_text_box(self, &abc, p);
402 	rop = apc_gp_get_rop( self);
403 	color = apc_gp_get_color(self);
404 
405 	apc_gp_set_fill_pattern( self, fillPatterns[fpSolid]);
406 	apc_gp_set_color( self, apc_gp_get_back_color(self));
407 	apc_gp_set_rop( self, ropCopyPut);
408 	for ( i = 0; i < 4; i++) {
409 		p[i].x += x;
410 		p[i].y += y;
411 	}
412 	i = p[2].x; p[2].x = p[3].x; p[3].x = i;
413 	i = p[2].y; p[2].y = p[3].y; p[3].y = i;
414 
415 	apc_gp_fill_poly( self, 4, p);
416 	apc_gp_set_rop( self, rop);
417 	apc_gp_set_color( self, color);
418 	apc_gp_set_fill_pattern( self, fp);
419 	sys alphaArenaPalette = palette;
420 }
421 
422 
423 Bool
apc_gp_text_out(Handle self,const char * text,int x,int y,int len,int flags)424 apc_gp_text_out( Handle self, const char * text, int x, int y, int len, int flags )
425 {objCheck false;{
426 	Bool ok = true;
427 	HDC ps = sys ps;
428 	int bk  = GetBkMode( ps), X = x, Y = y;
429 	int opa = is_apt( aptTextOpaque) ? OPAQUE : TRANSPARENT;
430 	Bool use_path, use_alpha;
431 
432 	int div = 32768L / (var font. maximalWidth ? var font. maximalWidth : 1);
433 	if ( div <= 0) div = 1;
434 	/* Win32 has problems with text_out strings that are wider than
435 	32K pixel - it doesn't plot the string at all. This hack is
436 	although ugly, but is better that Win32 default behaviour, and
437 	at least can be excused by the fact that all GP spaces have
438 	their geometrical limits. */
439 	if ( len > div) len = div;
440 
441 	if ( flags & toUTF8 ) {
442 		int mb_len;
443 		if ( !( text = ( char *) guts.alloc_utf8_to_wchar_visual( text, len, &mb_len))) return false;
444 		len = mb_len;
445 	}
446 
447 	use_alpha = sys alpha < 255;
448 	use_path = (GetROP2( sys ps) != R2_COPYPEN) && !use_alpha;
449 	if ( use_path ) {
450 		STYLUS_USE_BRUSH( ps);
451 		BeginPath(ps);
452 	} else if ( !use_alpha ) {
453 		STYLUS_USE_TEXT( ps);
454 		if ( opa != bk) SetBkMode( ps, opa);
455 	}
456 	SHIFT_XY(X,Y);
457 
458 	if ( use_alpha ) {
459 		if ( is_apt( aptTextOpaque))
460 			paint_text_background(self, (char*)text, x, y, len, flags & toUTF8);
461 		ok = aa_text_out( self, X, Y, (void*)text, len, flags & toUTF8);
462 	} else {
463 		ok = ( flags & toUTF8 ) ?
464 			TextOutW( ps, X, Y, ( U16*)text, len) :
465 			TextOutA( ps, X, Y, text, len);
466 		if ( !ok ) apiErr;
467 	}
468 
469 	if ( var font. style & (fsUnderlined | fsStruckOut))
470 		underscore_font( self, X, Y, gp_get_text_width( self, text, len, flags), use_alpha);
471 
472 	if ( use_path ) {
473 		EndPath(ps);
474 		FillPath(ps);
475 	} else if ( !use_alpha ) {
476 		if ( opa != bk) SetBkMode( ps, bk);
477 	}
478 
479 	if ( flags & toUTF8 ) free(( char *) text);
480 	return ok;
481 }}
482 
483 /*
484 
485 It seems that Windows decidecly doesn't shape combining characters, and
486 possibly doesn't kerning/ligatures in general for fixed width fonts. The two
487 functions, fix_combiners_pdx and fix_combiners_advances try to fix for this.
488 
489 It isn't clear whether this is Windows, or mono fonts in general, because
490 Courier New doesn't do that under x11/fontconfig, either, hinting at a very
491 special GSUB/GPOS setup there. This causes the addition of
492 MAPPER_FLAGS_COMBINING_SUPPORTED flag so that polyfont handler doesn't try to
493 run combiners on these fonts
494 
495 */
496 static void
fix_combiners_pdx(Handle self,PGlyphsOutRec t,INT * pdx)497 fix_combiners_pdx( Handle self, PGlyphsOutRec t, INT *pdx)
498 {
499 	int i;
500 	for ( i = 0; i < t->len; ) {
501 		int j, cluster_length, cluster_start;
502 		int first_glyph_width;
503 
504 		cluster_start = i++;
505 		for ( cluster_length = 1; i < t->len; ) {
506 			if ( t->advances[i] > 0 )
507 				break;
508 			cluster_length++;
509 			i++;
510 		}
511 
512 		if ( cluster_length == 1 )
513 			continue;
514 
515 		first_glyph_width = t->advances[cluster_start];
516 		for ( j = 1; j < cluster_length; j++)
517 			pdx[(cluster_start + j - 1) * 2] -= first_glyph_width * j;
518 		pdx[(cluster_start + j - 1) * 2] += first_glyph_width * (j - 1);
519 	}
520 }
521 
522 static Bool
gp_glyphs_out(Handle self,PGlyphsOutRec t,int x,int y,int * text_advance)523 gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y, int * text_advance)
524 {
525 	Bool ok;
526 	if ( t-> advances ) {
527 		#define SZ 1024
528 		INT dx[SZ], i, n, *pdx;
529 		int16_t *goffsets = t->positions;
530 		uint16_t *advances = t->advances;
531 
532 		if ( text_advance ) *text_advance = 0;
533 
534 		n = t-> len * 2;
535 		if ( n > SZ) {
536 			if ( !( pdx = malloc(sizeof(INT) * n)))
537 				pdx = dx;
538 		} else
539 			pdx = dx;
540 
541 		for ( i = 0; i < n; i += 2) {
542 			int gx     = *(goffsets++);
543 			int gy     = *(goffsets++);
544 			int adv    = *(advances++);
545 			pdx[i]     = adv;
546 			pdx[i + 1] = 0;
547 			if ( text_advance )
548 				*text_advance += adv;
549 
550 			if ( i == 0 ) {
551 				x += gx;
552 				y -= gy;
553 			} else {
554 				pdx[i - 2] += gx;
555 				pdx[i - 1] += gy;
556 			}
557 			pdx[i]     -= gx;
558 			pdx[i + 1] -= gy;
559 		}
560 
561 		if ( !(sys tmPitchAndFamily & TMPF_FIXED_PITCH ))
562 			fix_combiners_pdx(self, t, pdx);
563 		ok = ExtTextOutW(sys ps, x, y, ETO_GLYPH_INDEX | ETO_PDY, NULL, (LPCWSTR) t->glyphs, t->len, pdx);
564 		if ( pdx != dx ) free(pdx);
565 		#undef SZ
566 	} else {
567 		ok = ExtTextOutW(sys ps, x, y, ETO_GLYPH_INDEX, NULL, (LPCWSTR) t->glyphs, t->len, NULL);
568 		if ( text_advance ) {
569 			SIZE sz;
570 			if ( !GetTextExtentPointI( sys ps, (WCHAR*) t->glyphs, t->len, &sz)) apiErr;
571 			*text_advance += sz.cx;
572 		}
573 	}
574 	if ( !ok ) apiErr;
575 	return ok;
576 }
577 
578 Bool
apc_gp_glyphs_out(Handle self,PGlyphsOutRec t,int x,int y)579 apc_gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y)
580 {objCheck false;{
581 	Bool ok = true;
582 	HDC ps = sys ps;
583 	int xx, yy, savelen;
584 	int bk  = GetBkMode( ps);
585 	int opa = is_apt( aptTextOpaque) ? OPAQUE : TRANSPARENT;
586 	Bool use_path, use_alpha;
587 	FontContext fc;
588 	float s, c, fxx, fyy;
589 
590 	if ( t->len > 8192 ) t->len = 8192;
591 	use_path = GetROP2( sys ps) != R2_COPYPEN;
592 	use_alpha = sys alpha < 255;
593 	if ( use_path ) {
594 		STYLUS_USE_BRUSH( ps);
595 		BeginPath(ps);
596 	} else if ( use_alpha ) {
597 		if ( is_apt( aptTextOpaque))
598 			paint_text_background(self, (char*) t, x, y, 0, toGlyphs);
599 	} else {
600 		STYLUS_USE_TEXT( ps);
601 		if ( opa != bk) SetBkMode( ps, opa);
602 	}
603 
604 	if ( var font. direction != 0) {
605 		if ( sys font_sin == sys font_cos && sys font_sin == 0.0 ) {
606 			sys font_sin = sin( var font. direction / GRAD);
607 			sys font_cos = cos( var font. direction / GRAD);
608 		}
609 		s = sys font_sin;
610 		c = sys font_cos;
611 	} else {
612 		c = 1.0;
613 		s = 0.0;
614 	}
615 
616 	SHIFT_XY(x,y);
617 	fxx = xx = x;
618 	fyy = yy = y;
619 	savelen = t->len;
620 	font_context_init(&fc, self, t);
621 	while (( t-> len = font_context_next(&fc)) > 0 ) {
622 		int advance = 0;
623 		if ( !( ok = use_alpha ?
624 				aa_glyphs_out(self, t, xx, yy, fc.stop ? NULL : &advance, fc.curr) :
625 				gp_glyphs_out(self, t, xx, yy, fc.stop ? NULL : &advance)
626 			))
627 			break;
628 		if ( !fc.stop ) {
629 			fxx += (float)advance * c;
630 			fyy -= (float)advance * s;
631 			xx = fxx + ((fxx < 0) ? -.5 : +.5);
632 			yy = fyy + ((fyy < 0) ? -.5 : +.5);
633 
634 			t->glyphs    += t->len;
635 			if ( t-> advances ) {
636 				t->advances  += t->len;
637 				t->positions += t->len * 2;
638 			}
639 		}
640 	}
641 	font_context_done(&fc);
642 	t->len = savelen;
643 
644 	if ( var font. style & (fsUnderlined | fsStruckOut))
645 		underscore_font( self, x, yy, gp_get_glyphs_width( self, t, 0), use_alpha);
646 
647 	if ( use_path ) {
648 		EndPath(ps);
649 		FillPath(ps);
650 	} else if ( !use_alpha ) {
651 		if ( opa != bk) SetBkMode( ps, bk);
652 	}
653 
654 	return ok;
655 }}
656 
657 
658 /* Shaping code was borrowed from pangowin32-shape.c by Red Hat Software and Alexander Larsson */
659 
660 static WORD
make_langid(const char * lang)661 make_langid(const char *lang)
662 {
663 #define CASE(t,p,s) if (strcmp(lang, t) == 0) return MAKELANGID (LANG_##p, SUBLANG_##p##_##s)
664 #define CASEN(t,p) if (strcmp(lang, t) == 0) return MAKELANGID (LANG_##p, SUBLANG_NEUTRAL)
665 
666 /* Languages that most probably don't affect Uniscribe have been
667 * left out. Uniscribe is documented to use
668 * SCRIPT_CONTROL::uDefaultLanguage only to select digit shapes, so
669 * just leave languages with own digits.
670 */
671 
672 	CASEN ("ar", ARABIC);
673 	CASEN ("hy", ARMENIAN);
674 	CASEN ("as", ASSAMESE);
675 	CASEN ("az", AZERI);
676 	CASEN ("bn", BENGALI);
677 	CASE ("zh-tw", CHINESE, TRADITIONAL);
678 	CASE ("zh-cn", CHINESE, SIMPLIFIED);
679 	CASE ("zh-hk", CHINESE, HONGKONG);
680 	CASE ("zh-sg", CHINESE, SINGAPORE);
681 	CASE ("zh-mo", CHINESE, MACAU);
682 	CASEN ("dib", DIVEHI);
683 	CASEN ("fa", FARSI);
684 	CASEN ("ka", GEORGIAN);
685 	CASEN ("gu", GUJARATI);
686 	CASEN ("he", HEBREW);
687 	CASEN ("hi", HINDI);
688 	CASEN ("ja", JAPANESE);
689 	CASEN ("kn", KANNADA);
690 	CASE ("ks-in", KASHMIRI, INDIA);
691 	CASEN ("ks", KASHMIRI);
692 	CASEN ("kk", KAZAK);
693 	CASEN ("kok", KONKANI);
694 	CASEN ("ko", KOREAN);
695 	CASEN ("ky", KYRGYZ);
696 	CASEN ("ml", MALAYALAM);
697 	CASEN ("mni", MANIPURI);
698 	CASEN ("mr", MARATHI);
699 	CASEN ("mn", MONGOLIAN);
700 	CASE ("ne-in", NEPALI, INDIA);
701 	CASEN ("ne", NEPALI);
702 	CASEN ("or", ORIYA);
703 	CASEN ("pa", PUNJABI);
704 	CASEN ("sa", SANSKRIT);
705 	CASEN ("sd", SINDHI);
706 	CASEN ("syr", SYRIAC);
707 	CASEN ("ta", TAMIL);
708 	CASEN ("tt", TATAR);
709 	CASEN ("te", TELUGU);
710 	CASEN ("th", THAI);
711 	CASE ("ur-pk", URDU, PAKISTAN);
712 	CASE ("ur-in", URDU, INDIA);
713 	CASEN ("ur", URDU);
714 	CASEN ("uz", UZBEK);
715 
716 #undef CASE
717 #undef CASEN
718 
719 	return MAKELANGID (LANG_NEUTRAL, SUBLANG_NEUTRAL);
720 }
721 
722 static WORD
langid(const char * lang)723 langid(const char *lang)
724 {
725 #define LANGBUF 5
726 	static char last_lang[LANGBUF + 1] = "";
727 	static WORD last_langid = MAKELANGID (LANG_NEUTRAL, SUBLANG_NEUTRAL);
728 
729 	if ( strncmp( lang, last_lang, LANGBUF) == 0) return last_langid;
730 	last_langid = make_langid(lang);
731 	strncpy( last_lang, lang, LANGBUF);
732 	return last_langid;
733 #undef LANGBUF
734 }
735 
736 #pragma pack(1)
737 typedef struct {
738 	HFONT font;
739 	DWORD script;
740 } ScriptCacheKey;
741 #pragma pack()
742 
743 
744 /* convert UTF-32 to UTF-16, mark surrogates */
745 static Bool
build_wtext(PTextShapeRec t,WCHAR * wtext,unsigned int * wlen,unsigned int * first_surrogate_pair,unsigned int ** surrogate_map)746 build_wtext( PTextShapeRec t,
747 	WCHAR * wtext, unsigned int * wlen,
748 	unsigned int * first_surrogate_pair, unsigned int ** surrogate_map)
749 {
750 	int i;
751 	unsigned int index = 0, *curr = NULL;
752 	uint32_t *src;
753 	WCHAR *dst;
754 
755 	for ( i = *wlen = 0, src = t->text, dst = wtext; i < t->len; i++, index++) {
756 		uint32_t c = *src++;
757 		if ( c >= 0x10000 && c <= 0x10FFFF ) {
758 			c -= 0x10000;
759 			*(dst++) = 0xd800 + (c >> 10);
760 			*(dst++) = 0xdc00 + (c & 0x3ff);
761 			if ( !*surrogate_map ) {
762 				*first_surrogate_pair = i;
763 				*surrogate_map = malloc(sizeof(unsigned int*) * (t-> len - i) * 2);
764 				if ( !*surrogate_map ) return false;
765 				curr = *surrogate_map;
766 			}
767 			*(curr++) = index;
768 			*(curr++) = index;
769 			*wlen += 2;
770 		} else {
771 			if (( c >= 0xD800 && c <= 0xDFFF ) || ( c > 0x10FFFF )) c = 0;
772 			if ( *surrogate_map )
773 				*(curr++) = index;
774 			*(dst++) = c;
775 			(*wlen)++;
776 		}
777 	}
778 
779 	return true;
780 }
781 
782 static unsigned int
fill_null_glyphs(PTextShapeRec t,unsigned int char_pos,unsigned int itemlen,unsigned int * surrogate_map,unsigned int first_surrogate_pair,uint16_t advance)783 fill_null_glyphs(
784 	PTextShapeRec t,
785 	unsigned int char_pos, unsigned int itemlen,
786 	unsigned int * surrogate_map, unsigned int first_surrogate_pair,
787 	uint16_t advance
788 ) {
789 	int i, nglyphs;
790 	if ( surrogate_map ) {
791 		int p1 = char_pos;
792 		int p2 = p1 + itemlen - 1;
793 		if ( p1 >= first_surrogate_pair ) p1 = surrogate_map[p1 - first_surrogate_pair];
794 		if ( p2 >= first_surrogate_pair ) p2 = surrogate_map[p2 - first_surrogate_pair];
795 		nglyphs = p2 - p1 + 1;
796 	} else
797 		nglyphs = itemlen;
798 #ifdef _DEBUG
799 	printf("%d null glyphs, indexes: %x\n", nglyphs, t->indexes + t->n_glyphs);
800 #endif
801 	bzero( t->glyphs + t->n_glyphs, sizeof(uint16_t) * nglyphs);
802 	for ( i = 0; i < nglyphs; i++)
803 		t->indexes[ t->n_glyphs + i ] = i + char_pos;
804 	if ( t->advances ) {
805 		for ( i = 0; i < nglyphs; i++)
806 			t->advances[t-> n_glyphs + i] = advance;
807 		bzero( t->positions + t->n_glyphs * 2, sizeof(uint16_t) * nglyphs * 2);
808 	}
809 	t-> n_glyphs += nglyphs;
810 	return nglyphs;
811 }
812 
813 static void
convert_indexes(Bool rtl,unsigned int char_pos,unsigned int itemlen,unsigned int nglyphs,WORD * indexes,uint16_t * out_indexes)814 convert_indexes( Bool rtl, unsigned int char_pos, unsigned int itemlen, unsigned int nglyphs, WORD * indexes, uint16_t * out_indexes)
815 {
816 	int j, last_glyph, last_char;
817 	if (rtl) {
818 		for ( j = last_char = 0, last_glyph = nglyphs - 1; j < itemlen; j++) {
819 			int k, textlen = 1, glyphlen = last_glyph + 1;
820 			WORD curr_glyph = indexes[j];
821 			last_char = j;
822 			for ( k = j + 1; k < itemlen; k++) {
823 				if ( indexes[k] == curr_glyph )
824 					textlen++;
825 				else {
826 					glyphlen = curr_glyph - indexes[k];
827 					break;
828 				}
829 			}
830 			for ( k = 0; k < glyphlen; k++)
831 				out_indexes[last_glyph--] = j + char_pos;
832 			j += textlen - 1;
833 		}
834 	} else {
835 		for ( j = last_char = last_glyph = 0; j < itemlen; j++) {
836 			int k, textlen = 1, glyphlen = nglyphs - last_glyph;
837 			WORD curr_glyph = indexes[j];
838 			last_char = j;
839 			for ( k = j + 1; k < itemlen; k++) {
840 				if ( indexes[k] == curr_glyph )
841 					textlen++;
842 				else {
843 					glyphlen = indexes[k] - curr_glyph;
844 					break;
845 				}
846 			}
847 			for (k = 0; k < glyphlen; k++)
848 				out_indexes[last_glyph++] = j + char_pos;
849 			j += textlen - 1;
850 		}
851 	}
852 }
853 
854 /* see explanation in fix_combiners_pdx */
855 static void
fix_combiners_advances(Handle self,PTextShapeRec t,int nglyphs)856 fix_combiners_advances( Handle self, PTextShapeRec t, int nglyphs)
857 {
858 	int i;
859 	for ( i = 0; i < nglyphs; ) {
860 		int j, cluster_length, cluster_glyph_start;
861 		int cluster_text_start = t->indexes[t->n_glyphs + i];
862 
863 		cluster_glyph_start = i++;
864 		for ( cluster_length = 1; i < nglyphs; ) {
865 			if ( t->indexes[t->n_glyphs + i] != cluster_text_start )
866 				break;
867 			cluster_length++;
868 			i++;
869 		}
870 
871 		if ( cluster_length == 1 )
872 			continue;
873 
874 		for ( j = 1; j < cluster_length; j++) {
875 			uint32_t c = t->text[t->n_glyphs + cluster_text_start + j];
876 			if ( c < 0x300 || c > 0x36f )
877 				continue;
878 			t->advances[t->n_glyphs + cluster_glyph_start + j] = 0;
879 		}
880 	}
881 }
882 
883 static Bool
win32_unicode_shaper(Handle self,PTextShapeRec t)884 win32_unicode_shaper( Handle self, PTextShapeRec t)
885 {
886 	Bool ok = false;
887 	HRESULT hr;
888 	WCHAR * wtext = NULL;
889 	uint16_t * out_indexes, default_advance = 0;
890 	int i, item, item_step, nitems;
891 	SCRIPT_CONTROL control;
892 	SCRIPT_ITEM *items = NULL;
893 	WORD *indexes = NULL;
894 	SCRIPT_VISATTR *visuals = NULL;
895 	int *advances = NULL;
896 	GOFFSET *goffsets = NULL;
897 	unsigned int * surrogate_map = NULL, first_surrogate_pair = 0, wlen;
898 
899 	if ((items = malloc(sizeof(SCRIPT_ITEM) * (t-> len + 1))) == NULL)
900 		goto EXIT;
901 	if ((indexes = malloc(sizeof(WORD) * t-> n_glyphs_max)) == NULL)
902 		goto EXIT;
903 	if ((visuals = malloc(sizeof(SCRIPT_VISATTR) * t-> n_glyphs_max)) == NULL)
904 		goto EXIT;
905 	if ((wtext = malloc(sizeof(WCHAR) * 2 * t->len)) == NULL)
906 		goto EXIT;
907 	if ((advances = malloc(sizeof(int) * t->n_glyphs_max)) == NULL)
908 		goto EXIT;
909 	if ((goffsets = malloc(sizeof(GOFFSET) * t->n_glyphs_max)) == NULL)
910 		goto EXIT;
911 
912 	build_wtext( t, wtext, &wlen, &first_surrogate_pair, &surrogate_map);
913 
914 	bzero(&control, sizeof(control));
915 	control.uDefaultLanguage = t->language ?
916 		langid(t->language) :
917 		MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
918 
919 	if ((hr = ScriptItemize(wtext, wlen, t->n_glyphs_max, &control, NULL, items, &nitems)) != S_OK) {
920 		apiHErr(hr);
921 		goto EXIT;
922 	}
923 #ifdef _DEBUG
924 	printf("itemizer: %d\n", nitems);
925 #endif
926 
927 	if ( t->flags & toRTL ) {
928 		item = nitems - 1;
929 		item_step = -1;
930 	} else {
931 		item = 0;
932 		item_step = 1;
933 	}
934 
935 	for (
936 		i = 0, out_indexes = t-> indexes;
937 		i < nitems;
938 		i++, item += item_step
939 	) {
940 		int j, itemlen, nglyphs;
941 
942 		SCRIPT_CACHE * script_cache;
943 		ScriptCacheKey key = { sys fontResource->hfont, items[item].a.eScript };
944 		if (( script_cache = ( SCRIPT_CACHE*) hash_fetch( scriptCacheMan, &key, sizeof(key))) == NULL) {
945 			if ((script_cache = malloc(sizeof(SCRIPT_CACHE))) == NULL)
946 				goto EXIT;
947 			*script_cache = NULL;
948 			hash_store( scriptCacheMan, &key, sizeof(key), script_cache);
949 		}
950 
951 		itemlen = items[item+1].iCharPos - items[item].iCharPos;
952 		items[item].a.fRTL = (t->flags & toRTL) ? 1 : 0;
953 		//printf("shape(%d @ %d) len %d %s\n", item, items[item].iCharPos, itemlen, items[item].a.fRTL ? "RTL" : "LTR");
954 		if (( hr = ScriptShape(
955 			sys ps, script_cache,
956 			wtext + items[item].iCharPos, itemlen, t->n_glyphs_max,
957 			&items[item].a,
958 			t->glyphs + t->n_glyphs, indexes, visuals,
959 			&nglyphs
960 		)) != S_OK) {
961 			if ( hr == USP_E_SCRIPT_NOT_IN_FONT) {
962 #ifdef _DEBUG
963 				printf("USP_E_SCRIPT_NOT_IN_FONT\n");
964 #endif
965 				if ( default_advance == 0 ) {
966 					ABC abc;
967 					if ( GetCharABCWidthsI( sys ps, 0, 1, NULL, &abc))
968 						default_advance = abc.abcA + abc.abcB + abc.abcC;
969 					if ( default_advance <= 0 )
970 						default_advance = 1;
971 				}
972 				out_indexes += fill_null_glyphs(t, items[item].iCharPos, itemlen, surrogate_map, first_surrogate_pair, default_advance);
973 				continue;
974 			}
975 			apiHErr(hr);
976 			goto EXIT;
977 		}
978 		convert_indexes( items[item].a.fRTL, items[item].iCharPos, itemlen, nglyphs, indexes, out_indexes);
979 #ifdef _DEBUG
980 		{
981 			int i;
982 			printf("shape input %d: ", item);
983 			for ( i = 0; i < itemlen; i++) {
984 				printf("%x ", *(wtext + items[item].iCharPos + i));
985 			}
986 			printf("\n");
987 			printf("shape output: ");
988 			for ( i = 0; i < nglyphs; i++) {
989 				printf("%d(%x) ", indexes[i], t->glyphs[t->n_glyphs + i]);
990 			}
991 			printf("\n");
992 			printf("indexes: ");
993 			for ( i = 0; i < nglyphs; i++) {
994 				printf("%d ", out_indexes[i]);
995 			}
996 			printf("\n");
997 		}
998 #endif
999 
1000 		/* map from utf16 */
1001 		if ( surrogate_map ) {
1002 			int k;
1003 			uint16_t * out_glyphs = t-> glyphs + t-> n_glyphs;
1004 			for ( j = k = 0; j < nglyphs; j++, k++) {
1005 				if ( k < j)
1006 					out_glyphs[k] = out_glyphs[j];
1007 				if ( out_indexes[j] >= first_surrogate_pair)
1008 					out_indexes[k] = surrogate_map[out_indexes[j] - first_surrogate_pair];
1009 				else if ( k < j )
1010 					out_indexes[k] = out_indexes[j];
1011 			}
1012 		}
1013 
1014 		if ( t-> advances ) {
1015 			GOFFSET * i_g;
1016 			int * i_a, i;
1017 			ABC abc;
1018 			int16_t * o_g;
1019 			uint16_t *o_a;
1020 
1021 			if (( hr = ScriptPlace(sys ps, script_cache, t->glyphs + t->n_glyphs, nglyphs,
1022 			       visuals, &items[item].a,
1023 			       advances, goffsets, &abc)) != S_OK
1024 			) {
1025 				apiHErr(hr);
1026 				goto EXIT;
1027 			}
1028 			for (
1029 				i = 0,
1030 				i_a = advances,
1031 				i_g = goffsets,
1032 				o_a = t->advances  + t-> n_glyphs,
1033 				o_g = t->positions + t-> n_glyphs * 2;
1034 				i < nglyphs;
1035 				i++
1036 			) {
1037 				*(o_a++) = *(i_a++);
1038 				*(o_g++) = i_g->du;
1039 				*(o_g++) = i_g->dv;
1040 				i_g++;
1041 			}
1042 			if ( !(sys tmPitchAndFamily & TMPF_FIXED_PITCH ))
1043 				fix_combiners_advances(self, t, nglyphs);
1044 		}
1045 
1046 		t-> n_glyphs += nglyphs;
1047 		out_indexes += nglyphs;
1048 	}
1049 
1050 	ok = true;
1051 
1052 EXIT:
1053 	if ( surrogate_map  ) free(surrogate_map);
1054 	if ( goffsets ) free(goffsets);
1055 	if ( advances ) free(advances);
1056 	if ( indexes )  free(indexes);
1057 	if ( visuals  ) free(visuals);
1058 	if ( items    ) free(items);
1059 	if ( wtext    ) free(wtext);
1060 	return ok;
1061 }
1062 
1063 static Bool
win32_mapper(Handle self,PTextShapeRec t,Bool unicode)1064 win32_mapper( Handle self, PTextShapeRec t, Bool unicode)
1065 {
1066 	int i, len = t->len;
1067 	uint32_t *src = t-> text;
1068 	uint16_t *glyphs = t->glyphs;
1069 	INT buf[8192];
1070 	DWORD ret;
1071 
1072 	if ( len > 8192 ) len = 8192;
1073 
1074 	if ( unicode ) {
1075 		WCHAR *dst = (WCHAR*) buf;
1076 		for ( i = 0; i < t->len; i++)
1077 			*(dst++) = *(src++);
1078 		ret = GetGlyphIndicesW( sys ps, (LPCWSTR)buf, t->len, t->glyphs, GGI_MARK_NONEXISTING_GLYPHS);
1079 	} else {
1080 		char *dst = (char*) buf;
1081 		for ( i = 0; i < t->len; i++)
1082 			*(dst++) = *(src++);
1083 		ret = GetGlyphIndicesA( sys ps, (LPCSTR)buf, t->len, t->glyphs, GGI_MARK_NONEXISTING_GLYPHS);
1084 	}
1085 	if ( ret == GDI_ERROR)
1086 		apiErrRet;
1087 	t-> n_glyphs = ret;
1088 	for ( i = 0; i < t->n_glyphs; i++, glyphs++)
1089 		if (*glyphs == 0xffff) *glyphs = 0;
1090 
1091 	if ( t->advances ) {
1092 		INT *widths = buf;
1093 		uint16_t *advances = t->advances;
1094 		bzero(t->positions, t->n_glyphs * sizeof(int16_t) * 2);
1095 		if ( GetCharWidthI(sys ps, 0, t->n_glyphs, t->glyphs, buf) == 0)
1096 			apiErrRet;
1097 		for ( i = 0; i < t->n_glyphs; i++, widths++)
1098 			*(advances++) = (*widths >= 0) ? *widths : 0;
1099 	}
1100 
1101 	return true;
1102 }
1103 
1104 static Bool
win32_byte_mapper(Handle self,PTextShapeRec t)1105 win32_byte_mapper( Handle self, PTextShapeRec t)
1106 {
1107 	return win32_mapper(self, t, false);
1108 }
1109 
1110 static Bool
win32_unicode_mapper(Handle self,PTextShapeRec t)1111 win32_unicode_mapper( Handle self, PTextShapeRec t)
1112 {
1113 	return win32_mapper(self, t, true);
1114 }
1115 
1116 PTextShapeFunc
apc_gp_get_text_shaper(Handle self,int * type)1117 apc_gp_get_text_shaper( Handle self, int * type)
1118 {
1119 	if ( *type == tsBytes ) {
1120 		*type = (sys tmPitchAndFamily & TMPF_TRUETYPE) ?
1121 			tsGlyphs :
1122 			tsNone;
1123 		return win32_byte_mapper;
1124 	} else if ( *type == tsGlyphs ) {
1125 		*type = (sys tmPitchAndFamily & TMPF_TRUETYPE) ?
1126 			tsGlyphs :
1127 			tsNone;
1128 		return win32_unicode_mapper;
1129 	} else {
1130 		*type = (sys tmPitchAndFamily & TMPF_TRUETYPE) ?
1131 			tsFull :
1132 			tsNone;
1133 		return win32_unicode_shaper;
1134 	}
1135 }
1136 
1137 PFontABC
apc_gp_get_font_abc(Handle self,int first,int last,int flags)1138 apc_gp_get_font_abc( Handle self, int first, int last, int flags)
1139 {objCheck NULL;{
1140 	int i;
1141 	PFontABC  f1;
1142 	ABCFLOAT *f2 = NULL;
1143 	ABC *f3 = NULL;
1144 
1145 	if ( flags & toGlyphs ) {
1146 		if ( !(f3 = ( ABC*) malloc(( last - first + 1) * sizeof( ABC))))
1147 			return NULL;
1148 	} else {
1149 		if ( !( f2 = ( ABCFLOAT*) malloc(( last - first + 1) * sizeof( ABCFLOAT))))
1150 			return NULL;
1151 	}
1152 
1153 	if ( !( f1 = ( PFontABC) malloc(( last - first + 1) * sizeof( FontABC)))) {
1154 		if ( f2 ) free(f2);
1155 		if ( f3 ) free(f3);
1156 		return NULL;
1157 	}
1158 
1159 
1160 	if ( flags & toGlyphs ) {
1161 		if (!GetCharABCWidthsI( sys ps, first, last - first + 1, NULL, f3)) apiErr;
1162 	} else if ( flags & toUnicode ) {
1163 		if (!GetCharABCWidthsFloatW( sys ps, first, last, f2)) apiErr;
1164 	} else {
1165 		if (!GetCharABCWidthsFloatA( sys ps, first, last, f2)) apiErr;
1166 	}
1167 
1168 	for ( i = 0; i <= last - first; i++) {
1169 		f1[i].a = f2 ? f2[i].abcfA : f3[i].abcA;
1170 		f1[i].b = f2 ? f2[i].abcfB : f3[i].abcB;
1171 		f1[i].c = f2 ? f2[i].abcfC : f3[i].abcC;
1172 	}
1173 
1174 	if ( f2) free( f2);
1175 	if ( f3) free( f3);
1176 	return f1;
1177 }}
1178 
1179 /* extract vertical data from a bitmap */
1180 Bool
gp_get_font_def_bitmap(Handle self,int first,int last,int flags,PFontABC abc)1181 gp_get_font_def_bitmap( Handle self, int first, int last, int flags, PFontABC abc)
1182 {
1183 	Bool ret = true;
1184 	Font font;
1185 	int i, j, h, w, lineSize;
1186 	HBITMAP bm, oldBM;
1187 	BITMAPINFO bi;
1188 	HDC dc;
1189 	LOGFONTW logfont;
1190 	HFONT hfont, oldFont;
1191 	Byte * glyph, * empty;
1192 
1193 	/* don't to need exact dimension, just to fit the glyph is enough */
1194 	w = var font. maximalWidth * 2;
1195 	h = var font. height;
1196 	lineSize = (( w + 31) / 32) * 4;
1197 	w = lineSize * 8;
1198 	if ( !( glyph = malloc( lineSize * ( h + 1 ))))
1199 		return false;
1200 	empty = glyph + lineSize * h;
1201 	memset( empty, 0xff, lineSize);
1202 
1203 	if ( !( dc = CreateCompatibleDC( NULL ))) {
1204 		free( glyph );
1205 		return false;
1206 	}
1207 	if ( !( bm = CreateBitmap( w, h, 1, 1, NULL))) {
1208 		free( glyph );
1209 		return false;
1210 	}
1211 
1212 	bi. bmiHeader. biSize         = sizeof( bi. bmiHeader);
1213 	bi. bmiHeader. biPlanes       = 1;
1214 	bi. bmiHeader. biBitCount     = 1;
1215 	bi. bmiHeader. biSizeImage    = lineSize * h;
1216 	bi. bmiHeader. biWidth        = w;
1217 	bi. bmiHeader. biHeight       = h;
1218 	bi. bmiHeader. biCompression  = BI_RGB;
1219 	bi. bmiHeader. biClrUsed      = 2;
1220 	bi. bmiHeader. biClrImportant = 2;
1221 
1222 	oldBM    = SelectObject( dc, bm );
1223 
1224 	font = var font;
1225 	font. direction = 0;
1226 	font_font2logfont( &font, &logfont);
1227 	hfont = CreateFontIndirectW( &logfont);
1228 	oldFont = SelectObject( dc, hfont );
1229 
1230 	memset( abc, 0, sizeof(FontABC) * (last - first + 1));
1231 	for ( i = 0; i <= last - first; i++) {
1232 		Rectangle( dc, -1, -1, w+2, h+2 );
1233 		if ( flags & toGlyphs ) {
1234 			WCHAR ch = first + i;
1235 			ExtTextOutW( dc, var font. maximalWidth, 0, ETO_GLYPH_INDEX, NULL, &ch, 1, NULL);
1236 		} else if ( flags & toUnicode ) {
1237 			WCHAR ch = first + i;
1238 			TextOutW( dc, var font. maximalWidth, 0, &ch, 1);
1239 		} else {
1240 			CHAR ch = first + i;
1241 			TextOutA( dc, var font. maximalWidth, 0, &ch, 1);
1242 		}
1243 
1244 		if ( !GetDIBits( dc, bm, 0, h, glyph, &bi, DIB_RGB_COLORS)) {
1245 			ret = false;
1246 			break;
1247 		}
1248 
1249 /*
1250 		for ( j = 0; j < h; j++) {
1251 			int k, l;
1252 			for ( k = 0; k < lineSize; k++) {
1253 				Byte * p = glyph + j * lineSize + k;
1254 				printf(".");
1255 				for ( l = 0; l < 8; l++) {
1256 					int z = (*p) & ( 1 << (7-l) );
1257 					printf("%s", z ? "*" : " ");
1258 				}
1259 			}
1260 			printf("\n");
1261 		}
1262 */
1263 
1264 		for ( j = 0; j < h; j++) {
1265 			if ( memcmp( glyph + j * lineSize, empty, lineSize) != 0 ) {
1266 				abc[i]. a = j;
1267 				break;
1268 			}
1269 		}
1270 		for ( j = h - 1; j >= 0; j--) {
1271 			if ( memcmp( glyph + j * lineSize, empty, lineSize) != 0 ) {
1272 				abc[i]. c = h - j - 1;
1273 				break;
1274 			}
1275 		}
1276 
1277 		if ( abc[i]. a != 0 || abc[i].c != 0)
1278 			abc[i]. b = h - abc[i]. a - abc[i]. c;
1279 	}
1280 
1281 	SelectObject( dc, oldFont);
1282 	SelectObject( dc, oldBM );
1283 	DeleteObject( hfont );
1284 	DeleteObject( bm );
1285 	DeleteDC( dc );
1286 	free( glyph );
1287 	return ret;
1288 }
1289 
1290 PFontABC
apc_gp_get_font_def(Handle self,int first,int last,int flags)1291 apc_gp_get_font_def( Handle self, int first, int last, int flags)
1292 {objCheck NULL;{
1293 	int i;
1294 	DWORD ret;
1295 	PFontABC f1;
1296 	MAT2 gmat = { {0, 1}, {0, 0}, {0, 0}, {0, 1} };
1297 	GLYPHMETRICS g;
1298 
1299 	f1 = ( PFontABC) malloc(( last - first + 1) * sizeof( FontABC));
1300 	if ( !f1) return NULL;
1301 
1302 	for ( i = 0; i <= last - first; i++) {
1303 		memset(&g, 0, sizeof(g));
1304 		if ( flags & toGlyphs ) {
1305 			ret = GetGlyphOutlineW(sys ps, i + first, GGO_METRICS | GGO_GLYPH_INDEX, &g, sizeof(g), NULL, &gmat);
1306 		} else if ( flags & toUnicode ) {
1307 			ret = GetGlyphOutlineW(sys ps, i + first, GGO_METRICS, &g, sizeof(g), NULL, &gmat);
1308 		} else {
1309 			ret = GetGlyphOutlineA(sys ps, i + first, GGO_METRICS, &g, sizeof(g), NULL, &gmat);
1310 		}
1311 		if ( ret == GDI_ERROR ) {
1312 			if ( !gp_get_font_def_bitmap( self, first, last, flags, f1 )) {
1313 				free( f1 );
1314 				return NULL;
1315 			}
1316 			return f1;
1317 		}
1318 		f1[i]. a = var font. descent + g.gmptGlyphOrigin. y - g.gmBlackBoxY; /* XXX g.gmCellIncY ? */
1319 		f1[i]. b = g.gmBlackBoxY;
1320 		f1[i]. c = var font.ascent - g.gmptGlyphOrigin. y;
1321 	}
1322 
1323 	return f1;
1324 }}
1325 
1326 /*
1327  get_opentype_cmap1213_font_ranges is based on the following:
1328 
1329  wine:  dlls/dwrite/opentype.c
1330  	Copyright 2014 Aric Stewart for CodeWeavers
1331 
1332  pango: pangowin32.c (
1333  	Copyright (C) 1999 Red Hat Software
1334  	Copyright (C) 2000 Tor Lillqvist
1335  	Copyright (C) 2001 Alexander Larsson
1336 
1337  Thank you!
1338 */
1339 
1340 #define MAKE_TT_TABLE_NAME(c1, c2, c3, c4) \
1341    (((DWORD)c4) << 24 | ((DWORD)c3) << 16 | ((DWORD)c2) << 8 | ((DWORD)c1))
1342 #define CMAP (MAKE_TT_TABLE_NAME('c','m','a','p'))
1343 #define CMAP_HEADER_SIZE 4
1344 #define ENCODING_TABLE_SIZE 8
1345 #define BE16(x) (((x&0xff00)>>8)|((x&0xff)<<8))
1346 #define BE32(x) (((x&0xff000000)>>24)|((x&0xff0000)>>8)|((x&0xff00)<<8)|((x&0xff)<<24))
1347 
1348 #pragma pack(1)
1349 struct cmap_encoding_subtable
1350 {
1351 	WORD platform_id;
1352 	WORD encoding_id;
1353 	DWORD offset;
1354 };
1355 #pragma pack()
1356 
1357 unsigned long *
get_opentype_cmap1213_font_ranges(HDC ps,int * count)1358 get_opentype_cmap1213_font_ranges( HDC ps, int * count)
1359 {
1360 	static const uint16_t encodings[][2] = {
1361 		{ 3, 0 }, /* MS Symbol encoding is preferred. */
1362 		{ 3, 10 },
1363 		{ 0, 6 },
1364 		{ 0, 4 },
1365 		{ 3, 1 },
1366 		{ 0, 3 },
1367 		{ 0, 2 },
1368 		{ 0, 1 },
1369 		{ 0, 0 },
1370 	};
1371 
1372 	uint16_t i, j, n_tables, format;
1373 	uint32_t cmap_size, offset, n_groups, *groups;
1374 	unsigned long * ret = NULL;
1375 	struct cmap_encoding_subtable *table, *found_record;
1376 	uint8_t *cmap = NULL;
1377 
1378 	cmap_size = GetFontData(ps, CMAP, 0, NULL, 0);
1379 	if ( cmap_size == 0 || cmap_size == GDI_ERROR)
1380 		goto FAIL;
1381 	if ( !( cmap = malloc(cmap_size))) {
1382 		warn("Not enough memory");
1383 		goto FAIL;
1384 	}
1385 	if (GetFontData(ps, CMAP, 0, cmap, cmap_size) != cmap_size)
1386 		goto FAIL;
1387 #define READ16(v,offset) \
1388 	if (offset + 2 < cmap_size) \
1389 		v = BE16( *((uint16_t*)(cmap + offset)) ); \
1390 		else goto FAIL
1391 #define READ32(v,offset) \
1392 	if (offset + 4 < cmap_size) \
1393 		v = BE32( *((uint32_t*)(cmap + offset)) ); \
1394 		else goto FAIL
1395 #define READPTR(v,offset,size) \
1396 	if (offset + size <= cmap_size) \
1397 		v = (void*)(cmap + offset); \
1398 		else goto FAIL
1399 
1400 	READ16(n_tables, 2);
1401 	READPTR(table, CMAP_HEADER_SIZE, ENCODING_TABLE_SIZE * n_tables);
1402 	for (i = 0, found_record = NULL; i < sizeof(encodings)/sizeof(uint16_t)/2; i++) {
1403 		struct cmap_encoding_subtable *t;
1404 		uint16_t *enc = (uint16_t*)( encodings + i );
1405 		for ( j = 0, t = table; j < n_tables; j++, t++)
1406 			if ( enc[0] == BE16(t->platform_id) && enc[1] == BE16(t->encoding_id)) {
1407 				found_record = t;
1408 				goto STOP;
1409 			}
1410 	}
1411 	goto FAIL;
1412 STOP:
1413 
1414 	offset = BE32(found_record->offset);
1415 	READ16(format, offset);
1416 	/* don't implement logic for BMP planes as GetFontUnicodeRanges can retrieve it just fine */
1417 	if ( format != 12 && format != 13 )
1418 		return NULL;
1419 
1420 	READ32(n_groups, offset + 12);
1421 	READPTR(groups, offset + 16, n_groups * 3 * 4);
1422 
1423 	if ( !( ret = malloc(n_groups * sizeof(unsigned long) * 2))) {
1424 		warn("Not enough memory");
1425 		goto FAIL;
1426 	}
1427 	for ( i = 0; i < n_groups; i++) {
1428 		ret[(*count)++] = BE32(groups[i * 3]);
1429 		ret[(*count)++] = BE32(groups[i * 3 + 1]);
1430 	}
1431 
1432 	free(cmap);
1433 	return ret;
1434 
1435 FAIL:
1436 	if ( cmap ) free(cmap);
1437 	if ( ret ) free(ret);
1438 	*count = 0;
1439 	return NULL;
1440 }
1441 
1442 #undef READPTR
1443 #undef READ16
1444 #undef READ32
1445 #undef BE16
1446 #undef BE32
1447 #undef CMAP
1448 #undef CMAP_HEADER_SIZE
1449 #undef ENCODING_TABLE_SIZE
1450 #undef MAKE_TT_TABLE_NAME
1451 
1452 unsigned long *
get_font_ranges(HDC ps,int * count)1453 get_font_ranges( HDC ps, int * count)
1454 {
1455 	DWORD i, j, size;
1456 	GLYPHSET * gs;
1457 	unsigned long * ret;
1458 	WCRANGE *src;
1459 
1460 	*count = 0;
1461 	ret = get_opentype_cmap1213_font_ranges( ps, count );
1462 	if ( ret != NULL ) return ret;
1463 
1464 	if (( size = GetFontUnicodeRanges( ps, NULL )) == 0)
1465 		return NULL;
1466 	if (!( gs = malloc(size)))
1467 		apiErrRet;
1468 	bzero(gs, size);
1469 	gs-> cbThis = size;
1470 	if ( GetFontUnicodeRanges( ps, gs ) == 0) {
1471 		free(gs);
1472 		apiErrRet;
1473 	}
1474 	if ( !( ret = malloc(sizeof(unsigned long) * 2 * gs->cRanges))) {
1475 		free(gs);
1476 		return NULL;
1477 	}
1478 	for ( i = j = 0, src = gs-> ranges; i < gs->cRanges; i++, src++) {
1479 		ret[j++] = src->wcLow;
1480 		ret[j++] = src->wcLow + src->cGlyphs - 1;
1481 	}
1482 	*count = j;
1483 
1484 	free(gs);
1485 	return ret;
1486 }
1487 
1488 unsigned long *
apc_gp_get_font_ranges(Handle self,int * count)1489 apc_gp_get_font_ranges( Handle self, int * count)
1490 {
1491 	objCheck NULL;
1492 	return get_font_ranges(sys ps, count);
1493 }
1494 
1495 unsigned long *
apc_gp_get_mapper_ranges(PFont font,int * count,unsigned int * flags)1496 apc_gp_get_mapper_ranges(PFont font, int * count, unsigned int * flags)
1497 {
1498 	HDC dc;
1499 	unsigned long * ret;
1500 	char name[256];
1501 	LOGFONTW logfont;
1502 	HFONT hfont, hstock;
1503 
1504 	*count = 0;
1505 
1506 	strncpy(name, font->name, 256);
1507 	apc_font_pick( NULL_HANDLE, font, font);
1508 	if ( strcmp( font->name, name ) != 0 )
1509 		return NULL;
1510 
1511 	font_font2logfont( font, &logfont);
1512 	logfont.lfHeight = 0;
1513 	logfont.lfWidth  = 0;
1514 	if ( !( hfont = CreateFontIndirectW( &logfont))) {
1515 		apiErr;
1516 		return NULL;
1517 	}
1518 
1519 	if ( !( dc = dc_alloc())) {
1520 		DeleteObject(hfont);
1521 		return NULL;
1522 	}
1523 
1524 	hstock = SelectObject(dc, hfont);
1525 	ret = get_font_ranges(dc, count);
1526 
1527 	*flags = MAPPER_FLAGS_COMBINING_SUPPORTED;
1528 
1529 	SelectObject(dc, hstock);
1530 	dc_free();
1531 	DeleteObject(hfont);
1532 
1533 	return ret;
1534 }
1535 
1536 static char *
single_lang(const char * lang1)1537 single_lang(const char * lang1)
1538 {
1539 	char * m;
1540 	int l = strlen(lang1) + 1;
1541 	m = malloc( l + 3 + 1 );
1542 	strcpy( m, "en" );
1543 	strcpy( m + 3, lang1 );
1544 	m[l + 3] = 0;
1545 	return m;
1546 }
1547 
1548 typedef struct {
1549 	DWORD v[4];
1550 	const char * str;
1551 } LangId;
1552 
1553 static LangId languages[] = {
1554 	{
1555 		{0x00000001,0x00000000,0x00000000,0x00000000},
1556 		"fj ho ia ie io kj kwm ms ng nr om rn rw sn so ss st sw ts uz xh za zu"
1557 	},{
1558 		{0x00000003,0x00000000,0x00000000,0x00000000},
1559 		"aa an ay bi br ch da de en es eu fil fo fur fy gd gl gv ht id is it jv lb li mg nb nds nl nn no oc pap-an pap-aw pt rm sc sg sma smj sq su sv tl vo wa yap"
1560 	},{
1561 		{0x00000007,0x00000000,0x00000000,0x00000000},
1562 		"af ca co crh cs csb et fi fr hsb hu kl ku-tr mt na nso pl se sk smn tk tn tr vot wen wo"
1563 	},{
1564 		{0x20000007,0x00000000,0x00000000,0x00000000},
1565 		"cy ga gn"
1566 	},{
1567 		{0x0000000f,0x00000000,0x00000000,0x00000000},
1568 		"ro"
1569 	},{
1570 		{0x0000001f,0x00000000,0x00000000,0x00000000},
1571 		"az-az sms"
1572 	},{
1573 		{0x0000005f,0x00000000,0x00000000,0x00000000},
1574 		"ee ln"
1575 	},{
1576 		{0x2000005f,0x00000000,0x00000000,0x00000000},
1577 		"ak fat tw"
1578 	},{
1579 		{0x0000006f,0x00000000,0x00000000,0x00000000},
1580 		"nv"
1581 	},{
1582 		{0x2000004f,0x00000000,0x00000000,0x00000000},
1583 		"vi yo"
1584 	},{
1585 		{0x0000020f,0x00000000,0x00000000,0x00000000},
1586 		"mo"
1587 	},{
1588 		{0x00000027,0x00000000,0x00000000,0x00000000},
1589 		"ty"
1590 	},{
1591 		{0x20000003,0x00000000,0x00000000,0x00000000},
1592 		"ast"
1593 	},{
1594 		{0x00000023,0x00000000,0x00000000,0x00000000},
1595 		"qu quz"
1596 	},{
1597 		{0x00000043,0x00000000,0x00000000,0x00000000},
1598 		"shs"
1599 	},{
1600 		{0x20000043,0x00000000,0x00000000,0x00000000},
1601 		"bin"
1602 	},{
1603 		{0x00000005,0x00000000,0x00000000,0x00000000},
1604 		"bs eo hr ki la lg lt lv mh ny sl"
1605 	},{
1606 		{0x20000005,0x00000000,0x00000000,0x00000000},
1607 		"mi"
1608 	},{
1609 		{0x0000000d,0x00000000,0x00000000,0x00000000},
1610 		"kw"
1611 	},{
1612 		{0x0000001d,0x00000000,0x00000000,0x00000000},
1613 		"bm ff"
1614 	},{
1615 		{0x2000001d,0x00000000,0x00000000,0x00000000},
1616 		"ber-dz kab"
1617 	},{
1618 		{0x00000025,0x00000000,0x00000000,0x00000000},
1619 		"haw"
1620 	},{
1621 		{0x00000205,0x00000000,0x00000000,0x00000000},
1622 		"sh"
1623 	},{
1624 		{0x20000001,0x00000000,0x00000000,0x00000000},
1625 		"ig ve"
1626 	},{
1627 		{0x00000009,0x00000000,0x00000000,0x00000000},
1628 		"kr"
1629 	},{
1630 		{0x00000019,0x00000000,0x00000000,0x00000000},
1631 		"ha sco"
1632 	},{
1633 		{0x00000021,0x00000000,0x00000000,0x00000000},
1634 		"sm to"
1635 	},{
1636 		{0x20000041,0x00000000,0x00000000,0x00000000},
1637 		"hz"
1638 	},{
1639 		{0x00000400,0x00000000,0x00000000,0x00000000},
1640 		"hy"
1641 	},{
1642 		{0x00000800,0x00000000,0x00000000,0x00000000},
1643 		"he yi"
1644 	},{
1645 		{0x00002000,0x00000000,0x00000000,0x00000000},
1646 		"ar az-ir fa ks ku-iq ku-ir lah ota pa-pk pes prs ps-af ps-pk sd ug ur"
1647 	},{
1648 		{0x00004000,0x00000000,0x00000000,0x00000000},
1649 		"nqo"
1650 	},{
1651 		{0x00008000,0x00000000,0x00000000,0x00000000},
1652 		"bh bho brx doi hi hne kok mai mr ne sa sat"
1653 	},{
1654 		{0x00018000,0x00000000,0x00000000,0x00000000},
1655 		"mni"
1656 	},{
1657 		{0x00010000,0x00000000,0x00000000,0x00000000},
1658 		"as bn"
1659 	},{
1660 		{0x00020000,0x00000000,0x00000000,0x00000000},
1661 		"pa"
1662 	},{
1663 		{0x00040000,0x00000000,0x00000000,0x00000000},
1664 		"gu"
1665 	},{
1666 		{0x00080000,0x00000000,0x00000000,0x00000000},
1667 		"or"
1668 	},{
1669 		{0x00000204,0x00000000,0x00000000,0x00000000},
1670 		"cv"
1671 	},{
1672 		{0x00100000,0x00000000,0x00000000,0x00000000},
1673 		"ta"
1674 	},{
1675 		{0x00200000,0x00000000,0x00000000,0x00000000},
1676 		"te"
1677 	},{
1678 		{0x00400000,0x00000000,0x00000000,0x00000000},
1679 		"kn"
1680 	},{
1681 		{0x00800000,0x00000000,0x00000000,0x00000000},
1682 		"ml"
1683 	},{
1684 		{0x01000000,0x00000000,0x00000000,0x00000000},
1685 		"th"
1686 	},{
1687 		{0x02000000,0x00000000,0x00000000,0x00000000},
1688 		"lo"
1689 	},{
1690 		{0x04000000,0x00000000,0x00000000,0x00000000},
1691 		"ka"
1692 	},{
1693 		{0x00000000,0x08070000,0x00000000,0x00000000},
1694 		"ja"
1695 	},{
1696 		{0x00000000,0x08010000,0x00000000,0x00000000},
1697 		"zh-hk zh-mo"
1698 	},{
1699 		{0x00000020,0x08000000,0x00000000,0x00000000},
1700 		"zh-cn zh-sg"
1701 	},{
1702 		{0x00000000,0x01100000,0x00000000,0x00000000},
1703 		"ko"
1704 	},{
1705 		{0x00000000,0x28000000,0x00000000,0x00000000},
1706 		"zh-tw"
1707 	},{
1708 		{0x00000080,0x00000000,0x00000000,0x00000000},
1709 		"el"
1710 	},{
1711 		{0x00000000,0x00000000,0x00000040,0x00000000},
1712 		"bo dz"
1713 	},{
1714 		{0x00000000,0x00000000,0x00000080,0x00000000},
1715 		"syr"
1716 	},{
1717 		{0x00000000,0x00000000,0x00000100,0x00000000},
1718 		"dv"
1719 	},{
1720 		{0x00000000,0x00000000,0x00000200,0x00000000},
1721 		"si"
1722 	},{
1723 		{0x00000000,0x00000000,0x00000400,0x00000000},
1724 		"my"
1725 	},{
1726 		{0x00000000,0x00000000,0x00000800,0x00000000},
1727 		"am byn gez sid ti-er ti-et tig wal"
1728 	},{
1729 		{0x00000000,0x00000000,0x00001000,0x00000000},
1730 		"chr"
1731 	},{
1732 		{0x00000000,0x00000000,0x00002000,0x00000000},
1733 		"iu"
1734 	},{
1735 		{0x00000000,0x00000000,0x00010000,0x00000000},
1736 		"km"
1737 	},{
1738 		{0x00000000,0x00000000,0x00020000,0x00000000},
1739 		"mn-cn"
1740 	},{
1741 		{0x00000000,0x00000000,0x00080000,0x00000000},
1742 		"ii"
1743 	},{
1744 		{0x00000200,0x00000000,0x00000000,0x00000000},
1745 		"ab av ba be bg bua ce chm cu ik kaa kk ku-am kum kv ky lez mk mn-mn os ru sah sel sr tg tt tyv uk"
1746 	},{
1747 		{0x00000000,0x00000000,0x00000000,0x00000004},
1748 		"ber-ma"
1749 	}
1750 };
1751 
1752 char *
apc_gp_get_font_languages(Handle self)1753 apc_gp_get_font_languages( Handle self)
1754 {objCheck NULL;{
1755 	int i, size;
1756 	char * ret, * p;
1757 	FONTSIGNATURE f;
1758 	LangId *lang;
1759 
1760 	memset( &f, 0, sizeof(f));
1761 	i = GetTextCharsetInfo( sys ps, &f, 0);
1762 	if ( i == DEFAULT_CHARSET)
1763 		apiErrRet;
1764 
1765 	if ( f. fsUsb[0] == 0 && f. fsUsb[1] == 0 && f. fsUsb[2] == 0 && f. fsUsb[3] == 0) {
1766 		switch( i ) {
1767 		case SYMBOL_CHARSET      : return NULL;
1768 		case SHIFTJIS_CHARSET    : return single_lang("ja");
1769 		case HANGEUL_CHARSET     :
1770 		case GB2312_CHARSET      :
1771 		case CHINESEBIG5_CHARSET : return single_lang("zh");
1772 #ifdef JOHAB_CHARSET
1773 		case GREEK_CHARSET       : return single_lang("el");
1774 		case HEBREW_CHARSET      : return single_lang("he");
1775 		case ARABIC_CHARSET      : return single_lang("ar");
1776 		case VIETNAMESE_CHARSET  : return single_lang("vi");
1777 		case THAI_CHARSET        : return single_lang("th");
1778 		case RUSSIAN_CHARSET     : return single_lang("ru");
1779 #endif
1780 		}
1781 		return single_lang("");
1782 	}
1783 
1784 	size = 1024;
1785 	if ( !( p = ret = malloc( size )))
1786 		return NULL;
1787 	for ( i = 0, lang = languages; i < sizeof(languages)/sizeof(LangId); i++, lang++) {
1788 		DWORD *a = f.fsUsb;
1789 		DWORD *b = lang->v;
1790 		if (
1791 			((a[0] & b[0]) == b[0]) &&
1792 			((a[1] & b[1]) == b[1]) &&
1793 			((a[2] & b[2]) == b[2]) &&
1794 			((a[3] & b[3]) == b[3])
1795 		) {
1796 			int len = strlen(lang->str) + 1;
1797 			if ( p - ret + len + 1 > size ) {
1798 				char * p2;
1799 				size *= 2;
1800 				if ( !( p2 = realloc(p, size))) {
1801 					free(ret);
1802 					return NULL;
1803 				}
1804 				p   = p2 + (p - ret);
1805 				ret = p2;
1806 			}
1807 			strcpy( p, lang->str );
1808 			p += len;
1809 		}
1810 	}
1811 	*p = 0;
1812 
1813 	while ( p > ret ) {
1814 		if (*p == ' ') *p = 0;
1815 		p--;
1816 	}
1817 
1818 	return ret;
1819 }}
1820 
1821 int
apc_gp_get_text_width(Handle self,const char * text,int len,int flags)1822 apc_gp_get_text_width( Handle self, const char* text, int len, int flags)
1823 {
1824 	int ret;
1825 	flags &= ~toGlyphs;
1826 	if ( flags & toUTF8 ) {
1827 		int mb_len;
1828 		if ( !( text = ( char *) guts.alloc_utf8_to_wchar_visual( text, len, &mb_len))) return 0;
1829 		len = mb_len;
1830 	}
1831 	ret = gp_get_text_width( self, text, len, flags);
1832 	if ( flags & toUTF8)
1833 		free(( char*) text);
1834 	return ret;
1835 }
1836 
1837 int
apc_gp_get_glyphs_width(Handle self,PGlyphsOutRec t)1838 apc_gp_get_glyphs_width( Handle self, PGlyphsOutRec t)
1839 {
1840 	return gp_get_glyphs_width( self, t, t->flags);
1841 }
1842 
1843 void
gp_get_text_box(Handle self,ABC * abc,Point * pt)1844 gp_get_text_box( Handle self, ABC * abc, Point * pt)
1845 {
1846 	pt[0].y = pt[2]. y = var font. ascent - 1;
1847 	pt[1].y = pt[3]. y = - var font. descent;
1848 	pt[4].y = pt[0]. x = pt[1].x = 0;
1849 	pt[3].x = pt[2]. x = pt[4].x = abc->abcB;
1850 
1851 	if ( !is_apt( aptTextOutBaseline)) {
1852 		int i = 4, d = var font. descent;
1853 		while ( i--) pt[ i]. y += d;
1854 	}
1855 
1856 	if ( abc->abcA < 0) {
1857 		pt[0].x += abc->abcA;
1858 		pt[1].x += abc->abcA;
1859 	}
1860 	if ( abc->abcC < 0) {
1861 		pt[2].x -= abc->abcC;
1862 		pt[3].x -= abc->abcC;
1863 	}
1864 
1865 	if ( var font. direction != 0) {
1866 		int i;
1867 		float s, c;
1868 		if ( sys font_sin == sys font_cos && sys font_sin == 0.0 ) {
1869 			sys font_sin = sin( var font. direction / GRAD);
1870 			sys font_cos = cos( var font. direction / GRAD);
1871 		}
1872 		s = sys font_sin;
1873 		c = sys font_cos;
1874 		for ( i = 0; i < 5; i++) {
1875 			float x = pt[i]. x * c - pt[i]. y * s;
1876 			float y = pt[i]. x * s + pt[i]. y * c;
1877 			pt[i]. x = x + (( x > 0) ? 0.5 : -0.5);
1878 			pt[i]. y = y + (( y > 0) ? 0.5 : -0.5);
1879 		}
1880 	}
1881 }
1882 
1883 Point *
apc_gp_get_text_box(Handle self,const char * text,int len,int flags)1884 apc_gp_get_text_box( Handle self, const char* text, int len, int flags)
1885 {objCheck NULL;{
1886 	ABC abc;
1887 	Point * pt = ( Point *) malloc( sizeof( Point) * 5);
1888 	if ( !pt) return NULL;
1889 
1890 	memset( pt, 0, sizeof( Point) * 5);
1891 
1892 	flags &= ~toGlyphs;
1893 	if ( flags & toUTF8 ) {
1894 		int mb_len;
1895 		if ( !( text = ( char *) guts.alloc_utf8_to_wchar_visual( text, len, &mb_len))) {
1896 			free( pt);
1897 			return NULL;
1898 		}
1899 		len = mb_len;
1900 	}
1901 	gp_get_text_widths(self, text, len, flags | toAddOverhangs, &abc);
1902 	gp_get_text_box(self, &abc, pt);
1903 	if ( flags & toUTF8 ) free(( char*) text);
1904 	return pt;
1905 }}
1906 
1907 Point *
apc_gp_get_glyphs_box(Handle self,PGlyphsOutRec t)1908 apc_gp_get_glyphs_box( Handle self, PGlyphsOutRec t)
1909 {objCheck NULL;{
1910 	ABC abc;
1911 	Point * pt = ( Point *) malloc( sizeof( Point) * 5);
1912 	if ( !pt) return NULL;
1913 
1914 	memset( pt, 0, sizeof( Point) * 5);
1915 	if ( t-> fonts )
1916 		gp_get_polyfont_widths(self,t,toAddOverhangs,&abc);
1917 	else
1918 		gp_get_text_widths( self, (const char*)t->glyphs, t->len, t->flags | toGlyphs | toAddOverhangs, &abc);
1919 	gp_get_text_box(self, &abc, pt);
1920 
1921 	return pt;
1922 }}
1923 
1924 int
apc_gp_get_glyph_outline(Handle self,int index,int flags,int ** buffer)1925 apc_gp_get_glyph_outline( Handle self, int index, int flags, int ** buffer)
1926 {
1927 	int offset, gdi_size, r_size, *r_buf, *r_ptr;
1928 	Byte * gdi_buf;
1929 	GLYPHMETRICS gm;
1930 	MAT2 matrix;
1931 	UINT format;
1932 
1933 	*buffer = NULL;
1934 	memset(&matrix, 0, sizeof(matrix));
1935 	matrix.eM11.value = matrix.eM22.value = 1;
1936 
1937 	format = GGO_NATIVE;
1938 	if ( flags & ggoGlyphIndex )       format |= GGO_GLYPH_INDEX;
1939 	if (( flags & ggoUseHints ) == 0 ) format |= GGO_UNHINTED;
1940 
1941 	gdi_size = (flags & (ggoUnicode | ggoGlyphIndex)) ?
1942 		GetGlyphOutlineW(sys ps, index, format, &gm, 0, NULL, &matrix) :
1943 		GetGlyphOutlineA(sys ps, index, format, &gm, 0, NULL, &matrix);
1944 	if ( gdi_size <= 0 ) {
1945 		if ( gdi_size < 0 ) apiErr;
1946 		return gdi_size;
1947 	}
1948 
1949 	if (( gdi_buf = malloc(gdi_size)) == NULL ) {
1950 		warn("Not enough memory");
1951 		return -1;
1952 	}
1953 
1954 	if (
1955 		( (flags & (ggoUnicode | ggoGlyphIndex) ) ?
1956 			GetGlyphOutlineW(sys ps, index, format, &gm, gdi_size, gdi_buf, &matrix) :
1957 			GetGlyphOutlineA(sys ps, index, format, &gm, gdi_size, gdi_buf, &matrix)
1958 		) == GDI_ERROR
1959 	) {
1960 		apiErr;
1961 		free(gdi_buf);
1962 		return -1;
1963 	}
1964 
1965 	offset = 0;
1966 	r_size = 0;
1967 	while ( offset < gdi_size ) {
1968 		TTPOLYGONHEADER * h = ( TTPOLYGONHEADER*) (gdi_buf + offset);
1969 		unsigned int curve_offset = sizeof(TTPOLYGONHEADER);
1970 		r_size += 2 /* cmd=ggoMove */ + 2 /* x, y */;
1971 		while ( curve_offset < h->cb ) {
1972 			TTPOLYCURVE * c = (TTPOLYCURVE*) (gdi_buf + offset + curve_offset);
1973 			curve_offset += sizeof(WORD) * 2 + c->cpfx * sizeof(POINTFX);
1974 			r_size += 2 /* cmd */ + c->cpfx * 2;
1975 		}
1976 		offset += h->cb;
1977 	}
1978 	if (( r_buf = malloc(r_size * sizeof(int))) == NULL ) {
1979 		warn("Not enough memory");
1980 		free(gdi_buf);
1981 		return -1;
1982 	}
1983 	r_ptr = r_buf;
1984 
1985 	offset = 0;
1986 #define PTX(x) (x.value * 64 + x.fract / (0x10000 / 64))
1987 	while ( offset < gdi_size ) {
1988 		TTPOLYGONHEADER * h = ( TTPOLYGONHEADER*) (gdi_buf + offset);
1989 		unsigned int curve_offset = sizeof(TTPOLYGONHEADER);
1990 		*(r_ptr++) = ggoMove;
1991 		*(r_ptr++) = 1;
1992 		*(r_ptr++) = PTX(h->pfxStart.x);
1993 		*(r_ptr++) = PTX(h->pfxStart.y);
1994 		while ( curve_offset < h->cb ) {
1995 			int i;
1996 			TTPOLYCURVE * c = (TTPOLYCURVE*) (gdi_buf + offset + curve_offset);
1997 			switch ( c-> wType ) {
1998 			case TT_PRIM_LINE:
1999 				*(r_ptr++) = ggoLine;
2000 				break;
2001 			case TT_PRIM_QSPLINE:
2002 				*(r_ptr++) = ggoConic;
2003 				break;
2004 			case TT_PRIM_CSPLINE:
2005 				*(r_ptr++) = ggoCubic;
2006 				break;
2007 			default:
2008 				warn("Unknown constant TT_PRIM_%d\n", c->wType);
2009 				free(gdi_buf);
2010 				free(r_buf);
2011 				return 0;
2012 			}
2013 			*(r_ptr++) = c-> cpfx;
2014 			for ( i = 0; i < c-> cpfx; i++) {
2015 				*(r_ptr++) = PTX(c->apfx[i].x);
2016 				*(r_ptr++) = PTX(c->apfx[i].y);
2017 			}
2018 			curve_offset += sizeof(WORD) * 2 + c->cpfx * sizeof(POINTFX);
2019 		}
2020 		offset += h->cb;
2021 	}
2022 	free(gdi_buf);
2023 	*buffer = r_buf;
2024 	return r_size;
2025 }
2026 
2027 Bool
apc_gp_get_text_out_baseline(Handle self)2028 apc_gp_get_text_out_baseline( Handle self)
2029 {
2030 	objCheck 0;
2031 	return is_apt( aptTextOutBaseline);
2032 }
2033 
2034 Bool
apc_gp_get_text_opaque(Handle self)2035 apc_gp_get_text_opaque( Handle self)
2036 {
2037 	objCheck false;
2038 	return is_apt( aptTextOpaque);
2039 }
2040 
2041 Bool
apc_gp_set_text_opaque(Handle self,Bool opaque)2042 apc_gp_set_text_opaque( Handle self, Bool opaque)
2043 {
2044 	objCheck false;
2045 	apt_assign( aptTextOpaque, opaque);
2046 	return true;
2047 }
2048 
2049 
2050 Bool
apc_gp_set_text_out_baseline(Handle self,Bool baseline)2051 apc_gp_set_text_out_baseline( Handle self, Bool baseline)
2052 {
2053 	objCheck false;
2054 	apt_assign( aptTextOutBaseline, baseline);
2055 	if ( sys ps) SetTextAlign( sys ps, baseline ? TA_BASELINE : TA_BOTTOM);
2056 	return true;
2057 }
2058 
2059 #ifdef __cplusplus
2060 }
2061 #endif
2062