Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pl/plchar.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
/* plchar.c */
18
/* PCL font handling library -- operations on individual characters */
19
#include "math_.h"
20
#include "memory_.h"
21
#include "stdio_.h"             /* for gdebug.h */
22
#include "gdebug.h"
23
#include "gserrors.h"
24
#include "gstypes.h"
25
#include "gsmemory.h"
26
#include "gsstruct.h"
27
#include "gsmatrix.h"
28
#include "gsstate.h"
29
#include "gschar.h"
30
#include "gsimage.h"
31
#include "gspaint.h"
32
#include "gspath.h"
33
#include "gsbittab.h"
34
#include "gxarith.h"            /* for igcd */
35
#include "gxfont.h"
36
#include "gxfont42.h"
37
#include "plfont.h"
38
#include "plvalue.h"
39
#include "gscoord.h"
40
#include "gsstate.h"
41
#include "gxdevice.h"
42
#include "gxdevmem.h"
43
#include "gxpath.h"
44
/* We really shouldn't need the following, but currently they are needed */
45
/* for pgs->path and penum->log2_current_scale in pl_tt_build_char. */
46
#include "gxfixed.h"
47
#include "gxchar.h"
48
#include "gxfcache.h"
49
#include "gxttf.h"
50
#include "gzstate.h"
51
#include "gxfapi.h" /* for gx_fapi_bits_smear_horizontally and gx_fapi_bits_merge */
52
#include "plchar.h"
53
/* include the prototype for pixmap_high_level_pattern */
54
#include "gsptype1.h"
55
#include "gsgstate.h"
56
#include "gxgstate.h"
57
58
/* Define whether to cache TrueType characters. */
59
/* This would only be disabled for debugging. */
60
#define CACHE_TRUETYPE_CHARS
61
0
#define IF_COMPOUND_CHAR_LIMIT 8
62
63
/* Structure descriptors */
64
gs_private_st_ptrs1(st_pl_font_glyph, pl_font_glyph_t, "pl_font_glyph_t",
65
                    pl_font_glyph_enum_ptrs, pl_font_glyph_reloc_ptrs, data);
66
gs_private_st_element(st_pl_font_glyph_element, pl_font_glyph_t,
67
                      "pl_font_glyph_t[]",
68
                      pl_font_glyph_elt_enum_ptrs,
69
                      pl_font_glyph_elt_reloc_ptrs, st_pl_font_glyph);
70
71
int
72
pl_prepend_xl_dummy_header(gs_memory_t * mem, byte ** ppheader)
73
124
{
74
124
    return 0;
75
124
}
76
77
int
78
pl_swap_header(byte * header, uint gifct)
79
0
{
80
0
    return 0;
81
0
}
82
83
/* ---------------- Utilities ---------------- */
84
85
/* Look up a glyph in a font.  Return a pointer to the glyph's slot */
86
/* (data != 0) or where it should be added (data == 0). */
87
pl_font_glyph_t *
88
pl_font_lookup_glyph(const pl_font_t * plfont, gs_glyph glyph)
89
1.61M
{
90
1.61M
    uint size = plfont->glyphs.size;
91
1.61M
    uint skip = plfont->glyphs.skip;
92
1.61M
    uint index = glyph % size;
93
1.61M
    pl_font_glyph_t *pfg;
94
1.61M
    pl_font_glyph_t *result = 0;
95
96
1.61M
    while ((pfg = plfont->glyphs.table + index)->data ?
97
1.38M
           pfg->glyph != glyph : pfg->glyph != 0) {
98
0
        if (!pfg->data)
99
0
            result = pfg;
100
0
        index = (index >= skip ? index : index + size) - skip;
101
0
    }
102
1.61M
    return (!pfg->data && result) ? result : pfg;
103
1.61M
}
104
105
/* ---------------- Bitmap font support ---------------- */
106
107
/* Encode a character for a bitmap font.  This is simple, because */
108
/* bitmap fonts are always bound. */
109
static gs_glyph
110
pl_bitmap_encode_char(gs_font * pfont, gs_char chr, gs_glyph_space_t not_used)
111
405k
{
112
405k
    return (gs_glyph) chr;
113
405k
}
114
115
/* Get character existence and escapement for a bitmap font. */
116
/* This is simple for the same reason. */
117
static int
118
pl_bitmap_char_width(const pl_font_t * plfont, const void *pgs,
119
                     gs_char char_code, gs_point * pwidth)
120
0
{
121
0
    const byte *cdata = pl_font_lookup_glyph(plfont, char_code)->data;
122
123
0
    pwidth->x = pwidth->y = 0;
124
125
0
    if (cdata == 0) {
126
0
        return 1;
127
0
    }
128
0
    if (cdata[0] == 0) {        /* PCL XL characters don't have an escapement. */
129
0
        pwidth->x = pwidth->y = 0;
130
0
        return 0;
131
0
    }
132
133
0
    {
134
0
        const byte *params = cdata + 6;
135
136
0
        pwidth->x = (plfont->header[13] ?       /* variable pitch */
137
0
                     pl_get_int16(params + 8) * 0.25 :
138
0
                     pl_get_int16(params) /*lsb */ +pl_get_int16(params +
139
0
                                                                 4) /*width */
140
0
                     );
141
0
    }
142
0
    return 0;
143
0
}
144
145
static int
146
pl_bitmap_char_metrics(const pl_font_t * plfont, const void *pgs,
147
                       gs_char char_code, float metrics[4])
148
0
{
149
0
    gs_point width;
150
0
    const byte *cdata = pl_font_lookup_glyph(plfont, char_code)->data;
151
152
    /* never a vertical substitute */
153
0
    metrics[0] = metrics[1] = metrics[2] = metrics[3] = 0;
154
    /* no data - character not found */
155
0
    if (cdata == 0)
156
0
        return 1;
157
    /* We are not concerned about PCL XL characters */
158
0
    if (cdata[0] == 0)
159
0
        return 0;
160
161
0
    metrics[0] = (float)pl_get_int16(cdata + 6);
162
0
    pl_bitmap_char_width(plfont, pgs, char_code, &width);
163
0
    metrics[2] = width.x;
164
0
    return 0;
165
0
}
166
167
/*
168
 * For pseudo-bolding, we have to "smear" a bitmap horizontally and
169
 * vertically by ORing together a rectangle of bits below and to the left of
170
 * each output bit.  We do this separately for horizontal and vertical
171
 * smearing.  Eventually, we will replace the current procedure, which takes
172
 * time proportional to W * H * (N + log2(N)), with one that is only
173
 * proportional to N (but takes W * N additional buffer space).
174
 */
175
176
/* Allocate the line buffer for bolding.  We need 2 + bold scan lines. */
177
static byte *
178
alloc_bold_lines(gs_memory_t * mem, uint width, int bold, client_name_t cname)
179
0
{
180
0
    return gs_alloc_byte_array(mem, 2 + bold, bitmap_raster(width + bold),
181
0
                               cname);
182
0
}
183
184
/* Image a bitmap character, with or without bolding. */
185
int
186
pl_image_bitmap_char(gs_image_enum * ienum, const gs_image_t * pim,
187
                     const byte * bitmap_data, uint sraster, int bold,
188
                     byte * bold_lines, gs_gstate * pgs)
189
228k
{
190
228k
    uint dest_bytes = (pim->Width + 7) >> 3;
191
228k
    int code;
192
228k
    gs_image_enum *penum;
193
228k
    uint used;
194
195
228k
    code = gx_set_dev_color(pgs);
196
228k
    if (code == gs_error_Remap_Color)
197
0
        code = pixmap_high_level_pattern(pgs);
198
228k
    if (code != 0)
199
0
        return code;
200
228k
    penum = gs_image_enum_alloc(gs_gstate_memory(pgs), "pl_image_bitmap_char");
201
228k
    if (penum == NULL)
202
0
        return_error(gs_error_VMerror);
203
228k
    code = gs_image_init(penum, pim, pim->ImageMask | pim->CombineWithColor, true, pgs);
204
228k
    if (code < 0)
205
0
        goto free_penum_and_exit;
206
228k
    if (bold) {                 /* Pass individual smeared lines. */
207
0
        uint src_width = pim->Width - bold;
208
0
        uint src_height = pim->Height - bold;
209
0
        uint dest_raster = bitmap_raster(pim->Width);
210
0
        int n1 = bold + 1;
211
212
0
#define merged_line(i) (bold_lines + ((i) % n1 + 1) * dest_raster)
213
0
        int y;
214
215
0
        for (y = 0; y < pim->Height; ++y) {
216
0
            int y0 = (y < bold ? 0 : y - bold);
217
0
            int y1 = min(y + 1, src_height);
218
219
0
            if (y < src_height) {
220
0
                gx_fapi_bits_smear_horizontally(merged_line(y),
221
0
                                        bitmap_data + y * sraster,
222
0
                                        src_width, bold);
223
0
                {               /* Now re-establish the invariant -- see below. */
224
0
                    int kmask = 1;
225
226
0
                    for (; (y & kmask) == kmask && y - kmask >= y0;
227
0
                         kmask = (kmask << 1) + 1)
228
0
                        gx_fapi_bits_merge(merged_line(y - kmask),
229
0
                                   merged_line(y - (kmask >> 1)), dest_bytes);
230
0
                }
231
0
            }
232
233
            /*
234
             * As of this point in the loop, we maintain the following
235
             * invariant to cache partial merges of groups of lines: for
236
             * each Y, y0 <= Y < y1, let K be the maximum k such that Y
237
             * mod 2^k = 0 and Y + 2^k < y1; then merged_line(Y) holds
238
             * the union of horizontally smeared source lines Y through
239
             * Y + 2^k - 1.  The idea behind this is similar to the idea
240
             * of quicksort.
241
             */
242
243
0
            {                   /* Now construct the output line. */
244
0
                bool first = true;
245
0
                int iy;
246
247
0
                for (iy = y1 - 1; iy >= y0; --iy) {
248
0
                    int kmask = 1;
249
250
0
                    while ((iy & kmask) == kmask && iy - kmask >= y0)
251
0
                        iy -= kmask, kmask <<= 1;
252
0
                    if (first) {
253
0
                        memcpy(bold_lines, merged_line(iy), dest_bytes);
254
0
                        first = false;
255
0
                    } else
256
0
                        gx_fapi_bits_merge(bold_lines, merged_line(iy), dest_bytes);
257
0
                }
258
0
            }
259
260
0
            code = gs_image_next(penum, bold_lines, dest_bytes, &used);
261
0
            if (code != 0)
262
0
                break;
263
0
        }
264
0
#undef merged_line
265
228k
    } else {                    /* Pass the entire image at once. */
266
228k
        int i;
267
5.75M
        for (i = 0; i < pim->Height; i++) {
268
5.52M
            code = gs_image_next(penum, bitmap_data, dest_bytes, &used);
269
5.52M
            if (code < 0)
270
0
                break;
271
5.52M
            bitmap_data += sraster;
272
5.52M
        }
273
228k
    }
274
228k
free_penum_and_exit:
275
228k
    {
276
228k
        int code2 = gs_image_cleanup_and_free_enum(penum, pgs);
277
228k
        if (code == 0)
278
0
            code = code2;
279
228k
    }
280
228k
    return code;
281
228k
}
282
283
/* Render a character for a bitmap font. */
284
/* This handles both format 0 (PCL XL) and format 4 (PCL5 bitmap). */
285
static int
286
pl_bitmap_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont,
287
                     gs_char chr, gs_glyph glyph)
