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