1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
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.
14
/* $Id: ttfmain.c 8972 2008-08-12 07:35:33Z leonardo $ */
15
/* A Free Type interface adapter. */
16
/* Uses code fragments from the FreeType project. */
28
static const bool skip_instructions = 0; /* Debug purpose only. */
31
TT_Fixed a, b, c, d, tx, ty;
34
struct ttfSubGlyphUsage_s {
41
/*------------------------------------------------------------------- */
43
static TT_Fixed AVE(F26Dot6 a, F26Dot6 b)
47
static F26Dot6 shortToF26Dot6(short a)
48
{ return (F26Dot6)a << 6;
51
static F26Dot6 floatToF26Dot6(float a)
52
{ return (F26Dot6)(a * (1 << 6) + 0.5);
55
static TT_Fixed floatToF16Dot16(float a)
56
{ return (F26Dot6)(a * (1 << 16) + 0.5);
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);
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;
69
/*-------------------------------------------------------------------*/
71
static ttfPtrElem *ttfFont__get_table_ptr(ttfFont *f, char *id)
73
if (!memcmp(id, "cvt ", 4))
75
if (!memcmp(id, "fpgm", 4))
77
if (!memcmp(id, "glyf", 4))
79
if (!memcmp(id, "head", 4))
81
if (!memcmp(id, "hhea", 4))
83
if (!memcmp(id, "hmtx", 4))
85
if (!memcmp(id, "vhea", 4))
87
if (!memcmp(id, "vmtx", 4))
89
if (!memcmp(id, "loca", 4))
91
if (!memcmp(id, "maxp", 4))
93
if (!memcmp(id, "prep", 4))
95
if (!memcmp(id, "cmap", 4))
100
/*-------------------------------------------------------------------*/
102
TT_Error TT_Set_Instance_CharSizes(TT_Instance instance,
103
TT_F26Dot6 charWidth,
104
TT_F26Dot6 charHeight)
106
PInstance ins = instance.z;
109
return TT_Err_Invalid_Instance_Handle;
111
if (charWidth < 1*64)
114
if (charHeight < 1*64)
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;
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;
127
ins->metrics.x_ppem = ins->metrics.x_scale1 / 64;
128
ins->metrics.y_ppem = ins->metrics.y_scale1 / 64;
130
if (charWidth > charHeight)
131
ins->metrics.pointSize = charWidth;
133
ins->metrics.pointSize = charHeight;
136
return Instance_Reset(ins, FALSE);
139
/*-------------------------------------------------------------------*/
141
int ttfInterpreter__obtain(ttfMemory *mem, ttfInterpreter **ptti)
149
tti = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_ttfInterpreter, "ttfInterpreter__obtain");
154
tti->ttf_memory = mem;
156
tti->exec = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TExecution_Context, "ttfInterpreter__obtain");
158
mem->free(mem, tti, "ttfInterpreter__obtain");
161
memset(tti->exec, 0, sizeof(*tti->exec));
166
void ttfInterpreter__release(ttfInterpreter **ptti)
168
ttfInterpreter *tti = *ptti;
169
ttfMemory *mem = tti->ttf_memory;
173
mem->free(mem, tti->usage, "ttfInterpreter__release");
174
mem->free(mem, tti->exec, "ttfInterpreter__release");
175
mem->free(mem, *ptti, "ttfInterpreter__release");
179
/*-------------------------------------------------------------------*/
181
void ttfFont__init(ttfFont *this, ttfMemory *mem,
182
void (*DebugRepaint)(ttfFont *),
183
int (*DebugPrint)(ttfFont *, const char *s, ...))
185
memset(this, 0, sizeof(*this));
186
this->DebugRepaint = DebugRepaint;
187
this->DebugPrint = DebugPrint;
190
void ttfFont__finit(ttfFont *this)
191
{ ttfMemory *mem = this->tti->ttf_memory;
195
Context_Destroy(this->exec);
197
/* Context_Create was not called - see ttfFont__Open.
198
Must not call Context_Destroy for proper 'lock' count.
204
Instance_Destroy(this->inst);
205
mem->free(mem, this->inst, "ttfFont__finit");
208
Face_Destroy(this->face);
209
mem->free(mem, this->face, "ttfFont__finit");
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. */
217
FontError ttfFont__Open(ttfInterpreter *tti, ttfFont *this, ttfReader *r,
218
unsigned int nTTC, float w, float h,
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;
226
ttfMemory *mem = tti->ttf_memory;
230
this->design_grid = design_grid;
231
r->Read(r, sVersion, 4);
232
if(!memcmp(sVersion, "ttcf", 4)) {
234
unsigned int nPos = 0xbaadf00d; /* Quiet compiler. */
236
r->Read(r, sVersion, 4);
237
if(memcmp(sVersion, sVersion1, 4) && memcmp(sVersion, sVersion2, 4))
238
return fUnimplemented;
239
nFonts = ttfReader__UInt(r);
243
return fTableNotFound;
244
for(i = 0; i <= nTTC; i++)
245
nPos = ttfReader__UInt(r);
247
r->Read(r, sVersion, 4);
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++) {
257
unsigned int nOffset, nLength;
262
ttfReader__UInt(r); /* nCheckSum */
263
nOffset = ttfReader__UInt(r);
264
nLength = ttfReader__UInt(r);
265
e = ttfFont__get_table_ptr(this, sTag);
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);
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");
293
tti->usage = mem->alloc_bytes(mem,
294
sizeof(ttfSubGlyphUsage) * this->nMaxComponents * MAX_SUBGLYPH_NESTING,
296
if (tti->usage == NULL)
298
tti->usage_size = this->nMaxComponents * MAX_SUBGLYPH_NESTING;
300
this->face = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TFace, "ttfFont__Open");
301
if (this->face == NULL)
303
memset(this->face, 0, sizeof(*this->face));
305
this->face->font = this;
306
this->exec = tti->exec;
307
code = Face_Create(this->face);
313
this->inst = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TInstance, "ttfFont__Open");
314
if (this->inst == NULL)
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)
320
code = Instance_Create(this->inst, this->face);
321
if (code == TT_Err_Out_Of_Memory)
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)
330
if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement)
331
code1 = fBadInstruction;
336
ww = hh = shortToF26Dot6(this->nUnitsPerEm);
338
/* Round towards zero for a better view of mirrored characters : */
339
ww = floatToF26Dot6(w);
340
hh = floatToF26Dot6(h);
342
code = TT_Set_Instance_CharSizes(I, ww, hh);
343
this->inst->metrics = this->exec->metrics;
344
if (code == TT_Err_Invalid_Engine)
346
if (code == TT_Err_Out_Of_Memory)
348
if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement)
349
return fBadInstruction;
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;
362
this->exec->GS = this->inst->GS;
363
this->tti->usage_top = 0;
366
static void ttfFont__StopGlyph(ttfFont *this)
368
Context_Save(this->exec, this->inst);
371
/*-------------------------------------------------------------------*/
373
static void mount_zone( PGlyph_Zone source,
378
np = source->n_points;
379
nc = source->n_contours;
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;
387
target->contours = source->contours + nc;
389
target->n_points = 0;
390
target->n_contours = 0;
393
static void Init_Glyph_Component( PSubglyph_Record element,
394
PSubglyph_Record original,
395
PExecution_Context exec )
398
element->is_scaled = FALSE;
399
element->is_hinted = FALSE;
402
mount_zone( &original->zone, &element->zone );
404
element->zone = exec->pts;
406
element->zone.n_contours = 0;
407
element->zone.n_points = 0;
412
element->element_flag = 0;
413
element->preserve_pps = FALSE;
415
element->transform.xx = 1 << 16;
416
element->transform.xy = 0;
417
element->transform.yx = 0;
418
element->transform.yy = 1 << 16;
420
element->transform.ox = 0;
421
element->transform.oy = 0;
423
element->leftBearing = 0;
424
element->advanceWidth = 0;
427
static void cur_to_org( Int n, PGlyph_Zone zone )
431
for ( k = 0; k < n; k++ )
432
zone->org_x[k] = zone->cur_x[k];
434
for ( k = 0; k < n; k++ )
435
zone->org_y[k] = zone->cur_y[k];
438
static void org_to_cur( Int n, PGlyph_Zone zone )
442
for ( k = 0; k < n; k++ )
443
zone->cur_x[k] = zone->org_x[k];
445
for ( k = 0; k < n; k++ )
446
zone->cur_y[k] = zone->org_y[k];
450
/*-------------------------------------------------------------------*/
452
void ttfOutliner__init(ttfOutliner *this, ttfFont *f, ttfReader *r, ttfExport *exp,
453
bool bOutline, bool bFirst, bool bVertical)
456
this->bOutline = bOutline;
457
this->bFirst = bFirst;
459
this->bVertical = bVertical;
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;
469
if (m->a == 65536 && m->b == 0 &&
470
m->c == 0 && m->d == 65536 &&
471
m->tx == 0 && m->ty == 0)
473
for (; count != 0; --count) {
474
TransformF26Dot6PointFix(&p, *x, *y, m);
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;
486
FontError error = fNoError;
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;
500
if (r->get_metrics(r, glyphIndex, this->bVertical, &sideBearing, &nAdvance) < 0) {
501
/* fixme: the error code is missing due to interface restrictions. */
504
gOutline->sideBearing = shortToF26Dot6(sideBearing);
505
gOutline->advance.x = shortToF26Dot6(nAdvance);
506
gOutline->advance.y = 0;
507
this->bFirst = FALSE;
512
if (!r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size))
513
return fGlyphNotFound;
515
r->ReleaseGlyph(r, glyphIndex);
516
gOutline->xMinB = gOutline->yMinB = 0;
517
gOutline->xMaxB = gOutline->yMaxB = 0;
522
nPosBeg = r->Tell(r);
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);
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);
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;
541
subglyph.pp2.x = subglyph.pp1.x + nAdvance;
543
/* FreeType stuff end */
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;
553
gOutline->bCompound = TRUE;
554
if (tti->usage_top + pFont->nMaxComponents > tti->usage_size)
556
gOutline->contourCount = gOutline->pointCount = 0;
561
if (nUsage >= pFont->nMaxComponents) {
562
error = fMemoryError; goto ex;
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);
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);
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;
600
} while (flags & MORE_COMPONENTS);
601
/* Some fonts have bad WE_HAVE_INSTRUCTIONS, so use nNextGlyphPtr : */
605
n_ins = ((!r->Eof(r) && (bHaveInstructions || nPos < nNextGlyphPtr)) ? ttfReader__UShort(r) : 0);
607
r->ReleaseGlyph(r, glyphIndex);
609
for (i = 0; i < nUsage; i++) {
611
ttfSubGlyphUsage *e = &usage[i];
614
int nPointsStored = gOutline->pointCount, nContoursStored = gOutline->contourCount;
616
out.contourCount = 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)
636
else if (code != fNoError) {
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;
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;
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;
657
if (!skip_instructions && n_ins &&
658
!(pFont->inst->GS.instruct_control & 1)) {
661
r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size);
664
if (nPos + n_ins > glyph_size)
666
code = Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins);
668
int nPoints = gOutline->pointCount + 2;
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;
686
for (k = 0; k < nPoints; k++)
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;
694
code = TT_Err_Invalid_Engine;
696
code = Context_Run(exec, FALSE);
698
cur_to_org(nPoints, pts);
699
else if (code == TT_Err_Invalid_Engine)
702
error = fBadFontData;
704
Unset_CodeRange(exec);
705
Clear_CodeRange(exec, TT_CodeRange_Glyph);
707
} else if (gOutline->contourCount > 0) {
711
byte *onCurve, *stop, flag;
716
if (this->nContoursTotal + gOutline->contourCount > exec->n_contours) {
717
error = fBadFontData; goto ex;
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;
726
nPoints = gOutline->pointCount = endPoints[gOutline->contourCount - 1] + 1;
727
if (this->nPointsTotal + nPoints + 2 > exec->n_points) {
728
error = fBadFontData; goto ex;
730
n_ins = ttfReader__Short(r);
732
r->Seek(r, nPos + n_ins);
735
bInsOK = !Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins);
736
onCurve = pts->touch;
737
stop = onCurve + gOutline->pointCount;
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)
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);
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);
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);
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 );
776
/* Filter off the extra bits */
777
*onCurve++ = flag & ONCURVE;
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;
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;
804
for (k = 0; k < nPoints + 2; k++)
806
pts->cur_x[nPoints + 1] = (pts->cur_x[nPoints + 1] + 32) & -64;
807
org_to_cur(nPoints + 2, pts);
808
exec->is_composite = FALSE;
809
for (k = 0; k < nPoints + 2; k++)
810
pts->touch[k] &= TT_Flag_On_Curve;
812
code = TT_Err_Invalid_Engine;
814
code = Context_Run(exec, FALSE );
816
cur_to_org(nPoints + 2, pts);
817
else if (code == TT_Err_Invalid_Engine)
820
error = fBadInstruction;
821
gOutline->sideBearing = subglyph.bbox.xMin - subglyph.pp1.x;
822
gOutline->advance.x = subglyph.pp2.x - subglyph.pp1.x;
824
Unset_CodeRange(exec);
825
Clear_CodeRange(exec, TT_CodeRange_Glyph);
827
error = fBadFontData;
830
error = fBadFontData;
832
r->ReleaseGlyph(r, glyphIndex);
836
static FontError ttfOutliner__BuildGlyphOutline(ttfOutliner *this, int glyphIndex,
837
float orig_x, float orig_y, ttfGlyphOutline* gOutline)
839
FixMatrix m_orig = {1 << 16, 0, 0, 1 << 16, 0, 0};
841
/* Round towards zero like old character coordinate conversions do. */
842
m_orig.tx = floatToF16Dot16(orig_x);
843
m_orig.ty = floatToF16Dot16(orig_y);
844
return ttfOutliner__BuildGlyphOutlineAux(this, glyphIndex, &m_orig, gOutline);
848
#define AVECTOR_BUG 1 /* Work around a bug in AVector fonts. */
850
void ttfOutliner__DrawGlyphOutline(ttfOutliner *this)
851
{ ttfGlyphOutline* out = &this->out;
852
FloatMatrix *m = &this->post_transform;
853
ttfFont *pFont = this->pFont;
854
ttfExport *exp = this->exp;
855
TExecution_Context *exec = pFont->exec;
856
TGlyph_Zone *pts = &exec->pts;
857
short* endP = pts->contours;
858
byte* onCurve = pts->touch;
859
F26Dot6* x = pts->org_x;
860
F26Dot6* y = pts->org_y;
863
FloatPoint p0, p1, p2, p3;
865
F26Dot6 expand_x = Scale_X(&exec->metrics, pFont->nUnitsPerEm * 2);
866
F26Dot6 expand_y = Scale_Y(&exec->metrics, pFont->nUnitsPerEm * 2);
867
F26Dot6 xMin = out->xMinB - expand_x, xMax = out->xMaxB + expand_x;
868
F26Dot6 yMin = out->yMinB - expand_y, yMax = out->yMaxB + expand_y;
871
TransformF26Dot6PointFloat(&p1, out->advance.x, out->advance.y, m);
872
p1.x -= this->post_transform.tx;
873
p1.y -= this->post_transform.ty;
874
exp->SetWidth(exp, &p1);
876
for (ctr = out->contourCount; ctr != 0; --ctr) {
877
short pt, pts = *endP - sp;
885
continue; /* skip 1 and 2 point contours */
889
for (pt = 0; pt <= ep; pt++) {
890
px = x[pt], py = y[pt];
892
if (x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) {
893
short prevIndex = pt == 0 ? ep : pt - 1;
894
short nextIndex = pt == ep ? 0 : pt + 1;
897
px=AVE(x[prevIndex], x[nextIndex]);
898
py=AVE(y[prevIndex], y[nextIndex]);
901
TransformF26Dot6PointFloat(&p0, px, py, m);
902
exp->Point(exp, &p0, onCurve[pt], !pt);
908
if(onCurve[ep] & 1) {
911
} else if (onCurve[0] & 1) {
916
px = AVE(x[0], x[ep]);
917
py = AVE(y[0], y[ep]);
919
this->ppx = px; this->ppy = py;
920
TransformF26Dot6PointFloat(&p0, px, py, m);
921
exp->MoveTo(exp, &p0);
923
for (; pt <= ep; pt++) {
924
short prevIndex = pt == 0 ? ep : pt - 1;
925
short nextIndex = pt == ep ? 0 : pt + 1;
926
if (onCurve[pt] & 1) {
927
if (onCurve[prevIndex] & 1) {
930
if (this->ppx != px || this->ppy != py) {
931
TransformF26Dot6PointFloat(&p1, px, py, m);
932
exp->LineTo(exp, &p1);
933
this->ppx = px; this->ppy = py;
938
F26Dot6 prevX, prevY, nextX, nextY;
943
if(x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) {
944
px=AVE(x[prevIndex], x[nextIndex]);
945
py=AVE(y[prevIndex], y[nextIndex]);
948
if (onCurve[prevIndex] & 1) {
949
prevX = x[prevIndex];
950
prevY = y[prevIndex];
952
prevX = AVE(x[prevIndex], px);
953
prevY = AVE(y[prevIndex], py);
955
if (onCurve[nextIndex] & 1) {
956
nextX = x[nextIndex];
957
nextY = y[nextIndex];
959
nextX = AVE(px, x[nextIndex]);
960
nextY = AVE(py, y[nextIndex]);
962
if (this->ppx != nextX || this->ppy != nextY) {
963
double dx1, dy1, dx2, dy2, dx3, dy3;
964
const double prec = 1e-6;
966
TransformF26Dot6PointFloat(&p1, (prevX + (px << 1)) / 3, (prevY + (py << 1)) / 3, m);
967
TransformF26Dot6PointFloat(&p2, (nextX + (px << 1)) / 3, (nextY + (py << 1)) / 3, m);
968
TransformF26Dot6PointFloat(&p3, nextX, nextY, m);
969
dx1 = p1.x - p0.x, dy1 = p1.y - p0.y;
970
dx2 = p2.x - p0.x, dy2 = p2.y - p0.y;
971
dx3 = p3.x - p0.x, dy3 = p3.y - p0.y;
972
if (fabs(dx1 * dy3 - dy1 * dx3) > prec * fabs(dx1 * dx3 - dy1 * dy3) ||
973
fabs(dx2 * dy3 - dy2 * dx3) > prec * fabs(dx2 * dx3 - dy2 * dy3))
974
exp->CurveTo(exp, &p1, &p2, &p3);
976
exp->LineTo(exp, &p3);
977
this->ppx = nextX; this->ppy = nextY;
991
FontError ttfOutliner__Outline(ttfOutliner *this, int glyphIndex,
992
float orig_x, float orig_y, FloatMatrix *m1)
993
{ ttfFont *pFont = this->pFont;
996
this->post_transform = *m1;
997
this->out.contourCount = 0;
998
this->out.pointCount = 0;
999
this->out.bCompound = FALSE;
1000
this->nPointsTotal = 0;
1001
this->nContoursTotal = 0;
1002
this->out.advance.x = this->out.advance.y = 0;
1003
ttfFont__StartGlyph(pFont);
1004
error = ttfOutliner__BuildGlyphOutline(this, glyphIndex, orig_x, orig_y, &this->out);
1005
ttfFont__StopGlyph(pFont);
1006
if (pFont->nUnitsPerEm <= 0)
1007
pFont->nUnitsPerEm = 1024;
1008
if (pFont->design_grid) {
1009
this->post_transform.a /= pFont->nUnitsPerEm;
1010
this->post_transform.b /= pFont->nUnitsPerEm;
1011
this->post_transform.c /= pFont->nUnitsPerEm;
1012
this->post_transform.d /= pFont->nUnitsPerEm;
1014
if (error != fNoError && error != fPatented)