288
229k
{
289
229k
    pl_font_t *plfont = (pl_font_t *) pfont->client_data;
290
229k
    const byte *cdata = pl_font_lookup_glyph(plfont, glyph)->data;
291
229k
    bool orient = plfont->orient;
292
293
229k
    if (cdata == 0) {
294
80
        return gs_setcharwidth(penum, pgs, 0, 0);
295
228k
    } else {
296
228k
        const byte *params;
297
228k
        const byte *bitmap_data;
298
228k
        int lsb, ascent;
299
228k
        float delta_x;
300
228k
        gs_image_t image;
301
228k
        gs_image_enum *ienum;
302
228k
        int code;
303
228k
        uint bold;
304
228k
        byte *bold_lines = 0;
305
306
228k
        if (cdata[0] == 0) {    /* PCL XL format */
307
279
            params = cdata + 2;
308
279
            bitmap_data = cdata + round_up(10, ARCH_ALIGN_PTR_MOD);
309
279
            delta_x = 0;        /* irrelevant */
310
279
            lsb = pl_get_int16(params);
311
279
            ascent = pl_get_int16(params + 2);
312
228k
        } else {                /* PCL5 format */
313
228k
            params = cdata + 6;
314
228k
            bitmap_data = cdata + 16;
315
228k
            delta_x = (plfont->header[13] ?     /* variable pitch */
316
228k
                       pl_get_int16(params + 8) * 0.25 :
317
228k
                       (short)(pl_get_int16(params) /*lsb */
318
0
                               +pl_get_int16(params + 4)) /*width */ );
319
228k
            lsb = pl_get_int16(params);
320
228k
            ascent = pl_get_int16(params + 2);
321
228k
        }
322
228k
        ienum = gs_image_enum_alloc(pgs->memory, "pl_bitmap_build_char");
323
228k
        if (ienum == 0)
324
0
            return_error(gs_error_VMerror);
325
228k
        gs_image_t_init_mask(&image, true);
326
228k
        image.Width = pl_get_uint16(params + 4);
327
228k
        image.Height = pl_get_uint16(params + 6);
328
        /* Determine the amount of pseudo-bolding. */
329
228k
        if (plfont->bold_fraction != 0) {
330
0
            if (image.Height < image.Width)
331
0
                bold = (uint) (2 * image.Height * plfont->bold_fraction + 0.5);
332
0
            else
333
0
                bold = (uint) (2 * image.Width * plfont->bold_fraction + 0.5);
334
0
            bold_lines = alloc_bold_lines(pgs->memory, image.Width, bold,
335
0
                                          "pl_bitmap_build_char(bold_line)");
336
0
            if (bold_lines == 0) {
337
0
                code = gs_note_error(gs_error_VMerror);
338
0
                goto out;
339
0
            }
340
0
            image.Width += bold;
341
0
            image.Height += bold;
342
0
            ascent += bold;
343
0
        } else
344
228k
            bold = 0;
345
346
228k
        gs_make_identity(&image.ImageMatrix);
347
228k
        gs_matrix_rotate(&image.ImageMatrix, orient * -90,
348
228k
                         &image.ImageMatrix);
349
228k
        image.ImageMatrix.tx -= lsb;
350
228k
        image.ImageMatrix.ty += ascent;
351
228k
        image.adjust = true;
352
228k
        if (bold || orient != 0)
353
0
            code = gs_setcharwidth(penum, pgs, delta_x, 0);
354
228k
        else {
355
            /* we use cache device for portrait bitmap fonts to
356
               avoid image setup overhead.  */
357
228k
            float m[6];
358
359
228k
            m[0] = delta_x;
360
228k
            m[1] = 0;
361
228k
            m[2] = (float)lsb;
362
228k
            m[3] = (float)(image.Height - ascent);
363
228k
            m[4] = image.Width + m[2];
364
228k
            m[5] = (float)(-ascent);
365
228k
            code = gs_setcachedevice(penum, pgs, m);
366
228k
        }
367
228k
        if (code < 0)
368
0
            goto out;
369
#ifdef DEBUG
370
        if (gs_debug_c('B')) {
371
            int i;
372
            int pixels = round_up(image.Width, 8) * image.Height;
373
374
            dmprintf7(pgs->memory,
375
                      "bitmap font data chr=%ld, width=%d, height=%d, lsb=%d, ascent=%d, top offset=%d left offset=%d\n",
376
                      chr, image.Width, image.Height, lsb, ascent,
377
                      pl_get_int16(params + 2), pl_get_int16(params));
378
            for (i = 0; i < pixels; i++) {
379
                if (i % round_up(image.Width, 8) == 0)
380
                    dmprintf(pgs->memory, "\n");
381
                dmprintf1(pgs->memory, "%d",
382
                          bitmap_data[i >> 3] & (128 >> (i & 7)) ? 1 : 0);
383
            }
384
            dmprintf(pgs->memory, "\n");
385
        }
386
#endif
387
228k
        code = pl_image_bitmap_char(ienum, &image, bitmap_data,
388
228k
                                    (image.Width - bold + 7) >> 3, bold,
389
228k
                                    bold_lines, pgs);
390
228k
      out:gs_free_object(pgs->memory, bold_lines,
391
228k
                       "pl_bitmap_build_char(bold_lines)");
392
228k
        gs_free_object(pgs->memory, ienum, "pl_bitmap_build_char");
393
228k
        return (code < 0 ? code : 0);
394
228k
    }
395
229k
}
396
397
/* ---------------- TrueType font support ---------------- */
398
399
/* Look up a character in the TrueType character-to-TT-glyph map. */
400
/* Return a pointer to the glyph's slot (chr != gs_no_char) or where */
401
/* it should be added (chr == gs_no_char). */
402
pl_tt_char_glyph_t *
403
pl_tt_lookup_char(const pl_font_t * plfont, gs_glyph glyph)
404
1.06k
{
405
1.06k
    uint size = plfont->char_glyphs.size;
406
1.06k
    uint skip = plfont->char_glyphs.skip;
407
1.06k
    uint index = glyph % size;
408
1.06k
    pl_tt_char_glyph_t *ptcg;
409
1.06k
    pl_tt_char_glyph_t *result = 0;
410
411
1.06k
    while ((ptcg = plfont->char_glyphs.table + index)->chr != gs_no_char ?
412
632
           ptcg->chr != glyph : ptcg->glyph) {
413
1
        if (ptcg->chr == gs_no_char)
414
0
            result = ptcg;
415
1
        index = (index >= skip ? index : index + size) - skip;
416
1
    }
417
1.06k
    return (result ? result : ptcg);
418
1.06k
}
419
420
/* Get a string from a TrueType font. */
421
static int
422
pl_tt_string_proc(gs_font_type42 * pfont, ulong offset, uint length,
423
                  const byte ** pdata)
424
1.57G
{
425
1.57G
    pl_font_t *plfont = pfont->client_data;
426
427
1.57G
    *pdata = plfont->header + plfont->offsets.GT +
428
1.57G
        (plfont->large_sizes ? 6 : 4) + offset;
429
430
1.57G
    if (((*pdata) + length) > plfont->header + plfont->header_size)
431
14
        return_error(gs_error_invalidfont);
432
433
1.57G
    return 0;
434
1.57G
}
435
436
/* Return the vertical substitute for a glyph, if it has one; */
437
/* otherwise return GS_NO_GLYPH. */
438
gs_glyph
439
pl_font_vertical_glyph(gs_glyph glyph, const pl_font_t * plfont)
440
0
{
441
0
    long VT = plfont->offsets.VT;
442
0
    const byte *vtseg;
443
0
    uint i, len;
444
445
0
    if (VT < 0)
446
0
        return GS_NO_GLYPH;
447
0
    vtseg = plfont->header + VT;
448
0
    if (plfont->large_sizes)
449
0
        len = pl_get_uint32(vtseg + 2), i = 6;
450
0
    else
451
0
        len = pl_get_uint16(vtseg + 2), i = 4;
452
0
    len += i;
453
0
    for (; i < len; i += 4)
454
0
        if (glyph == pl_get_uint16(vtseg + i))
455
0
            return pl_get_uint16(vtseg + i + 2);
456
0
    return GS_NO_GLYPH;
457
0
}
458
459
/* retrieve lsb and width metrics for Format 1 Class 2 glyphs */
460
int
461
pl_tt_f1c2_get_metrics(gs_font_type42 * pfont, uint glyph_index,
462
                  int wmode, float *sbw)
463
3.61M
{
464
3.61M
    int code = gs_error_undefined;
465
3.61M
    pl_font_t *plfont = pfont->client_data;
466
3.61M
    const pl_font_glyph_t *pfg = 0;
467
3.61M
    const byte *cdata = 0;
468
469
3.61M
    if (plfont->glyphs.table != 0) {
470
        /* at least one caller calls before the glyph.table is valid, no chars yet
471
         * test routes caller to gs_type42_default_get_metrics
472
         */
473
379
        pfg = pl_font_lookup_glyph(plfont, glyph_index);
474
379
        cdata = pfg->data;
475
476
379
        if (cdata && (cdata[1] == 1 || cdata[1] == 2)) {
477
1
            double factor = 1.0 / pfont->data.unitsPerEm;
478
1
            uint width;
479
1
            int lsb;
480
481
1
            lsb = pl_get_int16(cdata + 4);
482
1
            width = pl_get_int16(cdata + 6);
483
484
            /* foo NB what about the top side bearing in class 2 ? */
485
486
1
            if (wmode) {
487
                /* NB BUG all other fonts work without this sign
488
                   change it should already be accounted for in the
489
                   character ctm */
490
0
                factor = -factor;       /* lsb and width go down the page */
491
0
                sbw[0] = 0, sbw[1] = lsb * factor;
492
0
                sbw[2] = 0, sbw[3] = width * factor;
493
1
            } else {
494
1
                sbw[0] = lsb * factor, sbw[1] = 0;
495
1
                sbw[2] = width * factor, sbw[3] = 0;
496
1
            }
497
1
            code = 0;           /* tt class 1,2 */
498
1
        }
499
379
    }
500
3.61M
    return code;
501
3.61M
}
502
503
/* get metrics with support for XL tt class 1 and 2
504
 * pl overrides gstype42_default_get_metrics
505
 */
506
static int
507
pl_tt_get_metrics(gs_font_type42 * pfont, uint glyph_index,
508
                  gs_type42_metrics_options_t options, float *sbw)
