Coverage Report

Created: 2026-04-09 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pxl/pxfont.c
Line
Count
Source
1
/* Copyright (C) 2001-2023 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
/* pxfont.c */
18
/* PCL XL font operators */
19
20
#include "math_.h"
21
#include "stdio_.h"
22
#include "string_.h"
23
#include "gdebug.h"
24
#include "plvalue.h"
25
#include "pxoper.h"
26
#include "pxstate.h"
27
#include "pxfont.h"
28
#include "gserrors.h"
29
#include "gsstruct.h"
30
#include "gschar.h"
31
#include "gspaint.h"
32
#include "gspath.h"
33
#include "gsstate.h"
34
#include "gscoord.h"
35
#include "gsimage.h"
36
#include "gsutil.h"             /* for string_match */
37
#include "gxfont.h"
38
#include "gxfont42.h"
39
#include "gxfixed.h"
40
#include "gxchar.h"
41
#include "gxpath.h"
42
#include "gzstate.h"
43
#include "pxptable.h"
44
#include "pxpthr.h"
45
46
#include "plfapi.h"
47
48
/* ---------------- Operator utilities ---------------- */
49
50
static const pl_symbol_map_t *
51
pxl_find_symbol_map(uint symbol_set)
52
810
{
53
810
    const pl_symbol_map_t **ppsm = pl_built_in_symbol_maps;
54
55
10.3k
    while (*ppsm != 0 && pl_get_uint16((*ppsm)->id) != symbol_set)
56
9.58k
        ++ppsm;
57
810
    return (*ppsm ? *ppsm : NULL);
58
810
}
59
60
/* Compute the symbol map from the font and symbol set. */
61
void
62
px_set_symbol_map(px_state_t * pxs, bool wide16)
63
810
{
64
810
    px_gstate_t *pxgs = pxs->pxgs;
65
66
810
    uint symbol_set = pxgs->symbol_set;
67
68
810
    pxgs->symbol_map = pxl_find_symbol_map(symbol_set);
69
810
}
70
71
static int
72
px_set_char_matrix(px_state_t * pxs)
73
798
{
74
798
    px_gstate_t *pxgs = pxs->pxgs;
75
76
798
    px_font_t *pxfont = pxgs->base_font;
77
78
798
    gs_matrix mat;
79
80
798
    if (pxfont == 0)
81
0
        return_error(errorNoCurrentFont);
82
798
    if (pxfont->scaling_technology == plfst_bitmap) {
83
        /*
84
         * Bitmaps don't scale, shear, or rotate; however, we have to
85
         * scale them to make the resolution match that of the device.
86
         * Note that we disregard the character size, and, in px_text,
87
         * all but the translation and orientation components of the
88
         * CTM.
89
         */
90
19
        if (pxgs->char_angle != 0 ||
91
19
            pxgs->char_shear.x != 0 || pxgs->char_shear.y != 0 ||
92
19
            pxgs->char_scale.x != 1 || pxgs->char_scale.y != 1)
93
0
            return_error(errorIllegalFontData);
94
95
        /* remove negative scale component */
96
19
        gs_make_scaling(pxs->units_per_measure.x / pxfont->resolution.x,
97
19
                        pxs->units_per_measure.y / pxfont->resolution.y,
98
19
                        &mat);
99
100
        /*
101
         * Rotate the bitmap to undo the effect of its built-in
102
         * orientation.
103
         */
104
19
        gs_matrix_rotate(&mat, 90.0 * pxfont->header[1], &mat);
105
779
    } else {
106
779
        float char_size = pxgs->char_size;
107
108
779
        int i;
109
110
779
        gs_make_identity(&mat);
111
        /* H-P and Microsoft have Y coordinates running opposite ways. */
112
779
        gs_matrix_scale(&mat, char_size, -char_size, &mat);
113
        /* Apply the character transformations in the reverse order. */
114
3.11k
        for (i = 0; i < 3; ++i)
115
2.33k
            switch (pxgs->char_transforms[i]) {
116
779
                case pxct_rotate:
117
779
                    if (pxgs->char_angle != 0)
118
11
                        gs_matrix_rotate(&mat, pxgs->char_angle, &mat);
119
779
                    break;
120
779
                case pxct_shear:
121
779
                    if (pxgs->char_shear.x != 0 || pxgs->char_shear.y != 0) {
122
0
                        gs_matrix smat;
123
124
0
                        gs_make_identity(&smat);
125
0
                        smat.yx = pxgs->char_shear.x;
126
0
                        smat.xy = pxgs->char_shear.y;
127
0
                        gs_matrix_multiply(&smat, &mat, &mat);
128
0
                    }
129
779
                    break;
130
779
                case pxct_scale:
131
779
                    if (pxgs->char_scale.x != 1 || pxgs->char_scale.y != 1)
132
0
                        gs_matrix_scale(&mat, pxgs->char_scale.x,
133
0
                                        pxgs->char_scale.y, &mat);
134
779
                    break;
135
2.33k
            }
136
779
    }
137
798
    pxgs->char_matrix = mat;
138
798
    pxgs->char_matrix_set = true;
139
798
    return 0;
140
798
}
141
142
/* ---------------- Operator implementations ---------------- */
143
144
/* Define a font.  The caller must fill in pxfont->storage and ->font_type. */
145
/* This procedure implements FontHeader loading; it is exported for */
146
/* initializing the error page font. */
147
int
148
px_define_font(px_font_t * pxfont, byte * header, ulong size, gs_id id,
149
               px_state_t * pxs)
