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