Coverage Report

Created: 2026-07-24 07:44

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
78
{
74
78
    return 0;
75
78
}
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.34M
{
90
1.34M
    uint size = plfont->glyphs.size;
91
1.34M
    uint skip = plfont->glyphs.skip;
92
1.34M
    uint index = glyph % size;
93
1.34M
    pl_font_glyph_t *pfg;
94
1.34M
    pl_font_glyph_t *result = 0;
95
96
1.34M
    while ((pfg = plfont->glyphs.table + index)->data ?
97
1.14M
           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.34M
    return (!pfg->data && result) ? result : pfg;
103
1.34M
}
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
337k
{
112
337k
    return (gs_glyph) chr;
113
337k
}
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
190k
{
190
190k
    uint dest_bytes = (pim->Width + 7) >> 3;
191
190k
    int code;
192
190k
    gs_image_enum *penum;
193
190k
    uint used;
194
195
190k
    code = gx_set_dev_color(pgs);
196
190k
    if (code == gs_error_Remap_Color)
197
0
        code = pixmap_high_level_pattern(pgs);
198
190k
    if (code != 0)
199
0
        return code;
200
190k
    penum = gs_image_enum_alloc(gs_gstate_memory(pgs), "pl_image_bitmap_char");
201
190k
    if (penum == NULL)
202
0
        return_error(gs_error_VMerror);
203
190k
    code = gs_image_init(penum, pim, pim->ImageMask | pim->CombineWithColor, true, pgs);
204
190k
    if (code < 0)
205
0
        goto free_penum_and_exit;
206
190k
    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
190k
    } else {                    /* Pass the entire image at once. */
266
190k
        int i;
267
4.79M
        for (i = 0; i < pim->Height; i++) {
268
4.60M
            code = gs_image_next(penum, bitmap_data, dest_bytes, &used);
269
4.60M
            if (code < 0)
270
0
                break;
271
4.60M
            bitmap_data += sraster;
272
4.60M
        }
273
190k
    }
274
190k
free_penum_and_exit:
275
190k
    {
276
190k
        int code2 = gs_image_cleanup_and_free_enum(penum, pgs);
277
190k
        if (code == 0)
278
0
            code = code2;
279
190k
    }
280
190k
    return code;
281
190k
}
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
190k
{
289
190k
    pl_font_t *plfont = (pl_font_t *) pfont->client_data;
290
190k
    const byte *cdata = pl_font_lookup_glyph(plfont, glyph)->data;
291
190k
    bool orient = plfont->orient;
292
293
190k
    if (cdata == 0) {
294
83
        return gs_setcharwidth(penum, pgs, 0, 0);
295
190k
    } else {
296
190k
        const byte *params;
297
190k
        const byte *bitmap_data;
298
190k
        int lsb, ascent;
299
190k
        float delta_x;
300
190k
        gs_image_t image;
301
190k
        gs_image_enum *ienum;
302
190k
        int code;
303
190k
        uint bold;
304
190k
        byte *bold_lines = 0;
305
306
190k
        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
190k
        } else {                /* PCL5 format */
313
190k
            params = cdata + 6;
314
190k
            bitmap_data = cdata + 16;
315
190k
            delta_x = (plfont->header[13] ?     /* variable pitch */
316
190k
                       pl_get_int16(params + 8) * 0.25 :
317
190k
                       (short)(pl_get_int16(params) /*lsb */
318
0
                               +pl_get_int16(params + 4)) /*width */ );
319
190k
            lsb = pl_get_int16(params);
320
190k
            ascent = pl_get_int16(params + 2);
321
190k
        }
322
190k
        ienum = gs_image_enum_alloc(pgs->memory, "pl_bitmap_build_char");
323
190k
        if (ienum == 0)
324
0
            return_error(gs_error_VMerror);
325
190k
        gs_image_t_init_mask(&image, true);
326
190k
        image.Width = pl_get_uint16(params + 4);
327
190k
        image.Height = pl_get_uint16(params + 6);
328
        /* Determine the amount of pseudo-bolding. */
329
190k
        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
190k
            bold = 0;
345
346
190k
        gs_make_identity(&image.ImageMatrix);
347
190k
        gs_matrix_rotate(&image.ImageMatrix, orient * -90,
348
190k
                         &image.ImageMatrix);
349
190k
        image.ImageMatrix.tx -= lsb;
350
190k
        image.ImageMatrix.ty += ascent;
351
190k
        image.adjust = true;
352
190k
        if (bold || orient != 0)
353
0
            code = gs_setcharwidth(penum, pgs, delta_x, 0);
354
190k
        else {
355
            /* we use cache device for portrait bitmap fonts to
356
               avoid image setup overhead.  */
357
190k
            float m[6];
358
359
190k
            m[0] = delta_x;
360
190k
            m[1] = 0;
361
190k
            m[2] = (float)lsb;
362
190k
            m[3] = (float)(image.Height - ascent);
363
190k
            m[4] = image.Width + m[2];
364
190k
            m[5] = (float)(-ascent);
365
190k
            code = gs_setcachedevice(penum, pgs, m);
366
190k
        }
367
190k
        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
190k
        code = pl_image_bitmap_char(ienum, &image, bitmap_data,
388
190k
                                    (image.Width - bold + 7) >> 3, bold,
389
190k
                                    bold_lines, pgs);
390
190k
      out:gs_free_object(pgs->memory, bold_lines,
391
190k
                       "pl_bitmap_build_char(bold_lines)");
392
190k
        gs_free_object(pgs->memory, ienum, "pl_bitmap_build_char");
393
190k
        return (code < 0 ? code : 0);
394
190k
    }
