Coverage Report

Created: 2025-06-10 07:27

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