509
0
{
510
0
    int wmode = gs_type42_metrics_options_wmode(options);
511
0
    int code;
512
513
0
    if ((code = pl_tt_f1c2_get_metrics (pfont, glyph_index, wmode, sbw)) != gs_error_undefined) {
514
0
        return code;
515
0
    }
516
    /* else call default implementation for tt class 0, incomplete font */
517
    /* first check for a vertical substitute if writing mode is
518
       vertical.  We unpleasantly replace the glyph_index parameter
519
       passed to procedure to be consist with the pl_tt_build_char()
520
       debacle */
521
0
    {
522
0
        pl_font_t *plfont = pfont->client_data;
523
524
0
        if (plfont->allow_vertical_substitutes) {
525
0
            gs_glyph vertical = pl_font_vertical_glyph(glyph_index, plfont);
526
527
0
            if (vertical != GS_NO_GLYPH)
528
0
                glyph_index = vertical;
529
0
        }
530
0
    }
531
532
    /* the graphics library does not do this correctly.  If there
533
       aren't two sets of metrics WMode should be ignored.  We work
534
       around that here. */
535
536
0
    if (wmode == 1) {
537
0
        const gs_type42_mtx_t *pmtx = &pfont->data.metrics[wmode];
538
539
0
        if (pmtx->length == 0) {
540
0
            wmode = 0;
541
0
        } else {
542
0
            if (gs_debug_c('=')) {
543
0
                dmprintf(pfont->memory, "Found vertical metrics\n");
544
0
            }
545
0
        }
546
0
    }
547
0
    return gs_type42_default_get_metrics(pfont, glyph_index, wmode, sbw);
548
0
}
549
550
/* Get the outline data for a glyph in a downloaded TrueType font. */
551
int
552
pl_tt_get_outline(gs_font_type42 * pfont, uint index, gs_glyph_data_t * pdata)
553
538
{
554
538
    pl_font_t *plfont = pfont->client_data;
555
538
    const pl_font_glyph_t *pfg = pl_font_lookup_glyph(plfont, index);
556
538
    const byte *cdata = pfg->data;
557
558
538
    if (cdata == 0) {
559
        /* undefined glyph */
560
45
        gs_glyph_data_from_null(pdata);
561
493
    } else {
562
493
        uint desc_size =
563
493
            (*cdata == 15 ? cdata[2] /* PCL5 */ : 0 /* PCL XL */ );
564
493
        uint data_size = pl_get_uint16(cdata + 2 + desc_size);
565
566
493
        if (data_size > pfg->data_len)
567
0
            data_size = pfg->data_len;
568
569
493
        if (data_size <= 4) {
570
            /* empty outline */
571
0
            gs_glyph_data_from_null(pdata);
572
493
        } else if (cdata[1] == 0 && (6 + desc_size + data_size - 4) <= pfg->data_len) {
573
492
            gs_glyph_data_from_bytes(pdata, cdata, 6 + desc_size, data_size - 4, NULL);
574
492
        } else if (cdata[1] == 1 && (10 + data_size - 8) <= pfg->data_len) {
575
1
            gs_glyph_data_from_bytes(pdata, cdata, 10, data_size - 8, NULL);
576
1
        } else if (cdata[1] == 2 && (12 + data_size - 10) <= pfg->data_len) {
577
0
            gs_glyph_data_from_bytes(pdata, cdata, 12, data_size - 10, NULL);
578
0
        }
579
0
        else {
580
            /* invalid, treat as empty outline */
581
0
            gs_glyph_data_from_null(pdata);
582
0
        }
583
493
    }
584
538
    return 0;
585
538
}
586
587
#define access(base, length, vptr)\
588
166M
  (*pfont->data.string_proc)(pfont, (ulong)(base), length, &vptr)
589
590
/* Find a table in a TrueType font. */
591
/* Return the data offset of the table; store the length in *plen. */
592
/* If the table is missing, return 0. */
593
ulong
594
tt_find_table(gs_font_type42 * pfont, const char *tname, uint * plen)
595
33.6M
{
596
33.6M
    const byte *OffsetTable;
597
33.6M
    uint numTables;
598
33.6M
    const byte *TableDirectory;
599
33.6M
    uint i;
600
33.6M
    ulong table_dir_offset = 0;
601
33.6M
    int code;
602
603
33.6M
    if (((code = access(0, 12, OffsetTable)) < 0) ||
604
33.6M
        ((code = access(table_dir_offset, 12, OffsetTable)) < 0))
605
0
        return 0;
606
607
33.6M
    numTables = pl_get_uint16(OffsetTable + 4);
608
609
33.6M
    if (access(table_dir_offset + 12, numTables * 16, TableDirectory) < 0)
610
0
        return 0;
611
612
108M
    for (i = 0; i < numTables; ++i) {
613
108M
        const byte *tab = TableDirectory + i * 16;
614
615
108M
        if (!memcmp(tab, tname, 4)) {
616
33.6M
            if (plen)
617
31.6M
                *plen = pl_get_uint32(tab + 12);
618
33.6M
            return pl_get_uint32(tab + 8);
619
33.6M
        }
620
108M
    }
621
432
    return 0;
622
33.6M
}
623
624
/*
625
 * Map a key through a cmap sub-table.  We export this so we can use
626
 * it someday for mapping between glyph vocabularies.  If the key is
627
 * not mappable, return gs_error_undefined; if the sub-table type is
628
 * unknown, return gs_error_invalidfont.
629
 */
630
static int
631
pl_cmap_lookup(const uint key, const byte * table, size_t table_len, uint * pvalue)
632
31.6M
{
633
31.6M
    const byte *table_lim = table + table_len;
634
635
    /* Dispatch according to the table type. */
636
31.6M
    switch (pl_get_uint16(table)) {
637
0
        case 0:
638
0
            {                   /* Apple standard 1-to-1 mapping. */
639
0
                if (table + key + 6 < table_lim) {
640
0
                    *pvalue = table[key + 6];
641
0
                    if_debug2('J', "[J]%u => %u\n", key, *pvalue);
642
0
                }
643
0
                else
644
0
                    return_error(gs_error_undefined);
645
0
                break;
646
0
            }
647
31.6M
        case 4:
648
31.6M
            {                   /* Microsoft/Adobe segmented mapping.  What a mess! */
649
31.6M
                uint segCount2 = pl_get_uint16(table + 6);
650
31.6M
                const byte *endCount = table + 14;
651
31.6M
                const byte *startCount = endCount + segCount2 + 2;
652
31.6M
                const byte *idDelta = startCount + segCount2;
653
31.6M
                const byte *idRangeOffset = idDelta + segCount2;
654
                /*const byte *glyphIdArray = idRangeOffset + segCount2; */
655
31.6M
                uint i2;
656
657
31.6M
                if (idRangeOffset > table_lim)
658
0
                    return_error(gs_error_undefined);
659
660
236M
                for (i2 = 0; i2 < segCount2 - 3; i2 += 2) {
661
236M
                    int delta, roff;
662
236M
                    uint start = pl_get_uint16(startCount + i2);
663
236M
                    uint glyph;
664
665
236M
                    if_debug4('J', "[J]start=%u end=%u delta=%d roff=%d\n",
666
236M
                              start, pl_get_uint16(endCount + i2),
667
236M
                              pl_get_int16(idDelta + i2),
668
236M
                              pl_get_int16(idRangeOffset + i2));
669
236M
                    if (key < start) {
670
546k
                        if_debug1('J', "[J]%u out of range\n", key);
671
546k
                        return_error(gs_error_undefined);
672
546k
                    }
673
235M
                    if (endCount + i2 + 2 > table_lim) {
674
0
                        break;
675
0
                    }
676
235M
                    if (key > pl_get_uint16(endCount + i2))
677
204M
                        continue;
678
679
30.9M
                    if (idRangeOffset + i2 + 2 > table_lim) {
680
0
                        break;
681
0
                    }
682
30.9M
                    delta = pl_get_int16(idDelta + i2);
683
30.9M
                    roff = pl_get_int16(idRangeOffset + i2);
684
30.9M
                    if (roff == 0) {
685
29.7M
                        *pvalue = (key + delta) & 0xffff;       /* mod 65536 */
686
29.7M
                        if_debug2('J', "[J]%u => %u\n", key, *pvalue);
687
29.7M
                        return 0;
688
29.7M
                    }
689
690
1.18M
                    if ((2 + idRangeOffset + i2 + roff + ((key - start) << 1)) > table_lim) {
691
0
                        break;
692
0
                    }
693
1.18M
                    glyph = pl_get_uint16(idRangeOffset + i2 + roff + ((key - start) << 1));
694
1.18M
                    *pvalue = (glyph == 0 ? 0 : glyph + delta);
695
1.18M
                    if_debug2('J', "[J]%u => %u\n", key, *pvalue);
696
1.18M
                    return 0;
697
1.18M
                }
698
                /*
699
                 * The TrueType documentation says that the last range is
700
                 * always supposed to end with 0xffff, so this shouldn't
701
                 * happen; however, in some real fonts, it does.
702
                 */
703
31.6M
                if_debug1('J', "[J]%u out of range\n", key);
704
81.7k
                return_error(gs_error_undefined);
705
31.6M
            }
706
0
        case 6:
707
0
            {                   /* Single interval lookup. */
708
0
                uint firstCode;
709
0
                uint entryCount;
710
711
0
                if (table + 10 > table_lim) {
712
0
                    return_error(gs_error_undefined);
713
0
                }
714
715
0
                firstCode = pl_get_uint16(table + 6);
716
0
                entryCount = pl_get_uint16(table + 8);
717
0
                if (key < firstCode || key >= firstCode + entryCount) {
718
0
                    if_debug1('J', "[J]%u out of range\n", key);
719
0
                    return_error(gs_error_undefined);
720
0
                }
721
722
0
                if (table + 12 + ((key - firstCode) << 1) > table_lim) {
723
0
                    return_error(gs_error_undefined);
724
0
                }
725
0
                *pvalue =
726
0
                    pl_get_uint16(table + 10 + ((key - firstCode) << 1));
727
0
                if_debug2('J', "[J]%u => %u\n", key, *pvalue);
728
0
                break;
729
0
            }
730
0
        default:
731
0
            return_error(gs_error_invalidfont);
732
31.6M
    }
733
0
    return 0;
734
31.6M
}
735
736
/* Encode a character using the TrueType cmap tables. */
737
/* (We think this is never used for downloaded fonts.) */
738
static gs_glyph
739
pl_tt_cmap_encode_char(gs_font_type42 * pfont, ulong cmap_offset,
740
                       uint cmap_len, gs_char chr)