395
190k
}
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
675
{
405
675
    uint size = plfont->char_glyphs.size;
406
675
    uint skip = plfont->char_glyphs.skip;
407
675
    uint index = glyph % size;
408
675
    pl_tt_char_glyph_t *ptcg;
409
675
    pl_tt_char_glyph_t *result = 0;
410
411
676
    while ((ptcg = plfont->char_glyphs.table + index)->chr != gs_no_char ?
412
407
           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
675
    return (result ? result : ptcg);
418
675
}
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.50G
{
425
1.50G
    pl_font_t *plfont = pfont->client_data;
426
427
1.50G
    *pdata = plfont->header + plfont->offsets.GT +
428
1.50G
        (plfont->large_sizes ? 6 : 4) + offset;
429
430
1.50G
    if (((*pdata) + length) > plfont->header + plfont->header_size)
431
14
        return_error(gs_error_invalidfont);
432
433
1.50G
    return 0;
434
1.50G
}
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.08M
{
464
3.08M
    int code = gs_error_undefined;
465
3.08M
    pl_font_t *plfont = pfont->client_data;
466
3.08M
    const pl_font_glyph_t *pfg = 0;
467
3.08M
    const byte *cdata = 0;
468
469
3.08M
    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
240
        pfg = pl_font_lookup_glyph(plfont, glyph_index);
474
240
        cdata = pfg->data;
475
476
240
        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
240
    }
500
3.08M
    return code;
501
3.08M
}
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
342
{
554
342
    pl_font_t *plfont = pfont->client_data;
555
342
    const pl_font_glyph_t *pfg = pl_font_lookup_glyph(plfont, index);
556
342
    const byte *cdata = pfg->data;
557
558
342
    if (cdata == 0) {
559
        /* undefined glyph */
560
31
        gs_glyph_data_from_null(pdata);
561
311
    } else {
562
311
        uint desc_size =
563
311
            (*cdata == 15 ? cdata[2] /* PCL5 */ : 0 /* PCL XL */ );
564
311
        uint data_size = pl_get_uint16(cdata + 2 + desc_size);
565
566
311
        if (data_size > pfg->data_len)
567
0
            data_size = pfg->data_len;
568
569
311
        if (data_size <= 4) {
570
            /* empty outline */
571
0
            gs_glyph_data_from_null(pdata);
572
311
        } else if (cdata[1] == 0 && (6 + desc_size + data_size - 4) <= pfg->data_len) {
573
311
            gs_glyph_data_from_bytes(pdata, cdata, 6 + desc_size, data_size - 4, NULL);
574
311
        } 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
311
    }
584
342
    return 0;
585
342
}
586
587
#define access(base, length, vptr)\
588
130M
  (*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
26.4M
{
596
26.4M
    const byte *OffsetTable;
597
26.4M
    uint numTables;
598
26.4M
    const byte *TableDirectory;
599
26.4M
    uint i;
600
26.4M
    ulong table_dir_offset = 0;
601
26.4M
    int code;
602
603
26.4M
    if (((code = access(0, 12, OffsetTable)) < 0) ||
604
26.4M
        ((code = access(table_dir_offset, 12, OffsetTable)) < 0))
605
0
        return 0;
606
607
26.4M
    numTables = pl_get_uint16(OffsetTable + 4);
608
609
26.4M
    if (access(table_dir_offset + 12, numTables * 16, TableDirectory) < 0)
610
0
        return 0;
611
612
86.5M
    for (i = 0; i < numTables; ++i) {
613
86.5M
        const byte *tab = TableDirectory + i * 16;
614
615
86.5M
        if (!memcmp(tab, tname, 4)) {
616
26.4M
            if (plen)
617
24.5M
                *plen = pl_get_uint32(tab + 12);
618
26.4M
            return pl_get_uint32(tab + 8);
619
26.4M
        }
620
86.5M
    }
621
272
    return 0;
622
26.4M
}
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
225M
                for (i2 = 0; i2 < segCount2 - 3; i2 += 2) {
661
225M
                    int delta, roff;
662
225M
                    uint start = pl_get_uint16(startCount + i2);
663
225M
                    uint glyph;
664
665
225M
                    if_debug4('J', "[J]start=%u end=%u delta=%d roff=%d\n",
666
225M
                              start, pl_get_uint16(endCount + i2),
667
225M
                              pl_get_int16(idDelta + i2),
668
225M
                              pl_get_int16(idRangeOffset + i2));
669
225M
                    if (key < start) {
670
397k
                        if_debug1('J', "[J]%u out of range\n", key);
671
397k
                        return_error(gs_error_undefined);
672
397k
                    }
673
224M
                    if (endCount + i2 + 2 > table_lim) {
674
0
                        break;
675
0
                    }
676
224M
                    if (key > pl_get_uint16(endCount + i2))
677
200M
                        continue;
678
679
24.0M
                    if (idRangeOffset + i2 + 2 > table_lim) {
680
0
                        break;
681
0
                    }
682
24.0M
                    delta = pl_get_int16(idDelta + i2);
683
24.0M
                    roff = pl_get_int16(idRangeOffset + i2);
684
24.0M
                    if (roff == 0) {
685
22.7M
                        *pvalue = (key + delta) & 0xffff;       /* mod 65536 */
686
22.7M
                        if_debug2('J', "[J]%u => %u\n", key, *pvalue);
687
22.7M
                        return 0;
688
22.7M
                    }
689
690
1.26M
                    if ((2 + idRangeOffset + i2 + roff + ((key - start) << 1)) > table_lim) {
691
0
                        break;
692
0
                    }
693
1.26M
                    glyph = pl_get_uint16(idRangeOffset + i2 + roff + ((key - start) << 1));
694
1.26M
                    *pvalue = (glyph == 0 ? 0 : glyph + delta);
695
1.26M
                    if_debug2('J', "[J]%u => %u\n", key, *pvalue);
696
1.26M
                    return 0;
697
1.26M
                }
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
56.4k
                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.0M
        for (i = 0; i < ncmaps; ++i) {
762
73.0M
            if_debug3m('j', pfont->memory,
763
73.0M
                       "[j]cmap %d: platform %u encoding %u\n", i,
764
73.0M
                       pl_get_uint16(cmap_sub + i * 8),
765
73.0M
                       pl_get_uint16(cmap_sub + i * 8 + 2));
766
73.0M
            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.0M
        }
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
270
{
786
270
    pl_font_t *plfont = pfont->client_data;
787
270
    const pl_tt_char_glyph_t *ptcg = pl_tt_lookup_char(plfont, chr);
788
789
270
    return (ptcg->chr == gs_no_char ? GS_NO_GLYPH : ptcg->glyph);
790
270
}
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
270
                      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
16.2k
{
1546
16.2k
    pfont->procs.encode_char = pl_bitmap_encode_char;
1547
16.2k
    pfont->procs.build_char = pl_bitmap_build_char;
1548
32.4k
#define plfont ((pl_font_t *)pfont->client_data)
1549
16.2k
    plfont->char_width = pl_bitmap_char_width;
1550
16.2k
    plfont->char_metrics = pl_bitmap_char_metrics;
1551
16.2k
#undef plfont
1552
16.2k
}
1553
1554
/* Initialize the procedures for a TrueType font. */
1555
void
1556
pl_tt_init_procs(gs_font_type42 * pfont)
1557
1.95M
{
1558
1.95M
    pfont->procs.encode_char = pl_tt_encode_char;
1559
1.95M
    pfont->procs.build_char = pl_tt_build_char;
1560
1.95M
    pfont->data.string_proc = pl_tt_string_proc;
1561
3.91M
#define plfont ((pl_font_t *)pfont->client_data)
1562
1.95M
    plfont->char_width = pl_tt_char_width;
1563
1.95M
    plfont->char_metrics = pl_tt_char_metrics;
1564
1.95M
#undef plfont
1565
1.95M
}
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.95M
{
1578
1.95M
    float upem = (float)pfont->data.unitsPerEm;
1579
1.95M
    ulong head = tt_find_table(pfont, "head", NULL);
1580
1.95M
    const byte *hdata;
1581
1582
1.95M
    pfont->data.get_glyph_index = pl_tt_get_glyph_index;
1583
1.95M
    if (downloaded)
1584
78
        pfont->data.get_outline = pl_tt_get_outline;
1585
    /* Set the FontBBox. */
1586
1.95M
    access(head, 44, hdata);
1587
1.95M
    pfont->FontBBox.p.x = pl_get_int16(hdata + 36) / upem;
1588
1.95M
    pfont->FontBBox.p.y = pl_get_int16(hdata + 38) / upem;
1589
1.95M
    pfont->FontBBox.q.x = pl_get_int16(hdata + 40) / upem;
1590
1.95M
    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.95M
    pfont->data.get_metrics = pl_tt_get_metrics;
1614
1.95M
}
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
16.3k
{
1633
16.3k
    uint size = num_glyphs + (num_glyphs >> 2) + 5;
1634
16.3k
    pl_font_glyph_t *glyphs =
1635
16.3k
        gs_alloc_struct_array(mem, size, pl_font_glyph_t,
1636
16.3k
                              &st_pl_font_glyph_element, cname);
1637
1638
16.3k
    if (glyphs == 0)
1639
0
        return_error(gs_error_VMerror);
1640
16.3k
    {
1641
16.3k
        uint i;
1642
1643
1.63M
        for (i = 0; i < size; ++i)
1644
1.62M
            glyphs[i].glyph = 0, glyphs[i].data = 0;
1645
16.3k
    }
1646
16.3k
    plfont->glyphs.table = glyphs;
1647
16.3k
    plfont->glyphs.used = 0;
1648
16.3k
    plfont->glyphs.limit = num_glyphs;
1649
16.3k
    plfont->glyphs.size = size;
1650
16.3k
    plfont->glyphs.skip = size * 2 / 3;
1651
16.3k
    while (igcd(plfont->glyphs.skip, size) > 1)
1652
0
        plfont->glyphs.skip++;
1653
16.3k
    return 0;
1654
16.3k
}
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
93
{
1683
93
    uint size = num_chars + (num_chars >> 2) + 5;
1684
93
    pl_tt_char_glyph_t *char_glyphs = (pl_tt_char_glyph_t *)
1685
93
        gs_alloc_byte_array(mem, size, sizeof(pl_tt_char_glyph_t), cname);
1686
1687
93
    if (char_glyphs == 0)
1688
0
        return_error(gs_error_VMerror);
1689
93
    {
1690
93
        uint i;
1691
1692
19.1k
        for (i = 0; i < size; ++i)
1693
19.0k
            char_glyphs[i].chr = gs_no_char, char_glyphs[i].glyph = 0;
1694
93
    }
1695
93
    plfont->char_glyphs.table = char_glyphs;
1696
93
    plfont->char_glyphs.used = 0;
1697
93
    plfont->char_glyphs.limit = num_chars;
1698
93
    plfont->char_glyphs.size = size;
1699
93
    plfont->char_glyphs.skip = size * 2 / 3;
1700
93
    while (igcd(plfont->char_glyphs.skip, size) > 1)
1701
0
        plfont->char_glyphs.skip++;
1702
93
    return 0;
1703
93
}
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.71k
{
1737
2.71k
    const font_glyph_t *pfg = vpfg;
1738
1739
2.71k
    return (cc->pair->font == pfg->font && cc->code == pfg->glyph);
1740
2.71k
}
1741
int
1742
pl_font_add_glyph(pl_font_t * plfont, gs_glyph glyph, const byte * cdata, const int cdata_len)
1743
1.14M
{
1744
1.14M
    gs_font *pfont = plfont->pfont;
1745
1.14M
    gs_glyph key = glyph;
1746
1.14M
    pl_tt_char_glyph_t *ptcg = 0;
1747
1.14M
    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.14M
  tcg:if (plfont->char_glyphs.table) {
1756
405
        ptcg = pl_tt_lookup_char(plfont, key);
1757
405
        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
405
        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
405
            key =
1769
405
                pl_get_uint16(cdata +
1770
405
                              ((cdata[1] ==
1771
405
                                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
405
    }
1776
1.14M
  fg:pfg = pl_font_lookup_glyph(plfont, key);
1777
1.14M
    if (pfg->data != 0) {       /* Remove the glyph and a possible cached representation. */
1778
134
        font_glyph_t match_fg;
1779
1780
134
        match_fg.font = pfont;
1781
134
        match_fg.glyph = key;
1782
134
        gx_purge_selected_cached_chars(pfont->dir, match_font_glyph,
1783
134
                                       &match_fg);
1784
        /* replacing a read only glyph nothing we can do, so return. */
1785
134
        if (plfont->data_are_permanent)
1786
0
            return 0;
1787
134
        gs_free_object(pfont->memory, (void *)pfg->data,
1788
134
                       "pl_font_add_glyph(old data)");
1789
1.14M
    } else {
1790
1.14M
        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.14M
        plfont->glyphs.used++;
1798
1.14M
    }
1799
1.14M
    if (ptcg) {
1800
405
        if (ptcg->chr == gs_no_char)
1801
404
            plfont->char_glyphs.used++;
1802
405
        ptcg->chr = glyph;
1803
405
        ptcg->glyph = key;
1804
405
    }
1805
1.14M
    pfg->glyph = key;
1806
1.14M
    pfg->data = cdata;
1807
1.14M
    pfg->data_len = cdata_len;
1808
1.14M
    return 0;
1809
1.14M
}
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
}