Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gxttfb.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* A bridge to True Type interpreter. */
18
19
#include "gx.h"
20
#include "gxfont.h"
21
#include "gxfont42.h"
22
#include "gxttfb.h"
23
#include "gxfixed.h"
24
#include "gxpath.h"
25
#include "gxfcache.h"
26
#include "gxmatrix.h"
27
#include "gxhintn.h"
28
#include "gzpath.h"
29
#include "ttfmemd.h"
30
#include "gsstruct.h"
31
#include "gserrors.h"
32
#include "gsfont.h"
33
#include "gdebug.h"
34
#include "memory_.h"
35
#include "math_.h"
36
#include "gxgstate.h"
37
#include "gxpaint.h"
38
#include "gzspotan.h"
39
#include <stdarg.h>
40
41
gs_public_st_composite(st_gx_ttfReader, gx_ttfReader,
42
    "gx_ttfReader", gx_ttfReader_enum_ptrs, gx_ttfReader_reloc_ptrs);
43
44
static
45
0
ENUM_PTRS_WITH(gx_ttfReader_enum_ptrs, gx_ttfReader *mptr)
46
0
    {
47
        /* The fields 'pfont' and 'glyph_data' may contain pointers from global
48
           to local memory ( see a comment in gxttfb.h).
49
           They must be NULL when a garbager is invoked.
50
           Due to that we don't enumerate and don't relocate them.
51
         */
52
0
        DISCARD(mptr);
53
0
        return 0;
54
0
    }
55
0
    ENUM_PTR(0, gx_ttfReader, memory);
56
0
ENUM_PTRS_END
57
58
0
static RELOC_PTRS_WITH(gx_ttfReader_reloc_ptrs, gx_ttfReader *mptr)
59
0
    DISCARD(mptr);
60
0
    RELOC_PTR(gx_ttfReader, memory);