741
31.6M
{
742
31.6M
    const byte *cmap;
743
31.6M
    const byte *cmap_sub;
744
31.6M
    const byte *table;
745
31.6M
    size_t table_len;
746
31.6M
    uint value;
747
31.6M
    int code;
748
749
31.6M
    access(cmap_offset, cmap_len, cmap);
750
    /* Since the Apple cmap format is of no help in determining */
751
    /* the encoding, look for a Microsoft table; but if we can't */
752
    /* find one, take the first one. */
753
31.6M
    cmap_sub = cmap + 4;
754
31.6M
    {
755
31.6M
        uint i;
756
31.6M
        uint16_t ncmaps = pl_get_uint16(cmap + 2);
757
758
31.6M
        if (ncmaps * 8 + 2 >= cmap_len)
759
0
            return GS_NO_GLYPH;
760
761
94.1M
        for (i = 0; i < ncmaps; ++i) {
762
94.1M
            if_debug3m('j', pfont->memory,
763
94.1M
                       "[j]cmap %d: platform %u encoding %u\n", i,
764
94.1M
                       pl_get_uint16(cmap_sub + i * 8),
765
94.1M
                       pl_get_uint16(cmap_sub + i * 8 + 2));
766
94.1M
            if (pl_get_uint16(cmap_sub + i * 8) == 3) {
767
31.6M
                cmap_sub += i * 8;
768
31.6M
                break;
769
31.6M
            }
770
94.1M
        }
771
31.6M
    }
772
0
    {
773
31.6M
        uint offset = cmap_offset + pl_get_uint32(cmap_sub + 4);
774
31.6M
        table_len = cmap_offset + cmap_len - offset;
775
776
31.6M
        access(offset, table_len, table);
777
31.6M
    }
778
31.6M
    code = pl_cmap_lookup((uint) chr, table, table_len, &value);
779
31.6M
    return (code < 0 ? GS_NO_GLYPH : value);
780
31.6M
}
781
782
/* Encode a character using the map built for downloaded TrueType fonts. */
783
static gs_glyph
784
pl_tt_dynamic_encode_char(const gs_font_type42 * pfont, gs_char chr)
785
430
{
786
430
    pl_font_t *plfont = pfont->client_data;
787
430
    const pl_tt_char_glyph_t *ptcg = pl_tt_lookup_char(plfont, chr);
788
789
430
    return (ptcg->chr == gs_no_char ? GS_NO_GLYPH : ptcg->glyph);
790
430
}
791
792
/* Return the galley character for a character code, if any; */
793
/* otherwise return gs_no_char. */
794
/* Note that we return 0xffff for a character that is explicitly */
795
/* designated as undefined. */
796
static gs_char
797
pl_font_galley_character(gs_char chr, const pl_font_t * plfont)
798
0
{
799
0
    long GC = plfont->offsets.GC;
800
0
    const byte *gcseg;
801
0
    uint b0, b1;
802
0
    uint i, len;
803
0
    uint default_char;
804
805
0
    if (GC < 0)
806
0
        return gs_no_char;
807
0
    gcseg = plfont->header + GC;
808
0
    if (plfont->large_sizes)
809
0
        len = pl_get_uint32(gcseg + 2), i = 12;
810
0
    else
811
0
        len = pl_get_uint16(gcseg + 2), i = 10;
812
0
    if (len != pl_get_uint16(gcseg + i - 2) * 6 + 6)    /* bad data */
813
0
        return gs_no_char;
814
0
    default_char = pl_get_uint16(gcseg + i - 4);        /* default character */
815
0
    len += i - 6;
816
0
    b0 = chr >> 8;
817
0
    b1 = chr & 0xff;
818
0
    for (; i < len; i += 6)
819
0
        if (b0 >= gcseg[i] && b0 <= gcseg[i + 1] &&
820
0
            b1 >= gcseg[i + 2] && b1 <= gcseg[i + 3]
821
0
            )
822
0
            return pl_get_uint16(gcseg + i + 4);
823
0
    return default_char;
824
0
}
825
826
/* Encode a character for a TrueType font. */
827
/* What we actually return is the TT glyph index.  Note that */
828
/* we may return either GS_NO_GLYPH or 0 for an undefined character. */
829
gs_glyph
830
pl_tt_encode_char(gs_font * pfont_generic, gs_char chr,
831
                  gs_glyph_space_t not_used)
832
31.6M
{
833
31.6M
    gs_font_type42 *pfont = (gs_font_type42 *) pfont_generic;
834
31.6M
    uint cmap_len;
835
31.6M
    ulong cmap_offset = tt_find_table(pfont, "cmap", &cmap_len);
836
31.6M
    gs_glyph glyph = (cmap_offset == 0 ?
837
                      /* This is a downloaded font with no cmap. */
838
430
                      pl_tt_dynamic_encode_char(pfont, chr) :
839
31.6M
                      pl_tt_cmap_encode_char(pfont, cmap_offset, cmap_len,
840
31.6M
                                             chr));
841
31.6M
    pl_font_t *plfont = pfont->client_data;
842
31.6M
    pl_font_glyph_t *pfg;
843
844
31.6M
    if (plfont->offsets.GC < 0)
845
31.6M
        return glyph;           /* no substitute */
846
0
    pfg = pl_font_lookup_glyph(plfont, glyph);
847
    /* If the character is missing, use the galley character instead. */
848
0
    if (!pfg->data) {
849
0
        gs_char galley_char = pl_font_galley_character(chr, plfont);
850
0
        if (galley_char != gs_no_char) {
851
0
            return
852
0
                (galley_char == 0xffff ? 0 :
853
0
                 cmap_offset == 0 ?
854
0
                 pl_tt_dynamic_encode_char(pfont, galley_char) :
855
0
                 pl_tt_cmap_encode_char(pfont, cmap_offset, cmap_len,
856
0
                                        galley_char));
857
0
        }
858
0
    }
859
0
    return glyph;               /* no substitute */
860
0
}
861
862
/* Get metrics */
863
static int
864
pl_tt_char_metrics(const pl_font_t * plfont, const void *pgs,
865
                   gs_char char_code, float metrics[4])
866
0
{
867
0
    gs_glyph unused_glyph = GS_NO_GLYPH;
868
0
    gs_glyph glyph =
869
0
        pl_tt_encode_char(plfont->pfont, char_code, unused_glyph);
870
0
    if (glyph == GS_NO_GLYPH) {
871
0
        return 1;
872
0
    }
873
0
    return gs_type42_get_metrics((gs_font_type42 *) plfont->pfont,
874
0
                                 glyph, metrics);
875
0
}
876
877
/* Get character existence and escapement for a TrueType font. */
878
static int
879
pl_tt_char_width(const pl_font_t * plfont, const void *pgs, gs_char char_code,
880
                 gs_point * pwidth)
881
0
{
882
0
    gs_font *pfont = plfont->pfont;
883
0
    gs_char chr = char_code;
884
0
    gs_glyph unused_glyph = GS_NO_GLYPH;
885
0
    gs_glyph glyph = pl_tt_encode_char(pfont, chr, unused_glyph);
886
0
    int code;
887
0
    float sbw[4];
888
889
0
    pwidth->x = pwidth->y = 0;
890
891
    /* Check for a vertical substitute. */
892
0
    if (pfont->WMode & 1) {
893
0
        gs_glyph vertical = pl_font_vertical_glyph(glyph, plfont);
894
895
0
        if (vertical != GS_NO_GLYPH)
896
0
            glyph = vertical;
897
0
    }
898
899
    /* undefined character */
900
0
    if (glyph == 0xffff || glyph == GS_NO_GLYPH)
901
0
        return 1;
902
903
0
    code = gs_type42_get_metrics((gs_font_type42 *) pfont, glyph, sbw);
904
0
    if (code < 0)
905
0
        return code;
906
    /* character exists */
907
0
    pwidth->x = sbw[2];
908
0
    return 0;
909
0
}
910
911
/* Render a TrueType character. */
912
static int
913
pl_tt_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont,
914
                 gs_char chr, gs_glyph orig_glyph)
