Coverage Report

Created: 2026-09-14 07:34

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
79
{
74
79
    return 0;
75
79
}
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.29M
{
90
1.29M
    uint size = plfont->glyphs.size;
91
1.29M
    uint skip = plfont->glyphs.skip;
92
1.29M
    uint index = glyph % size;
93
1.29M
    pl_font_glyph_t *pfg;
94
1.29M
    pl_font_glyph_t *result = 0;
95
96
1.29M
    while ((pfg = plfont->glyphs.table + index)->data ?
97
1.11M
           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.29M
    return (!pfg->data && result) ? result : pfg;
103
1.29M
}
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
325k
{
112
325k
    return (gs_glyph) chr;
113
325k
}
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
184k
{
190
184k
    uint dest_bytes = (pim->Width + 7) >> 3;
191
184k
    int code;
192
184k
    gs_image_enum *penum;
193
184k
    uint used;
194
195
184k
    code = gx_set_dev_color(pgs);
196
184k
    if (code == gs_error_Remap_Color)
197
0
        code = pixmap_high_level_pattern(pgs);
198
184k
    if (code != 0)
199
0
        return code;
200
184k
    penum = gs_image_enum_alloc(gs_gstate_memory(pgs), "pl_image_bitmap_char");
201
184k
    if (penum == NULL)
202
0
        return_error(gs_error_VMerror);
203
184k
    code = gs_image_init(penum, pim, pim->ImageMask | pim->CombineWithColor, true, pgs);
204
184k
    if (code < 0)
205
0
        goto free_penum_and_exit;
206
184k
    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
184k
    } else {                    /* Pass the entire image at once. */
266
184k
        int i;
267
4.62M
        for (i = 0; i < pim->Height; i++) {
268
4.44M
            code = gs_image_next(penum, bitmap_data, dest_bytes, &used);
269
4.44M
            if (code < 0)
270
0
                break;
271
4.44M
            bitmap_data += sraster;
272
4.44M
        }
273
184k
    }
274
184k
free_penum_and_exit:
275
184k
    {
276
184k
        int code2 = gs_image_cleanup_and_free_enum(penum, pgs);
277
184k
        if (code == 0)
278
0
            code = code2;
279
184k
    }
280
184k
    return code;
281
184k
}
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
184k
{
289
184k
    pl_font_t *plfont = (pl_font_t *) pfont->client_data;
290
184k
    const byte *cdata = pl_font_lookup_glyph(plfont, glyph)->data;
291
184k
    bool orient = plfont->orient;
292
293
184k
    if (cdata == 0) {
294
77
        return gs_setcharwidth(penum, pgs, 0, 0);
295
184k
    } else {
296
184k
        const byte *params;
297
184k
        const byte *bitmap_data;
298
184k
        int lsb, ascent;
299
184k
        float delta_x;
300
184k
        gs_image_t image;
301
184k
        gs_image_enum *ienum;
302
184k
        int code;
303
184k
        uint bold;
304
184k
        byte *bold_lines = 0;
305
306
184k
        if (cdata[0] == 0) {    /* PCL XL format */
307
263
            params = cdata + 2;
308
263
            bitmap_data = cdata + round_up(10, ARCH_ALIGN_PTR_MOD);
309
263
            delta_x = 0;        /* irrelevant */
310
263
            lsb = pl_get_int16(params);
311
263
            ascent = pl_get_int16(params + 2);
312
183k
        } else {                /* PCL5 format */
313
183k
            params = cdata + 6;
314
183k
            bitmap_data = cdata + 16;
315
183k
            delta_x = (plfont->header[13] ?     /* variable pitch */
316
183k
                       pl_get_int16(params + 8) * 0.25 :
317
183k
                       (short)(pl_get_int16(params) /*lsb */
318
0
                               +pl_get_int16(params + 4)) /*width */ );
319
183k
            lsb = pl_get_int16(params);
320
183k
            ascent = pl_get_int16(params + 2);
321
183k
        }
322
184k
        ienum = gs_image_enum_alloc(pgs->memory, "pl_bitmap_build_char");
323
184k
        if (ienum == 0)
324
0
            return_error(gs_error_VMerror);
325
184k
        gs_image_t_init_mask(&image, true);
326
184k
        image.Width = pl_get_uint16(params + 4);
327
184k
        image.Height = pl_get_uint16(params + 6);
328
        /* Determine the amount of pseudo-bolding. */
329
184k
        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
184k
            bold = 0;
345
346
184k
        gs_make_identity(&image.ImageMatrix);
347
184k
        gs_matrix_rotate(&image.ImageMatrix, orient * -90,
348
184k
                         &image.ImageMatrix);
349
184k
        image.ImageMatrix.tx -= lsb;
350
184k
        image.ImageMatrix.ty += ascent;
351
184k
        image.adjust = true;
352
184k
        if (bold || orient != 0)
353
0
            code = gs_setcharwidth(penum, pgs, delta_x, 0);
354
184k
        else {
355
            /* we use cache device for portrait bitmap fonts to
356
               avoid image setup overhead.  */
357
184k
            float m[6];
358
359
184k
            m[0] = delta_x;
360
184k
            m[1] = 0;
361
184k
            m[2] = (float)lsb;
362
184k
            m[3] = (float)(image.Height - ascent);
363
184k
            m[4] = image.Width + m[2];
364
184k
            m[5] = (float)(-ascent);
365
184k
            code = gs_setcachedevice(penum, pgs, m);
366
184k
        }
367
184k
        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
184k
        code = pl_image_bitmap_char(ienum, &image, bitmap_data,
388
184k
                                    (image.Width - bold + 7) >> 3, bold,
389
184k
                                    bold_lines, pgs);
390
184k
      out:gs_free_object(pgs->memory, bold_lines,
391
184k
                       "pl_bitmap_build_char(bold_lines)");
392
184k
        gs_free_object(pgs->memory, ienum, "pl_bitmap_build_char");
393
184k
        return (code < 0 ? code : 0);
394
184k
    }
395
184k
}
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
627
{
405
627
    uint size = plfont->char_glyphs.size;
406
627
    uint skip = plfont->char_glyphs.skip;
407
627
    uint index = glyph % size;
408
627
    pl_tt_char_glyph_t *ptcg;
409
627
    pl_tt_char_glyph_t *result = 0;
410
411
628
    while ((ptcg = plfont->char_glyphs.table + index)->chr != gs_no_char ?
412
388
           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
627
    return (result ? result : ptcg);
418
627
}
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.12G
{
425
1.12G
    pl_font_t *plfont = pfont->client_data;
426
427
1.12G
    *pdata = plfont->header + plfont->offsets.GT +
428
1.12G
        (plfont->large_sizes ? 6 : 4) + offset;
429
430
1.12G
    if (((*pdata) + length) > plfont->header + plfont->header_size)
431
14
        return_error(gs_error_invalidfont);
432
433
1.12G
    return 0;
434
1.12G
}
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
2.80M
{
464
2.80M
    int code = gs_error_undefined;
465
2.80M
    pl_font_t *plfont = pfont->client_data;
466
2.80M
    const pl_font_glyph_t *pfg = 0;
467
2.80M
    const byte *cdata = 0;
468
469
2.80M
    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
213
        pfg = pl_font_lookup_glyph(plfont, glyph_index);
474
213
        cdata = pfg->data;
475
476
213
        if (cdata && (cdata[1] == 1 || cdata[1] == 2)) {
477
0
            double factor = 1.0 / pfont->data.unitsPerEm;
478
0
            uint width;
479
0
            int lsb;
480
481
0
            lsb = pl_get_int16(cdata + 4);
482
0
            width = pl_get_int16(cdata + 6);
483
484
            /* foo NB what about the top side bearing in class 2 ? */
485
486
0
            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
0
            } else {
494
0
                sbw[0] = lsb * factor, sbw[1] = 0;
495
0
                sbw[2] = width * factor, sbw[3] = 0;
496
0
            }
497
0
            code = 0;           /* tt class 1,2 */
498
0
        }
499
213
    }