150
14.4k
{
151
14.4k
    gs_memory_t *mem = pxs->memory;
152
153
14.4k
    uint num_chars;
154
155
14.4k
    int code = 0;
156
157
    /* Check for a valid font. */
158
14.4k
    if (size < 8 /* header */  + 6 /* 1 required segment */  +
159
14.4k
        6                       /* NULL segment */
160
14.4k
        )
161
0
        return_error(errorIllegalFontData);
162
14.4k
    if (header[0] != 0 /* format */  ||
163
14.4k
        header[5] != 0          /* variety */
164
14.4k
        )
165
0
        return_error(errorIllegalFontHeaderFields);
166
167
14.4k
    pxfont->header = (byte *) header;   /* remove const cast */
168
14.4k
    pxfont->header_size = size;
169
14.4k
    {
170
14.4k
        static const pl_font_offset_errors_t errors = {
171
14.4k
            errorIllegalFontData,
172
14.4k
            errorIllegalFontSegment,
173
14.4k
            errorIllegalFontHeaderFields,
174
14.4k
            errorIllegalNullSegmentSize,
175
14.4k
            errorMissingRequiredSegment,
176
14.4k
            errorIllegalGlobalTrueTypeSegment,
177
14.4k
            errorIllegalGalleyCharacterSegment,
178
14.4k
            errorIllegalVerticalTxSegment,
179
14.4k
            errorIllegalBitmapResolutionSegment
180
14.4k
        };
181
14.4k
        int code =
182
14.4k
            pl_font_scan_segments(mem, pxfont, 4, 8, size, true, &errors);
183
184
14.4k
        if (code < 0)
185
6
            return code;
186
14.4k
    }
187
14.4k
    num_chars = pl_get_uint16(header + 6);
188
    /* Allocate the character table. */
189
14.4k
    {                           /* Some fonts ask for unreasonably large tables.... */
190
14.4k
        int code = pl_font_alloc_glyph_table(pxfont, min(num_chars, 300),
191
14.4k
                                             mem, "px_define_font(glyphs)");
192
193
14.4k
        if (code < 0)
194
0
            return code;
195
14.4k
    }
196
    /* Now construct a gs_font. */
197
14.4k
    if (pxfont->scaling_technology == plfst_bitmap) {   /* Bitmap font. */
198
14.3k
        gs_font_base *pfont =
199
14.3k
            gs_alloc_struct(mem, gs_font_base, &st_gs_font_base,
200
14.3k
                            "px_define_font(gs_font_base)");
201
202
14.3k
        int code;
203
204
14.3k
        if (pfont == 0)
205
0
            return_error(errorInsufficientMemory);
206
14.3k
        code = px_fill_in_font((gs_font *) pfont, pxfont, pxs);
207
14.3k
        if (code < 0)
208
0
            return code;
209
14.3k
        pl_fill_in_bitmap_font(pfont, id);
210
14.3k
    } else {                    /* TrueType font. */
211
89
        gs_font_type42 *pfont =
212
89
            gs_alloc_struct(mem, gs_font_type42, &st_gs_font_type42,
213
89
                            "px_define_font(gs_font_type42)");
214
215
89
        int code;
216
217
89
        if (pfont == 0)
218
0
            return_error(errorInsufficientMemory);
219
        /* Some fonts ask for unreasonably large tables.... */
220
89
        code = pl_tt_alloc_char_glyphs(pxfont, min(num_chars, 300), mem,
221
89
                                       "px_define_font(char_glyphs)");
222
89
        if (code < 0)
223
0
            return code;
224
225
89
        code = px_fill_in_font((gs_font *) pfont, pxfont, pxs);
226
89
        if (code < 0)
227
0
            return code;
228
89
        {
229
            /* some pcl xl drivers generate an incorrect sfnt
230
               version, in particular they will use a true type
231
               collection header where truetype was intended.  The
232
               hp printer does not detect this problem.  Brutishly,
233
               we write in what the driver writers intended here
234
               and bypass and avoid later failures that would
235
               result from an incorrect header. */
236
89
            static const byte version1_0[4] = { 0, 1, 0, 0 };
237
            /* offset to the sfnt version.   */
238
89
            uint offs = pxfont->offsets.GT + (pxfont->large_sizes ? 6 : 4);
239
240
89
            if (gs_object_size(mem, header) >= offs + sizeof(version1_0))
241
89
                memcpy(header + offs, version1_0, sizeof(version1_0));
242
89
        }
243
89
        code = pl_fill_in_tt_font(pfont, NULL, id);
244
89
        if (code < 0)
245
5
            return code;
246
89
    }
247
14.4k
    pxfont->params.symbol_set = pl_get_uint16(header + 2);
248
249
14.4k
    if (header[4] == plfst_TrueType) {
250
84
        pxfont->is_xl_format = true;
251
84
        pl_prepend_xl_dummy_header(mem, &header); /* lgtm [cpp/useless-expression] */
252
84
        pxfont->header = header;
253
84
        pxfont->header_size = gs_object_size(mem, header);
254
14.3k
    } else {
255
14.3k
        pxfont->is_xl_format = false;
256
14.3k
    }
257
258
14.4k
    if ((code = gs_definefont(pxs->font_dir, pxfont->pfont)) < 0) {
259
0
        return (code);
260
0
    }
261
262
14.4k
    if (pxfont->scaling_technology == plfst_TrueType) {
263
84
        code = pl_fapi_passfont(pxfont, 0, NULL, NULL, NULL, 0);
264
84
    }
265
266
14.4k
    return (code);
267
14.4k
}
268
269
/* Concatenate a widened (16-bit) font name onto an error message string. */
270
void
271
px_concat_font_name(char *message, uint max_message, const px_value_t * pfnv)
272
68
{
273
68
    char *mptr = message + strlen(message);
274
275
68
    uint fnsize = pfnv->value.array.size;
276
277
68
    uint i;
278
279
    /*
280
     **** We truncate 16-bit font name chars to 8 bits
281
     **** for the message.
282
     */
283
1.22k
    for (i = 0; i < fnsize && mptr - message < max_message; ++mptr, ++i)
284
1.15k
        if ((*mptr = (byte) integer_elt(pfnv, i)) < 32)
285
33
            *mptr = '?';
286
68
    *mptr = 0;
287
68
}
288
289
static inline bool
290
px_downloaded_and_bound(pl_font_t * plfont)
291
3.86k
{
292
3.86k
    return (plfont->storage != pxfsInternal && pl_font_is_bound(plfont));
293
3.86k
}
294
295
/** Convert pxl text arguments into an array of gs_chars
296
 * caller must allocate the correct size array pchar and free it later
297
 */
