1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* A Free Type interface adapter. */
18 /* Uses code fragments from the FreeType project. */
19
20 #include "ttmisc.h"
21 #include "ttfoutl.h"
22 #include "ttfmemd.h"
23
24 #include "ttfinp.h"
25 #include "ttfsfnt.h"
26 #include "ttobjs.h"
27 #include "ttinterp.h"
28 #include "ttcalc.h"
29
30 static const bool skip_instructions = 0; /* Debug purpose only. */
31
32 typedef struct {
33 TT_Fixed a, b, c, d, tx, ty;
34 } FixMatrix;
35
36 struct ttfSubGlyphUsage_s {
37 FixMatrix m;
38 int index;
39 int flags;
40 short arg1, arg2;
41 };
42
43 /*------------------------------------------------------------------- */
44
AVE(F26Dot6 a,F26Dot6 b)45 static TT_Fixed AVE(F26Dot6 a, F26Dot6 b)
46 { return (a + b) / 2;
47 }
48
shortToF26Dot6(short a)49 static F26Dot6 shortToF26Dot6(short a)
50 { return (F26Dot6)a << 6;
51 }
52
floatToF26Dot6(float a)53 static F26Dot6 floatToF26Dot6(float a)
54 { return (F26Dot6)(a * (1 << 6) + 0.5);
55 }
56
floatToF16Dot16(float a)57 static TT_Fixed floatToF16Dot16(float a)
58 { return (F26Dot6)(a * (1 << 16) + 0.5);
59 }
60
TransformF26Dot6PointFix(F26Dot6Point * pt,F26Dot6 dx,F26Dot6 dy,FixMatrix * m)61 static void TransformF26Dot6PointFix(F26Dot6Point *pt, F26Dot6 dx, F26Dot6 dy, FixMatrix *m)
62 { pt->x = MulDiv(dx, m->a, 65536) + MulDiv(dy, m->c, 65536) + (m->tx >> 10);
63 pt->y = MulDiv(dx, m->b, 65536) + MulDiv(dy, m->d, 65536) + (m->ty >> 10);
64 }
65
TransformF26Dot6PointFloat(FloatPoint * pt,F26Dot6 dx,F26Dot6 dy,FloatMatrix * m)66 static void TransformF26Dot6PointFloat(FloatPoint *pt, F26Dot6 dx, F26Dot6 dy, FloatMatrix *m)
67 { pt->x = dx * m->a / 64 + dy * m->c / 64 + m->tx;
68 pt->y = dx * m->b / 64 + dy * m->d / 64 + m->ty;
69 }
70
71 /*-------------------------------------------------------------------*/
72
ttfFont__get_table_ptr(ttfFont * f,char * id)73 static ttfPtrElem *ttfFont__get_table_ptr(ttfFont *f, char *id)
74 {
75 if (!memcmp(id, "cvt ", 4))
76 return &f->t_cvt_;
77 if (!memcmp(id, "fpgm", 4))
78 return &f->t_fpgm;
79 if (!memcmp(id, "glyf", 4))
80 return &f->t_glyf;
81 if (!memcmp(id, "head", 4))
82 return &f->t_head;
83 if (!memcmp(id, "hhea", 4))
84 return &f->t_hhea;
85 if (!memcmp(id, "hmtx", 4))
86 return &f->t_hmtx;
87 if (!memcmp(id, "vhea", 4))
88 return &f->t_vhea;
89 if (!memcmp(id, "vmtx", 4))
90 return &f->t_vmtx;
91 if (!memcmp(id, "loca", 4))
92 return &f->t_loca;
93 if (!memcmp(id, "maxp", 4))
94 return &f->t_maxp;
95 if (!memcmp(id, "prep", 4))
96 return &f->t_prep;
97 if (!memcmp(id, "cmap", 4))
98 return &f->t_cmap;
99 return 0;
100 }
101
102 /*-------------------------------------------------------------------*/
103
TT_Set_Instance_CharSizes(TT_Instance instance,TT_F26Dot6 charWidth,TT_F26Dot6 charHeight)104 TT_Error TT_Set_Instance_CharSizes(TT_Instance instance,
105 TT_F26Dot6 charWidth,
106 TT_F26Dot6 charHeight)
107 {
108 PInstance ins = instance.z;
109
110 if ( !ins )
111 return TT_Err_Invalid_Instance_Handle;
112
113 if (charWidth < 1*64)
114 charWidth = 1*64;
115
116 if (charHeight < 1*64)
117 charHeight = 1*64;
118
119 ins->metrics.x_scale1 = charWidth;
120 ins->metrics.y_scale1 = charHeight;
121 ins->metrics.x_scale2 = ins->face->font->nUnitsPerEm;
122 ins->metrics.y_scale2 = ins->face->font->nUnitsPerEm;
123
124 if (ins->face->font->nFlags & 8) {
125 ins->metrics.x_scale1 = (ins->metrics.x_scale1+32) & -64;
126 ins->metrics.y_scale1 = (ins->metrics.y_scale1+32) & -64;
127 }
128
129 ins->metrics.x_ppem = ins->metrics.x_scale1 / 64;
130 ins->metrics.y_ppem = ins->metrics.y_scale1 / 64;
131
132 if (charWidth > charHeight)
133 ins->metrics.pointSize = charWidth;
134 else
135 ins->metrics.pointSize = charHeight;
136
137 ins->valid = FALSE;
138 return Instance_Reset(ins, FALSE);
139 }
140
141 /*-------------------------------------------------------------------*/
142
ttfInterpreter__obtain(ttfMemory * mem,ttfInterpreter ** ptti)143 int ttfInterpreter__obtain(ttfMemory *mem, ttfInterpreter **ptti)
144 {
145 ttfInterpreter *tti;
146
147 if (*ptti) {
148 (*ptti)->lock++;
149 return 0;
150 }
151 tti = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_ttfInterpreter, "ttfInterpreter__obtain");
152 if (!tti)
153 return fMemoryError;
154 tti->usage = 0;
155 tti->usage_size = 0;
156 tti->ttf_memory = mem;
157 tti->lock = 1;
158 tti->exec = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TExecution_Context, "ttfInterpreter__obtain");
159 if (!tti->exec) {
160 mem->free(mem, tti, "ttfInterpreter__obtain");
161 return fMemoryError;
162 }
163 memset(tti->exec, 0, sizeof(*tti->exec));
164 *ptti = tti;
165 return 0;
166 }
167
ttfInterpreter__release(ttfInterpreter ** ptti)168 void ttfInterpreter__release(ttfInterpreter **ptti)
169 {
170 ttfInterpreter *tti = *ptti;
171 ttfMemory *mem = tti->ttf_memory;
172
173 if(--tti->lock)
174 return;
175 mem->free(mem, tti->usage, "ttfInterpreter__release");
176 mem->free(mem, tti->exec, "ttfInterpreter__release");
177 mem->free(mem, *ptti, "ttfInterpreter__release");
178 *ptti = 0;
179 }
180
181 /*-------------------------------------------------------------------*/
182
ttfFont__init(ttfFont * self,ttfMemory * mem,void (* DebugRepaint)(ttfFont *),int (* DebugPrint)(ttfFont *,const char * s,...),const gs_memory_t * DebugMem)183 void ttfFont__init(ttfFont *self, ttfMemory *mem,
184 void (*DebugRepaint)(ttfFont *),
185 int (*DebugPrint)(ttfFont *, const char *s, ...),
186 const gs_memory_t *DebugMem)
187 {
188 memset(self, 0, sizeof(*self));
189 self->DebugRepaint = DebugRepaint;
190 self->DebugPrint = DebugPrint;
191 self->DebugMem = DebugMem;
192 }
193
ttfFont__finit(ttfFont * self)194 void ttfFont__finit(ttfFont *self)
195 { ttfMemory *mem = self->tti->ttf_memory;
196
197 if (self->exec) {
198 if (self->inst)
199 Context_Destroy(self->exec);
200 else {
201 /* Context_Create was not called - see ttfFont__Open.
202 Must not call Context_Destroy for proper 'lock' count.
203 */
204 }
205 }
206 self->exec = NULL;
207 if (self->inst)
208 Instance_Destroy(self->inst);
209 mem->free(mem, self->inst, "ttfFont__finit");
210 self->inst = NULL;
211 if (self->face)
212 Face_Destroy(self->face);
213 mem->free(mem, self->face, "ttfFont__finit");
214 self->face = NULL;
215 }
216
217 #define MAX_SUBGLYPH_NESTING 3 /* Arbitrary. We need this because we don't want
218 a ttfOutliner__BuildGlyphOutline recursion
219 while a glyph is loaded in ttfReader. */
220
ttfFont__Open(ttfInterpreter * tti,ttfFont * self,ttfReader * r,unsigned int nTTC,float w,float h,bool design_grid)221 FontError ttfFont__Open(ttfInterpreter *tti, ttfFont *self, ttfReader *r,
222 unsigned int nTTC, float w, float h,
223 bool design_grid)
224 { char sVersion[4], sVersion1[4] = {0, 1, 0, 0};
225 char sVersion2[4] = {0, 2, 0, 0};
226 unsigned int nNumTables, i;
227 TT_Error code, code1 = 0;
228 int k;
229 TT_Instance I;
230 ttfMemory *mem = tti->ttf_memory;
231 F26Dot6 ww, hh;
232
233 self->tti = tti;
234 self->design_grid = design_grid;
235 r->Read(r, sVersion, 4);
236 if(!memcmp(sVersion, "ttcf", 4)) {
237 unsigned int nFonts;
238 unsigned int nPos = 0xbaadf00d; /* Quiet compiler. */
239
240 r->Read(r, sVersion, 4);
241 if(memcmp(sVersion, sVersion1, 4) && memcmp(sVersion, sVersion2, 4))
242 return fUnimplemented;
243 nFonts = ttfReader__UInt(r);
244 if (nFonts == 0)
245 return fBadFontData;
246 if(nTTC >= nFonts)
247 return fTableNotFound;
248 for(i = 0; i <= nTTC; i++)
249 nPos = ttfReader__UInt(r);
250 r->Seek(r, nPos);
251 r->Read(r, sVersion, 4);
252 }
253 if(memcmp(sVersion, sVersion1, 4) && memcmp(sVersion, "true", 4))
254 return fUnimplemented;
255 nNumTables = ttfReader__UShort(r);
256 ttfReader__UShort(r); /* nSearchRange */
257 ttfReader__UShort(r); /* nEntrySelector */
258 ttfReader__UShort(r); /* nRangeShift */
259 for (i = 0; i < nNumTables; i++) {
260 char sTag[5];
261 unsigned int nOffset, nLength;
262 ttfPtrElem *e;
263
264 sTag[4] = 0;
265 r->Read(r, sTag, 4);
266 ttfReader__UInt(r); /* nCheckSum */
267 nOffset = ttfReader__UInt(r);
268 nLength = ttfReader__UInt(r);
269 e = ttfFont__get_table_ptr(self, sTag);
270 if (e != NULL) {
271 e->nPos = nOffset;
272 e->nLen = nLength;
273 }
274 }
275 r->Seek(r, self->t_head.nPos + offset_of(sfnt_FontHeader, flags));
276 self->nFlags = ttfReader__UShort(r);
277 r->Seek(r, self->t_head.nPos + offset_of(sfnt_FontHeader, unitsPerEm));
278 self->nUnitsPerEm = ttfReader__UShort(r);
279 if (self->nUnitsPerEm <= 0)
280 self->nUnitsPerEm = 1024;
281 r->Seek(r, self->t_head.nPos + offset_of(sfnt_FontHeader, indexToLocFormat));
282 self->nIndexToLocFormat = ttfReader__UShort(r);
283 r->Seek(r, self->t_maxp.nPos + offset_of(sfnt_maxProfileTable, numGlyphs));
284 self->nNumGlyphs = ttfReader__UShort(r);
285 r->Seek(r, self->t_maxp.nPos + offset_of(sfnt_maxProfileTable, maxComponentElements));
286 self->nMaxComponents = ttfReader__UShort(r);
287 if(self->nMaxComponents < 10)
288 self->nMaxComponents = 10; /* work around DynaLab bug in lgoth.ttf */
289 r->Seek(r, self->t_hhea.nPos + offset_of(sfnt_MetricsHeader, numberLongMetrics));
290 self->nLongMetricsHorz = ttfReader__UShort(r);
291 if (self->t_vhea.nPos != 0) {
292 r->Seek(r, self->t_vhea.nPos + offset_of(sfnt_MetricsHeader, numberLongMetrics));
293 self->nLongMetricsVert = ttfReader__UShort(r);
294 } else
295 self->nLongMetricsVert = 0;
296 if (tti->usage_size < self->nMaxComponents * MAX_SUBGLYPH_NESTING) {
297 tti->ttf_memory->free(tti->ttf_memory, tti->usage, "ttfFont__Open");
298 tti->usage_size = 0;
299 tti->usage = mem->alloc_bytes(mem,
300 sizeof(ttfSubGlyphUsage) * self->nMaxComponents * MAX_SUBGLYPH_NESTING,
301 "ttfFont__Open");
302 if (tti->usage == NULL)
303 return fMemoryError;
304 tti->usage_size = self->nMaxComponents * MAX_SUBGLYPH_NESTING;
305 }
306 self->face = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TFace, "ttfFont__Open");
307 if (self->face == NULL)
308 return fMemoryError;
309 memset(self->face, 0, sizeof(*self->face));
310 self->face->r = r;
311 self->face->font = self;
312 self->exec = tti->exec;
313 code = Face_Create(self->face);
314 if (code)
315 return fMemoryError;
316 code = r->Error(r);
317 if (code < 0)
318 return fBadFontData;
319 self->inst = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TInstance, "ttfFont__Open");
320 if (self->inst == NULL)
321 return fMemoryError;
322 memset(self->inst, 0, sizeof(*self->inst));
323 code = Context_Create(self->exec, self->face); /* See comment in the implementation of Context_Create. */
324 if (code == TT_Err_Out_Of_Memory)
325 return fMemoryError;
326 code = Instance_Create(self->inst, self->face);
327 if (code == TT_Err_Out_Of_Memory)
328 return fMemoryError;
329 if (code)
330 return fBadFontData;
331 for(k = 0; k < self->face->cvtSize; k++)
332 self->inst->cvt[k] = shortToF26Dot6(self->face->cvt[k]);
333 code = Instance_Init(self->inst);
334 if (code == TT_Err_Out_Of_Memory)
335 return fMemoryError;
336 if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement)
337 code1 = fBadInstruction;
338 else if (code)
339 return fBadFontData;
340 I.z = self->inst;
341 if (design_grid)
342 ww = hh = shortToF26Dot6(self->nUnitsPerEm);
343 else {
344 /* Round towards zero for a better view of mirrored characters : */
345 ww = floatToF26Dot6(w);
346 hh = floatToF26Dot6(h);
347 }
348 code = TT_Set_Instance_CharSizes(I, ww, hh);
349 self->inst->metrics = self->exec->metrics;
350 if (code == TT_Err_Invalid_Engine)
351 return fPatented;
352 if (code == TT_Err_Out_Of_Memory)
353 return fMemoryError;
354 if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement)
355 return fBadInstruction;
356 if (code)
357 return fBadFontData;
358 if (code1)
359 return code1;
360 return code;
361 }
362
ttfFont__StartGlyph(ttfFont * self)363 static void ttfFont__StartGlyph(ttfFont *self)
364 { Context_Load( self->exec, self->inst );
365 if ( self->inst->GS.instruct_control & 2 )
366 self->exec->GS = Default_GraphicsState;
367 else
368 self->exec->GS = self->inst->GS;
369 self->tti->usage_top = 0;
370 }
371
ttfFont__StopGlyph(ttfFont * self)372 static void ttfFont__StopGlyph(ttfFont *self)
373 {
374 Context_Save(self->exec, self->inst);
375 }
376
377 /*-------------------------------------------------------------------*/
378
mount_zone(PGlyph_Zone source,PGlyph_Zone target)379 static void mount_zone( PGlyph_Zone source,
380 PGlyph_Zone target )
381 {
382 Int np, nc;
383
384 np = source->n_points;
385 nc = source->n_contours;
386
387 target->org_x = source->org_x + np;
388 target->org_y = source->org_y + np;
389 target->cur_x = source->cur_x + np;
390 target->cur_y = source->cur_y + np;
391 target->touch = source->touch + np;
392
393 target->contours = source->contours + nc;
394
395 target->n_points = 0;
396 target->n_contours = 0;
397 }
398
Init_Glyph_Component(PSubglyph_Record element,PSubglyph_Record original,PExecution_Context exec)399 static void Init_Glyph_Component( PSubglyph_Record element,
400 PSubglyph_Record original,
401 PExecution_Context exec )
402 {
403 element->index = -1;
404 element->is_scaled = FALSE;
405 element->is_hinted = FALSE;
406
407 if (original)
408 mount_zone( &original->zone, &element->zone );
409 else
410 element->zone = exec->pts;
411
412 element->zone.n_contours = 0;
413 element->zone.n_points = 0;
414
415 element->arg1 = 0;
416 element->arg2 = 0;
417
418 element->element_flag = 0;
419 element->preserve_pps = FALSE;
420
421 element->transform.xx = 1 << 16;
422 element->transform.xy = 0;
423 element->transform.yx = 0;
424 element->transform.yy = 1 << 16;
425
426 element->transform.ox = 0;
427 element->transform.oy = 0;
428
429 element->leftBearing = 0;
430 element->advanceWidth = 0;
431 }
432
cur_to_org(Int n,PGlyph_Zone zone)433 static void cur_to_org( Int n, PGlyph_Zone zone )
434 {
435 Int k;
436
437 for ( k = 0; k < n; k++ )
438 zone->org_x[k] = zone->cur_x[k];
439
440 for ( k = 0; k < n; k++ )
441 zone->org_y[k] = zone->cur_y[k];
442 }
443
org_to_cur(Int n,PGlyph_Zone zone)444 static void org_to_cur( Int n, PGlyph_Zone zone )
445 {
446 Int k;
447
448 for ( k = 0; k < n; k++ )
449 zone->cur_x[k] = zone->org_x[k];
450
451 for ( k = 0; k < n; k++ )
452 zone->cur_y[k] = zone->org_y[k];
453 }
454
455 /*-------------------------------------------------------------------*/
456
ttfOutliner__init(ttfOutliner * self,ttfFont * f,ttfReader * r,ttfExport * exp,bool bOutline,bool bFirst,bool bVertical)457 void ttfOutliner__init(ttfOutliner *self, ttfFont *f, ttfReader *r, ttfExport *exp,
458 bool bOutline, bool bFirst, bool bVertical)
459 {
460 self->r = r;
461 self->bOutline = bOutline;
462 self->bFirst = bFirst;
463 self->pFont = f;
464 self->bVertical = bVertical;
465 self->exp = exp;
466 }
467
MoveGlyphOutline(TGlyph_Zone * pts,int nOffset,ttfGlyphOutline * out,FixMatrix * m)468 static void MoveGlyphOutline(TGlyph_Zone *pts, int nOffset, ttfGlyphOutline *out, FixMatrix *m)
469 { F26Dot6* x = pts->org_x + nOffset;
470 F26Dot6* y = pts->org_y + nOffset;
471 short count = out->pointCount;
472 F26Dot6Point p;
473
474 if (m->a == 65536 && m->b == 0 &&
475 m->c == 0 && m->d == 65536 &&
476 m->tx == 0 && m->ty == 0)
477 return;
478 for (; count != 0; --count) {
479 TransformF26Dot6PointFix(&p, *x, *y, m);
480 *x++ = p.x;
481 *y++ = p.y;
482 }
483 }
484
ttfOutliner__BuildGlyphOutlineAux(ttfOutliner * self,int glyphIndex,FixMatrix * m_orig,ttfGlyphOutline * gOutline)485 static FontError ttfOutliner__BuildGlyphOutlineAux(ttfOutliner *self, int glyphIndex,
486 FixMatrix *m_orig, ttfGlyphOutline* gOutline)
487 { ttfFont *pFont = self->pFont;
488 ttfReader *r = self->r;
489 ttfInterpreter *tti = pFont->tti;
490 short sideBearing;
491 FontError error = fNoError;
492 short arg1, arg2;
493 short count;
494 unsigned int i;
495 unsigned short nAdvance;
496 unsigned int nNextGlyphPtr = 0;
497 unsigned int nPosBeg;
498 TExecution_Context *exec = pFont->exec;
499 TGlyph_Zone *pts = &exec->pts;
500 TSubglyph_Record subglyph;
501 ttfSubGlyphUsage *usage = tti->usage + tti->usage_top;
502 const byte *glyph = NULL;
503 int glyph_size;
504 bool execute_bytecode = true;
505 int nPoints = 0;
506
507 retry:
508 if (r->get_metrics(r, glyphIndex, self->bVertical, &sideBearing, &nAdvance) < 0) {
509 /* fixme: the error code is missing due to interface restrictions. */
510 goto errex;
511 }
512 gOutline->sideBearing = shortToF26Dot6(sideBearing);
513 gOutline->advance.x = shortToF26Dot6(nAdvance);
514 gOutline->advance.y = 0;
515 self->bFirst = FALSE;
516
517 if (!self->bOutline)
518 return fNoError;
519 if (!r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size))
520 return fGlyphNotFound;
521 if (r->Eof(r)) {
522 r->ReleaseGlyph(r, glyphIndex);
523 gOutline->xMinB = gOutline->yMinB = 0;
524 gOutline->xMaxB = gOutline->yMaxB = 0;
525 return fNoError;
526 }
527 if (r->Error(r))
528 goto errex;
529 nPosBeg = r->Tell(r);
530
531 gOutline->contourCount = ttfReader__Short(r);
532 subglyph.bbox.xMin = ttfReader__Short(r);
533 subglyph.bbox.yMin = ttfReader__Short(r);
534 subglyph.bbox.xMax = ttfReader__Short(r);
535 subglyph.bbox.yMax = ttfReader__Short(r);
536
537 gOutline->xMinB = Scale_X(&exec->metrics, subglyph.bbox.xMin);
538 gOutline->yMinB = Scale_Y(&exec->metrics, subglyph.bbox.yMin);
539 gOutline->xMaxB = Scale_X(&exec->metrics, subglyph.bbox.xMax);
540 gOutline->yMaxB = Scale_Y(&exec->metrics, subglyph.bbox.yMax);
541
542 /* FreeType stuff beg */
543 Init_Glyph_Component(&subglyph, NULL, pFont->exec);
544 subglyph.leftBearing = sideBearing;
545 subglyph.advanceWidth = nAdvance;
546 subglyph.pp1.x = subglyph.bbox.xMin - sideBearing;
547 subglyph.pp1.y = 0;
548 subglyph.pp2.x = subglyph.pp1.x + nAdvance;
549 subglyph.pp2.y = 0;
550 /* FreeType stuff end */
551
552 if (gOutline->contourCount == 0)
553 gOutline->pointCount = 0;
554 else if (gOutline->contourCount == -1) {
555 unsigned short flags, index, bHaveInstructions = 0;
556 unsigned int nUsage = 0;
557 unsigned int nPos;
558 unsigned int n_ins;
559
560 gOutline->bCompound = TRUE;
561 if (tti->usage_top + pFont->nMaxComponents > tti->usage_size)
562 return fBadFontData;
563 gOutline->contourCount = gOutline->pointCount = 0;
564 do {
565 FixMatrix m;
566 ttfSubGlyphUsage *e;
567
568 if (nUsage >= pFont->nMaxComponents) {
569 error = fMemoryError; goto ex;
570 }
571 flags = ttfReader__UShort(r);
572 index = ttfReader__UShort(r);
573 bHaveInstructions |= (flags & WE_HAVE_INSTRUCTIONS);
574 if (flags & ARG_1_AND_2_ARE_WORDS) {
575 arg1 = ttfReader__Short(r);
576 arg2 = ttfReader__Short(r);
577 } else {
578 if (flags & ARGS_ARE_XY_VALUES) {
579 /* offsets are signed */
580 arg1 = ttfReader__SignedByte(r);
581 arg2 = ttfReader__SignedByte(r);
582 } else { /* anchor points are unsigned */
583 arg1 = ttfReader__Byte(r);
584 arg2 = ttfReader__Byte(r);
585 }
586 }
587 m.b = m.c = m.tx = m.ty = 0;
588 if (flags & WE_HAVE_A_SCALE)
589 m.a = m.d = (TT_Fixed)ttfReader__Short(r) << 2;
590 else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
591 m.a = (TT_Fixed)ttfReader__Short(r) << 2;
592 m.d = (TT_Fixed)ttfReader__Short(r) << 2;
593 } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
594 m.a = (TT_Fixed)ttfReader__Short(r)<<2;
595 m.b = (TT_Fixed)ttfReader__Short(r)<<2;
596 m.c = (TT_Fixed)ttfReader__Short(r)<<2;
597 m.d = (TT_Fixed)ttfReader__Short(r)<<2;
598 } else
599 m.a = m.d = 65536;
600 e = &usage[nUsage];
601 e->m = m;
602 e->index = index;
603 e->arg1 = arg1;
604 e->arg2 = arg2;
605 e->flags = flags;
606 nUsage++;
607 } while (flags & MORE_COMPONENTS);
608 /* Some fonts have bad WE_HAVE_INSTRUCTIONS, so use nNextGlyphPtr : */
609 if (r->Error(r))
610 goto errex;
611 nPos = r->Tell(r);
612 n_ins = ((!r->Eof(r) && (bHaveInstructions || nPos < nNextGlyphPtr)) ? ttfReader__UShort(r) : 0);
613 nPos = r->Tell(r);
614 r->ReleaseGlyph(r, glyphIndex);
615 glyph = NULL;
616 for (i = 0; i < nUsage; i++) {
617 ttfGlyphOutline out;
618 ttfSubGlyphUsage *e = &usage[i];
619 int j;
620 TT_Error code;
621 int nPointsStored = gOutline->pointCount, nContoursStored = gOutline->contourCount;
622
623 out.contourCount = 0;
624 out.pointCount = 0;
625 out.bCompound = FALSE;
626 pts->org_x += nPointsStored;
627 pts->org_y += nPointsStored;
628 pts->cur_x += nPointsStored;
629 pts->cur_y += nPointsStored;
630 pts->touch += nPointsStored;
631 pts->contours += nContoursStored;
632 tti->usage_top += nUsage;
633 code = ttfOutliner__BuildGlyphOutlineAux(self, e->index, m_orig, &out);
634 pts->org_x -= nPointsStored;
635 pts->org_y -= nPointsStored;
636 pts->cur_x -= nPointsStored;
637 pts->cur_y -= nPointsStored;
638 pts->touch -= nPointsStored;
639 tti->usage_top -= nUsage;
640 pts->contours -= nContoursStored;
641 if (code == fPatented)
642 error = code;
643 else if (code != fNoError) {
644 error = code;
645 goto ex;
646 }
647 if (flags & ARGS_ARE_XY_VALUES) {
648 e->m.tx = Scale_X( &exec->metrics, e->arg1 ) << 10;
649 e->m.ty = Scale_Y( &exec->metrics, e->arg2 ) << 10;
650 } else {
651 e->m.tx = (pts->org_x[e->arg1] - pts->org_x[gOutline->pointCount + e->arg2]) << 10;
652 e->m.ty = (pts->org_y[e->arg1] - pts->org_y[gOutline->pointCount + e->arg2]) << 10;
653 }
654 MoveGlyphOutline(pts, nPointsStored, &out, &e->m);
655 for (j = nContoursStored; j < out.contourCount + nContoursStored; j++)
656 pts->contours[j] += nPointsStored;
657 gOutline->contourCount += out.contourCount;
658 gOutline->pointCount += out.pointCount;
659 if(e->flags & USE_MY_METRICS) {
660 gOutline->advance.x = out.advance.x;
661 gOutline->sideBearing = out.sideBearing;
662 }
663 }
664 if (execute_bytecode && !skip_instructions && n_ins &&
665 !(pFont->inst->GS.instruct_control & 1)) {
666 TT_Error code;
667
668 r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size);
669 if (r->Error(r))
670 goto errex;
671 if (nPos + n_ins > glyph_size)
672 goto errex;
673 code = Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins);
674 if (!code) {
675 int k;
676 F26Dot6 x;
677
678 nPoints = gOutline->pointCount + 2;
679 exec->pts = subglyph.zone;
680 pts->n_points = nPoints;
681 pts->n_contours = gOutline->contourCount;
682 /* add phantom points : */
683 pts->org_x[nPoints - 2] = Scale_X(&exec->metrics, subglyph.pp1.x);
684 pts->org_y[nPoints - 2] = Scale_Y(&exec->metrics, subglyph.pp1.y);
685 pts->org_x[nPoints - 1] = Scale_X(&exec->metrics, subglyph.pp2.x);
686 pts->org_y[nPoints - 1] = Scale_Y(&exec->metrics, subglyph.pp2.y);
687 pts->touch[nPoints - 1] = 0;
688 pts->touch[nPoints - 2] = 0;
689 /* if hinting, round the phantom points (not sure) : */
690 x = pts->org_x[nPoints - 2];
691 x = ((x + 32) & -64) - x;
692 if (x)
693 for (k = 0; k < nPoints; k++)
694 pts->org_x[k] += x;
695 pts->cur_x[nPoints - 1] = (pts->cur_x[nPoints - 1] + 32) & -64;
696 for (k = 0; k < nPoints; k++)
697 pts->touch[k] = pts->touch[k] & TT_Flag_On_Curve;
698 org_to_cur(nPoints, pts);
699 exec->is_composite = TRUE;
700 if (pFont->patented)
701 code = TT_Err_Invalid_Engine;
702 else
703 code = Context_Run(exec, FALSE);
704 if (!code)
705 cur_to_org(nPoints, pts);
706 else if (code == TT_Err_Invalid_Engine)
707 error = fPatented;
708 else {
709 /* We have a range of errors that can be caused by
710 * bad bytecode
711 */
712 if ((int)code >= TT_Err_Invalid_Opcode
713 && (int)code <= TT_Err_Invalid_Displacement) {
714 error = fBadInstruction;
715 }
716 else {
717 error = fBadFontData;
718 }
719 }
720 }
721 Unset_CodeRange(exec);
722 Clear_CodeRange(exec, TT_CodeRange_Glyph);
723 }
724 } else if (gOutline->contourCount > 0) {
725 uint16 i;
726 bool bInsOK;
727 byte *onCurve, *stop, flag;
728 short *endPoints;
729 unsigned int nPos;
730 unsigned int n_ins;
731
732 if (self->nContoursTotal + gOutline->contourCount > exec->n_contours) {
733 error = fBadFontData; goto ex;
734 }
735 endPoints = pts->contours;
736 for (i = 0; i < gOutline->contourCount; i++)
737 endPoints[i] = ttfReader__Short(r);
738 for (i = 1; i < gOutline->contourCount; i++)
739 if (endPoints[i - 1] < 0 || endPoints[i - 1] >= endPoints[i]) {
740 error = fBadFontData; goto ex;
741 }
742 nPoints = gOutline->pointCount = endPoints[gOutline->contourCount - 1] + 1;
743 if (nPoints < 0 || self->nPointsTotal + nPoints + 2 > exec->n_points) {
744 error = fBadFontData; goto ex;
745 }
746 n_ins = ttfReader__Short(r);
747 nPos = r->Tell(r);
748 r->Seek(r, nPos + n_ins);
749 if (r->Error(r))
750 goto errex;
751 bInsOK = !Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins);
752 onCurve = pts->touch;
753 stop = onCurve + gOutline->pointCount;
754
755 while (onCurve < stop) {
756 *onCurve++ = flag = ttfReader__Byte(r);
757 if (flag & REPEAT_FLAGS) {
758 count = ttfReader__Byte(r);
759 for (--count; count >= 0 && onCurve < stop; --count)
760 *onCurve++ = flag;
761 }
762 }
763 /* Lets do X */
764 { short coord = (self->bVertical ? 0 : sideBearing - subglyph.bbox.xMin);
765 F26Dot6* x = pts->org_x;
766 onCurve = pts->touch;
767 while (onCurve < stop) {
768 if ((flag = *onCurve++) & XSHORT) {
769 if (flag & SHORT_X_IS_POS)
770 coord += ttfReader__Byte(r);
771 else
772 coord -= ttfReader__Byte(r);
773 } else if (!(flag & NEXT_X_IS_ZERO))
774 coord += ttfReader__Short(r);
775 *x++ = Scale_X(&exec->metrics, coord);
776 }
777 }
778 /* Lets do Y */
779 { short coord = 0;
780 F26Dot6* y = pts->org_y;
781 onCurve = pts->touch;
782 while (onCurve < stop) {
783 if((flag = *onCurve) & YSHORT)
784 if ( flag & SHORT_Y_IS_POS )
785 coord += ttfReader__Byte(r);
786 else
787 coord -= ttfReader__Byte(r);
788 else if(!(flag & NEXT_Y_IS_ZERO))
789 coord += ttfReader__Short(r);
790 *y++ = Scale_Y( &exec->metrics, coord );
791
792 /* Filter off the extra bits */
793 *onCurve++ = flag & ONCURVE;
794 }
795 }
796 MoveGlyphOutline(pts, 0, gOutline, m_orig);
797 self->nContoursTotal += gOutline->contourCount;
798 self->nPointsTotal += nPoints;
799 if (execute_bytecode && !skip_instructions &&
800 !r->Error(r) && n_ins && bInsOK && !(pFont->inst->GS.instruct_control & 1)) {
801 TGlyph_Zone *pts = &exec->pts;
802 int k;
803 F26Dot6 x;
804 TT_Error code;
805
806 exec->is_composite = FALSE;
807 /* add phantom points : */
808 pts->org_x[nPoints ] = Scale_X(&exec->metrics, subglyph.pp1.x);
809 pts->org_y[nPoints ] = Scale_Y(&exec->metrics, subglyph.pp1.y);
810 pts->org_x[nPoints + 1] = Scale_X(&exec->metrics, subglyph.pp2.x);
811 pts->org_y[nPoints + 1] = Scale_Y(&exec->metrics, subglyph.pp2.y);
812 pts->touch[nPoints ] = 0;
813 pts->touch[nPoints + 1] = 0;
814 pts->n_points = nPoints + 2;
815 pts->n_contours = gOutline->contourCount;
816 /* if hinting, round the phantom points (not sure) : */
817 x = pts->org_x[nPoints];
818 x = ((x + 32) & -64) - x;
819 if (x)
820 for (k = 0; k < nPoints + 2; k++)
821 pts->org_x[k] += x;
822 org_to_cur(nPoints + 2, pts);
823 exec->is_composite = FALSE;
824 for (k = 0; k < nPoints + 2; k++)
825 pts->touch[k] &= TT_Flag_On_Curve;
826 if (pFont->patented)
827 code = TT_Err_Invalid_Engine;
828 else
829 code = Context_Run(exec, FALSE );
830 if (!code)
831 cur_to_org(nPoints + 2, pts);
832 else if (code == TT_Err_Invalid_Engine)
833 error = fPatented;
834 else
835 error = fBadInstruction;
836 gOutline->sideBearing = subglyph.bbox.xMin - subglyph.pp1.x;
837 gOutline->advance.x = subglyph.pp2.x - subglyph.pp1.x;
838 }
839 Unset_CodeRange(exec);
840 Clear_CodeRange(exec, TT_CodeRange_Glyph);
841 } else
842 error = fBadFontData;
843 goto ex;
844 errex:;
845 error = fBadFontData;
846 ex:;
847 r->ReleaseGlyph(r, glyphIndex);
848
849 if (error == fBadInstruction && execute_bytecode) {
850 /* reset a load of stuff so we can try again without hinting */
851 nNextGlyphPtr = 0;
852 exec = pFont->exec;
853 pts = &exec->pts;
854 usage = tti->usage + tti->usage_top;
855 glyph = NULL;
856 self->nPointsTotal -= (nPoints + 2);
857 nPoints = 0;
858 self->nContoursTotal -= gOutline->contourCount;
859 error = fNoError;
860 execute_bytecode = false;
861 r->Seek(r, nPosBeg);
862 goto retry;
863 }
864
865 return error;
866 }
867
ttfOutliner__BuildGlyphOutline(ttfOutliner * self,int glyphIndex,float orig_x,float orig_y,ttfGlyphOutline * gOutline)868 static FontError ttfOutliner__BuildGlyphOutline(ttfOutliner *self, int glyphIndex,
869 float orig_x, float orig_y, ttfGlyphOutline* gOutline)
870 {
871 FixMatrix m_orig = {1 << 16, 0, 0, 1 << 16, 0, 0};
872
873 /* Round towards zero like old character coordinate conversions do. */
874 m_orig.tx = floatToF16Dot16(orig_x);
875 m_orig.ty = floatToF16Dot16(orig_y);
876 return ttfOutliner__BuildGlyphOutlineAux(self, glyphIndex, &m_orig, gOutline);
877 }
878
879 #define AVECTOR_BUG 1 /* Work around a bug in AVector fonts. */
880
ttfOutliner__DrawGlyphOutline(ttfOutliner * self)881 void ttfOutliner__DrawGlyphOutline(ttfOutliner *self)
882 { ttfGlyphOutline* out = &self->out;
883 FloatMatrix *m = &self->post_transform;
884 ttfFont *pFont = self->pFont;
885 ttfExport *exp = self->exp;
886 TExecution_Context *exec = pFont->exec;
887 TGlyph_Zone *epts = &exec->pts;
888 short* endP = epts->contours;
889 byte* onCurve = epts->touch;
890 F26Dot6* x = epts->org_x;
891 F26Dot6* y = epts->org_y;
892 F26Dot6 px, py;
893 short sp, ctr;
894 FloatPoint p0, p1, p2, p3;
895 # if AVECTOR_BUG
896 F26Dot6 expand_x = Scale_X(&exec->metrics, pFont->nUnitsPerEm * 2);
897 F26Dot6 expand_y = Scale_Y(&exec->metrics, pFont->nUnitsPerEm * 2);
898 F26Dot6 xMin = out->xMinB - expand_x, xMax = out->xMaxB + expand_x;
899 F26Dot6 yMin = out->yMinB - expand_y, yMax = out->yMaxB + expand_y;
900 # endif
901
902 TransformF26Dot6PointFloat(&p1, out->advance.x, out->advance.y, m);
903 p1.x -= self->post_transform.tx;
904 p1.y -= self->post_transform.ty;
905 exp->SetWidth(exp, &p1);
906 sp = -1;
907 for (ctr = out->contourCount; ctr != 0; --ctr) {
908 short pt, pts = *endP - sp;
909 short ep = pts - 1;
910
911 if (pts < 3) {
912 x += pts;
913 y += pts;
914 onCurve += pts;
915 sp = *endP++;
916 continue; /* skip 1 and 2 point contours */
917 }
918
919 if (exp->bPoints) {
920 for (pt = 0; pt <= ep; pt++) {
921 px = x[pt], py = y[pt];
922 # if AVECTOR_BUG
923 if (x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) {
924 short prevIndex = pt == 0 ? ep : pt - 1;
925 short nextIndex = pt == ep ? 0 : pt + 1;
926 if (nextIndex > ep)
927 nextIndex = 0;
928 px=AVE(x[prevIndex], x[nextIndex]);
929 py=AVE(y[prevIndex], y[nextIndex]);
930 }
931 # endif
932 TransformF26Dot6PointFloat(&p0, px, py, m);
933 exp->Point(exp, &p0, onCurve[pt], !pt);
934 }
935 }
936
937 if (exp->bOutline) {
938 pt = 0;
939 if(onCurve[ep] & 1) {
940 px = x[ep];
941 py = y[ep];
942 } else if (onCurve[0] & 1) {
943 px = x[0];
944 py = y[0];
945 pt = 1;
946 } else {
947 px = AVE(x[0], x[ep]);
948 py = AVE(y[0], y[ep]);
949 }
950 self->ppx = px; self->ppy = py;
951 TransformF26Dot6PointFloat(&p0, px, py, m);
952 exp->MoveTo(exp, &p0);
953
954 for (; pt <= ep; pt++) {
955 short prevIndex = pt == 0 ? ep : pt - 1;
956 short nextIndex = pt == ep ? 0 : pt + 1;
957 if (onCurve[pt] & 1) {
958 if (onCurve[prevIndex] & 1) {
959 px = x[pt];
960 py = y[pt];
961 if (self->ppx != px || self->ppy != py) {
962 TransformF26Dot6PointFloat(&p1, px, py, m);
963 exp->LineTo(exp, &p1);
964 self->ppx = px; self->ppy = py;
965 p0 = p1;
966 }
967 }
968 } else {
969 F26Dot6 prevX, prevY, nextX, nextY;
970
971 px = x[pt];
972 py = y[pt];
973 # if AVECTOR_BUG
974 if(x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) {
975 px=AVE(x[prevIndex], x[nextIndex]);
976 py=AVE(y[prevIndex], y[nextIndex]);
977 }
978 # endif
979 if (onCurve[prevIndex] & 1) {
980 prevX = x[prevIndex];
981 prevY = y[prevIndex];
982 } else {
983 prevX = AVE(x[prevIndex], px);
984 prevY = AVE(y[prevIndex], py);
985 }
986 if (onCurve[nextIndex] & 1) {
987 nextX = x[nextIndex];
988 nextY = y[nextIndex];
989 } else {
990 nextX = AVE(px, x[nextIndex]);
991 nextY = AVE(py, y[nextIndex]);
992 }
993 if (self->ppx != nextX || self->ppy != nextY) {
994 double dx1, dy1, dx2, dy2, dx3, dy3;
995 const double prec = 1e-6;
996
997 TransformF26Dot6PointFloat(&p1, (prevX + (px << 1)) / 3, (prevY + (py << 1)) / 3, m);
998 TransformF26Dot6PointFloat(&p2, (nextX + (px << 1)) / 3, (nextY + (py << 1)) / 3, m);
999 TransformF26Dot6PointFloat(&p3, nextX, nextY, m);
1000 dx1 = p1.x - p0.x, dy1 = p1.y - p0.y;
1001 dx2 = p2.x - p0.x, dy2 = p2.y - p0.y;
1002 dx3 = p3.x - p0.x, dy3 = p3.y - p0.y;
1003 if (fabs(dx1 * dy3 - dy1 * dx3) > prec * fabs(dx1 * dx3 - dy1 * dy3) ||
1004 fabs(dx2 * dy3 - dy2 * dx3) > prec * fabs(dx2 * dx3 - dy2 * dy3))
1005 exp->CurveTo(exp, &p1, &p2, &p3);
1006 else
1007 exp->LineTo(exp, &p3);
1008 self->ppx = nextX; self->ppy = nextY;
1009 p0 = p3;
1010 }
1011 }
1012 }
1013 exp->Close(exp);
1014 }
1015 x += pts;
1016 y += pts;
1017 onCurve += pts;
1018 sp = *endP++;
1019 }
1020 }
1021
ttfOutliner__Outline(ttfOutliner * self,int glyphIndex,float orig_x,float orig_y,FloatMatrix * m1)1022 FontError ttfOutliner__Outline(ttfOutliner *self, int glyphIndex,
1023 float orig_x, float orig_y, FloatMatrix *m1)
1024 { ttfFont *pFont = self->pFont;
1025 FontError error;
1026
1027 self->post_transform = *m1;
1028 self->out.contourCount = 0;
1029 self->out.pointCount = 0;
1030 self->out.bCompound = FALSE;
1031 self->nPointsTotal = 0;
1032 self->nContoursTotal = 0;
1033 self->out.advance.x = self->out.advance.y = 0;
1034 ttfFont__StartGlyph(pFont);
1035 error = ttfOutliner__BuildGlyphOutline(self, glyphIndex, orig_x, orig_y, &self->out);
1036 ttfFont__StopGlyph(pFont);
1037 if (pFont->nUnitsPerEm <= 0)
1038 pFont->nUnitsPerEm = 1024;
1039 if (pFont->design_grid) {
1040 self->post_transform.a /= pFont->nUnitsPerEm;
1041 self->post_transform.b /= pFont->nUnitsPerEm;
1042 self->post_transform.c /= pFont->nUnitsPerEm;
1043 self->post_transform.d /= pFont->nUnitsPerEm;
1044 }
1045 return error;
1046 }
1047