61
0
RELOC_PTRS_END
62
63
static bool gx_ttfReader__Eof(ttfReader *self)
64
29.5M
{
65
29.5M
    gx_ttfReader *r = (gx_ttfReader *)self;
66
67
29.5M
    if (r->extra_glyph_index != -1)
68
129k
        return r->pos >= r->glyph_data.bits.size;
69
    /* We can't know whether pfont->data.string_proc has more bytes,
70
       so we never report Eof for it. */
71
29.3M
    return false;
72
29.5M
}
73
74
static void gx_ttfReader__Read(ttfReader *self, void *p, int n)
75
43.1M
{
76
43.1M
    gx_ttfReader *r = (gx_ttfReader *)self;
77
43.1M
    const byte *q;
78
79
43.1M
    if (r->error >= 0) {
80
43.0M
        if (r->extra_glyph_index != -1) {
81
8.30M
            q = r->glyph_data.bits.data + r->pos;
82
8.30M
            r->error = ((r->pos >= r->glyph_data.bits.size ||
83
8.30M
                        r->glyph_data.bits.size - r->pos < n) ?
84
8.30M
                            gs_note_error(gs_error_invalidfont) : 0);
85
8.30M
            if (r->error == 0)
86
8.30M
                memcpy(p, q, n);
87
34.7M
        } else {
88
34.7M
            unsigned int cnt;
89
34.7M
            r->error = 0;
90
91
34.7M
            for (cnt = 0; cnt < (uint)n; cnt += r->error) {
92
34.7M
                r->error = r->pfont->data.string_proc(r->pfont, (ulong)r->pos + cnt, (ulong)n - cnt, &q);
93
34.7M
                if (r->error < 0)
94
0
                    break;
95
34.7M
                else if ( r->error == 0) {
96
34.7M
                    memcpy((char *)p + cnt, q, n - cnt);
97
34.7M
                    break;
98
34.7M
                } else {
99
0
                    memcpy((char *)p + cnt, q, r->error);
100
0
                }
101
34.7M
            }
102
34.7M
        }
103
43.0M
    }
104
43.1M
    if (r->error < 0) {
105
87.7k
        memset(p, 0, n);
106
87.7k
        return;
107
87.7k
    }
108
43.0M
    r->pos += n;
109
43.0M
}
110
111
static void gx_ttfReader__Seek(ttfReader *self, int nPos)
112
778k
{
113
778k
    gx_ttfReader *r = (gx_ttfReader *)self;
114
115
778k
    r->pos = nPos;
116
778k
}
117
118
static int gx_ttfReader__Tell(ttfReader *self)
119
217k
{
120
217k
    gx_ttfReader *r = (gx_ttfReader *)self;
121
122
217k
    return r->pos;
123
217k
}
124
125
static bool gx_ttfReader__Error(ttfReader *self)
126
390k
{
127
390k
    gx_ttfReader *r = (gx_ttfReader *)self;
128
129
390k
    return r->error;
130
390k
}
131
132
static int gx_ttfReader__LoadGlyph(ttfReader *self, int glyph_index, const byte **p, int *size)
133
127k
{
134
127k
    gx_ttfReader *r = (gx_ttfReader *)self;
135
127k
    gs_font_type42 *pfont = r->pfont;
136
127k
    int code;
137
138
127k
    if (r->extra_glyph_index != -1)
139
0
        return 0; /* We only maintain a single glyph buffer.
140
                     It's enough because ttfOutliner__BuildGlyphOutline
141
                     is optimized for that, and pfont->data.get_outline
142
                     implements a charstring cache. */
143
127k
    r->glyph_data.memory = pfont->memory;
144
127k
    code = pfont->data.get_outline(pfont, (uint)glyph_index, &r->glyph_data);
145
127k
    r->extra_glyph_index = glyph_index;
146
127k
    r->pos = 0;
147
127k
    if (code < 0)
148
0
        r->error = code;
149
127k
    else if (code > 0) {
150
        /* Should not happen. */
151
0
        r->error = gs_note_error(gs_error_unregistered);
152
127k
    } else {
153
127k
        *p = r->glyph_data.bits.data;
154
127k
        *size = r->glyph_data.bits.size;
155
127k
    }
156
127k
    return 2; /* found */
157
127k
}
158
159
static void gx_ttfReader__ReleaseGlyph(ttfReader *self, int glyph_index)
160
129k
{
161
129k
    gx_ttfReader *r = (gx_ttfReader *)self;
162
163
129k
    if (r->extra_glyph_index != glyph_index)
164
2.31k
        return;
165
127k
    r->extra_glyph_index = -1;
166
127k
    gs_glyph_data_free(&r->glyph_data, "gx_ttfReader__ReleaseExtraGlyph");
167
127k
}
168
169
static void gx_ttfReader__Reset(gx_ttfReader *self)
170
193k
{
171
193k
    if (self->extra_glyph_index != -1) {
172
0
        self->extra_glyph_index = -1;
173
0
        gs_glyph_data_free(&self->glyph_data, "gx_ttfReader__Reset");
174
0
    }
175
193k
    self->error = 0;
176
193k
    self->pos = 0;
177
193k
}
178
179
gx_ttfReader *gx_ttfReader__create(gs_memory_t *mem)
180
69.2k
{
181
69.2k
    gx_ttfReader *r = gs_alloc_struct(mem, gx_ttfReader, &st_gx_ttfReader, "gx_ttfReader__create");
182
183
69.2k
    if (r != NULL) {
184
69.2k
        r->super.Eof = gx_ttfReader__Eof;
185
69.2k
        r->super.Read = gx_ttfReader__Read;
186
69.2k
        r->super.Seek = gx_ttfReader__Seek;
187
69.2k
        r->super.Tell = gx_ttfReader__Tell;
188
69.2k
        r->super.Error = gx_ttfReader__Error;
189
69.2k
        r->super.LoadGlyph = gx_ttfReader__LoadGlyph;
190
69.2k
        r->super.ReleaseGlyph = gx_ttfReader__ReleaseGlyph;
191
69.2k
        r->pos = 0;
192
69.2k
        r->error = 0;
193
69.2k
        r->extra_glyph_index = -1;
194
69.2k
        memset(&r->glyph_data, 0, sizeof(r->glyph_data));
195
69.2k
        r->pfont = NULL;
196
69.2k
        r->memory = mem;
197
69.2k
        gx_ttfReader__Reset(r);
198
69.2k
    }
199
69.2k
    return r;
200
69.2k
}
201
202
void gx_ttfReader__destroy(gx_ttfReader *self)
203
69.2k
{
204
69.2k
    gs_free_object(self->memory, self, "gx_ttfReader__destroy");
205
69.2k
}
206
207
static int
208
gx_ttfReader__default_get_metrics(const ttfReader *ttf, uint glyph_index, bool bVertical,
209
                                  short *sideBearing, unsigned short *nAdvance)
