Coverage Report

Created: 2026-04-09 07:06

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