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