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