Coverage Report

Created: 2025-06-10 07:24

/src/ghostpdl/base/gxttfb.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 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
526k
{
65
526k
    gx_ttfReader *r = (gx_ttfReader *)self;
66
67
526k
    if (r->extra_glyph_index != -1)
68
18.7k
        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
508k
    return false;
72
526k
}
73
74
static void gx_ttfReader__Read(ttfReader *self, void *p, int n)
75
2.07M
{
76
2.07M
    gx_ttfReader *r = (gx_ttfReader *)self;
77
2.07M
    const byte *q;
78
79
2.07M
    if (r->error >= 0) {
80
1.98M
        if (r->extra_glyph_index != -1) {
81
1.42M
            q = r->glyph_data.bits.data + r->pos;
82
1.42M
            r->error = ((r->pos >= r->glyph_data.bits.size ||
83
1.42M
                        r->glyph_data.bits.size - r->pos < n) ?
84
1.42M
                            gs_note_error(gs_error_invalidfont) : 0);
85
1.42M
            if (r->error == 0)
86
1.42M
                memcpy(p, q, n);
87
1.42M
        } else {
88
558k
            unsigned int cnt;
89
558k
            r->error = 0;
90
91
558k
            for (cnt = 0; cnt < (uint)n; cnt += r->error) {
92
558k
                r->error = r->pfont->data.string_proc(r->pfont, (ulong)r->pos + cnt, (ulong)n - cnt, &q);
93
558k
                if (r->error < 0)
94
0
                    break;
95
558k
                else if ( r->error == 0) {
96
558k
                    memcpy((char *)p + cnt, q, n - cnt);
97
558k
                    break;
98
558k
                } else {
99
0
                    memcpy((char *)p + cnt, q, r->error);
100
0
                }
101
558k
            }
102
558k
        }
103
1.98M
    }
104
2.07M
    if (r->error < 0) {
105
89.7k
        memset(p, 0, n);
106
89.7k
        return;
107
89.7k
    }
108
1.98M
    r->pos += n;
109
1.98M
}
110
111
static void gx_ttfReader__Seek(ttfReader *self, int nPos)
112
23.3k
{
113
23.3k
    gx_ttfReader *r = (gx_ttfReader *)self;
114
115
23.3k
    r->pos = nPos;
116
23.3k
}
117
118
static int gx_ttfReader__Tell(ttfReader *self)
119
32.7k
{
120
32.7k
    gx_ttfReader *r = (gx_ttfReader *)self;
121
122
32.7k
    return r->pos;
123
32.7k
}
124
125
static bool gx_ttfReader__Error(ttfReader *self)
126
49.1k
{
127
49.1k
    gx_ttfReader *r = (gx_ttfReader *)self;
128
129
49.1k
    return r->error;
130
49.1k
}
131
132
static int gx_ttfReader__LoadGlyph(ttfReader *self, int glyph_index, const byte **p, int *size)
133
18.5k
{
134
18.5k
    gx_ttfReader *r = (gx_ttfReader *)self;
135
18.5k
    gs_font_type42 *pfont = r->pfont;
136
18.5k
    int code;
137
138
18.5k
    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
18.5k
    r->glyph_data.memory = pfont->memory;
144
18.5k
    code = pfont->data.get_outline(pfont, (uint)glyph_index, &r->glyph_data);
145
18.5k
    r->extra_glyph_index = glyph_index;
146
18.5k
    r->pos = 0;
147
18.5k
    if (code < 0)
148
0
        r->error = code;
149
18.5k
    else if (code > 0) {
150
        /* Should not happen. */
151
0
        r->error = gs_note_error(gs_error_unregistered);
152
18.5k
    } else {
153
18.5k
        *p = r->glyph_data.bits.data;
154
18.5k
        *size = r->glyph_data.bits.size;
155
18.5k
    }
156
18.5k
    return 2; /* found */
157
18.5k
}
158
159
static void gx_ttfReader__ReleaseGlyph(ttfReader *self, int glyph_index)
160
18.9k
{
161
18.9k
    gx_ttfReader *r = (gx_ttfReader *)self;
162
163
18.9k
    if (r->extra_glyph_index != glyph_index)
164
445
        return;
165
18.5k
    r->extra_glyph_index = -1;
166
18.5k
    gs_glyph_data_free(&r->glyph_data, "gx_ttfReader__ReleaseExtraGlyph");
167
18.5k
}
168
169
static void gx_ttfReader__Reset(gx_ttfReader *self)
170
19.0k
{
171
19.0k
    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
19.0k
    self->error = 0;
176
19.0k
    self->pos = 0;
177
19.0k
}
178
179
gx_ttfReader *gx_ttfReader__create(gs_memory_t *mem)
180
742
{
181
742
    gx_ttfReader *r = gs_alloc_struct(mem, gx_ttfReader, &st_gx_ttfReader, "gx_ttfReader__create");
182
183
742
    if (r != NULL) {
184
742
        r->super.Eof = gx_ttfReader__Eof;
185
742
        r->super.Read = gx_ttfReader__Read;
186
742
        r->super.Seek = gx_ttfReader__Seek;
187
742
        r->super.Tell = gx_ttfReader__Tell;
188
742
        r->super.Error = gx_ttfReader__Error;
189
742
        r->super.LoadGlyph = gx_ttfReader__LoadGlyph;
190
742
        r->super.ReleaseGlyph = gx_ttfReader__ReleaseGlyph;
191
742
        r->pos = 0;
192
742
        r->error = 0;
193
742
        r->extra_glyph_index = -1;
194
742
        memset(&r->glyph_data, 0, sizeof(r->glyph_data));
195
742
        r->pfont = NULL;
196
742
        r->memory = mem;
197
742
        gx_ttfReader__Reset(r);
198
742
    }
199
742
    return r;
200
742
}
201
202
void gx_ttfReader__destroy(gx_ttfReader *self)
203
742
{
204
742
    gs_free_object(self->memory, self, "gx_ttfReader__destroy");
205
742
}
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
18.7k
{
211
18.7k
    gx_ttfReader *self = (gx_ttfReader *)ttf;
212
18.7k
    float sbw[4];
213
18.7k
    int sbw_offset = bVertical;
214
18.7k
    int code;
215
18.7k
    int factor = self->pfont->data.unitsPerEm;
216
217
18.7k
    code = self->pfont->data.get_metrics(self->pfont, glyph_index, bVertical, sbw);
218
18.7k
    if (code < 0)
219
235
        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
18.4k
    *sideBearing = (short)floor(sbw[0 + sbw_offset] * factor + 0.5);
226
18.4k
    *nAdvance = (short)floor(sbw[2 + sbw_offset] * factor + 0.5);
227
18.4k
    return 0;
228
18.7k
}
229
230
void gx_ttfReader__set_font(gx_ttfReader *self, gs_font_type42 *pfont)
231
38.1k
{
232
38.1k
    self->pfont = pfont;
233
38.1k
    self->super.get_metrics = gx_ttfReader__default_get_metrics;
234
38.1k
}
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
149
{
263
149
    char buf[gs_font_name_max + 1];
264
149
    int l;
265
149
    gs_font_type42 *base_font = pfont;
266
267
149
    while ((gs_font_type42 *)base_font->base != base_font)
268
0
        base_font = (gs_font_type42 *)base_font->base;
269
149
    if (!base_font->data.warning_bad_instruction) {
270
149
        l = min(sizeof(buf) - 1, base_font->font_name.size);
271
149
        memcpy(buf, base_font->font_name.chars, l);
272
149
        buf[l] = 0;
273
149
        if (glyph_index >= 0)
274
0
            emprintf2(pfont->memory,
275
149
                      "Failed to interpret TT instructions for glyph index %d of font %s. "
276
149
                      "Continue ignoring instructions of the font.\n",
277
149
                      glyph_index, buf);
278
149
        else
279
149
            emprintf1(pfont->memory,
280
149
                      "Failed to interpret TT instructions in font %s. "
281
149
                      "Continue ignoring instructions of the font.\n",
282
149
                      buf);
283
149
        base_font->data.warning_bad_instruction = true;
284
149
    }
285
149
}
286
287
static void WarnPatented(gs_font_type42 *pfont, ttfFont *ttf, const char *txt)
288
1.37k
{
289
1.37k
    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
1.37k
}
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
13.7k
{
321
13.7k
    gs_memory_t *mem = ((gx_ttfMemory *)self)->memory;
322
323
13.7k
    return gs_alloc_bytes(mem, size, cname);
324
13.7k
}
325
326
static void *gx_ttfMemory__alloc_struct(ttfMemory *self, const ttfMemoryDescriptor *d,  const char *cname)
327
2.31k
{
328
2.31k
    gs_memory_t *mem = ((gx_ttfMemory *)self)->memory;
329
330
2.31k
    return mem->procs.alloc_struct(mem, (const gs_memory_struct_type_t *)d, cname);
331
2.31k
}
332
333
static void gx_ttfMemory__free(ttfMemory *self, void *p,  const char *cname)
334
25.3k
{
335
25.3k
    gs_memory_t *mem = ((gx_ttfMemory *)self)->memory;
336
337
25.3k
    gs_free_object(mem, p, cname);
338
25.3k
}
339
340
/*----------------------------------------------*/
341
342
static inline float reminder(float v, int x)
343
38.1k
{
344
38.1k
    return ((v / x) - floor(v / x)) * x;
345
38.1k
}
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
19.0k
{
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
19.0k
    int scale_x = 1 << log2_scale->x;
362
19.0k
    int scale_y = 1 << log2_scale->y;
363
19.0k
    bool atp = gs_currentaligntopixels(pfont->dir);
364
19.0k
    bool design_grid1;
365
366
19.0k
    char_size->x = hypot(char_tm->xx, char_tm->xy);
367
19.0k
    char_size->y = hypot(char_tm->yx, char_tm->yy);
368
19.0k
    if (char_size->x <= 2 && char_size->y <= 2) {
369
        /* Disable the grid fitting for very small fonts. */
370
0
        design_grid1 = true;
371
0
    } else
372
19.0k
        design_grid1 = design_grid || !(gs_currentgridfittt(pfont->dir) & 1);
373
19.0k
    *dg = design_grid1;
374
19.0k
    subpix_origin->x = (atp ? 0 : reminder(char_tm->tx, scale_x) / scale_x);
375
19.0k
    subpix_origin->y = (atp ? 0 : reminder(char_tm->ty, scale_y) / scale_y);
376
19.0k
    post_transform->xx = char_tm->xx / (design_grid1 ? 1 : char_size->x);
377
19.0k
    post_transform->xy = char_tm->xy / (design_grid1 ? 1 : char_size->x);
378
19.0k
    post_transform->yx = char_tm->yx / (design_grid1 ? 1 : char_size->y);
379
19.0k
    post_transform->yy = char_tm->yy / (design_grid1 ? 1 : char_size->y);
380
19.0k
    post_transform->tx = char_tm->tx - subpix_origin->x;
381
19.0k
    post_transform->ty = char_tm->ty - subpix_origin->y;
382
19.0k
}
383
384
/*----------------------------------------------*/
385
386
ttfFont *ttfFont__create(gs_font_dir *dir)
387
742
{
388
742
    gs_memory_t *mem = dir->memory->stable_memory;
389
742
    ttfFont *ttf;
390
391
742
    if (dir->ttm == NULL) {
392
417
        gx_ttfMemory *m = gs_alloc_struct(mem, gx_ttfMemory, &st_gx_ttfMemory, "ttfFont__create(gx_ttfMemory)");
393
394
417
        if (!m)
395
0
            return 0;
396
417
        m->super.alloc_struct = gx_ttfMemory__alloc_struct;
397
417
        m->super.alloc_bytes = gx_ttfMemory__alloc_bytes;
398
417
        m->super.free = gx_ttfMemory__free;
399
417
        m->memory = mem;
400
417
        dir->ttm = m;
401
417
    }
402
742
    if(ttfInterpreter__obtain(&dir->ttm->super, &dir->tti))
403
0
        return 0;
404
742
    if(gx_san__obtain(mem, &dir->san))
405
0
        return 0;
406
742
    ttf = gs_alloc_struct(mem, ttfFont, &st_ttfFont, "ttfFont__create");
407
742
    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
742
    ttfFont__init(ttf, &dir->ttm->super, DebugRepaint, NULL, mem);
414
742
#endif
415
416
742
    return ttf;
417
742
}
418
419
void ttfFont__destroy(ttfFont *self, gs_font_dir *dir)
420
742
{
421
742
    gs_memory_t *mem = dir->memory->stable_memory;
422
423
742
    ttfFont__finit(self);
424
742
    gs_free_object(mem, self, "ttfFont__destroy");
425
742
    ttfInterpreter__release(&dir->tti);
426
742
    gx_san__release(&dir->san);
427
742
    if (dir->tti == NULL && dir->ttm != NULL) {
428
417
        gs_free_object(mem, dir->ttm, "ttfFont__destroy(gx_ttfMemory)");
429
417
        dir->ttm = NULL;
430
417
    }
431
742
}
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
742
{
437
742
    gs_point char_size, subpix_origin;
438
742
    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
742
    unsigned int nTTC = 0;
445
742
    bool dg;
446
447
742
    decompose_matrix(pfont, char_tm, log2_scale, design_grid, &char_size, &subpix_origin, &post_transform, &dg);
448
742
    switch(ttfFont__Open(tti, self, &r->super, nTTC, char_size.x, char_size.y, dg)) {
449
581
        case fNoError:
450
581
            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
149
        case fBadInstruction:
456
149
            WarnBadInstruction(pfont, -1);
457
149
            goto recover;
458
12
        case fPatented:
459
12
            WarnPatented(pfont, self, "The font");
460
161
        recover:
461
161
            self->patented = true;
462
161
            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
742
    }
471
742
}
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
21.8k
{
485
21.8k
    gx_ttfExport *e = (gx_ttfExport *)self;
486
487
21.8k
    if (e->error >= 0)
488
21.8k
        e->error = gx_path_add_point(e->path, float2fixed(p->x), float2fixed(p->y));
489
21.8k
}
490
491
static void gx_ttfExport__LineTo(ttfExport *self, FloatPoint *p)
492
100k
{
493
100k
    gx_ttfExport *e = (gx_ttfExport *)self;
494
495
100k
    if (e->error >= 0)
496
100k
        e->error = gx_path_add_line_notes(e->path, float2fixed(p->x), float2fixed(p->y), sn_none);
497
100k
}
498
499
static void gx_ttfExport__CurveTo(ttfExport *self, FloatPoint *p0, FloatPoint *p1, FloatPoint *p2)
500
301k
{
501
301k
    gx_ttfExport *e = (gx_ttfExport *)self;
502
503
301k
    if (e->error >= 0) {
504
301k
        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
301k
            e->error = gx_path_add_curve_notes(e->path, float2fixed(p0->x), float2fixed(p0->y),
514
301k
                                     float2fixed(p1->x), float2fixed(p1->y),
515
301k
                                     float2fixed(p2->x), float2fixed(p2->y), sn_none);
516
301k
    }
517
301k
}
518
519
static void gx_ttfExport__Close(ttfExport *self)
520
21.8k
{
521
21.8k
    gx_ttfExport *e = (gx_ttfExport *)self;
522
523
21.8k
    if (e->error >= 0)
524
21.8k
        e->error = gx_path_close_subpath_notes(e->path, sn_none);
525
21.8k
}
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
17.7k
{
534
17.7k
    gx_ttfExport *e = (gx_ttfExport *)self;
535
536
17.7k
    e->w.x = float2fixed(p->x);
537
17.7k
    e->w.y = float2fixed(p->y);
538
17.7k
}
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
18.3k
{
748
18.3k
    gx_ttfExport e;
749
18.3k
    ttfOutliner o;
750
18.3k
    gs_point char_size, subpix_origin;
751
18.3k
    gs_matrix post_transform;
752
    /* Ghostscript proceses a TTC index in gs/lib/gs_ttf.ps, */
753
    /* so that TTC never comes here. */
754
18.3k
    FloatMatrix m1;
755
18.3k
    bool dg;
756
18.3k
    uint gftt = gs_currentgridfittt(pfont->dir);
757
18.3k
    bool ttin = (gftt & 1);
758
18.3k
    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
18.3k
    bool auth = (gftt & 2);
766
767
18.3k
    decompose_matrix(pfont, m, pscale, design_grid, &char_size, &subpix_origin, &post_transform, &dg);
768
18.3k
    m1.a = post_transform.xx;
769
18.3k
    m1.b = post_transform.xy;
770
18.3k
    m1.c = post_transform.yx;
771
18.3k
    m1.d = post_transform.yy;
772
18.3k
    m1.tx = post_transform.tx;
773
18.3k
    m1.ty = post_transform.ty;
774
18.3k
    e.super.bPoints = false;
775
18.3k
    e.super.bOutline = true;
776
18.3k
    e.super.MoveTo = gx_ttfExport__MoveTo;
777
18.3k
    e.super.LineTo = gx_ttfExport__LineTo;
778
18.3k
    e.super.CurveTo = gx_ttfExport__CurveTo;
779
18.3k
    e.super.Close = gx_ttfExport__Close;
780
18.3k
    e.super.Point = gx_ttfExport__Point;
781
18.3k
    e.super.SetWidth = gx_ttfExport__SetWidth;
782
18.3k
    e.super.DebugPaint = gx_ttfExport__DebugPaint;
783
18.3k
    e.error = 0;
784
18.3k
    e.path = path;
785
18.3k
    e.w.x = 0;
786
18.3k
    e.w.y = 0;
787
18.3k
    e.monotonize = auth;
788
18.3k
    gx_ttfReader__Reset(r);
789
18.3k
    ttfOutliner__init(&o, ttf, &r->super, &e.super, true, false, pfont->WMode != 0);
790
18.3k
    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
1.36k
        case fPatented:
795
            /* The returned outline did not apply a bytecode (it is not grid-fitted). */
796
1.36k
            if (!auth)
797
1.36k
                WarnPatented(pfont, ttf, "Some glyphs of the font");
798
1.36k
        recover :
799
1.36k
            if (!design_grid && auth)
800
0
                return grid_fit(pfont->dir->san, path, pfont, pscale, &e, &o);
801
            /* Falls through. */
802
17.7k
        case fNoError:
803
17.7k
            if (!design_grid && !ttin && auth)
804
0
                return grid_fit(pfont->dir->san, path, pfont, pscale, &e, &o);
805
17.7k
            code = ttfOutliner__DrawGlyphOutline(&o);
806
17.7k
            if (code < 0)
807
0
                return code;
808
17.7k
            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
555
        case fBadFontData:
814
555
            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
18.3k
    }
823
18.3k
}