298
static void
299
px_str_to_gschars(px_args_t * par, px_state_t * pxs, gs_char * pchr)
300
3.86k
{
301
3.86k
    const px_value_t *pstr = par->pv[0];
302
3.86k
    const unsigned char *str = (const unsigned char *)pstr->value.array.data;
303
3.86k
    uint len = pstr->value.array.size;
304
3.86k
    int i;
305
3.86k
    gs_char chr;
306
3.86k
    const pl_symbol_map_t *psm = pxs->pxgs->symbol_map;
307
3.86k
    bool db = px_downloaded_and_bound(pxs->pxgs->base_font);
308
309
230k
    for (i = 0; i < len; i++) {
310
226k
        if (pstr->type & pxd_ubyte) {
311
226k
            chr = str[i];
312
226k
        } else {
313
0
            chr = uint16at(&str[i << 1], (pstr->type & pxd_big_endian));
314
0
        }
315
226k
        pchr[i] = pl_map_symbol((db ? NULL : psm), chr,
316
226k
                                pxs->pxgs->base_font->storage == pxfsInternal,
317
226k
                                false /* pxl does not support MSL */ ,
318
226k
                                pxs->memory);
319
226k
    }
320
3.86k
}
321
322
/* startup for the processing text */
323
static int
324
px_text_setup(gs_gstate * pgs, const gs_char * str, uint size,
325
              const float *x_widths, const float *y_widths,
326
              uint widths_size, gs_memory_t * mem, gs_text_enum_t ** ppte,
327
              bool to_path, bool can_cache)