210
127k
{
211
127k
    gx_ttfReader *self = (gx_ttfReader *)ttf;
212
127k
    float sbw[4];
213
127k
    int sbw_offset = bVertical;
214
127k
    int code;
215
127k
    int factor = self->pfont->data.unitsPerEm;
216
217
127k
    code = self->pfont->data.get_metrics(self->pfont, glyph_index, bVertical, sbw);
218
127k
    if (code < 0)
219
308
        return code;
220
    /* Due to an obsolete convention, simple_glyph_metrics scales
221
       the metrics into 1x1 rectangle as Postscript like.
222
       In same time, the True Type interpreter needs
223
       the original design units.
224
       Undo the scaling here with accurate rounding. */
225
127k
    *sideBearing = (short)floor(sbw[0 + sbw_offset] * factor + 0.5);
226
127k
    *nAdvance = (short)floor(sbw[2 + sbw_offset] * factor + 0.5);
227
127k
    return 0;
228
127k
}
229
230
void gx_ttfReader__set_font(gx_ttfReader *self, gs_font_type42 *pfont)
231
387k
{
232
387k
    self->pfont = pfont;
233
387k
    self->super.get_metrics = gx_ttfReader__default_get_metrics;
234
387k
}
235
236
/*----------------------------------------------*/
237
238
static void DebugRepaint(ttfFont *ttf)
239
0
{
240
0
}
241
242
#ifdef DEBUG
243
static int DebugPrint(ttfFont *ttf, const char *fmt, ...)
244
{
245
    char buf[500];
246
    va_list args;
247
    int count;
248
249
    if (gs_debug_c('Y')) {
250
        va_start(args, fmt);
251
        count = vsnprintf(buf, sizeof(buf), fmt, args);
252
        /* NB: moved debug output from stdout to stderr
253
         */
254
        errwrite(ttf->DebugMem, buf, count);
255
        va_end(args);
256
    }
257
    return 0;
258
}
259
#endif
260
261
static void WarnBadInstruction(gs_font_type42 *pfont, int glyph_index)
262
22.1k
{
263
22.1k
    char buf[gs_font_name_max + 1];
264
22.1k
    int l;
265
22.1k
    gs_font_type42 *base_font = pfont;
266
267
22.1k
    while ((gs_font_type42 *)base_font->base != base_font)
268
0
        base_font = (gs_font_type42 *)base_font->base;
269
22.1k
    if (!base_font->data.warning_bad_instruction) {
270
939
        l = min(sizeof(buf) - 1, base_font->font_name.size);
271
939
        memcpy(buf, base_font->font_name.chars, l);
272
939
        buf[l] = 0;
273
939
        if (glyph_index >= 0)
274
0
            emprintf2(pfont->memory,
275
939
                      "Failed to interpret TT instructions for glyph index %d of font %s. "
276
939
                      "Continue ignoring instructions of the font.\n",
277
939
                      glyph_index, buf);
278
939
        else
279
939
            emprintf1(pfont->memory,
280
939
                      "Failed to interpret TT instructions in font %s. "
281
939
                      "Continue ignoring instructions of the font.\n",
282
939
                      buf);
283
939
        base_font->data.warning_bad_instruction = true;
284
939
    }
285
22.1k
}
286
287
static void WarnPatented(gs_font_type42 *pfont, ttfFont *ttf, const char *txt)
288
16.3k
{
289
16.3k
    if (!ttf->design_grid) {
290
0
        char buf[gs_font_name_max + 1];
291
0
        int l;
292
0
        gs_font_type42 *base_font = pfont;
293
294
0
        while ((gs_font_type42 *)base_font->base != base_font)
295
0
            base_font = (gs_font_type42 *)base_font->base;
296
0
        if (!base_font->data.warning_patented) {
297
0
            l = min(sizeof(buf) - 1, base_font->font_name.size);
298
0
            memcpy(buf, base_font->font_name.chars, l);
299
0
            buf[l] = 0;
300
0
            emprintf2(pfont->memory,
301
0
                      "%s %s requires a patented True Type interpreter.\n",
302
0
                      txt,
303
0
                      buf);
304
0
            base_font->data.warning_patented = true;
305
0
        }
306
0
    }
307
16.3k
}
308
309
/*----------------------------------------------*/
310
311
struct gx_ttfMemory_s {
312
    ttfMemory super;
313
    gs_memory_t *memory;
314
};
315
316
gs_private_st_simple(st_gx_ttfMemory, gx_ttfMemory, "gx_ttfMemory");
317
/* st_gx_ttfMemory::memory points to a root. */
318
319
static void *gx_ttfMemory__alloc_bytes(ttfMemory *self, int size,  const char *cname)
320
1.08M
{
321
1.08M
    gs_memory_t *mem = ((gx_ttfMemory *)self)->memory;
322
323
1.08M
    return gs_alloc_bytes(mem, size, cname);
324
1.08M
}
325
326
static void *gx_ttfMemory__alloc_struct(ttfMemory *self, const ttfMemoryDescriptor *d,  const char *cname)
327
141k
{
328
141k
    gs_memory_t *mem = ((gx_ttfMemory *)self)->memory;
329
330
141k
    return mem->procs.alloc_struct(mem, (const gs_memory_struct_type_t *)d, cname);
331
141k
}
332
333
static void gx_ttfMemory__free(ttfMemory *self, void *p,  const char *cname)
334
1.55M
{
335
1.55M
    gs_memory_t *mem = ((gx_ttfMemory *)self)->memory;
336
337
1.55M
    gs_free_object(mem, p, cname);
338
1.55M
}
339
340
/*----------------------------------------------*/
341
342
static inline float reminder(float v, int x)
343
387k
{
344
387k
    return ((v / x) - floor(v / x)) * x;
345
387k
}
346
347
static void decompose_matrix(const gs_font_type42 *pfont, const gs_matrix * char_tm,
348
    const gs_log2_scale_point *log2_scale, bool design_grid,
349
    gs_point *char_size, gs_point *subpix_origin, gs_matrix *post_transform, bool *dg)
