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