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