350
193k
{
351
    /*
352
     *  char_tm maps to subpixels.
353
     */
354
    /*
355
     *  We use a Free Type 1 True Type interpreter, which cannot perform
356
     *  a grid-fitting with skewing/rotation. It appears acceptable
357
     *  because we want to minimize invocations of patented instructions.
358
     *  We believe that skewing/rotation requires the patented intrivial cases
359
     *  of projection/freedom vectors.
360
     */
361
193k
    int scale_x = 1 << log2_scale->x;
362
193k
    int scale_y = 1 << log2_scale->y;
363
193k
    bool atp = gs_currentaligntopixels(pfont->dir);
364
193k
    bool design_grid1;
365
366
193k
    char_size->x = hypot(char_tm->xx, char_tm->xy);
367
193k
    char_size->y = hypot(char_tm->yx, char_tm->yy);
368
193k
    if (char_size->x <= 2 && char_size->y <= 2) {
369
        /* Disable the grid fitting for very small fonts. */
370
133k
        design_grid1 = true;
371
133k
    } else
372
60.1k
        design_grid1 = design_grid || !(gs_currentgridfittt(pfont->dir) & 1);
373
193k
    *dg = design_grid1;
374
193k
    subpix_origin->x = (atp ? 0 : reminder(char_tm->tx, scale_x) / scale_x);
375
193k
    subpix_origin->y = (atp ? 0 : reminder(char_tm->ty, scale_y) / scale_y);
376
193k
    post_transform->xx = char_tm->xx / (design_grid1 ? 1 : char_size->x);
377
193k
    post_transform->xy = char_tm->xy / (design_grid1 ? 1 : char_size->x);
378
193k
    post_transform->yx = char_tm->yx / (design_grid1 ? 1 : char_size->y);
379
193k
    post_transform->yy = char_tm->yy / (design_grid1 ? 1 : char_size->y);
380
193k
    post_transform->tx = char_tm->tx - subpix_origin->x;
381
193k
    post_transform->ty = char_tm->ty - subpix_origin->y;
382
193k
}
383
384
/*----------------------------------------------*/
385
386
ttfFont *ttfFont__create(gs_font_dir *dir)
387
69.2k
{
388
69.2k
    gs_memory_t *mem = dir->memory->stable_memory;
389
69.2k
    ttfFont *ttf;
390
391
69.2k
    if (dir->ttm == NULL) {
392
1.69k
        gx_ttfMemory *m = gs_alloc_struct(mem, gx_ttfMemory, &st_gx_ttfMemory, "ttfFont__create(gx_ttfMemory)");
393
394
1.69k
        if (!m)
395
0
            return 0;
396
1.69k
        m->super.alloc_struct = gx_ttfMemory__alloc_struct;
397
1.69k
        m->super.alloc_bytes = gx_ttfMemory__alloc_bytes;
398
1.69k
        m->super.free = gx_ttfMemory__free;
399
1.69k
        m->memory = mem;
400
1.69k
        dir->ttm = m;
401
1.69k
    }
402
69.2k
    if(ttfInterpreter__obtain(&dir->ttm->super, &dir->tti))
403
0
        return 0;
404
69.2k
    if(gx_san__obtain(mem, &dir->san))
405
0
        return 0;
406
69.2k
    ttf = gs_alloc_struct(mem, ttfFont, &st_ttfFont, "ttfFont__create");
407
69.2k
    if (ttf == NULL)
408
0
        return 0;
409
#ifdef DEBUG
410
    ttfFont__init(ttf, &dir->ttm->super, DebugRepaint,
411
                  (gs_debug_c('Y') ? DebugPrint : NULL), mem);
412
#else
413
69.2k
    ttfFont__init(ttf, &dir->ttm->super, DebugRepaint, NULL, mem);
414
69.2k
#endif
415
416
69.2k
    return ttf;
417
69.2k
}
418
419
void ttfFont__destroy(ttfFont *self, gs_font_dir *dir)
420
69.2k
{
421
69.2k
    gs_memory_t *mem = dir->memory->stable_memory;
422
423
69.2k
    ttfFont__finit(self);
424
69.2k
    gs_free_object(mem, self, "ttfFont__destroy");
425
69.2k
    ttfInterpreter__release(&dir->tti);
426
69.2k
    gx_san__release(&dir->san);
427
69.2k
    if (dir->tti == NULL && dir->ttm != NULL) {
428
1.69k
        gs_free_object(mem, dir->ttm, "ttfFont__destroy(gx_ttfMemory)");
429
1.69k
        dir->ttm = NULL;
430
1.69k
    }
431
69.2k
}
432
433
int ttfFont__Open_aux(ttfFont *self, ttfInterpreter *tti, gx_ttfReader *r, gs_font_type42 *pfont,
434
               const gs_matrix * char_tm, const gs_log2_scale_point *log2_scale,
435
               bool design_grid)