915
0
{
916
0
    gs_glyph glyph = orig_glyph;
917
918
0
#define pbfont ((gs_font_base *)pfont)
919
0
#define pfont42 ((gs_font_type42 *)pfont)
920
0
    int code;
921
0
    pl_font_t *plfont = (pl_font_t *) pfont->client_data;
922
0
    float bold_fraction =
923
0
        gs_show_in_charpath(penum) != cpm_show ? 0.0 : plfont->bold_fraction;
924
0
    uint bold_added;
925
0
    double scale = 1.0;
926
0
    float sbw[4], w2[6];
927
0
    int ipx = 0;
928
0
    int ipy = 0;
929
0
    int iqx, iqy;
930
0
    gx_device_memory *pmdev;
931
0
    bool ctm_modified = false;
932
0
    bool bold_device_created = false;
933
0
    gs_matrix save_ctm;
934
935
0
#define isDownloaded(p42) ((p42)->data.proc_data == 0)
936
0
#ifdef CACHE_TRUETYPE_CHARS
937
0
#  define tt_set_cache(penum, pgs, w2)\
938
0
     gs_setcachedevice(penum, pgs, w2)
939
#else
940
#  define tt_set_cache(penum, pgs, w2)\
941
     gs_setcharwidth(penum, pgs, w2[0], w2[1]);
942
#endif
943
    /* undefined */
944
0
    if (glyph == GS_NO_GLYPH)
945
0
        return 0;
946
    /* Get the metrics and set the cache device. */
947
0
    code = gs_type42_get_metrics(pfont42, glyph, sbw);
948
0
    if (code < 0)
949
0
        return code;
950
0
    w2[0] = sbw[2], w2[1] = sbw[3];
951
952
    /* Adjust the bounding box for stroking if needed. */
953
954
0
    {
955
0
        const gs_rect *pbbox = &pbfont->FontBBox;
956
957
0
        w2[2] = pbbox->p.x, w2[3] = pbbox->p.y;
958
0
        w2[4] = pbbox->q.x, w2[5] = pbbox->q.y;
959
0
        if (pfont->PaintType) {
960
0
            double expand = max(1.415, gs_currentmiterlimit(pgs)) *
961
0
                gs_currentlinewidth(pgs) / 2;
962
963
0
            w2[2] -= expand, w2[3] -= expand;
964
0
            w2[4] += expand, w2[5] += expand;
965
0
        }
966
0
    }
967
968
    /* Establish a current point. */
969
0
    if ((code = gs_moveto(pgs, 0.0, 0.0)) < 0)
970
0
        return code;
971
972
0
    {
973
        /* Check for a vertical substitute. */
974
0
        if (plfont->allow_vertical_substitutes) {
975
0
            pl_font_t *plfont = pfont->client_data;
976
0
            gs_glyph vertical = pl_font_vertical_glyph(glyph, plfont);
977
978
0
            if (vertical != GS_NO_GLYPH) {
979
0
                glyph = vertical;
980
0
            }
981
0
        }
982
        /* now check for rotation.  This is the ringer, fonts with
983
           escapement 1 em get rotated.  If you hold an HP
984
           engineer's head close to your ear you can hear the
985
           ocean. */
986
0
        if ((pfont->WMode & 1) && sbw[2] == 1.0) {
987
            /* save the ctm */
988
0
            gs_currentmatrix(pgs, &save_ctm);
989
0
            ctm_modified = true;
990
            /* magic numbers - we don't completely understand
991
               the translation magic used by HP.  This provides a
992
               good approximation */
993
0
            gs_translate(pgs, 1.0 / 1.15, -(1.0 - 1.0 / 1.15));
994
0
            gs_rotate(pgs, 90);
995
0
        }
996
0
    }
997
998
    /*
999
     * If we want pseudo-bold, render untransformed to an intermediate
1000
     * bitmap, smear it, and then transform it to produce the output.
1001
     * This is really messy.
1002
     */
1003
0
    if (bold_fraction == 0) {
1004
0
        code = tt_set_cache(penum, pgs, w2);
1005
0
        if (code < 0)
1006
0
            return code;
1007
0
        bold_added = 0;
1008
0
    } else {
1009
0
        gs_matrix mat, smat;
1010
0
        gs_rect sbox;
1011
1012
0
        code = gs_gsave(pgs);
1013
0
        if (code < 0)
1014
0
            return code;
1015
0
        gs_currentmatrix(pgs, &mat);
1016
        /* Determine an appropriate scale for the bitmap. */
1017
0
        scale = max(fabs(mat.xx) + fabs(mat.yx), fabs(mat.xy) + fabs(mat.yy));
1018
0
        gs_make_scaling(scale, scale, &smat);
1019
0
        sbox.p.x = w2[2], sbox.p.y = w2[3];
1020
0
        sbox.q.x = w2[4], sbox.q.y = w2[5];
1021
0
        code = gs_bbox_transform(&sbox, &smat, &sbox);
1022
0
        if (code < 0)
1023
0
            return code;
1024
0
        ipx = (int)sbox.p.x, ipy = (int)sbox.p.y;
1025
0
        iqx = (int)ceil(sbox.q.x), iqy = (int)ceil(sbox.q.y);
1026
        /* Set up the memory device for the bitmap.  NB should check code. */
1027
0
        code = gs_make_mem_mono_device_with_copydevice(&pmdev, pgs->memory, pgs->device);
1028
0
        if (code < 0)
1029
0
            return code;
1030
1031
0
        bold_device_created = true;
1032
        /* due to rounding, bold added (integer) can be zero while
1033
           bold fraction (float) is non zero in which case we add
1034
           1 scan line.  We do not "0" bold simply because it is
1035
           inconvenient to back out at this point.  We don't have
1036
           any HP tests which would show measurable difference
1037
           either way (0 or 1). */
1038
0
        bold_added = max((int)(scale * bold_fraction * 2 + 0.5), 1);
1039
0
        pmdev->width = iqx - ipx + bold_added;
1040
0
        pmdev->height = iqy - ipy;
1041
0
        pmdev->bitmap_memory = pgs->memory;
1042
0
        code = (*dev_proc(pmdev, open_device)) ((gx_device *) pmdev);
1043
0
        if (code < 0) {
1044
0
            gs_grestore(pgs);
1045
0
            return code;
1046
0
        }
1047
        /* NB we have no idea why opening the device doesn't set
1048
           the is_open flag, but this meme is repeated in various
1049
           parts of the code, if it isn't done closing the memory
1050
           device will not have no effect (release bitmap and
1051
           mask). */
1052
0
        pmdev->is_open = true;
1053
        /* Don't allow gs_setdevice to reset things. */
1054
0
        gx_set_device_only(pgs, (gx_device *) pmdev);
1055
1056
0
        {
1057
0
            gs_fixed_rect cbox;
1058
1059
0
            cbox.p.x = cbox.p.y = fixed_0;
1060
0
            cbox.q.x = int2fixed(pmdev->width);
1061
0
            cbox.q.y = int2fixed(pmdev->height);
1062
0
            code = gx_clip_to_rectangle(pgs, &cbox);
1063
0
            if (code < 0)
1064
0
                return code;
1065
0
        }
1066
        /* Make sure we clear the entire bitmap. */
1067
0
        memset(pmdev->base, 0, (size_t)bitmap_raster(pmdev->width) * pmdev->height);
1068
0
        code = gx_set_device_color_1(pgs);     /* write 1's */
1069
0
        if (code < 0)
1070
0
            return code;
1071
0
        smat.tx = (float)(-ipx);
1072
0
        smat.ty = (float)(-ipy);
1073
0
        gs_setmatrix(pgs, &smat);
1074
0
    }
1075
0
    code = gs_type42_append(glyph, pgs, pgs->path,
1076
0
                            (gs_text_enum_t *) penum, pfont,
1077
0
                            gs_show_in_charpath(penum) != cpm_show);
1078
0
    if (code >= 0) {
1079
        /* Save the current value of fill adjust and use the
1080
           special value of -1 to indicate dropout prevention
1081
           should be enabled, later restore the old fill adjust
1082
           value.  Similar code for the PDF and PS interpreter is
1083
           in zchar42.c */
1084
0
        gs_fixed_point fa = pgs->fill_adjust;
1085
1086
0
        pgs->fill_adjust.x = pgs->fill_adjust.y = -1;
1087
0
        code = (pfont->PaintType ? gs_stroke(pgs) : gs_fill(pgs));
1088
0
        pgs->fill_adjust = fa;
1089
0
    }
1090
0
    if (ctm_modified)
1091
0
        gs_setmatrix(pgs, &save_ctm);
1092
0
    if (bold_added && (code >= 0))
1093
0
        code = gs_grestore(pgs);
1094
1095
0
    if (code < 0 || !bold_added)
1096
0
        return (code < 0 ? code : 0);
1097
1098
    /* Now smear the bitmap and copy it to the destination. */
1099
1100
0
    {
1101
0
        gs_image_t image;
1102
0
        gs_image_enum *ienum =
1103
0
            gs_image_enum_alloc(pgs->memory, "pl_tt_build_char");
1104
0
        byte *bold_lines =
1105
0
            alloc_bold_lines(pgs->memory, pmdev->width - bold_added,
1106
0
                             bold_added,
1107
0
                             "pl_tt_build_char(bold_lines)");
1108
1109
0
        if (ienum == 0 || bold_lines == 0) {
1110
0
            code = gs_note_error(gs_error_VMerror);
1111
0
            goto out;
1112
0
        }
1113
0
        gs_image_t_init_mask(&image, true);
1114
0
        image.Width = pmdev->width;
1115
0
        image.Height = pmdev->height + bold_added;
1116
0
        gs_make_scaling(scale, scale, &image.ImageMatrix);
1117
0
        image.ImageMatrix.tx = (float)(-ipx);
1118
0
        image.ImageMatrix.ty = (float)(-ipy);
1119
0
        image.adjust = true;
1120
0
        code = gs_setcharwidth(penum, pgs, w2[0], w2[1]);
1121
0
        if (code < 0)
1122
0
            goto out;
1123
0
        code = pl_image_bitmap_char(ienum, &image, pmdev->base,
1124
0
                                    bitmap_raster(pmdev->width), bold_added,
1125
0
                                    bold_lines, pgs);
1126
0
      out:if (bold_device_created)
1127
0
            gx_device_retain((gx_device *) pmdev, false);
1128
0
        gs_free_object(pgs->memory, bold_lines,
1129
0
                       "pl_tt_build_char(bold_lines)");
1130
0
        gs_free_object(pgs->memory, ienum, "pl_tt_build_char(image enum)");
1131
0
    }
1132
0
    return (code < 0 ? code : 0);
1133
0
#undef pfont42
1134
0
#undef pbfont
1135
0
}
1136
1137
/* We don't have to do any character encoding, since Intellifonts are */
1138
/* indexed by character code (if bound) or MSL code (if unbound). */
1139
static gs_glyph
1140
pl_intelli_encode_char(gs_font * pfont, gs_char pchr,
1141
                       gs_glyph_space_t not_used)
