Coverage Report

Created: 2026-04-01 07:17

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
59
{
73
59
    return 0;
74
59
}
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.01M
{
89
1.01M
    uint size = plfont->glyphs.size;
90
1.01M
    uint skip = plfont->glyphs.skip;
91
1.01M
    uint index = glyph % size;
92
1.01M
    pl_font_glyph_t *pfg;
93
1.01M
    pl_font_glyph_t *result = 0;
94
95
1.01M
    while ((pfg = plfont->glyphs.table + index)->data ?
96
866k
           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.01M
    return (!pfg->data && result) ? result : pfg;
102
1.01M
}
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
254k
{
111
254k
    return (gs_glyph) chr;
112
254k
}
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
144k
{
189
144k
    uint dest_bytes = (pim->Width + 7) >> 3;
190
144k
    int code;
191
144k
    gs_image_enum *penum;
192
144k
    uint used;
193
194
144k
    code = gx_set_dev_color(pgs);
195
144k
    if (code == gs_error_Remap_Color)
196
0
        code = pixmap_high_level_pattern(pgs);
197
144k
    if (code != 0)
198
0
        return code;
199
144k
    penum = gs_image_enum_alloc(gs_gstate_memory(pgs), "pl_image_bitmap_char");
200
144k
    if (penum == NULL)
201
0
        return_error(gs_error_VMerror);
202
144k
    code = gs_image_init(penum, pim, pim->ImageMask | pim->CombineWithColor, true, pgs);
203
144k
    if (code < 0)
204
0
        goto free_penum_and_exit;
205
144k
    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
144k
    } else {                    /* Pass the entire image at once. */
265
144k
        int i;
266
3.62M
        for (i = 0; i < pim->Height; i++) {
267
3.48M
            code = gs_image_next(penum, bitmap_data, dest_bytes, &used);
268
3.48M
            if (code < 0)
269
0
                break;
270
3.48M
            bitmap_data += sraster;
271
3.48M
        }
272
144k
    }
273
144k
free_penum_and_exit:
274
144k
    {
275
144k
        int code2 = gs_image_cleanup_and_free_enum(penum, pgs);
276
144k
        if (code == 0)
277
0
            code = code2;
278
144k
    }
279
144k
    return code;
280
144k
}
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
144k
{
288
144k
    pl_font_t *plfont = (pl_font_t *) pfont->client_data;
289
144k
    const byte *cdata = pl_font_lookup_glyph(plfont, glyph)->data;
290
144k
    bool orient = plfont->orient;
291
292
144k
    if (cdata == 0) {
293
89
        return gs_setcharwidth(penum, pgs, 0, 0);
294
144k
    } else {
295
144k
        const byte *params;
296
144k
        const byte *bitmap_data;
297
144k
        int lsb, ascent;
298
144k
        float delta_x;
299
144k
        gs_image_t image;
300
144k
        gs_image_enum *ienum;
301
144k
        int code;
302
144k
        uint bold;
303
144k
        byte *bold_lines = 0;
304
305
144k
        if (cdata[0] == 0) {    /* PCL XL format */
306
289
            params = cdata + 2;
307
289
            bitmap_data = cdata + round_up(10, ARCH_ALIGN_PTR_MOD);
308
289
            delta_x = 0;        /* irrelevant */
309
289
            lsb = pl_get_int16(params);
310
289
            ascent = pl_get_int16(params + 2);
311
143k
        } else {                /* PCL5 format */
312
143k
            params = cdata + 6;
313
143k
            bitmap_data = cdata + 16;
314
143k
            delta_x = (plfont->header[13] ?     /* variable pitch */
315
143k
                       pl_get_int16(params + 8) * 0.25 :
316
143k
                       (short)(pl_get_int16(params) /*lsb */
317
0
                               +pl_get_int16(params + 4)) /*width */ );
318
143k
            lsb = pl_get_int16(params);
319
143k
            ascent = pl_get_int16(params + 2);
320
143k
        }
321
144k
        ienum = gs_image_enum_alloc(pgs->memory, "pl_bitmap_build_char");
322
144k
        if (ienum == 0)
323
0
            return_error(gs_error_VMerror);
324
144k
        gs_image_t_init_mask(&image, true);
325
144k
        image.Width = pl_get_uint16(params + 4);
326
144k
        image.Height = pl_get_uint16(params + 6);
327
        /* Determine the amount of pseudo-bolding. */
328
144k
        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
144k
            bold = 0;
341
342
144k
        gs_make_identity(&image.ImageMatrix);
343
144k
        gs_matrix_rotate(&image.ImageMatrix, orient * -90,
344
144k
                         &image.ImageMatrix);
345
144k
        image.ImageMatrix.tx -= lsb;
346
144k
        image.ImageMatrix.ty += ascent;
347
144k
        image.adjust = true;
348
144k
        if (bold || orient != 0)
349
0
            code = gs_setcharwidth(penum, pgs, delta_x, 0);
350
144k
        else {
351
            /* we use cache device for portrait bitmap fonts to
352
               avoid image setup overhead.  */
353
144k
            float m[6];
354
355
144k
            m[0] = delta_x;
356
144k
            m[1] = 0;
357
144k
            m[2] = (float)lsb;
358
144k
            m[3] = (float)(image.Height - ascent);
359
144k
            m[4] = image.Width + m[2];
360
144k
            m[5] = (float)(-ascent);
361
144k
            code = gs_setcachedevice(penum, pgs, m);
362
144k
        }
363
144k
        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
144k
        code = pl_image_bitmap_char(ienum, &image, bitmap_data,
384
144k
                                    (image.Width - bold + 7) >> 3, bold,
385
144k
                                    bold_lines, pgs);
386
144k
      out:gs_free_object(pgs->memory, bold_lines,
387
144k
                       "pl_bitmap_build_char(bold_lines)");
388
144k
        gs_free_object(pgs->memory, ienum, "pl_bitmap_build_char");
389
144k
        return (code < 0 ? code : 0);
390
144k
    }
391
144k
}
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
525
{
401
525
    uint size = plfont->char_glyphs.size;
402
525
    uint skip = plfont->char_glyphs.skip;
403
525
    uint index = glyph % size;
404
525
    pl_tt_char_glyph_t *ptcg;
405
525
    pl_tt_char_glyph_t *result = 0;
406
407
525
    while ((ptcg = plfont->char_glyphs.table + index)->chr != gs_no_char ?
408
345
           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
525
    return (result ? result : ptcg);
414
525
}
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
816M
{
421
816M
    pl_font_t *plfont = pfont->client_data;
422
423
816M
    *pdata = plfont->header + plfont->offsets.GT +
424
816M
        (plfont->large_sizes ? 6 : 4) + offset;
425
426
816M
    if (*pdata > plfont->header + plfont->header_size)
427
3
        return_error(gs_error_invalidfont);
428
429
816M
    return 0;
430
816M
}
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
2.71M
{
460
2.71M
    int code = gs_error_undefined;
461
2.71M
    pl_font_t *plfont = pfont->client_data;
462
2.71M
    const pl_font_glyph_t *pfg = 0;
463
2.71M
    const byte *cdata = 0;
464
465
2.71M
    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
161
        pfg = pl_font_lookup_glyph(plfont, glyph_index);
470
161
        cdata = pfg->data;
471
472
161
        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
161
    }
496
2.71M
    return code;
497
2.71M
}
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
227
{
550
227
    pl_font_t *plfont = pfont->client_data;
551
227
    const pl_font_glyph_t *pfg = pl_font_lookup_glyph(plfont, index);
552
227
    const byte *cdata = pfg->data;
553
554
227
    if (cdata == 0) {
555
        /* undefined glyph */
556
14
        gs_glyph_data_from_null(pdata);
557
213
    } else {
558
213
        uint desc_size =
559
213
            (*cdata == 15 ? cdata[2] /* PCL5 */ : 0 /* PCL XL */ );
560
213
        uint data_size = pl_get_uint16(cdata + 2 + desc_size);
561
562
213
        if (data_size > pfg->data_len)
563
0
            data_size = pfg->data_len;
564
565
213
        if (data_size <= 4) {
566
            /* empty outline */
567
0
            gs_glyph_data_from_null(pdata);
568
213
        } else if (cdata[1] == 0) {
569
213
            gs_glyph_data_from_bytes(pdata,
570
213
                                     cdata,
571
213
                                     6 + desc_size, data_size - 4, NULL);
572
213
        } 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
213
    }
578
227
    return 0;
579
227
}
580
581
#define access(base, length, vptr)\
582
53.7M
  (*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
10.9M
{
590
10.9M
    const byte *OffsetTable;
591
10.9M
    uint numTables;
592
10.9M
    const byte *TableDirectory;
593
10.9M
    uint i;
594
10.9M
    ulong table_dir_offset = 0;
595
10.9M
    int code;
596
597
10.9M
    if (((code = access(0, 12, OffsetTable)) < 0) ||
598
10.9M
        ((code = access(table_dir_offset, 12, OffsetTable)) < 0))
599
0
        return 0;
600
601
10.9M
    numTables = pl_get_uint16(OffsetTable + 4);
602
603
10.9M
    if (access(table_dir_offset + 12, numTables * 16, TableDirectory) < 0)
604
0
        return 0;
605
606
36.8M
    for (i = 0; i < numTables; ++i) {
607
36.8M
        const byte *tab = TableDirectory + i * 16;
608
609
36.8M
        if (!memcmp(tab, tname, 4)) {
610
10.9M
            if (plen)
611
9.88M
                *plen = pl_get_uint32(tab + 12);
612
10.9M
            return pl_get_uint32(tab + 8);
613
10.9M
        }
614
36.8M
    }
615
181
    return 0;
616
10.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
9.88M
{                               /* Dispatch according to the table type. */
627
9.88M
    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
9.88M
        case 4:
635
9.88M
            {                   /* Microsoft/Adobe segmented mapping.  What a mess! */
636
9.88M
                uint segCount2 = pl_get_uint16(table + 6);
637
9.88M
                const byte *endCount = table + 14;
638
9.88M
                const byte *startCount = endCount + segCount2 + 2;
639
9.88M
                const byte *idDelta = startCount + segCount2;
640
9.88M
                const byte *idRangeOffset = idDelta + segCount2;
641
                /*const byte *glyphIdArray = idRangeOffset + segCount2; */
642
9.88M
                uint i2;
643
644
165M
                for (i2 = 0; i2 < segCount2 - 3; i2 += 2) {
645
165M
                    int delta, roff;
646
165M
                    uint start = pl_get_uint16(startCount + i2);
647
165M
                    uint glyph;
648
649
165M
                    if_debug4('J', "[J]start=%u end=%u delta=%d roff=%d\n",
650
165M
                              start, pl_get_uint16(endCount + i2),
651
165M
                              pl_get_int16(idDelta + i2),
652
165M
                              pl_get_int16(idRangeOffset + i2));
653
165M
                    if (key < start) {
654
66.9k
                        if_debug1('J', "[J]%u out of range\n", key);
655
66.9k
                        return_error(gs_error_undefined);
656
66.9k
                    }
657
165M
                    if (key > pl_get_uint16(endCount + i2))
658
156M
                        continue;
659
9.78M
                    delta = pl_get_int16(idDelta + i2);
660
9.78M
                    roff = pl_get_int16(idRangeOffset + i2);
661
9.78M
                    if (roff == 0) {
662
8.67M
                        *pvalue = (key + delta) & 0xffff;       /* mod 65536 */
663
8.67M
                        if_debug2('J', "[J]%u => %u\n", key, *pvalue);
664
8.67M
                        return 0;
665
8.67M
                    }
666
1.10M
                    glyph = pl_get_uint16(idRangeOffset + i2 + roff +
667
1.10M
                                          ((key - start) << 1));
668
1.10M
                    *pvalue = (glyph == 0 ? 0 : glyph + delta);
669
1.10M
                    if_debug2('J', "[J]%u => %u\n", key, *pvalue);
670
1.10M
                    return 0;
671
9.78M
                }
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
9.88M
                if_debug1('J', "[J]%u out of range\n", key);
678
37.4k
                return_error(gs_error_undefined);
679
9.88M
            }
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
9.88M
    }
697
0
    return 0;
698
9.88M
}
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
9.88M
{
706
9.88M
    const byte *cmap;
707
9.88M
    const byte *cmap_sub;
708
9.88M
    const byte *table;
709
9.88M
    uint value;
710
9.88M
    int code;
711
712
9.88M
    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
9.88M
    cmap_sub = cmap + 4;
717
9.88M
    {
718
9.88M
        uint i;
719
720
29.5M
        for (i = 0; i < pl_get_uint16(cmap + 2); ++i) {
721
29.5M
            if_debug3m('j', pfont->memory,
722
29.5M
                       "[j]cmap %d: platform %u encoding %u\n", i,
723
29.5M
                       pl_get_uint16(cmap_sub + i * 8),
724
29.5M
                       pl_get_uint16(cmap_sub + i * 8 + 2));
725
29.5M
            if (pl_get_uint16(cmap_sub + i * 8) == 3) {
726
9.88M
                cmap_sub += i * 8;
727
9.88M
                break;
728
9.88M
            }
729
29.5M
        }
730
9.88M
    }
731
9.88M
    {
732
9.88M
        uint offset = cmap_offset + pl_get_uint32(cmap_sub + 4);
733
734
9.88M
        access(offset, cmap_offset + cmap_len - offset, table);
735
9.88M
    }
736
9.88M
    code = pl_cmap_lookup((uint) chr, table, &value);
737
9.88M
    return (code < 0 ? GS_NO_GLYPH : value);
738
9.88M
}
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
180
{
744
180
    pl_font_t *plfont = pfont->client_data;
745
180
    const pl_tt_char_glyph_t *ptcg = pl_tt_lookup_char(plfont, chr);
746
747
180
    return (ptcg->chr == gs_no_char ? GS_NO_GLYPH : ptcg->glyph);
748
180
}
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
9.88M
{
791
9.88M
    gs_font_type42 *pfont = (gs_font_type42 *) pfont_generic;
792
9.88M
    uint cmap_len;
793
9.88M
    ulong cmap_offset = tt_find_table(pfont, "cmap", &cmap_len);
794
9.88M
    gs_glyph glyph = (cmap_offset == 0 ?
795
                      /* This is a downloaded font with no cmap. */
796
180
                      pl_tt_dynamic_encode_char(pfont, chr) :
797
9.88M
                      pl_tt_cmap_encode_char(pfont, cmap_offset, cmap_len,
798
9.88M
                                             chr));
799
9.88M
    pl_font_t *plfont = pfont->client_data;
800
9.88M
    pl_font_glyph_t *pfg;
801
802
9.88M
    if (plfont->offsets.GC < 0)
803
9.88M
        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
12.3k
{
1486
12.3k
    pfont->procs.encode_char = pl_bitmap_encode_char;
1487
12.3k
    pfont->procs.build_char = pl_bitmap_build_char;
1488
24.6k
#define plfont ((pl_font_t *)pfont->client_data)
1489
12.3k
    plfont->char_width = pl_bitmap_char_width;
1490
12.3k
    plfont->char_metrics = pl_bitmap_char_metrics;
1491
12.3k
#undef plfont
1492
12.3k
}
1493
1494
/* Initialize the procedures for a TrueType font. */
1495
void
1496
pl_tt_init_procs(gs_font_type42 * pfont)
1497
1.08M
{
1498
1.08M
    pfont->procs.encode_char = pl_tt_encode_char;
1499
1.08M
    pfont->procs.build_char = pl_tt_build_char;
1500
1.08M
    pfont->data.string_proc = pl_tt_string_proc;
1501
2.17M
#define plfont ((pl_font_t *)pfont->client_data)
1502
1.08M
    plfont->char_width = pl_tt_char_width;
1503
1.08M
    plfont->char_metrics = pl_tt_char_metrics;
1504
1.08M
#undef plfont
1505
1.08M
}
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.08M
{
1518
1.08M
    float upem = (float)pfont->data.unitsPerEm;
1519
1.08M
    ulong head = tt_find_table(pfont, "head", NULL);
1520
1.08M
    const byte *hdata;
1521
1522
1.08M
    pfont->data.get_glyph_index = pl_tt_get_glyph_index;
1523
1.08M
    if (downloaded)
1524
59
        pfont->data.get_outline = pl_tt_get_outline;
1525
    /* Set the FontBBox. */
1526
1.08M
    access(head, 44, hdata);
1527
1.08M
    pfont->FontBBox.p.x = pl_get_int16(hdata + 36) / upem;
1528
1.08M
    pfont->FontBBox.p.y = pl_get_int16(hdata + 38) / upem;
1529
1.08M
    pfont->FontBBox.q.x = pl_get_int16(hdata + 40) / upem;
1530
1.08M
    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.08M
    pfont->data.get_metrics = pl_tt_get_metrics;
1554
1.08M
}
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
12.3k
{
1573
12.3k
    uint size = num_glyphs + (num_glyphs >> 2) + 5;
1574
12.3k
    pl_font_glyph_t *glyphs =
1575
12.3k
        gs_alloc_struct_array(mem, size, pl_font_glyph_t,
1576
12.3k
                              &st_pl_font_glyph_element, cname);
1577
1578
12.3k
    if (glyphs == 0)
1579
0
        return_error(gs_error_VMerror);
1580
12.3k
    {
1581
12.3k
        uint i;
1582
1583
1.26M
        for (i = 0; i < size; ++i)
1584
1.25M
            glyphs[i].glyph = 0, glyphs[i].data = 0;
1585
12.3k
    }
1586
12.3k
    plfont->glyphs.table = glyphs;
1587
12.3k
    plfont->glyphs.used = 0;
1588
12.3k
    plfont->glyphs.limit = num_glyphs;
1589
12.3k
    plfont->glyphs.size = size;
1590
12.3k
    plfont->glyphs.skip = size * 2 / 3;
1591
12.3k
    while (igcd(plfont->glyphs.skip, size) > 1)
1592
0
        plfont->glyphs.skip++;
1593
12.3k
    return 0;
1594
12.3k
}
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
62
{
1623
62
    uint size = num_chars + (num_chars >> 2) + 5;
1624
62
    pl_tt_char_glyph_t *char_glyphs = (pl_tt_char_glyph_t *)
1625
62
        gs_alloc_byte_array(mem, size, sizeof(pl_tt_char_glyph_t), cname);
1626
1627
62
    if (char_glyphs == 0)
1628
0
        return_error(gs_error_VMerror);
1629
62
    {
1630
62
        uint i;
1631
1632
12.7k
        for (i = 0; i < size; ++i)
1633
12.7k
            char_glyphs[i].chr = gs_no_char, char_glyphs[i].glyph = 0;
1634
62
    }
1635
62
    plfont->char_glyphs.table = char_glyphs;
1636
62
    plfont->char_glyphs.used = 0;
1637
62
    plfont->char_glyphs.limit = num_chars;
1638
62
    plfont->char_glyphs.size = size;
1639
62
    plfont->char_glyphs.skip = size * 2 / 3;
1640
62
    while (igcd(plfont->char_glyphs.skip, size) > 1)
1641
0
        plfont->char_glyphs.skip++;
1642
62
    return 0;
1643
62
}
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
3.83k
{
1677
3.83k
    const font_glyph_t *pfg = vpfg;
1678
1679
3.83k
    return (cc->pair->font == pfg->font && cc->code == pfg->glyph);
1680
3.83k
}
1681
int
1682
pl_font_add_glyph(pl_font_t * plfont, gs_glyph glyph, const byte * cdata, const int cdata_len)
1683
866k
{
1684
866k
    gs_font *pfont = plfont->pfont;
1685
866k
    gs_glyph key = glyph;
1686
866k
    pl_tt_char_glyph_t *ptcg = 0;
1687
866k
    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
866k
  tcg:if (plfont->char_glyphs.table) {
1696
345
        ptcg = pl_tt_lookup_char(plfont, key);
1697
345
        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
345
        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
345
            key =
1709
345
                pl_get_uint16(cdata +
1710
345
                              ((cdata[1] ==
1711
345
                                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
345
    }
1716
866k
  fg:pfg = pl_font_lookup_glyph(plfont, key);
1717
866k
    if (pfg->data != 0) {       /* Remove the glyph and a possible cached representation. */
1718
185
        font_glyph_t match_fg;
1719
1720
185
        match_fg.font = pfont;
1721
185
        match_fg.glyph = key;
1722
185
        gx_purge_selected_cached_chars(pfont->dir, match_font_glyph,
1723
185
                                       &match_fg);
1724
        /* replacing a read only glyph nothing we can do, so return. */
1725
185
        if (plfont->data_are_permanent)
1726
0
            return 0;
1727
185
        gs_free_object(pfont->memory, (void *)pfg->data,
1728
185
                       "pl_font_add_glyph(old data)");
1729
866k
    } else {
1730
866k
        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
866k
        plfont->glyphs.used++;
1738
866k
    }
1739
866k
    if (ptcg) {
1740
345
        if (ptcg->chr == gs_no_char)
1741
344
            plfont->char_glyphs.used++;
1742
345
        ptcg->chr = glyph;
1743
345
        ptcg->glyph = key;
1744
345
    }
1745
866k
    pfg->glyph = key;
1746
866k
    pfg->data = cdata;
1747
866k
    pfg->data_len = cdata_len;
1748
866k
    return 0;
1749
866k
}
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
}