436
69.2k
{
437
69.2k
    gs_point char_size, subpix_origin;
438
69.2k
    gs_matrix post_transform;
439
    /*
440
     * Ghostscript proceses a TTC index in gs/lib/gs_ttf.ps,
441
     * and *pfont already adjusted to it.
442
     * Therefore TTC headers never comes here.
443
     */
444
69.2k
    unsigned int nTTC = 0;
445
69.2k
    bool dg;
446
447
69.2k
    decompose_matrix(pfont, char_tm, log2_scale, design_grid, &char_size, &subpix_origin, &post_transform, &dg);
448
69.2k
    switch(ttfFont__Open(tti, self, &r->super, nTTC, char_size.x, char_size.y, dg)) {
449
46.9k
        case fNoError:
450
46.9k
            return 0;
451
0
        case fMemoryError:
452
0
            return_error(gs_error_VMerror);
453
0
        case fUnimplemented:
454
0
            return_error(gs_error_unregistered);
455
22.1k
        case fBadInstruction:
456
22.1k
            WarnBadInstruction(pfont, -1);
457
22.1k
            goto recover;
458
101
        case fPatented:
459
101
            WarnPatented(pfont, self, "The font");
460
22.2k
        recover:
461
22.2k
            self->patented = true;
462
22.2k
            return 0;
463
0
        default:
464
0
            { int code = r->super.Error(&r->super);
465
466
0
                if (code < 0)
467
0
                    return code;
468
0
                return_error(gs_error_invalidfont);
469
0
            }
470
69.2k
    }
471
69.2k
}
472
473
/*----------------------------------------------*/
474
475
typedef struct gx_ttfExport_s {
476
    ttfExport super;
477
    gx_path *path;
478
    gs_fixed_point w;
479
    int error;
480
    bool monotonize;
481
} gx_ttfExport;
482
483
static void gx_ttfExport__MoveTo(ttfExport *self, FloatPoint *p)
484
149k
{
485
149k
    gx_ttfExport *e = (gx_ttfExport *)self;
486
487
149k
    if (e->error >= 0)
488
149k
        e->error = gx_path_add_point(e->path, float2fixed(p->x), float2fixed(p->y));
489
149k
}
490
491
static void gx_ttfExport__LineTo(ttfExport *self, FloatPoint *p)
492
719k
{
493
719k
    gx_ttfExport *e = (gx_ttfExport *)self;
494
495
719k
    if (e->error >= 0)
496
719k
        e->error = gx_path_add_line_notes(e->path, float2fixed(p->x), float2fixed(p->y), sn_none);
497
719k
}
498
499
static void gx_ttfExport__CurveTo(ttfExport *self, FloatPoint *p0, FloatPoint *p1, FloatPoint *p2)
500
1.46M
{
501
1.46M
    gx_ttfExport *e = (gx_ttfExport *)self;
502
503
1.46M
    if (e->error >= 0) {
504
1.46M
        if (e->monotonize) {
505
0
            curve_segment s;
506
507
0
            s.notes = sn_none;
508
0
            s.p1.x = float2fixed(p0->x), s.p1.y = float2fixed(p0->y),
509
0
            s.p2.x = float2fixed(p1->x), s.p2.y = float2fixed(p1->y),
510
0
            s.pt.x = float2fixed(p2->x), s.pt.y = float2fixed(p2->y);
511
0
            e->error = gx_curve_monotonize(e->path, &s);
512
0
        } else
513
1.46M
            e->error = gx_path_add_curve_notes(e->path, float2fixed(p0->x), float2fixed(p0->y),
514
1.46M
                                     float2fixed(p1->x), float2fixed(p1->y),
515
1.46M
                                     float2fixed(p2->x), float2fixed(p2->y), sn_none);
516
1.46M
    }
517
1.46M
}
518
519
static void gx_ttfExport__Close(ttfExport *self)
520
149k
{
521
149k
    gx_ttfExport *e = (gx_ttfExport *)self;
522
523
149k
    if (e->error >= 0)
524
149k
        e->error = gx_path_close_subpath_notes(e->path, sn_none);
525
149k
}
526
527
static void gx_ttfExport__Point(ttfExport *self, FloatPoint *p, bool bOnCurve, bool bNewPath)
528
0
{
529
    /* Never called. */
530
0
}
531
532
static void gx_ttfExport__SetWidth(ttfExport *self, FloatPoint *p)
533
123k
{
534
123k
    gx_ttfExport *e = (gx_ttfExport *)self;
535
536
123k
    e->w.x = float2fixed(p->x);
537
123k
    e->w.y = float2fixed(p->y);
538
123k
}
539
540
static void gx_ttfExport__DebugPaint(ttfExport *self)
541
0
{
542
0
}
543
544
/*----------------------------------------------*/
545
546
static int
547
path_to_hinter(t1_hinter *h, gx_path *path)
548
0
{   int code;
549
0
    gs_path_enum penum;
550
0
    gs_fixed_point pts[3];
551
0
    gs_fixed_point p = {0, 0}; /* initialize to avoid a warning */
552
0
    bool first = true;
553
0
    int op;
554
555
0
    code = gx_path_enum_init(&penum, path);
556
0
    if (code < 0)
557
0
        return code;
558
0
    while ((op = gx_path_enum_next(&penum, pts)) != 0) {
559
0
        switch (op) {
560
0
            case gs_pe_moveto:
561
0
                if (first) {
562
0
                    first = false;
563
0
                    p = pts[0];
564
0
                    code = t1_hinter__rmoveto(h, p.x, p.y);
565
0
                } else
566
0
                    code = t1_hinter__rmoveto(h, pts[0].x - p.x, pts[0].y - p.y);
567
0
                break;
568
0
            case gs_pe_lineto:
569
0
            case gs_pe_gapto:
570
0
                code = t1_hinter__rlineto(h, pts[0].x - p.x, pts[0].y - p.y);
571
0
                break;
572
0
            case gs_pe_curveto:
573
0
                code = t1_hinter__rcurveto(h, pts[0].x - p.x, pts[0].y - p.y,
574
0
                                        pts[1].x - pts[0].x, pts[1].y - pts[0].y,
575
0
                                        pts[2].x - pts[1].x, pts[2].y - pts[1].y);
576
0
                pts[0] = pts[2];
577
0
                break;
578
0
            case gs_pe_closepath:
579
0
                code = t1_hinter__closepath(h);
580
0
                break;
581
0
            default:
582
0
                return_error(gs_error_unregistered);
583
0
        }
584
0
        if (code < 0)
585
0
            return code;
586
0
        p = pts[0];
587
0
    }
588
0
    return 0;
589
0
}
590
591
0
#define exch(a,b) a^=b; b^=a; a^=b;
592
593
static void
594
transpose_path(gx_path *path)
595
0
{   segment *s = (segment *)path->first_subpath;
596
597
0
    exch(path->bbox.p.x, path->bbox.p.y);
598
0
    exch(path->bbox.q.x, path->bbox.q.y);
599
0
    for (; s; s = s->next) {
600
0
        if (s->type == s_curve) {
601
0
            curve_segment *c = (curve_segment *)s;
602
603
0
            exch(c->p1.x, c->p1.y);
604
0
            exch(c->p2.x, c->p2.y);
605
0
        }
606
0
        exch(s->pt.x, s->pt.y);
607
0
    }
608
0
}
609
610
typedef struct {
611
    t1_hinter super;
612
    int transpose;
613
    fixed midx;
614
} t1_hinter_aux;
615
616
static int
617
stem_hint_handler(void *client_data, gx_san_sect *ss)
618
0
{
619
0
    t1_hinter_aux *h = (t1_hinter_aux *)client_data;
620
621
0
    if (ss->side_mask == 3) {
622
        /* Orient horizontal hints to help with top/bottom alignment zones.
623
           Otherwize glyphs may get a random height due to serif adjustsment. */
624
0
        if (ss->xl > h->midx && h->transpose)
625
0
            return (h->transpose ? t1_hinter__hstem : t1_hinter__vstem)
626
0
                        (&h->super, ss->xr, ss->xl - ss->xr);
627
0
        else
628
0
            return (h->transpose ? t1_hinter__hstem : t1_hinter__vstem)
629
0
                        (&h->super, ss->xl, ss->xr - ss->xl);
630
0
    } else
631
0
        return t1_hinter__overall_hstem(&h->super, ss->xl, ss->xr - ss->xl, ss->side_mask);
632
0
}
633
634
0
#define OVERALL_HINT 0 /* Overall hints help to emulate Type 1 alignment zones
635
                          (except for overshoot suppression.)