1142
0
{
1143
0
    return (gs_glyph) pchr;
1144
0
}
1145
1146
/* Define the structure of the Intellifont metrics. */
1147
typedef struct intelli_metrics_s
1148
{
1149
    byte charSymbolBox[4][2];
1150
    byte charEscapementBox[4][2];
1151
    byte halfLine[2];
1152
    byte centerline[2];
1153
} intelli_metrics_t;
1154
1155
/* Merge the bounding box of a character into the composite box, */
1156
/* and set the escapement.  Return true if the character is defined. */
1157
static bool
1158
pl_intelli_merge_box(float wbox[6], const pl_font_t * plfont, gs_glyph glyph, int depth)
1159
0
{
1160
0
    const byte *cdata = pl_font_lookup_glyph(plfont, glyph)->data;
1161
1162
    /* 8 is an arbitrary limit to catch circular referencing glyphs */
1163
0
    if (cdata == 0 || depth > IF_COMPOUND_CHAR_LIMIT)
1164
0
        return false;
1165
0
    wbox[1] = 0;
1166
0
    if (cdata[3] == 4) {        /* Compound character.  Merge the component boxes; */
1167
        /* use the compound character's escapement. */
1168
0
        bool found = false;
1169
0
        uint i;
1170
1171
0
        for (i = 0; i < cdata[6]; ++i) {
1172
0
            gs_glyph g = (gs_glyph)pl_get_uint16(cdata + 8 + i * 6);
1173
0
            if (g == glyph)
1174
0
                return false;
1175
0
            found |= pl_intelli_merge_box(wbox, plfont, g, ++depth);
1176
0
        }
1177
0
        wbox[0] = (float)pl_get_int16(cdata + 4);
1178
0
        return found;
1179
0
    }
1180
    /* Non-compound character. */
1181
0
    cdata += 4;                 /* skip PCL character header */
1182
0
    {
1183
0
        const intelli_metrics_t *metrics =
1184
0
            (const intelli_metrics_t *)(cdata + pl_get_uint16(cdata + 2));
1185
0
        int llx = pl_get_int16(metrics->charSymbolBox[0]);
1186
0
        int lly = pl_get_int16(metrics->charSymbolBox[1]);
1187
0
        int urx = pl_get_int16(metrics->charSymbolBox[2]);
1188
0
        int ury = pl_get_int16(metrics->charSymbolBox[3]);
1189
1190
0
        wbox[0] = (float)(pl_get_int16(metrics->charEscapementBox[2]) -
1191
0
                          pl_get_int16(metrics->charEscapementBox[0]));
1192
0
        wbox[2] = min(wbox[2], llx);
1193
0
        wbox[3] = min(wbox[3], lly);
1194
0
        wbox[4] = max(wbox[4], urx);
1195
0
        wbox[5] = max(wbox[5], ury);
1196
0
    }
1197
0
    return true;
1198
0
}
1199
1200
/* Do the work for rendering an Intellifont character. */
1201
/* The caller has done the setcachedevice. */
1202
static int
1203
pl_intelli_show_char(gs_gstate * pgs, const pl_font_t * plfont, gs_glyph glyph, int depth)
1204
0
{
1205
0
    int code;
1206
0
    const byte *cdata, *cdata_end;
1207
0
    pl_font_glyph_t *font_glyph;
1208
0
    const intelli_metrics_t *metrics;
1209
0
    int *xBuffer = NULL, *yBuffer = NULL;
1210
0
    client_name_t cname = (client_name_t) "pl_intelli_show_char";
1211
1212
0
    font_glyph = pl_font_lookup_glyph(plfont, glyph);
1213
0
    cdata = font_glyph->data;
1214
0
    cdata_end = cdata + font_glyph->data_len;
1215
1216
    /* 8 is an arbitrary limit to catch circular referencing glyphs */
1217
0
    if (depth > IF_COMPOUND_CHAR_LIMIT)
1218
0
        return_error(gs_error_invalidfont);
1219
1220
0
    if (cdata == 0) {
1221
0
        if_debug1m('1', pgs->memory, "[1] no character data for glyph %ld\n",
1222
0
                   glyph);
1223
0
        return 0;
1224
0
    }
1225
0
    if (cdata[3] == 4) {        /* Compound character */
1226
0
        gs_matrix save_ctm;
1227
0
        int i;
1228
1229
0
        gs_currentmatrix(pgs, &save_ctm);
1230
0
        for (i = 0; i < cdata[6]; ++i) {
1231
0
            const byte *edata = cdata + 8 + i * 6;
1232
0
            double x_offset = pl_get_int16(edata + 2);
1233
0
            double y_offset = pl_get_int16(edata + 4);
1234
0
            gs_glyph g = (gs_glyph)pl_get_uint16(edata);
1235
1236
0
            if (g == glyph)
1237
0
                return_error(gs_error_invalidfont);
1238
1239
0
            gs_translate(pgs, x_offset, y_offset);
1240
0
            code = pl_intelli_show_char(pgs, plfont, g, ++depth);
1241
0
            gs_setmatrix(pgs, &save_ctm);
1242
0
            if (code < 0)
1243
0
                return code;
1244
0
        }
1245
0
        return 0;
1246
0
    }
1247
1248
    /* compound character */
1249
    /* not compound character */
1250
0
    {
1251
0
        const byte *outlines;
1252
0
        uint num_loops;
1253
0
        uint i;
1254
1255
0
        cdata += 4;             /* skip PCL character header */
1256
0
        outlines = cdata + pl_get_uint16(cdata + 6);
1257
0
        if (outlines >= cdata_end)
1258
0
            return 0;
1259
1260
0
        num_loops = pl_get_uint16(outlines);
1261
1262
0
        if_debug2m('1', pgs->memory, "[1]ifont glyph %lu: loops=%u\n",
1263
0
                   (ulong) glyph, num_loops);
1264
1265
0
        if (num_loops == 0)
1266
0
            return -1;
1267
1268
0
        for (i = 0; i < num_loops; ++i) {
1269
0
            const byte *xyc;
1270
0
            uint num_points;
1271
0
            uint num_aux_points;
1272
0
            const byte *x_coords, *y_coords, *x_coords_last;
1273
0
            const byte *x_aux_coords, *y_aux_coords, *x_aux_coords_last;
1274
0
            int llx, lly, urx, ury;     /* character bounding box */
1275
0
            int x, y;
1276
0
            int xAux, yAux;
1277
0
            int *xScan, *yScan, *xLast;
1278
0
            int pointBufferSize;
1279
0
            size_t sz;
1280
1281
0
            if ((outlines + 4 + i * 8) >= cdata_end) {
1282
0
                code = gs_note_error(gs_error_invalidfont);
1283
0
                break;
1284
0
            }
1285
0
            xyc = cdata + pl_get_uint16(outlines + 4 + i * 8);
1286
0
            if (xyc + 4 >= cdata_end) {
1287
0
                code = gs_note_error(gs_error_invalidfont);
1288
0
                break;
1289
0
            }
1290
1291
0
            num_points = pl_get_uint16(xyc);
1292
0
            num_aux_points = pl_get_uint16(xyc + 2);
1293
1294
0
            x_coords = xyc + 4;
1295
0
            y_coords = x_coords + num_points * 2;
1296
0
            x_coords_last = y_coords;
1297
1298
0
            if (x_coords_last >= cdata_end
1299
0
                || (y_coords + num_points * 2) >= cdata_end) {
1300
0
                code = 0;
1301
0
                break;
1302
0
            }
1303
1304
0
            metrics =
1305
0
                (const intelli_metrics_t *)(cdata + pl_get_uint16(cdata + 2));
1306
0
            llx = pl_get_int16(metrics->charSymbolBox[0]);
1307
0
            lly = pl_get_int16(metrics->charSymbolBox[1]);
1308
0
            urx = pl_get_int16(metrics->charSymbolBox[2]);
1309
0
            ury = pl_get_int16(metrics->charSymbolBox[3]);
1310
1311
0
            pointBufferSize = num_points;       /* allocate enough to hold all points */
1312
0
            if (num_aux_points != 0xffff) {
1313
0
                pointBufferSize += num_aux_points;
1314
0
                x_aux_coords = y_coords + num_points * 2;
1315
0
                y_aux_coords = x_aux_coords + num_aux_points;
1316
0
                x_aux_coords_last = y_coords;
1317
0
                if ((y_aux_coords + num_aux_points * 2) >= cdata_end) {
1318
0
                    if (x_aux_coords_last >= cdata_end) {
1319
0
                        pointBufferSize -= num_aux_points;
1320
0
                        num_aux_points = 0xffff;
1321
0
                        x_aux_coords = NULL;
1322
0
                        y_aux_coords = NULL;
1323
0
                        x_aux_coords_last = NULL;
1324
0
                    }
1325
0
                    else {
1326
                        /* if we don't have enough data for all the declared points
1327
                         * use as much as we have.
1328
                         */
1329
0
                        pointBufferSize -= num_aux_points;
1330
0
                        num_aux_points = (cdata_end - y_aux_coords) / 2;
1331
0
                        pointBufferSize += num_aux_points;
1332
0
                        x_aux_coords_last = x_aux_coords + num_aux_points;
1333
0
                    }
1334
0
                }
1335
0
            } else {
1336
0
                x_aux_coords = NULL;
1337
0
                y_aux_coords = NULL;
1338
0
                x_aux_coords_last = NULL;
1339
0
            }
1340
1341
0
            sz = pointBufferSize * sizeof(int);
1342
1343
0
            if (i == 0) {
1344
0
                xBuffer = (int *)gs_alloc_bytes(pgs->memory, sz, cname);
1345
0
                yBuffer = (int *)gs_alloc_bytes(pgs->memory, sz, cname);
1346
0
            } else {
1347
                /* NB we don't have a font that tests this yet */
1348
0
                xBuffer =
1349
0
                    (int *)gs_resize_object(pgs->memory, xBuffer, sz, cname);
1350
0
                yBuffer =
1351
0
                    (int *)gs_resize_object(pgs->memory, yBuffer, sz, cname);
1352
0
            }
1353
1354
0
            if (xBuffer == NULL || yBuffer == NULL) {
1355
0
                if (xBuffer != NULL)
1356
0
                    gs_free_object(pgs->memory, xBuffer, "x point buffer");
1357
0
                if (yBuffer != NULL)
1358
0
                    gs_free_object(pgs->memory, yBuffer, "y point buffer");
1359
0
                return_error(gs_error_VMerror);
1360
0
            }
1361
1362
0
            xLast = NULL;
1363
1364
0
            if_debug2m('1', pgs->memory,
1365
0
                       "[1]num_points=%u num_aux_points=%u\n", num_points,
1366
0
                       num_aux_points);
1367
1368
            /* collect the points in the buffers, since we need to clean them up later */
1369
            /* only points inside the bounding box are allowed */
1370
            /* aux points are points inserted between two points, making the outline smoother */
1371
            /* the aux points could be used for curve fitting, but we add line segments */
1372
0
            for (xScan = xBuffer, yScan = yBuffer; x_coords < x_coords_last;
1373
0
                 x_coords += 2, y_coords += 2) {
1374
0
                x = pl_get_uint16(x_coords) & 0x3fff;
1375
0
                y = pl_get_uint16(y_coords) & 0x3fff;
1376
1377
0
                if_debug4m('1', pgs->memory, "[1]%s (%d,%d) %s\n",
1378
0
                           (*x_coords & 0x80 ? " line" : "curve"), x, y,
1379
0
                           (*y_coords & 0x80 ? " line" : "curve"));
1380
1381
0
                if (xScan > xBuffer) {  /* not first point, therefore aux is possible */
1382
0
                    if (x_aux_coords < x_aux_coords_last && !(*x_coords & 0x80)) {      /* use an aux point */
1383
                        /* The auxiliary dx and dy values are signed. */
1384
0
                        int dx = (*x_aux_coords++ ^ 0x80) - 0x80;
1385
0
                        int dy = (*y_aux_coords++ ^ 0x80) - 0x80;
1386
1387
0
                        if_debug2m('1', pgs->memory, "[1]... aux (%d,%d)\n",
1388
0
                                   dx, dy);
1389
1390
0
                        xAux = (x + *(xScan - 1)) / 2 + dx;
1391
0
                        yAux = (y + *(yScan - 1)) / 2 + dy;
1392
0
                        if ((xAux >= llx && xAux <= urx) && (yAux >= lly && yAux <= ury)) {     /* aux point is inside bounding box */
1393
0
                            *xScan++ = xAux;
1394
0
                            *yScan++ = yAux;
1395
0
                        }
1396
                        /* end point inside bounding box */
1397
                        /* what do points outside the bounding box mean? */
1398
0
                    }           /* use an aux point */
1399
0
                }
1400
                /* not first point */
1401
0
                if ((x >= llx && x <= urx) && (y >= lly && y <= ury)) { /* point inside bounding box */
1402
0
                    *xScan++ = x;
1403
0
                    *yScan++ = y;
1404
0
                }               /* point inside bounding box */
1405
0
            }                   /* for num_points - first time through */
1406
1407
0
            if (num_aux_points != 0xffff)
1408
0
                xLast = xScan;
1409
0
            else
1410
0
                xLast = xScan - 1;      /* discard the last point */
1411
1412
0
            xScan = xBuffer;
1413
0
            yScan = yBuffer;
1414
0
            if (xLast > xBuffer) {
1415
0
                code = gs_moveto(pgs, (double) * xScan++, (double) * yScan++);
1416
0
                if (code < 0)
1417
0
                    goto cleanup;
1418
0
            }
1419
1420
0
            for (; xScan < xLast;) {
1421
0
                code = gs_lineto(pgs, (double) * xScan++, (double) * yScan++);
1422
0
                if (code < 0)
1423
0
                    goto cleanup;
1424
0
            }
1425
            /* close the path of this loop */
1426
0
            code = gs_closepath(pgs);
1427
0
            if (code < 0)
1428
0
                break;
1429
1430
0
        }                       /* for num_loops */
1431
1432
0
      cleanup:
1433
0
        gs_free_object(pgs->memory, xBuffer, "x point buffer");
1434
0
        gs_free_object(pgs->memory, yBuffer, "y point buffer");
1435
0
    }                           /* end not compound */
1436
0
    return code;
1437
0
}
1438
1439
/* Get character existence and escapement for an Intellifont. */
1440
static int
1441
pl_intelli_char_width(const pl_font_t * plfont, const void *pgs,
1442
                      gs_char char_code, gs_point * pwidth)
