Coverage Report

Created: 2026-08-08 08:00

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