328
3.86k
{
329
3.86k
    gs_text_params_t text;
330
3.86k
    int code;
331
332
3.86k
    text.operation =
333
3.86k
        TEXT_FROM_CHARS | TEXT_REPLACE_WIDTHS | TEXT_RETURN_WIDTH;
334
3.86k
    if (to_path)
335
0
        text.operation |= TEXT_DO_TRUE_CHARPATH;
336
3.86k
    else
337
3.86k
        text.operation |= TEXT_DO_DRAW;
338
3.86k
    text.operation |= can_cache ? 0 : TEXT_NO_CACHE;
339
3.86k
    text.data.chars = str;
340
3.86k
    text.size = size;
341
3.86k
    text.x_widths = x_widths;
342
3.86k
    text.y_widths = y_widths;
343
3.86k
    text.widths_size = widths_size;
344
3.86k
    code = gs_text_begin(pgs, &text, mem, ppte);
345
3.86k
    if (code < 0)
346
1
        return code;
347
348
3.86k
    return code;
349
3.86k
}
350
351
/* Paint text or add it to the path. */
352
/* This procedure implements the Text and TextPath operators. */
353
/* Attributes: pxaTextData, pxaXSpacingData, pxaYSpacingData. */
354
355
int
356
px_text(px_args_t * par, px_state_t * pxs, bool to_path)
357
3.86k
{
358
3.86k
    gs_memory_t *mem = pxs->memory;
359
3.86k
    gs_gstate *pgs = pxs->pgs;
360
3.86k
    px_gstate_t *pxgs = pxs->pxgs;
361
3.86k
    gs_text_enum_t *penum;
362
3.86k
    const px_value_t *pstr = par->pv[0];
363
3.86k
    uint len = pstr->value.array.size;
364
3.86k
    const px_value_t *pxdata = par->pv[1];
365
3.86k
    const px_value_t *pydata = par->pv[2];
366
3.86k
    gs_font *pfont = gs_currentfont(pgs);
367
3.86k
    int code = 0;
368
3.86k
    gs_char *pchr = 0;
369
3.86k
    pl_font_t *plfont;
370
371
3.86k
    if (pfont == 0)
372
1
        return_error(errorNoCurrentFont);
373
374
3.86k
    plfont = (pl_font_t *) pfont->client_data;
375
3.86k
    if ((pxdata != 0 && pxdata->value.array.size != len) ||
376
3.86k
        (pydata != 0 && pydata->value.array.size != len)
377
3.86k
        )
378
1
        return_error(errorIllegalArraySize);
379
3.86k
    if (!pxgs->base_font)
380
0
        return_error(errorNoCurrentFont);
381
3.86k
    if (!pxgs->char_matrix_set) {
382
798
        gs_matrix *cm = &pxgs->char_matrix;
383
384
798
        float det;
385
386
798
        code = px_set_char_matrix(pxs);
387
798
        if (code < 0)
388
0
            return code;
389
        /* check for a singular matrix - this does not generate an
390
           interpreter error on hp.  Casts prevent double precision
391
           temporary variables, as in gsmatrix.c. */
392
798
        det = (float)(cm->xx * cm->yy) - (float)(cm->xy * cm->yx);
393
798
        if (det == 0)
394
0
            return 0;
395
798
    }
396
397
3.86k
    {
398
3.86k
        gs_matrix cmat;
399
400
3.86k
        gs_matrix_multiply(&pfont->orig_FontMatrix, &pxgs->char_matrix,
401
3.86k
                           &cmat);
402
3.86k
        gs_setcharmatrix(pgs, &cmat);
403
3.86k
    }
404
405
    /* The character matrix is not visible to devices.  High level
406
       devices get character scaling information from the font's
407
       matrix (FontMatrix).  */
408
3.86k
    gs_matrix_multiply(&pfont->orig_FontMatrix, &pxgs->char_matrix,
409
3.86k
                       &pfont->FontMatrix);
410
    /* we don't need to consider the vertical mess for resident fonts */
411
3.86k
    if (plfont->storage != pxfsDownLoaded) {
412
3.80k
        pfont->WMode = 0;       /* horizontal */
413
3.80k
        plfont->allow_vertical_substitutes = false;
414
3.80k
    } else {                    /* downloaded */
415
59
        pfont->WMode = pxgs->writing_mode;
416
        /* allow vertical substitutes for non-bitmap characters if requested. */
417
59
        if (pxgs->char_sub_mode == eVerticalSubstitution &&
418
0
            plfont->scaling_technology != plfst_bitmap)
419
0
            plfont->allow_vertical_substitutes = true;
420
59
        else
421
59
            plfont->allow_vertical_substitutes = false;
422
59
    }
423
424
    /* set bold fraction - charpaths are not algorithmically boldened */
425
3.86k
    if (to_path == false)
426
3.86k
        plfont->bold_fraction = pxgs->char_bold_value;
427
428
3.86k
    pchr = (gs_char *) gs_alloc_byte_array(mem, len, sizeof(gs_char),
429
3.86k
                                           "px_text gs_char[]");
430
3.86k
    if (pchr == 0)
431
0
        return_error(errorInsufficientMemory);
432
433
3.86k
    px_str_to_gschars(par, pxs, pchr);
434
435
3.86k
    {
436
3.86k
        uint i;
437
3.86k
        float *fxvals = 0;
438
3.86k
        float *fyvals = 0;
439
440
3.86k
        if (len > 0) {
441
3.86k
            fxvals =
442
3.86k
                (float *)gs_alloc_byte_array(mem, len + 1, sizeof(float),
443
3.86k
                                             "px_text fxvals");
444
3.86k
            fyvals =
445
3.86k
                (float *)gs_alloc_byte_array(mem, len + 1, sizeof(float) * 2,
446
3.86k
                                             "px_text fyals");
447
3.86k
            if (fxvals == 0 || fyvals == 0)
448
0
                return_error(errorInsufficientMemory);
449
3.86k
        }
450
230k
        for (i = 0; i < len; i++) {
451
226k
            fxvals[i] = pxdata ? real_elt(pxdata, i) : 0.0;
452
226k
            fyvals[i] = pydata ? real_elt(pydata, i) : 0.0;
453
226k
        }
454
455
3.86k
        code = px_text_setup(pgs, pchr, len, fxvals, fyvals,
456
3.86k
                             len, mem, &penum, to_path,
457
3.86k
                             pxgs->char_bold_value == 0 &&
458
3.86k
                             plfont->allow_vertical_substitutes == 0);
459
460
3.86k
        if (code >= 0) {
461
3.86k
            code = gs_text_process(penum);
462
3.86k
            gs_text_release(pgs, penum, "pxtext");
463
3.86k
        }
464
3.86k
        if (fxvals)
465
3.86k
            gs_free_object(mem, fxvals, "px_text fvals");
466
3.86k
        if (fyvals)
467
3.86k
            gs_free_object(mem, fyvals, "py_text fvals");
468
3.86k
    }
469
470
3.86k
    gs_free_object(mem, pchr, "px_text gs_char");
471
3.86k
    return (code == gs_error_invalidfont ?
472
3.86k
            gs_note_error(errorBadFontData) : code);
473
3.86k
}
474
475
/* ---------------- Operators ---------------- */
476
477
const byte apxSetFont[] = {
478
    0, pxaFontName, pxaCharSize, pxaSymbolSet, pxaPCLSelectFont, 0
479
};
480
int
481
pxSetFont(px_args_t * par, px_state_t * pxs)
482
816
{
483
816
    px_gstate_t *pxgs = pxs->pxgs;
484
816
    px_font_t *pxfont;
485
816
    px_value_t *pfnv;
486
816
    uint symbol_set;
487
816
    int code;
488
489
816
    if (!par->pv[3]) {
490
816
         if (!par->pv[0] || !par->pv[1] || !par->pv[2])
491
6
             return gs_note_error(errorMissingAttribute);
492
810
        pfnv = par->pv[0];
493
        /* force "find_font" to fail if the symbol set is not
494
           specified */
495
810
        symbol_set = (par->pv[2] ? par->pv[2]->value.i : (uint)-1);
496
810
        code = px_find_font(pfnv, symbol_set, &pxfont, pxs);
497
810
        if (code < 0) {
498
0
            switch (code) {
499
0
                case errorFontUndefined:
500
0
                    strcpy(pxs->error_line, "FontUndefined - ");
501
0
                    goto undef;
502
0
                case errorFontUndefinedNoSubstituteFound:
503
0
                    strcpy(pxs->error_line,
504
0
                           "FontUndefinedNoSubstituteFound - ");
505
0
                  undef:px_concat_font_name(pxs->error_line, px_max_error_line,
506
0
                                        pfnv);
507
0
                    break;
508
0
                case errorSymbolSetRemapUndefined:
509
0
                    strcpy(pxs->error_line, "SymbolSetRemapUndefined - ");
510
0
                    px_concat_font_name(pxs->error_line, px_max_error_line,
511
0
                                        pfnv);
512
0
                    {
513
0
                        char setstr[26];        /* 64-bit value plus message */
514
515
0
                        gs_snprintf(setstr, sizeof(setstr), " : %d", symbol_set);
516
0
                        strncat(pxs->error_line, setstr,
517
0
                                px_max_error_line - strlen(pxs->error_line));
518
0
                        pxs->error_line[px_max_error_line] = 0;
519
0
                    }
520
0
                    break;
521
0
            }
522
0
            return code;
523
0
        }
524
810
        code = gs_setfont(pxs->pgs, pxfont->pfont);
525
810
        if (code < 0)
526
0
            return code;
527
810
        pxgs->char_size = real_value(par->pv[1], 0);
528
810
        pxgs->symbol_set = symbol_set;
529
810
        pxgs->base_font = pxfont;
530
810
        px_set_symbol_map(pxs, pxfont->font_type == plft_16bit);
531
810
        pxgs->char_matrix_set = false;
532
810
    } else {                    /* PCLSelectFont */
533
0
        code = pxpcl_selectfont(par, pxs);
534
0
        if (code < 0)
535
0
            return code;
536
0
    }
537
810
    return 0;
538
816
}
539
540
const byte apxBeginFontHeader[] = {
541
    pxaFontName, pxaFontFormat, 0, 0
542
};
543
int
544
pxBeginFontHeader(px_args_t * par, px_state_t * pxs)
545
301
{
546
301
    px_value_t *pfnv = par->pv[0];
547
301
    gs_memory_t *mem = pxs->memory;
548
301
    px_font_t *pxfont;
549
301
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
550
551
301
    if (code >= 0) {
552
0
        strcpy(pxs->error_line, "FontNameAlreadyExists - ");
553
0
        px_concat_font_name(pxs->error_line, px_max_error_line, pfnv);
554
0
        return_error(errorFontNameAlreadyExists);
555
0
    }
556
    /* Make a partially filled-in dictionary entry. */
557
301
    pxfont = pl_alloc_font(mem, "pxBeginFontHeader(pxfont)");
558
301
    if (pxfont == 0)
559
0
        return_error(errorInsufficientMemory);
560
301
    pxfont->storage = pxfsDownLoaded;
561
301
    pxfont->data_are_permanent = false;
562
301
    code = px_dict_put(&pxs->font_dict, par->pv[0], pxfont);
563
301
    if (code < 0) {
564
0
        gs_free_object(mem, pxfont, "pxBeginFontHeader(pxfont)");
565
0
        return code;
566
0
    }
567
301
    pxs->download_font = pxfont;
568
301
    pxs->download_bytes.data = 0;
569
301
    pxs->download_bytes.size = 0;
570
301
    return 0;
571
301
}
572
573
const byte apxReadFontHeader[] = {
574
    pxaFontHeaderLength, 0, 0
575
};
576
int
577
pxReadFontHeader(px_args_t * par, px_state_t * pxs)
578
1.52k
{
579
1.52k
    ulong len = par->pv[0]->value.i;
580
1.52k
    ulong left = len - par->source.position;
581
1.52k
    int code = pxNeedData;
582
583
1.52k
    if (left > 0) {
584
1.52k
        ulong pos;
585
586
1.52k
        if (par->source.position == 0) {        /* (Re-)allocate the downloaded data. */
587
1.52k
            void *new_data;
588
589
1.52k
            if (par->source.available == 0)
590
766
                return code;
591
760
            new_data =
592
760
                (pxs->download_bytes.size == 0 ?
593
295
                 gs_alloc_bytes(pxs->memory, len, "pxReadFontHeader") :
594
760
                 gs_resize_object(pxs->memory, pxs->download_bytes.data,
595
760
                                  pxs->download_bytes.size + len,
596
760
                                  "pxReadFontHeader"));
597
760
            if (new_data == 0)
598
0
                return_error(errorInsufficientMemory);
599
760
            pxs->download_bytes.data = new_data;
600
760
            pxs->download_bytes.size += len;
601
760
        }
602
760
        if (left > par->source.available)
603
3
            left = par->source.available;
604
757
        else
605
757
            code = 0;
606
760
        pos = pxs->download_bytes.size - len + par->source.position;
607
760
        memcpy(pxs->download_bytes.data + pos, par->source.data, left);
608
760
        par->source.position += left;
609
760
        par->source.data += left;
610
760
        par->source.available -= left;
611
760
        if (pos < 8 && pos + left >= 8) {       /* Check the font header fields now. */
612
295
            const byte *data = pxs->download_bytes.data;
613
614
295
            if (data[0] | data[5])
615
1
                return_error(errorIllegalFontHeaderFields);
616
294
            switch (data[4]) {
617
100
                case plfst_TrueType:
618
100
                    if (data[1])
619
0
                        return_error(errorIllegalFontHeaderFields);
620
100
                    break;
621
192
                case plfst_bitmap:
622
192
                    if (data[1] & ~3)
623
1
                        return_error(errorIllegalFontHeaderFields);
624
191
                    break;
625
191
                default:
626
2
                    return_error(errorIllegalFontHeaderFields);
627
294
            }
628
294
        }
629
760
    }
630
756
    return code;
631
1.52k
}
632
633
const byte apxEndFontHeader[] = { 0, 0 };
634
int
635
pxEndFontHeader(px_args_t * par, px_state_t * pxs)
636
275
{
637
275
    px_font_t *pxfont = pxs->download_font;
638
275
    int code = px_define_font(pxfont, pxs->download_bytes.data,
639
275
                              (ulong) pxs->download_bytes.size,
640
275
                              gs_next_ids(pxs->memory, 1), pxs);
641
642
        /****** HOW TO DETERMINE FONT TYPE? ******/
643
275
    pxfont->font_type = plft_16bit;
644
    /* Clear pointers for GC */
645
275
    pxs->download_font = 0;
646
275
    pxs->download_bytes.data = 0;
647
275
    return code;
648
275
}
649
650
const byte apxBeginChar[] = {
651
    pxaFontName, 0, 0
652
};
653
int
654
pxBeginChar(px_args_t * par, px_state_t * pxs)
655
253
{
656
253
    px_value_t *pfnv = par->pv[0];
657
253
    px_font_t *pxfont;
658
253
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
659
660
253
    if (code >= 0 && pxfont == 0)
661
0
        code = gs_note_error(errorFontUndefined);
662
253
    if (code < 0) {
663
23
        if (code == errorFontUndefined) {
664
0
            strcpy(pxs->error_line, "FontUndefined - ");
665
0
            px_concat_font_name(pxs->error_line, px_max_error_line, pfnv);
666
0
        }
667
23
        return code;
668
23
    }
669
230
    if (pxfont->storage != pxfsDownLoaded)
670
0
        return_error(errorCannotReplaceCharacter);
671
230
    pxs->download_font = pxfont;
672
230
    return 0;
673
230
}
674
675
const byte apxReadChar[] = {
676
    pxaCharCode, pxaCharDataSize, 0, 0
677
};
678
int
679
pxReadChar(px_args_t * par, px_state_t * pxs)
680
2.32k
{
681
2.32k
    uint char_code = par->pv[0]->value.i;
682
2.32k
    uint size = par->pv[1]->value.i;
683
2.32k
    uint pos = par->source.position;
684
685
2.32k
    if (pos == 0) {
686
        /* We're starting a character definition. */
687
2.23k
        byte *def;
688
689
2.23k
        if (size < 2)
690
0
            return_error(errorIllegalCharacterData);
691
2.23k
        if (par->source.available == 0)
692
1.11k
            return pxNeedData;
693
1.11k
        def = gs_alloc_bytes(pxs->memory, size, "pxReadChar");
694
1.11k
        if (def == 0)
695
0
            return_error(errorInsufficientMemory);
696
1.11k
        pxs->download_bytes.data = def;
697
1.11k
        pxs->download_bytes.size = size;
698
1.11k
    }
699
2.41k
    while (pos < size) {
700
1.33k
        uint copy = min(par->source.available, size - pos);
701
702
1.33k
        if (copy == 0)
703
126
            return pxNeedData;
704
1.20k
        memcpy(pxs->download_bytes.data + pos, par->source.data, copy);
705
1.20k
        par->source.data += copy;
706
1.20k
        par->source.available -= copy;
707
1.20k
        par->source.position = pos += copy;
708
1.20k
    }
709
    /* We have the complete character. */
710
    /* Do error checks before installing. */
711
1.08k
    {
712
1.08k
        byte *data = pxs->download_bytes.data;
713
714
1.08k
        int code = 0;
715
716
1.08k
        switch (data[0]) {
717
591
            case 0:            /* bitmap */
718
591
                if (false /* NB FIXME header[4] != plfst_bitmap */ )
719
0
                    code = gs_note_error(errorFSTMismatch);
720
591
                else if (data[1] != 0)
721
3
                    code = gs_note_error(errorUnsupportedCharacterClass);
722
588
                else if (size < 10)
723
0
                    code = gs_note_error(errorIllegalCharacterData);
724
588
                else {
725
588
                    int loff = pl_get_int16(data + 2);
726
588
                    int toff = pl_get_int16(data + 4);
727
588
                    uint width = pl_get_uint16(data + 6);
728
588
                    uint height = pl_get_uint16(data + 8);
729
588
                    uint bmp_size = ((width + 7) >> 3) * height;
730
588
                    uint bmp_offset = round_up(10, ARCH_ALIGN_PTR_MOD);
731
732
588
                    if (size != 10 + ((width + 7) >> 3) * height)
733
9
                        code = gs_note_error(errorIllegalCharacterData);
734
579
                    else if ((-16384 > toff) || (toff > 16384))
735
0
                        code = gs_note_error(errorIllegalCharacterData);
736
579
                    else if ((-16384 > loff) || (loff > 16384))
737
0
                        code = gs_note_error(errorIllegalCharacterData);
738
579
                    else if ((1 > height) || (height > 16384))
739
0
                        code = gs_note_error(errorIllegalCharacterData);
740
579
                    else if ((1 > width) || (width > 16384))
741
0
                        code = gs_note_error(errorIllegalCharacterData);
742
743
588
                    if (code >= 0) {
744
                        /* try to get the bitmap aligned */
745
579
                        data =
746
579
                            gs_resize_object(pxs->memory, data,
747
579
                                             bmp_offset + bmp_size,
748
579
                                             "pxReadChar");
749
579
                        if (data)
750
579
                            memmove(data + bmp_offset, data + 10, bmp_size);
751
0
                        else
752
0
                            code = gs_note_error(errorInsufficientMemory);
753
579
                    }
754
588
                }
755
591
                break;
756
485
            case 1:            /* TrueType outline */
757
485
                if (false /* NB FIXME header[4] != plfst_TrueType */ )
758
0
                    code = gs_note_error(errorFSTMismatch);
759
485
                else if (data[1] != 0 && data[1] != 1 && data[1] != 2)
760
0
                    code = gs_note_error(errorUnsupportedCharacterClass);
761
485
                else if (size < 6 || size != 2 + pl_get_uint16(data + 2))
762
1
                    code = gs_note_error(errorIllegalCharacterData);
763
485
                break;
764
6
            default:
765
6
                code = gs_note_error(errorUnsupportedCharacterFormat);
766
1.08k
        }
767
1.08k
        if (code >= 0) {
768
1.06k
            code = pl_font_add_glyph(pxs->download_font, char_code,
769
1.06k
                                    (byte *) data, pxs->download_bytes.size);     /* const cast */
770
1.06k
            if (code < 0)
771
0
                code = gs_note_error(errorInternalOverflow);
772
1.06k
        }
773
774
1.08k
        if (code < 0)
775
19
            gs_free_object(pxs->memory, pxs->download_bytes.data,
776
1.08k
                           "pxReadChar");
777
1.08k
        pxs->download_bytes.data = 0;
778
1.08k
        return code;
779
1.08k
    }
780
1.08k
}
781
782
const byte apxEndChar[] = { 0, 0 };
783
int
784
pxEndChar(px_args_t * par, px_state_t * pxs)
785
52
{
786
52
    return 0;
787
52
}
788
789
const byte apxRemoveFont[] = {
790
    pxaFontName, 0, 0
791
};
792
int
793
pxRemoveFont(px_args_t * par, px_state_t * pxs)
794
0
{
795
0
    px_value_t *pfnv = par->pv[0];
796
0
    px_font_t *pxfont;
797
0
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
798
0
    const char *error = 0;
799
800
0
    if (code < 0)
801
0
        error = "UndefinedFontNotRemoved - ";
802
0
    else if (pxfont == 0)       /* built-in font, assume internal */
803
0
        error = "InternalFontNotRemoved - ";
804
0
    else
805
0
        switch (pxfont->storage) {
806
0
            case pxfsInternal:
807
0
                error = "InternalFontNotRemoved - ";
808
0
                break;
809
0
            case pxfsMassStorage:
810
0
                error = "MassStorageFontNotRemoved - ";
811
0
                break;
812
0
            default:           /* downloaded */
813
0
                ;
814
0
        }
815
816
0
    if (error) {                /* Construct a warning message including the font name. */
817
0
        char message[px_max_error_line + 1];
818
819
0
        strcpy(message, error);
820
0
        px_concat_font_name(message, px_max_error_line, pfnv);
821
0
        code = px_record_warning(message, false, pxs);
822
0
    }
823
824
0
    if (error == NULL && pxfont != NULL) {
825
        /*
826
         * If we're deleting the current font we have to update the
827
         * graphics state.
828
         */
829
0
        if (pxfont->pfont == gs_currentfont(pxs->pgs))
830
0
            gs_setfont(pxs->pgs, NULL);
831
832
0
        px_dict_undef(&pxs->font_dict, par->pv[0]);
833
0
    }
834
835
0
    return code;
836
0
}