1443
0
{
1444
0
    const byte *cdata = pl_font_lookup_glyph(plfont, char_code)->data;
1445
0
    int wx;
1446
1447
0
    if (!pwidth)
1448
0
        return (cdata == 0 ? 1 : 0);
1449
0
    if (cdata == 0) {
1450
0
        pwidth->x = pwidth->y = 0;
1451
0
        return 1;
1452
0
    }
1453
0
    switch (cdata[3]) {
1454
0
        case 3:                /* non-compound character */
1455
0
            cdata += 4;         /* skip PCL character header */
1456
0
            {
1457
0
                const intelli_metrics_t *metrics =
1458
0
                    (const intelli_metrics_t *)(cdata +
1459
0
                                                pl_get_uint16(cdata + 2));
1460
0
                wx = pl_get_int16(metrics->charEscapementBox[2]) -
1461
0
                    pl_get_int16(metrics->charEscapementBox[0]);
1462
0
            }
1463
0
            break;
1464
0
        case 4:                /* compound character */
1465
0
            wx = pl_get_int16(cdata + 4);
1466
0
            break;
1467
0
        default:               /* shouldn't happen */
1468
0
            pwidth->x = pwidth->y = 0;
1469
0
            return 0;
1470
0
    }
1471
0
    pwidth->x = (double) wx / 8782.0;
1472
0
    return 0;
1473
0
}
1474
1475
static int
1476
pl_intelli_char_metrics(const pl_font_t * plfont, const void *pgs,
1477
                        gs_char char_code, float metrics[4])
1478
0
{
1479
0
    gs_point width;
1480
0
    const byte *cdata = pl_font_lookup_glyph(plfont, char_code)->data;
1481
1482
0
    metrics[0] = metrics[1] = metrics[2] = metrics[3] = 0;
1483
1484
0
    if (cdata == 0) {
1485
0
        return 1;
1486
0
    }
1487
1488
    /* compound */
1489
0
    if (cdata[3] == 4) {
1490
0
        dmprintf(plfont->pfont->memory,
1491
0
                 "warning compound intellifont metrics not supported");
1492
0
        return 0;
1493
0
    }
1494
1495
0
    cdata += 4;
1496
1497
0
    {
1498
0
        const intelli_metrics_t *intelli_metrics =
1499
0
            (const intelli_metrics_t *)(cdata + pl_get_uint16(cdata + 2));
1500
1501
        /* NB probably not right */
1502
        /* never a vertical substitute, doesn't yet handle compound characters */
1503
0
        metrics[0] = (float)pl_get_int16(intelli_metrics->charSymbolBox[0]);
1504
0
        metrics[0] /= 8782.0;
1505
0
        pl_intelli_char_width(plfont, pgs, char_code, &width);
1506
0
        metrics[2] = width.x;
1507
0
        return 0;
1508
0
    }
1509
0
}
1510
1511
/* Render a character for an Intellifont. */
1512
static int
1513
pl_intelli_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont,
1514
                      gs_char chr, gs_glyph glyph)
1515
0
{
1516
0
    const pl_font_t *plfont = (const pl_font_t *)pfont->client_data;
1517
0
    float wbox[6];
1518
0
    int code;
1519
1520
0
    wbox[0] = wbox[1] = 0;
1521
0
    wbox[2] = wbox[3] = 65536.0;
1522
0
    wbox[4] = wbox[5] = -65536.0;
1523
0
    if (!pl_intelli_merge_box(wbox, plfont, glyph, 0)) {
1524
0
        wbox[2] = wbox[3] = wbox[4] = wbox[5] = 0;
1525
0
        code = gs_setcachedevice(penum, pgs, wbox);
1526
0
        return (code < 0 ? code : 0);
1527
0
    }
1528
0
    code = gs_setcachedevice(penum, pgs, wbox);
1529
0
    if (code < 0)
1530
0
        return code;
1531
0
    code = pl_intelli_show_char(pgs, plfont, glyph, 0);
1532
0
    if (code < 0)
1533
0
        return code;
1534
    /* Since we don't take into account which side of the loops is */
1535
    /* outside, we take the easy way out.... */
1536
0
    code = gs_eofill(pgs);
1537
0
    return (code < 0 ? code : 0);
1538
0
}
1539
1540
/* ---------------- Internal initialization ---------------- */
1541
1542
/* Initialize the procedures for a bitmap font. */
1543
void
1544
pl_bitmap_init_procs(gs_font_base * pfont)
1545
19.5k
{
1546
19.5k
    pfont->procs.encode_char = pl_bitmap_encode_char;
1547
19.5k
    pfont->procs.build_char = pl_bitmap_build_char;
1548
39.0k
#define plfont ((pl_font_t *)pfont->client_data)
1549
19.5k
    plfont->char_width = pl_bitmap_char_width;
1550
19.5k
    plfont->char_metrics = pl_bitmap_char_metrics;
1551
19.5k
#undef plfont
1552
19.5k
}
1553
1554
/* Initialize the procedures for a TrueType font. */
1555
void
1556
pl_tt_init_procs(gs_font_type42 * pfont)
1557
2.00M
{
1558
2.00M
    pfont->procs.encode_char = pl_tt_encode_char;
1559
2.00M
    pfont->procs.build_char = pl_tt_build_char;
1560
2.00M
    pfont->data.string_proc = pl_tt_string_proc;
1561
4.01M
#define plfont ((pl_font_t *)pfont->client_data)
1562
2.00M
    plfont->char_width = pl_tt_char_width;
1563
2.00M
    plfont->char_metrics = pl_tt_char_metrics;
1564
2.00M
#undef plfont
1565
2.00M
}
1566
1567
static uint
1568
pl_tt_get_glyph_index(gs_font_type42 * pfont42, gs_glyph glyph)
1569
0
{
1570
    /* identity */
1571
0
    return glyph;
1572
0
}
1573
1574
/* Finish initializing a TrueType font. */
1575
void
1576
pl_tt_finish_init(gs_font_type42 * pfont, bool downloaded)
1577
2.00M
{
1578
2.00M
    float upem = (float)pfont->data.unitsPerEm;
1579
2.00M
    ulong head = tt_find_table(pfont, "head", NULL);
1580
2.00M
    const byte *hdata;
1581
1582
2.00M
    pfont->data.get_glyph_index = pl_tt_get_glyph_index;
1583
2.00M
    if (downloaded)
1584
124
        pfont->data.get_outline = pl_tt_get_outline;
1585
    /* Set the FontBBox. */
1586
2.00M
    access(head, 44, hdata);
1587
2.00M
    pfont->FontBBox.p.x = pl_get_int16(hdata + 36) / upem;
1588
2.00M
    pfont->FontBBox.p.y = pl_get_int16(hdata + 38) / upem;
1589
2.00M
    pfont->FontBBox.q.x = pl_get_int16(hdata + 40) / upem;
1590
2.00M
    pfont->FontBBox.q.y = pl_get_int16(hdata + 42) / upem;
1591
#ifdef DEBUG
1592
    if (gs_debug_c('m')) {
1593
        const byte *OffsetTable;
1594
        uint numTables;
1595
        const byte *TableDirectory;
1596
        uint i;
1597
1598
        access(0, 12, OffsetTable);
1599
        numTables = pl_get_uint16(OffsetTable + 4);
1600
        access(12, numTables * 16, TableDirectory);
1601
        for (i = 0; i < numTables; ++i) {
1602
            const byte *tab = TableDirectory + i * 16;
1603
1604
            dmprintf6(pfont->memory,
1605
                      "%c%c%c%c offset = %lu length = %lu\n",
1606
                      tab[0], tab[1], tab[2], tab[3],
1607
                      (ulong) pl_get_uint32(tab + 8),
1608
                      (ulong) pl_get_uint32(tab + 12));
1609
        }
1610
    }
1611
#endif
1612
    /* override default get metrics */
1613
2.00M
    pfont->data.get_metrics = pl_tt_get_metrics;
1614
2.00M
}
1615
1616
void
1617
pl_intelli_init_procs(gs_font_base * pfont)
1618
0
{
1619
0
    pfont->procs.encode_char = pl_intelli_encode_char;
1620
0
    pfont->procs.build_char = pl_intelli_build_char;
1621
0
#define plfont ((pl_font_t *)pfont->client_data)
1622
0
    plfont->char_width = pl_intelli_char_width;
1623
0
    plfont->char_metrics = pl_intelli_char_metrics;
1624
0
#undef plfont
1625
0
}
1626
/* ---------------- Public procedures ---------------- */
1627
1628
/* Allocate the glyph table. */
1629
int
1630
pl_font_alloc_glyph_table(pl_font_t * plfont, uint num_glyphs,
1631
                          gs_memory_t * mem, client_name_t cname)
1632
19.6k
{
1633
19.6k
    uint size = num_glyphs + (num_glyphs >> 2) + 5;
1634
19.6k
    pl_font_glyph_t *glyphs =
1635
19.6k
        gs_alloc_struct_array(mem, size, pl_font_glyph_t,
1636
19.6k
                              &st_pl_font_glyph_element, cname);
1637
1638
19.6k
    if (glyphs == 0)
1639
0
        return_error(gs_error_VMerror);
1640
19.6k
    {
1641
19.6k
        uint i;
1642
1643
1.97M
        for (i = 0; i < size; ++i)
1644
1.95M
            glyphs[i].glyph = 0, glyphs[i].data = 0;
1645
19.6k
    }
1646
19.6k
    plfont->glyphs.table = glyphs;
1647
19.6k
    plfont->glyphs.used = 0;
1648
19.6k
    plfont->glyphs.limit = num_glyphs;
1649
19.6k
    plfont->glyphs.size = size;
1650
19.6k
    plfont->glyphs.skip = size * 2 / 3;
1651
19.6k
    while (igcd(plfont->glyphs.skip, size) > 1)
1652
0
        plfont->glyphs.skip++;
1653
19.6k
    return 0;
1654
19.6k
}
1655
1656
/* Expand the glyph table. */
1657
static int
1658
expand_glyph_table(pl_font_t * plfont, gs_memory_t * mem)
1659
0
{
1660
0
    pl_glyph_table_t old_table;
1661
0
    int code;
1662
0
    uint i;
1663
1664
0
    old_table = plfont->glyphs;
1665
0
    code = pl_font_alloc_glyph_table(plfont, old_table.size, mem,
1666
0
                                     "expand_glyph_table(new table)");
1667
0
    if (code < 0)
1668
0
        return code;
1669
0
    for (i = 0; i < old_table.size; ++i)
1670
0
        if (old_table.table[i].data)
1671
0
            *pl_font_lookup_glyph(plfont, old_table.table[i].glyph) =
1672
0
                old_table.table[i];
1673
0
    gs_free_object(mem, old_table.table, "expand_glyph_table(old table)");
1674
0
    plfont->glyphs.used = old_table.used;
1675
0
    return 0;
1676
0
}
1677
1678
/* Allocate the TrueType character to glyph index map. */
1679
int
1680
pl_tt_alloc_char_glyphs(pl_font_t * plfont, uint num_chars, gs_memory_t * mem,
1681
                        client_name_t cname)
