~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to base/ttfmain.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

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