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