1682
139
{
1683
139
    uint size = num_chars + (num_chars >> 2) + 5;
1684
139
    pl_tt_char_glyph_t *char_glyphs = (pl_tt_char_glyph_t *)
1685
139
        gs_alloc_byte_array(mem, size, sizeof(pl_tt_char_glyph_t), cname);
1686
1687
139
    if (char_glyphs == 0)
1688
0
        return_error(gs_error_VMerror);
1689
139
    {
1690
139
        uint i;
1691
1692
28.6k
        for (i = 0; i < size; ++i)
1693
28.4k
            char_glyphs[i].chr = gs_no_char, char_glyphs[i].glyph = 0;
1694
139
    }
1695
139
    plfont->char_glyphs.table = char_glyphs;
1696
139
    plfont->char_glyphs.used = 0;
1697
139
    plfont->char_glyphs.limit = num_chars;
1698
139
    plfont->char_glyphs.size = size;
1699
139
    plfont->char_glyphs.skip = size * 2 / 3;
1700
139
    while (igcd(plfont->char_glyphs.skip, size) > 1)
1701
0
        plfont->char_glyphs.skip++;
1702
139
    return 0;
1703
139
}
1704
1705
/* Expand the character to glyph index map. */
1706
static int
1707
expand_char_glyph_table(pl_font_t * plfont, gs_memory_t * mem)
1708
0
{
1709
0
    pl_tt_char_glyph_table_t old_table;
1710
0
    int code;
1711
0
    uint i;
1712
1713
0
    old_table = plfont->char_glyphs;
1714
0
    code = pl_tt_alloc_char_glyphs(plfont, old_table.size, mem,
1715
0
                                   "expand_char_glyphs(new table)");
1716
0
    if (code < 0)
1717
0
        return code;
1718
0
    for (i = 0; i < old_table.size; ++i)
1719
0
        if (old_table.table[i].chr != gs_no_char)
1720
0
            *pl_tt_lookup_char(plfont, old_table.table[i].chr) =
1721
0
                old_table.table[i];
1722
0
    gs_free_object(mem, old_table.table, "expand_char_glyphs(old table)");
1723
0
    plfont->char_glyphs.used = old_table.used;
1724
0
    return 0;
1725
0
}
1726
1727
/* Add a glyph to a font.  Return -1 if the table is full. */
1728
typedef struct font_glyph_s
1729
{
1730
    gs_font *font;
1731
    gs_glyph glyph;
1732
} font_glyph_t;
1733
1734
static bool
1735
match_font_glyph(const gs_memory_t * mem, cached_char * cc, void *vpfg)
1736
4.25k
{
1737
4.25k
    const font_glyph_t *pfg = vpfg;
1738
1739
4.25k
    return (cc->pair->font == pfg->font && cc->code == pfg->glyph);
1740
4.25k
}
1741
int
1742
pl_font_add_glyph(pl_font_t * plfont, gs_glyph glyph, const byte * cdata, const int cdata_len)
1743
1.38M
{
1744
1.38M
    gs_font *pfont = plfont->pfont;
1745
1.38M
    gs_glyph key = glyph;
1746
1.38M
    pl_tt_char_glyph_t *ptcg = 0;
1747
1.38M
    pl_font_glyph_t *pfg;
1748
1749
    /*
1750
     * If this is a downloaded TrueType font, the "glyph" is actually
1751
     * a character code, and the actual TrueType glyph index is in the
1752
     * character header.  In this case, the character data must be either
1753
     * a PCL5 format 15 or a PCL XL format 1 downloaded character.
1754
     */
1755
1.38M
  tcg:if (plfont->char_glyphs.table) {
1756
631
        ptcg = pl_tt_lookup_char(plfont, key);
1757
631
        if (ptcg->chr == gs_no_char && plfont->char_glyphs.used >= plfont->char_glyphs.limit) { /* Table is full, try to expand it. */
1758
0
            int code = expand_char_glyph_table(plfont, pfont->memory);
1759
1760
0
            if (code < 0)
1761
0
                return code;
1762
0
            goto tcg;
1763
0
        }
1764
        /* get glyph id from character download */
1765
631
        if (cdata[0] == 1)
1766
            /* pxl truetype format 1,
1767
             * class 0 at offset 4, class 1 at offset 8 or class 2 at 10  */
1768
631
            key =
1769
631
                pl_get_uint16(cdata +
1770
631
                              ((cdata[1] ==
1771
631
                                0) ? 4 : ((cdata[1] == 1) ? 8 : 10)));
1772
0
        else
1773
            /* pcl truetype format 15 */
1774
0
            key = pl_get_uint16(cdata + cdata[2] + 4);
1775
631
    }
1776
1.38M
  fg:pfg = pl_font_lookup_glyph(plfont, key);
1777
1.38M
    if (pfg->data != 0) {       /* Remove the glyph and a possible cached representation. */
1778
183
        font_glyph_t match_fg;
1779
1780
183
        match_fg.font = pfont;
1781
183
        match_fg.glyph = key;
1782
183
        gx_purge_selected_cached_chars(pfont->dir, match_font_glyph,
1783
183
                                       &match_fg);
1784
        /* replacing a read only glyph nothing we can do, so return. */
1785
183
        if (plfont->data_are_permanent)
1786
0
            return 0;
1787
183
        gs_free_object(pfont->memory, (void *)pfg->data,
1788
183
                       "pl_font_add_glyph(old data)");
1789
1.38M
    } else {
1790
1.38M
        if (plfont->glyphs.used >= plfont->glyphs.limit) {      /* Table is full, try to expand it. */
1791
0
            int code = expand_glyph_table(plfont, pfont->memory);
1792
1793
0
            if (code < 0)
1794
0
                return code;
1795
0
            goto fg;
1796
0
        }
1797
1.38M
        plfont->glyphs.used++;
1798
1.38M
    }
1799
1.38M
    if (ptcg) {
1800
631
        if (ptcg->chr == gs_no_char)
1801
625
            plfont->char_glyphs.used++;
1802
631
        ptcg->chr = glyph;
1803
631
        ptcg->glyph = key;
1804
631
    }
1805
1.38M
    pfg->glyph = key;
1806
1.38M
    pfg->data = cdata;
1807
1.38M
    pfg->data_len = cdata_len;
1808
1.38M
    return 0;
1809
1.38M
}
1810
1811
static bool
1812
is_composite(const byte * pgdata)
1813
0
{
1814
0
    return (pl_get_int16(pgdata) == -1);
1815
0
}
1816
1817
int
1818
pl_font_disable_composite_metrics(pl_font_t * plfont, gs_glyph glyph)
1819
0
{
1820
0
    gs_glyph key = glyph;
1821
0
    gs_font_type42 *pfont = (gs_font_type42 *) plfont->pfont;
1822
0
    gs_glyph_data_t glyph_data;
1823
0
    int code;
1824
1825
    /* This is the unusual way of looking up a glyph thanks to the pcl
1826
       font wrapper format.  It is documented in several other places
1827
       in this file.  If a char_glyphs table is not available it is
1828
       not a downloadedd TT font wrapper so we do nothing. */
1829
0
    if (plfont->char_glyphs.table) {
1830
0
        pl_tt_char_glyph_t *ptcg = pl_tt_lookup_char(plfont, key);
1831
1832
0
        if (ptcg->chr == gs_no_char)
1833
0
            return 0;
1834
0
        key = ptcg->glyph;
1835
0
    } else {
1836
0
        return -1;
1837
0
    }
1838
1839
    /* should never fail as this procedure is called only after a
1840
       glyph has been successfully added. */
1841
0
    code = pfont->data.get_outline(pfont, key, &glyph_data);
1842
0
    if (code < 0)
1843
0
        return code;
1844
1845
    /* null glyph */
1846
0
    if (glyph_data.bits.data == 0)
1847
0
        return 0;
1848
1849
    /* the glyph is guaranteed by the langauges to be have a reasonable
1850
       header (enough to test for a composite glyph and do the tests
1851
       below for components) so a UMR or overflow is not possible but
1852
       it would be better to add checks.  The component parser below  */
1853
0
    if (!is_composite(glyph_data.bits.data))
1854
0
        return 0;
1855
1856
    /* enumerate the components and rewrite the flags field to not use
1857
       metrics from the component.  Similar to the enumeration code in
1858
       gstype42.c */
1859
0
    {
1860
0
        uint flags;
1861
0
        byte *next_component = (byte *) glyph_data.bits.data + 10;
1862
1863
0
        do {
1864
0
            gs_matrix_fixed mat;
1865
0
            byte *last_component = next_component;
1866
1867
0
            memset(&mat, 0, sizeof(mat));       /* arbitrary */
1868
0
            gs_type42_parse_component((const byte **)&next_component, &flags,
1869
0
                                      &mat, NULL,
1870
0
                                      (const gs_font_type42 *)plfont->pfont,
1871
0
                                      &mat);
1872
0
            if (flags & TT_CG_USE_MY_METRICS)
1873
                /* bit 9 of the flags is the "use my metrics" flag
1874
                   which is bit 1 of byte 0 big endian wise */
1875
0
                last_component[0] &= ~(1 << 1);
1876
0
        } while (flags & TT_CG_MORE_COMPONENTS);
1877
0
    }
1878
0
    return 0;
1879
0
}
1880
/* Remove a glyph from a font.  Return 1 if the glyph was present. */
1881
int
1882
pl_font_remove_glyph(pl_font_t * plfont, gs_glyph glyph)
1883
0
{
1884
0
    gs_font *pfont = plfont->pfont;
1885
0
    gs_glyph key = glyph;
1886
0
    pl_font_glyph_t *pfg;
1887
1888
    /* See above regarding downloaded TrueType fonts. */
1889
0
    if (plfont->char_glyphs.table) {
1890
0
        pl_tt_char_glyph_t *ptcg = pl_tt_lookup_char(plfont, key);
1891
1892
0
        if (ptcg->chr == gs_no_char)
1893
0
            return 0;
1894
0
        key = ptcg->glyph;
1895
0
        ptcg->chr = gs_no_char;
1896
0
        ptcg->glyph = 1;        /* mark as deleted */
1897
0
        plfont->char_glyphs.used--;
1898
        /* we have to clear out the widths cache now */
1899
0
        pl_font_glyph_width_cache_remove_nodes(plfont);
1900
0
    }
1901
    /* may not have a glyph table in case of cloned resident */
1902
0
    if (plfont->glyphs.table == 0)
1903
0
        return 0;
1904
0
    pfg = pl_font_lookup_glyph(plfont, key);
1905
0
    if (pfg->data == 0)
1906
0
        return 0;               /* character not defined */
1907
0
    {                           /* Remove the glyph from the character cache. */
1908
0
        font_glyph_t match_fg;
1909
1910
0
        match_fg.font = pfont;
1911
0
        match_fg.glyph = key;
1912
0
        gx_purge_selected_cached_chars(pfont->dir, match_font_glyph,
1913
0
                                       &match_fg);
1914
0
        gs_free_object(pfont->memory, (void *)pfg->data,
1915
0
                       "pl_font_remove_glyph(data)");
1916
0
    }
1917
0
    pfg->data = 0;
1918
0
    pfg->glyph = 1;             /* mark as deleted */
1919
0
    plfont->glyphs.used--;
1920
    /* we have to clear out the widths cache now */
1921
0
    pl_font_glyph_width_cache_remove_nodes(plfont);
1922
0
    return 1;
1923
0
}