500
2.80M
    return code;
501
2.80M
}
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
309
{
554
309
    pl_font_t *plfont = pfont->client_data;
555
309
    const pl_font_glyph_t *pfg = pl_font_lookup_glyph(plfont, index);
556
309
    const byte *cdata = pfg->data;
557
558
309
    if (cdata == 0) {
559
        /* undefined glyph */
560
28
        gs_glyph_data_from_null(pdata);
561
281
    } else {
562
281
        uint desc_size =
563
281
            (*cdata == 15 ? cdata[2] /* PCL5 */ : 0 /* PCL XL */ );
564
281
        uint data_size = pl_get_uint16(cdata + 2 + desc_size);
565
566
281
        if (data_size > pfg->data_len)
567
0
            data_size = pfg->data_len;
568
569
281
        if (data_size <= 4) {
570
            /* empty outline */
571
0
            gs_glyph_data_from_null(pdata);
572
281
        } else if (cdata[1] == 0 && (6 + desc_size + data_size - 4) <= pfg->data_len) {
573
281
            gs_glyph_data_from_bytes(pdata, cdata, 6 + desc_size, data_size - 4, NULL);
574
281
        } else if (cdata[1] == 1 && (10 + data_size - 8) <= pfg->data_len) {
575
0
            gs_glyph_data_from_bytes(pdata, cdata, 10, data_size - 8, NULL);
576
0
        } 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
281
    }
584
309
    return 0;
585
309
}
586
587
#define access(base, length, vptr)\
588
128M
  (*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
25.9M
{
596
25.9M
    const byte *OffsetTable;
597
25.9M
    uint numTables;
598
25.9M
    const byte *TableDirectory;
599
25.9M
    uint i;
600
25.9M
    ulong table_dir_offset = 0;
601
25.9M
    int code;
602
603
25.9M
    if (((code = access(0, 12, OffsetTable)) < 0) ||
604
25.9M
        ((code = access(table_dir_offset, 12, OffsetTable)) < 0))
605
0
        return 0;
606
607
25.9M
    numTables = pl_get_uint16(OffsetTable + 4);
608
609
25.9M
    if (access(table_dir_offset + 12, numTables * 16, TableDirectory) < 0)
610
0
        return 0;
611
612
83.1M
    for (i = 0; i < numTables; ++i) {
613
83.1M
        const byte *tab = TableDirectory + i * 16;
614
615
83.1M
        if (!memcmp(tab, tname, 4)) {
616
25.9M
            if (plen)
617
24.5M
                *plen = pl_get_uint32(tab + 12);
618
25.9M
            return pl_get_uint32(tab + 8);
619
25.9M
        }
620
83.1M
    }
621
242
    return 0;
622
25.9M
}
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
24.5M
{
633
24.5M
    const byte *table_lim = table + table_len;
634
635
    /* Dispatch according to the table type. */
636
24.5M
    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
24.5M
        case 4:
648
24.5M
            {                   /* Microsoft/Adobe segmented mapping.  What a mess! */
649
24.5M
                uint segCount2 = pl_get_uint16(table + 6);
650
24.5M
                const byte *endCount = table + 14;
651
24.5M
                const byte *startCount = endCount + segCount2 + 2;
652
24.5M
                const byte *idDelta = startCount + segCount2;
653
24.5M
                const byte *idRangeOffset = idDelta + segCount2;
654
                /*const byte *glyphIdArray = idRangeOffset + segCount2; */
655
24.5M
                uint i2;
656
657
24.5M
                if (idRangeOffset > table_lim)
658
0
                    return_error(gs_error_undefined);
659
660
193M
                for (i2 = 0; i2 < segCount2 - 3; i2 += 2) {
661
193M
                    int delta, roff;
662
193M
                    uint start = pl_get_uint16(startCount + i2);
663
193M
                    uint glyph;
664
665
193M
                    if_debug4('J', "[J]start=%u end=%u delta=%d roff=%d\n",
666
193M
                              start, pl_get_uint16(endCount + i2),
667
193M
                              pl_get_int16(idDelta + i2),
668
193M
                              pl_get_int16(idRangeOffset + i2));
669
193M
                    if (key < start) {
670
375k
                        if_debug1('J', "[J]%u out of range\n", key);
671
375k
                        return_error(gs_error_undefined);
672
375k
                    }
673
193M
                    if (endCount + i2 + 2 > table_lim) {
674
0
                        break;
675
0
                    }
676
193M
                    if (key > pl_get_uint16(endCount + i2))
677
168M
                        continue;
678
679
24.1M
                    if (idRangeOffset + i2 + 2 > table_lim) {
680
0
                        break;
681
0
                    }
682
24.1M
                    delta = pl_get_int16(idDelta + i2);
683
24.1M
                    roff = pl_get_int16(idRangeOffset + i2);
684
24.1M
                    if (roff == 0) {
685
23.1M
                        *pvalue = (key + delta) & 0xffff;       /* mod 65536 */
686
23.1M
                        if_debug2('J', "[J]%u => %u\n", key, *pvalue);
687
23.1M
                        return 0;
688
23.1M
                    }
689
690
1.01M
                    if ((2 + idRangeOffset + i2 + roff + ((key - start) << 1)) > table_lim) {
691
0
                        break;
692
0
                    }
693
1.01M
                    glyph = pl_get_uint16(idRangeOffset + i2 + roff + ((key - start) << 1));
694
1.01M
                    *pvalue = (glyph == 0 ? 0 : glyph + delta);
695
1.01M
                    if_debug2('J', "[J]%u => %u\n", key, *pvalue);
696
1.01M
                    return 0;
697
1.01M
                }
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
24.5M
                if_debug1('J', "[J]%u out of range\n", key);
704
44.2k
                return_error(gs_error_undefined);
705
24.5M
            }
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
24.5M
    }
733
0
    return 0;
734
24.5M
}
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
24.5M
{
742
24.5M
    const byte *cmap;
743
24.5M
    const byte *cmap_sub;
744
24.5M
    const byte *table;
745
24.5M
    size_t table_len;
746
24.5M
    uint value;
747
24.5M
    int code;
748
749
24.5M
    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
24.5M
    cmap_sub = cmap + 4;
754
24.5M
    {
755
24.5M
        uint i;
756
24.5M
        uint16_t ncmaps = pl_get_uint16(cmap + 2);
757
758
24.5M
        if (ncmaps * 8 + 2 >= cmap_len)
759
0
            return GS_NO_GLYPH;
760
761
73.2M
        for (i = 0; i < ncmaps; ++i) {
762
73.2M
            if_debug3m('j', pfont->memory,
763
73.2M
                       "[j]cmap %d: platform %u encoding %u\n", i,
764
73.2M
                       pl_get_uint16(cmap_sub + i * 8),
765
73.2M
                       pl_get_uint16(cmap_sub + i * 8 + 2));
766
73.2M
            if (pl_get_uint16(cmap_sub + i * 8) == 3) {
767
24.5M
                cmap_sub += i * 8;
768
24.5M
                break;
769
24.5M
            }
770
73.2M
        }
771
24.5M
    }
772
0
    {
773
24.5M
        uint offset = cmap_offset + pl_get_uint32(cmap_sub + 4);
774
24.5M
        table_len = cmap_offset + cmap_len - offset;
775
776
24.5M
        access(offset, table_len, table);
777
24.5M
    }
778
24.5M
    code = pl_cmap_lookup((uint) chr, table, table_len, &value);
779
24.5M
    return (code < 0 ? GS_NO_GLYPH : value);
780
24.5M
}
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
240
{
786
240
    pl_font_t *plfont = pfont->client_data;
787
240
    const pl_tt_char_glyph_t *ptcg = pl_tt_lookup_char(plfont, chr);
788
789
240
    return (ptcg->chr == gs_no_char ? GS_NO_GLYPH : ptcg->glyph);
790
240
}
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
24.5M
{
833
24.5M
    gs_font_type42 *pfont = (gs_font_type42 *) pfont_generic;
834
24.5M
    uint cmap_len;
835
24.5M
    ulong cmap_offset = tt_find_table(pfont, "cmap", &cmap_len);
836
24.5M
    gs_glyph glyph = (cmap_offset == 0 ?
837
                      /* This is a downloaded font with no cmap. */
838
240
                      pl_tt_dynamic_encode_char(pfont, chr) :
839
24.5M
                      pl_tt_cmap_encode_char(pfont, cmap_offset, cmap_len,
840
24.5M
                                             chr));
841
24.5M
    pl_font_t *plfont = pfont->client_data;
842
24.5M
    pl_font_glyph_t *pfg;
843
844
24.5M
    if (plfont->offsets.GC < 0)
845
24.5M
        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
15.7k
{
1546
15.7k
    pfont->procs.encode_char = pl_bitmap_encode_char;
1547
15.7k
    pfont->procs.build_char = pl_bitmap_build_char;
1548
31.4k
#define plfont ((pl_font_t *)pfont->client_data)
1549
15.7k
    plfont->char_width = pl_bitmap_char_width;
1550
15.7k
    plfont->char_metrics = pl_bitmap_char_metrics;
1551
15.7k
#undef plfont
1552
15.7k
}
1553
1554
/* Initialize the procedures for a TrueType font. */
1555
void
1556
pl_tt_init_procs(gs_font_type42 * pfont)
1557
1.42M
{
1558
1.42M
    pfont->procs.encode_char = pl_tt_encode_char;
1559
1.42M
    pfont->procs.build_char = pl_tt_build_char;
1560
1.42M
    pfont->data.string_proc = pl_tt_string_proc;
1561
2.84M
#define plfont ((pl_font_t *)pfont->client_data)
1562
1.42M
    plfont->char_width = pl_tt_char_width;
1563
1.42M
    plfont->char_metrics = pl_tt_char_metrics;
1564
1.42M
#undef plfont
1565
1.42M
}
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
1.42M
{
1578
1.42M
    float upem = (float)pfont->data.unitsPerEm;
1579
1.42M
    ulong head = tt_find_table(pfont, "head", NULL);
1580
1.42M
    const byte *hdata;
1581
1582
1.42M
    pfont->data.get_glyph_index = pl_tt_get_glyph_index;
1583
1.42M
    if (downloaded)
1584
79
        pfont->data.get_outline = pl_tt_get_outline;
1585
    /* Set the FontBBox. */
1586
1.42M
    access(head, 44, hdata);
1587
1.42M
    pfont->FontBBox.p.x = pl_get_int16(hdata + 36) / upem;
1588
1.42M
    pfont->FontBBox.p.y = pl_get_int16(hdata + 38) / upem;
1589
1.42M
    pfont->FontBBox.q.x = pl_get_int16(hdata + 40) / upem;
1590
1.42M
    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
1.42M
    pfont->data.get_metrics = pl_tt_get_metrics;
1614
1.42M
}
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
15.7k
{
1633
15.7k
    uint size = num_glyphs + (num_glyphs >> 2) + 5;
1634
15.7k
    pl_font_glyph_t *glyphs =
1635
15.7k
        gs_alloc_struct_array(mem, size, pl_font_glyph_t,
1636
15.7k
                              &st_pl_font_glyph_element, cname);
1637
1638
15.7k
    if (glyphs == 0)
1639
0
        return_error(gs_error_VMerror);
1640
15.7k
    {
1641
15.7k
        uint i;
1642
1643
1.58M
        for (i = 0; i < size; ++i)
1644
1.57M
            glyphs[i].glyph = 0, glyphs[i].data = 0;
1645
15.7k
    }
1646
15.7k
    plfont->glyphs.table = glyphs;
1647
15.7k
    plfont->glyphs.used = 0;
1648
15.7k
    plfont->glyphs.limit = num_glyphs;
1649
15.7k
    plfont->glyphs.size = size;
1650
15.7k
    plfont->glyphs.skip = size * 2 / 3;
1651
15.7k
    while (igcd(plfont->glyphs.skip, size) > 1)
1652
0
        plfont->glyphs.skip++;
1653
15.7k
    return 0;
1654
15.7k
}
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
94
{
1683
94
    uint size = num_chars + (num_chars >> 2) + 5;
1684
94
    pl_tt_char_glyph_t *char_glyphs = (pl_tt_char_glyph_t *)
1685
94
        gs_alloc_byte_array(mem, size, sizeof(pl_tt_char_glyph_t), cname);
1686
1687
94
    if (char_glyphs == 0)
1688
0
        return_error(gs_error_VMerror);
1689
94
    {
1690
94
        uint i;
1691
1692
19.3k
        for (i = 0; i < size; ++i)
1693
19.2k
            char_glyphs[i].chr = gs_no_char, char_glyphs[i].glyph = 0;
1694
94
    }
1695
94
    plfont->char_glyphs.table = char_glyphs;
1696
94
    plfont->char_glyphs.used = 0;
1697
94
    plfont->char_glyphs.limit = num_chars;
1698
94
    plfont->char_glyphs.size = size;
1699
94
    plfont->char_glyphs.skip = size * 2 / 3;
1700
94
    while (igcd(plfont->char_glyphs.skip, size) > 1)
1701
0
        plfont->char_glyphs.skip++;
1702
94
    return 0;
1703
94
}
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
2.68k
{
1737
2.68k
    const font_glyph_t *pfg = vpfg;
1738
1739
2.68k
    return (cc->pair->font == pfg->font && cc->code == pfg->glyph);
1740
2.68k
}
1741
int
1742
pl_font_add_glyph(pl_font_t * plfont, gs_glyph glyph, const byte * cdata, const int cdata_len)
1743
1.11M
{
1744
1.11M
    gs_font *pfont = plfont->pfont;
1745
1.11M
    gs_glyph key = glyph;
1746
1.11M
    pl_tt_char_glyph_t *ptcg = 0;
1747
1.11M
    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.11M
  tcg:if (plfont->char_glyphs.table) {
1756
387
        ptcg = pl_tt_lookup_char(plfont, key);
1757
387
        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
387
        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
387
            key =
1769
387
                pl_get_uint16(cdata +
1770
387
                              ((cdata[1] ==
1771
387
                                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
387
    }
1776
1.11M
  fg:pfg = pl_font_lookup_glyph(plfont, key);
1777
1.11M
    if (pfg->data != 0) {       /* Remove the glyph and a possible cached representation. */
1778
139
        font_glyph_t match_fg;
1779
1780
139
        match_fg.font = pfont;
1781
139
        match_fg.glyph = key;
1782
139
        gx_purge_selected_cached_chars(pfont->dir, match_font_glyph,
1783
139
                                       &match_fg);
1784
        /* replacing a read only glyph nothing we can do, so return. */
1785
139
        if (plfont->data_are_permanent)
1786
0
            return 0;
1787
139
        gs_free_object(pfont->memory, (void *)pfg->data,
1788
139
                       "pl_font_add_glyph(old data)");
1789
1.11M
    } else {
1790
1.11M
        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.11M
        plfont->glyphs.used++;
1798
1.11M
    }
1799
1.11M
    if (ptcg) {
1800
387
        if (ptcg->chr == gs_no_char)
1801
385
            plfont->char_glyphs.used++;
1802
387
        ptcg->chr = glyph;
1803
387
        ptcg->glyph = key;
1804
387
    }
1805
1.11M
    pfg->glyph = key;
1806
1.11M
    pfg->data = cdata;
1807
1.11M
    pfg->data_len = cdata_len;
1808
1.11M
    return 0;
1809
1.11M
}
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
}