636
                          For example, without it comparefiles/type42_glyph_index.ps
637
                          some glyphs have different height due to
638
                          serifs are aligned in same way as horizontal stems,
639
                          but both sides of a stem have same priority.
640
641
                          This stuff appears low useful, because horizontal
642
                          hint orientation performs this job perfectly.
643
                          fixme : remove.
644
                          fixme : remove side_mask from gxhintn.c .
645
                          */
646
647
static int grid_fit(gx_device_spot_analyzer *padev, gx_path *path,
648
        gs_font_type42 *pfont, const gs_log2_scale_point *pscale, gx_ttfExport *e, ttfOutliner *o)
649
0
{
650
    /* Not completed yet. */
651
0
    gs_gstate gs_stub;
652
0
    gx_fill_params params;
653
0
    gx_device_color devc_stub;
654
0
    int code;
655
0
    t1_hinter_aux h;
656
0
    gs_matrix m, fm, fmb;
657
0
    gs_matrix_fixed ctm_temp;
658
0
    bool atp = gs_currentaligntopixels(pfont->dir);
659
0
    int FontType = 1; /* Will apply Type 1 hinter. */
660
0
    fixed sbx = 0, sby = 0; /* stub */
661
0
    double scale = 1.0 / o->pFont->nUnitsPerEm;
662
0
    gs_fixed_rect bbox;
663
664
0
    m.xx = o->post_transform.a;
665
0
    m.xy = o->post_transform.b;
666
0
    m.yx = o->post_transform.c;
667
0
    m.yy = o->post_transform.d;
668
0
    m.tx = o->post_transform.tx;
669
0
    m.ty = o->post_transform.ty;
670
0
    code = gs_matrix_fixed_from_matrix(&ctm_temp, &m);
671
0
    if (code < 0)
672
0
        return code;
673
0
    code = gs_matrix_scale(&pfont->FontMatrix, scale, scale, &fm);
674
0
    if (code < 0)
675
0
        return code;
676
0
    code = gs_matrix_scale(&pfont->base->FontMatrix, scale, scale, &fmb);
677
0
    if (code < 0)
678
0
        return code;
679
0
    t1_hinter__init(&h.super, path); /* Will export to */
680
0
    code = t1_hinter__set_mapping(&h.super, &ctm_temp,
681
0
                        &fm, &fmb,
682
0
                        pscale->x, pscale->x, 0, 0,
683
0
                        ctm_temp.tx_fixed, ctm_temp.ty_fixed, atp);
684
0
    if (code < 0)
685
0
        return code;
686
0
    if (!h.super.disable_hinting) {
687
0
        o->post_transform.a = o->post_transform.d = 1;
688
0
        o->post_transform.b = o->post_transform.c = 0;
689
0
        o->post_transform.tx = o->post_transform.ty = 0;
690
0
        code = ttfOutliner__DrawGlyphOutline(o);
691
0
        if (code < 0)
692
0
            return code;
693
0
        code = t1_hinter__set_font42_data(&h.super, FontType, &pfont->data, false);
694
0
        if (code < 0)
695
0
            return code;
696
0
        code = t1_hinter__sbw(&h.super, sbx, sby, e->w.x, e->w.y);
697
0
        if (code < 0)
698
0
            return code;
699
0
        code = gx_path_bbox(path, &bbox);
700
0
        if (code < 0)
701
0
            return code;
702
0
        memset(&gs_stub, 0, sizeof(gs_stub));
703
0
        gs_stub.memory = padev->memory;
704
0
        set_nonclient_dev_color(&devc_stub, 1);
705
0
        params.rule = gx_rule_winding_number;
706
0
        params.adjust.x = params.adjust.y = 0;
707
0
        params.flatness = fixed2float(max(bbox.q.x - bbox.p.x, bbox.q.y - bbox.p.y)) / 100.0;
708
709
0
        for (h.transpose = 0; h.transpose < 2; h.transpose++) {
710
0
            h.midx = (padev->xmin + padev->xmax) / 2;
711
0
            if (h.transpose)
712
0
                transpose_path(path);
713
0
            gx_san_begin(padev);
714
0
            code = dev_proc(padev, fill_path)((gx_device *)padev,
715
0
                            &gs_stub, path, &params, &devc_stub, NULL);
716
0
            gx_san_end(padev);
717
0
            if (code >= 0)
718
0
                code = gx_san_generate_stems(padev, OVERALL_HINT && h.transpose,
719
0
                                &h, stem_hint_handler);
720
0
            if (h.transpose)
721
0
                transpose_path(path);
722
0
            if (code < 0)
723
0
                return code;
724
0
        }
725
726
        /*  fixme : Storing hints permanently would be useful.
727
            Note that if (gftt & 1), the outline and hints are already scaled.
728
        */
729
0
        code = path_to_hinter(&h.super, path);
730
0
        if (code < 0)
731
0
            return code;
732
0
        code = gx_path_new(path);
733
0
        if (code < 0)
734
0
            return code;
735
0
        code = t1_hinter__endglyph(&h.super);
736
0
    } else {
737
0
        code = ttfOutliner__DrawGlyphOutline(o);
738
0
        if (code < 0)
739
0
            return e->error;
740
0
    }
741
0
    return code;
742
0
}
743
744
int gx_ttf_outline(ttfFont *ttf, gx_ttfReader *r, gs_font_type42 *pfont, int glyph_index,
745
        const gs_matrix *m, const gs_log2_scale_point *pscale,
746
        gx_path *path, bool design_grid)
