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