747
124k
{
748
124k
    gx_ttfExport e;
749
124k
    ttfOutliner o;
750
124k
    gs_point char_size, subpix_origin;
751
124k
    gs_matrix post_transform;
752
    /* Ghostscript proceses a TTC index in gs/lib/gs_ttf.ps, */
753
    /* so that TTC never comes here. */
754
124k
    FloatMatrix m1;
755
124k
    bool dg;
756
124k
    uint gftt = gs_currentgridfittt(pfont->dir);
757
124k
    bool ttin = (gftt & 1);
758
124k
    int code;
759
    /*  gs_currentgridfittt values (binary) :
760
        00 - no grid fitting;
761
        01 - Grid fit with TT interpreter; On failure warn and render unhinted.
762
        10 - Interpret in the design grid and then autohint.
763
        11 - Grid fit with TT interpreter; On failure render autohinted.
764
    */
765
124k
    bool auth = (gftt & 2);
766
767
124k
    decompose_matrix(pfont, m, pscale, design_grid, &char_size, &subpix_origin, &post_transform, &dg);
768
124k
    m1.a = post_transform.xx;
769
124k
    m1.b = post_transform.xy;
770
124k
    m1.c = post_transform.yx;
771
124k
    m1.d = post_transform.yy;
772
124k
    m1.tx = post_transform.tx;
773
124k
    m1.ty = post_transform.ty;
774
124k
    e.super.bPoints = false;
775
124k
    e.super.bOutline = true;
776
124k
    e.super.MoveTo = gx_ttfExport__MoveTo;
777
124k
    e.super.LineTo = gx_ttfExport__LineTo;
778
124k
    e.super.CurveTo = gx_ttfExport__CurveTo;
779
124k
    e.super.Close = gx_ttfExport__Close;
780
124k
    e.super.Point = gx_ttfExport__Point;
781
124k
    e.super.SetWidth = gx_ttfExport__SetWidth;
782
124k
    e.super.DebugPaint = gx_ttfExport__DebugPaint;
783
124k
    e.error = 0;
784
124k
    e.path = path;
785
124k
    e.w.x = 0;
786
124k
    e.w.y = 0;
787
124k
    e.monotonize = auth;
788
124k
    gx_ttfReader__Reset(r);
789
124k
    ttfOutliner__init(&o, ttf, &r->super, &e.super, true, false, pfont->WMode != 0);
790
124k
    switch(ttfOutliner__Outline(&o, glyph_index, subpix_origin.x, subpix_origin.y, &m1)) {
791
0
        case fBadInstruction:
792
0
            WarnBadInstruction(pfont, glyph_index);
793
0
            goto recover;
794
16.2k
        case fPatented:
795
            /* The returned outline did not apply a bytecode (it is not grid-fitted). */
796
16.2k
            if (!auth)
797
16.2k
                WarnPatented(pfont, ttf, "Some glyphs of the font");
798
16.2k
        recover :
799
16.2k
            if (!design_grid && auth)
800
0
                return grid_fit(pfont->dir->san, path, pfont, pscale, &e, &o);
801
            /* Falls through. */
802
123k
        case fNoError:
803
123k
            if (!design_grid && !ttin && auth)
804
0
                return grid_fit(pfont->dir->san, path, pfont, pscale, &e, &o);
805
123k
            code = ttfOutliner__DrawGlyphOutline(&o);
806
123k
            if (code < 0)
807
0
                return code;
808
123k
            return 0;
809
0
        case fMemoryError:
810
0
            return_error(gs_error_VMerror);
811
0
        case fUnimplemented:
812
0
            return_error(gs_error_unregistered);
813
941
        case fBadFontData:
814
941
            return_error(gs_error_invalidfont);
815
0
        default:
816
0
            { int code = r->super.Error(&r->super);
817
818
0
                if (code < 0)
819
0
                    return code;
820
0
                return_error(gs_error_invalidfont);
821
0
            }
822
124k
    }
823
124k
}