Coverage Report

Created: 2026-10-28 08:05

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-2026 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* 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
922
{
53
922
    const pl_symbol_map_t **ppsm = pl_built_in_symbol_maps;
54
55
12.4k
    while (*ppsm != 0 && pl_get_uint16((*ppsm)->id) != symbol_set)
56
11.5k
        ++ppsm;
57
922
    return (*ppsm ? *ppsm : NULL);
58
922
}
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
922
{
64
922
    px_gstate_t *pxgs = pxs->pxgs;
65
66
922
    uint symbol_set = pxgs->symbol_set;
67
68
922
    pxgs->symbol_map = pxl_find_symbol_map(symbol_set);
69
922
}
70
71
static int
72
px_set_char_matrix(px_state_t * pxs)
73
902
{
74
902
    px_gstate_t *pxgs = pxs->pxgs;
75
76
902
    px_font_t *pxfont = pxgs->base_font;
77
78
902
    gs_matrix mat;
79
80
902
    if (pxfont == 0)
81
0
        return_error(errorNoCurrentFont);
82
902
    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
883
    } else {
106
883
        float char_size = pxgs->char_size;
107
108
883
        int i;
109
110
883
        gs_make_identity(&mat);
111
        /* H-P and Microsoft have Y coordinates running opposite ways. */
112
883
        gs_matrix_scale(&mat, char_size, -char_size, &mat);
113
        /* Apply the character transformations in the reverse order. */
114
3.53k
        for (i = 0; i < 3; ++i)
115
2.64k
            switch (pxgs->char_transforms[i]) {
116
883
                case pxct_rotate:
117
883
                    if (pxgs->char_angle != 0)
118
15
                        gs_matrix_rotate(&mat, pxgs->char_angle, &mat);
119
883
                    break;
120
883
                case pxct_shear:
121
883
                    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
883
                    break;
130
883
                case pxct_scale:
131
883
                    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
883
                    break;
135
2.64k
            }
136
883
    }
137
902
    pxgs->char_matrix = mat;
138
902
    pxgs->char_matrix_set = true;
139
902
    return 0;
140
902
}
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
19.5k
{
151
19.5k
    gs_memory_t *mem = pxs->memory;
152
153
19.5k
    uint num_chars;
154
155
19.5k
    int code = 0;
156
157
    /* Check for a valid font. */
158
19.5k
    if (size < 8 /* header */  + 6 /* 1 required segment */  +
159
19.5k
        6                       /* NULL segment */
160
19.5k
        )
161
0
        return_error(errorIllegalFontData);
162
19.5k
    if (header[0] != 0 /* format */  ||
163
19.5k
        header[5] != 0          /* variety */
164
19.5k
        )
165
0
        return_error(errorIllegalFontHeaderFields);
166
167
19.5k
    pxfont->header = (byte *) header;   /* remove const cast */
168
19.5k
    pxfont->header_size = size;
169
19.5k
    {
170
19.5k
        static const pl_font_offset_errors_t errors = {
171
19.5k
            errorIllegalFontData,
172
19.5k
            errorIllegalFontSegment,
173
19.5k
            errorIllegalFontHeaderFields,
174
19.5k
            errorIllegalNullSegmentSize,
175
19.5k
            errorMissingRequiredSegment,
176
19.5k
            errorIllegalGlobalTrueTypeSegment,
177
19.5k
            errorIllegalGalleyCharacterSegment,
178
19.5k
            errorIllegalVerticalTxSegment,
179
19.5k
            errorIllegalBitmapResolutionSegment
180
19.5k
        };
181
19.5k
        int code =
182
19.5k
            pl_font_scan_segments(mem, pxfont, 4, 8, size, true, &errors);
183
184
19.5k
        if (code < 0)
185
11
            return code;
186
19.5k
    }
187
19.5k
    num_chars = pl_get_uint16(header + 6);
188
    /* Allocate the character table. */
189
19.5k
    {                           /* Some fonts ask for unreasonably large tables.... */
190
19.5k
        int code = pl_font_alloc_glyph_table(pxfont, min(num_chars, 300),
191
19.5k
                                             mem, "px_define_font(glyphs)");
192
193
19.5k
        if (code < 0)
194
0
            return code;
195
19.5k
    }
196
    /* Now construct a gs_font. */
197
19.5k
    if (pxfont->scaling_technology == plfst_bitmap) {   /* Bitmap font. */
198
19.4k
        gs_font_base *pfont =
199
19.4k
            gs_alloc_struct(mem, gs_font_base, &st_gs_font_base,
200
19.4k
                            "px_define_font(gs_font_base)");
201
202
19.4k
        int code;
203
204
19.4k
        if (pfont == 0)
205
0
            return_error(errorInsufficientMemory);
206
19.4k
        code = px_fill_in_font((gs_font *) pfont, pxfont, pxs);
207
19.4k
        if (code < 0)
208
0
            return code;
209
19.4k
        pl_fill_in_bitmap_font(pfont, id);
210
19.4k
    } else {                    /* TrueType font. */
211
139
        gs_font_type42 *pfont =
212
139
            gs_alloc_struct(mem, gs_font_type42, &st_gs_font_type42,
213
139
                            "px_define_font(gs_font_type42)");
214
215
139
        int code;
216
217
139
        if (pfont == 0)
218
0
            return_error(errorInsufficientMemory);
219
        /* Some fonts ask for unreasonably large tables.... */
220
139
        code = pl_tt_alloc_char_glyphs(pxfont, min(num_chars, 300), mem,
221
139
                                       "px_define_font(char_glyphs)");
222
139
        if (code < 0)
223
0
            return code;
224
225
139
        code = px_fill_in_font((gs_font *) pfont, pxfont, pxs);
226
139
        if (code < 0)
227
0
            return code;
228
139
        {
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
139
            static const byte version1_0[4] = { 0, 1, 0, 0 };
237
            /* offset to the sfnt version.   */
238
139
            uint offs = pxfont->offsets.GT + (pxfont->large_sizes ? 6 : 4);
239
240
139
            if (gs_object_size(mem, header) >= offs + sizeof(version1_0))
241
139
                memcpy(header + offs, version1_0, sizeof(version1_0));
242
139
        }
243
139
        code = pl_fill_in_tt_font(pfont, NULL, id);
244
139
        if (code < 0)
245
15
            return code;
246
139
    }
247
19.5k
    pxfont->params.symbol_set = pl_get_uint16(header + 2);
248
249
19.5k
    if (header[4] == plfst_TrueType) {
250
124
        pxfont->is_xl_format = true;
251
124
        pl_prepend_xl_dummy_header(mem, &header); /* lgtm [cpp/useless-expression] */
252
124
        pxfont->header = header;
253
124
        pxfont->header_size = gs_object_size(mem, header);
254
19.4k
    } else {
255
19.4k
        pxfont->is_xl_format = false;
256
19.4k
    }
257
258
19.5k
    if ((code = gs_definefont(pxs->font_dir, pxfont->pfont)) < 0) {
259
0
        return (code);
260
0
    }
261
262
19.5k
    if (pxfont->scaling_technology == plfst_TrueType) {
263
124
        code = pl_fapi_passfont(pxfont, 0, NULL, NULL, NULL, 0);
264
124
    }
265
266
19.5k
    return (code);
267
19.5k
}
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
74
{
273
74
    char *mptr = message + strlen(message);
274
275
74
    uint fnsize = pfnv->value.array.size;
276
277
74
    uint i;
278
279
    /*
280
     **** We truncate 16-bit font name chars to 8 bits
281
     **** for the message.
282
     */
283
1.27k
    for (i = 0; i < fnsize && mptr - message < max_message; ++mptr, ++i)
284
1.20k
        if ((*mptr = (byte) integer_elt(pfnv, i)) < 32)
285
15
            *mptr = '?';
286
74
    *mptr = 0;
287
74
}
288
289
static inline bool
290
px_downloaded_and_bound(pl_font_t * plfont)
291
3.58k
{
292
3.58k
    return (plfont->storage != pxfsInternal && pl_font_is_bound(plfont));
293
3.58k
}
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.58k
{
301
3.58k
    const px_value_t *pstr = par->pv[0];
302
3.58k
    const unsigned char *str = (const unsigned char *)pstr->value.array.data;
303
3.58k
    uint len = pstr->value.array.size;
304
3.58k
    int i;
305
3.58k
    gs_char chr;
306
3.58k
    const pl_symbol_map_t *psm = pxs->pxgs->symbol_map;
307
3.58k
    bool db = px_downloaded_and_bound(pxs->pxgs->base_font);
308
309
223k
    for (i = 0; i < len; i++) {
310
220k
        if (pstr->type & pxd_ubyte) {
311
220k
            chr = str[i];
312
220k
        } else {
313
0
            chr = uint16at(&str[i << 1], (pstr->type & pxd_big_endian));
314
0
        }
315
220k
        pchr[i] = pl_map_symbol((db ? NULL : psm), chr,
316
220k
                                pxs->pxgs->base_font->storage == pxfsInternal,
317
220k
                                false /* pxl does not support MSL */ ,
318
220k
                                pxs->memory);
319
220k
    }
320
3.58k
}
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.58k
{
329
3.58k
    gs_text_params_t text;
330
3.58k
    int code;
331
332
3.58k
    text.operation =
333
3.58k
        TEXT_FROM_CHARS | TEXT_REPLACE_WIDTHS | TEXT_RETURN_WIDTH;
334
3.58k
    if (to_path)
335
0
        text.operation |= TEXT_DO_TRUE_CHARPATH;
336
3.58k
    else
337
3.58k
        text.operation |= TEXT_DO_DRAW;
338
3.58k
    text.operation |= can_cache ? 0 : TEXT_NO_CACHE;
339
3.58k
    text.data.chars = str;
340
3.58k
    text.size = size;
341
3.58k
    text.x_widths = x_widths;
342
3.58k
    text.y_widths = y_widths;
343
3.58k
    text.widths_size = widths_size;
344
3.58k
    code = gs_text_begin(pgs, &text, mem, ppte);
345
3.58k
    if (code < 0)
346
0
        return code;
347
348
3.58k
    return code;
349
3.58k
}
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.58k
{
358
3.58k
    gs_memory_t *mem = pxs->memory;
359
3.58k
    gs_gstate *pgs = pxs->pgs;
360
3.58k
    px_gstate_t *pxgs = pxs->pxgs;
361
3.58k
    gs_text_enum_t *penum;
362
3.58k
    const px_value_t *pstr = par->pv[0];
363
3.58k
    uint len = pstr->value.array.size;
364
3.58k
    const px_value_t *pxdata = par->pv[1];
365
3.58k
    const px_value_t *pydata = par->pv[2];
366
3.58k
    gs_font *pfont = gs_currentfont(pgs);
367
3.58k
    int code = 0;
368
3.58k
    gs_char *pchr = 0;
369
3.58k
    pl_font_t *plfont;
370
371
3.58k
    if (pfont == 0)
372
1
        return_error(errorNoCurrentFont);
373
374
3.58k
    plfont = (pl_font_t *) pfont->client_data;
375
3.58k
    if ((pxdata != 0 && pxdata->value.array.size != len) ||
376
3.58k
        (pydata != 0 && pydata->value.array.size != len)
377
3.58k
        )
378
3
        return_error(errorIllegalArraySize);
379
3.58k
    if (!pxgs->base_font)
380
0
        return_error(errorNoCurrentFont);
381
3.58k
    if (!pxgs->char_matrix_set) {
382
902
        gs_matrix *cm = &pxgs->char_matrix;
383
384
902
        float det;
385
386
902
        code = px_set_char_matrix(pxs);
387
902
        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
902
        det = (float)(cm->xx * cm->yy) - (float)(cm->xy * cm->yx);
393
902
        if (det == 0)
394
0
            return 0;
395
902
    }
396
397
3.58k
    {
398
3.58k
        gs_matrix cmat;
399
400
3.58k
        gs_matrix_multiply(&pfont->orig_FontMatrix, &pxgs->char_matrix,
401
3.58k
                           &cmat);
402
3.58k
        gs_setcharmatrix(pgs, &cmat);
403
3.58k
    }
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.58k
    gs_matrix_multiply(&pfont->orig_FontMatrix, &pxgs->char_matrix,
409
3.58k
                       &pfont->FontMatrix);
410
    /* we don't need to consider the vertical mess for resident fonts */
411
3.58k
    if (plfont->storage != pxfsDownLoaded) {
412
3.50k
        pfont->WMode = 0;       /* horizontal */
413
3.50k
        plfont->allow_vertical_substitutes = false;
414
3.50k
    } else {                    /* downloaded */
415
73
        pfont->WMode = pxgs->writing_mode;
416
        /* allow vertical substitutes for non-bitmap characters if requested. */
417
73
        if (pxgs->char_sub_mode == eVerticalSubstitution &&
418
0
            plfont->scaling_technology != plfst_bitmap)
419
0
            plfont->allow_vertical_substitutes = true;
420
73
        else
421
73
            plfont->allow_vertical_substitutes = false;
422
73
    }
423
424
    /* set bold fraction - charpaths are not algorithmically boldened */
425
3.58k
    if (to_path == false)
426
3.58k
        plfont->bold_fraction = pxgs->char_bold_value;
427
428
3.58k
    pchr = (gs_char *) gs_alloc_byte_array(mem, len, sizeof(gs_char),
429
3.58k
                                           "px_text gs_char[]");
430
3.58k
    if (pchr == 0)
431
0
        return_error(errorInsufficientMemory);
432
433
3.58k
    px_str_to_gschars(par, pxs, pchr);
434
435
3.58k
    {
436
3.58k
        uint i;
437
3.58k
        float *fxvals = 0;
438
3.58k
        float *fyvals = 0;
439
440
3.58k
        if (len > 0) {
441
3.58k
            fxvals =
442
3.58k
                (float *)gs_alloc_byte_array(mem, len + 1, sizeof(float),
443
3.58k
                                             "px_text fxvals");
444
3.58k
            fyvals =
445
3.58k
                (float *)gs_alloc_byte_array(mem, len + 1, sizeof(float) * 2,
446
3.58k
                                             "px_text fyals");
447
3.58k
            if (fxvals == 0 || fyvals == 0)
448
0
                return_error(errorInsufficientMemory);
449
3.58k
        }
450
223k
        for (i = 0; i < len; i++) {
451
220k
            fxvals[i] = pxdata ? real_elt(pxdata, i) : 0.0;
452
220k
            fyvals[i] = pydata ? real_elt(pydata, i) : 0.0;
453
220k
        }
454
455
3.58k
        code = px_text_setup(pgs, pchr, len, fxvals, fyvals,
456
3.58k
                             len, mem, &penum, to_path,
457
3.58k
                             pxgs->char_bold_value == 0 &&
458
3.58k
                             plfont->allow_vertical_substitutes == 0);
459
460
3.58k
        if (code >= 0) {
461
3.58k
            code = gs_text_process(penum);
462
3.58k
            gs_text_release(pgs, penum, "pxtext");
463
3.58k
        }
464
3.58k
        if (fxvals)
465
3.58k
            gs_free_object(mem, fxvals, "px_text fvals");
466
3.58k
        if (fyvals)
467
3.58k
            gs_free_object(mem, fyvals, "py_text fvals");
468
3.58k
    }
469
470
3.58k
    gs_free_object(mem, pchr, "px_text gs_char");
471
3.58k
    return (code == gs_error_invalidfont ?
472
3.58k
            gs_note_error(errorBadFontData) : code);
473
3.58k
}
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
929
{
483
929
    px_gstate_t *pxgs = pxs->pxgs;
484
929
    px_font_t *pxfont;
485
929
    px_value_t *pfnv;
486
929
    uint symbol_set;
487
929
    int code;
488
489
929
    if (!par->pv[3]) {
490
929
         if (!par->pv[0] || !par->pv[1] || !par->pv[2])
491
7
             return gs_note_error(errorMissingAttribute);
492
922
        pfnv = par->pv[0];
493
        /* force "find_font" to fail if the symbol set is not
494
           specified */
495
922
        symbol_set = (par->pv[2] ? par->pv[2]->value.i : (uint)-1);
496
922
        code = px_find_font(pfnv, symbol_set, &pxfont, pxs);
497
922
        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
922
        code = gs_setfont(pxs->pgs, pxfont->pfont);
525
922
        if (code < 0)
526
0
            return code;
527
922
        pxgs->char_size = real_value(par->pv[1], 0);
528
922
        pxgs->symbol_set = symbol_set;
529
922
        pxgs->base_font = pxfont;
530
922
        px_set_symbol_map(pxs, pxfont->font_type == plft_16bit);
531
922
        pxgs->char_matrix_set = false;
532
922
    } else {                    /* PCLSelectFont */
533
0
        code = pxpcl_selectfont(par, pxs);
534
0
        if (code < 0)
535
0
            return code;
536
0
    }
537
922
    return 0;
538
929
}
539
540
const byte apxBeginFontHeader[] = {
541
    pxaFontName, pxaFontFormat, 0, 0
542
};
543
int
544
pxBeginFontHeader(px_args_t * par, px_state_t * pxs)
545
393
{
546
393
    px_value_t *pfnv = par->pv[0];
547
393
    gs_memory_t *mem = pxs->memory;
548
393
    px_font_t *pxfont;
549
393
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
550
551
393
    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
393
    pxfont = pl_alloc_font(mem, "pxBeginFontHeader(pxfont)");
558
393
    if (pxfont == 0)
559
0
        return_error(errorInsufficientMemory);
560
393
    pxfont->storage = pxfsDownLoaded;
561
393
    pxfont->data_are_permanent = false;
562
393
    code = px_dict_put(&pxs->font_dict, par->pv[0], pxfont);
563
393
    if (code < 0) {
564
0
        gs_free_object(mem, pxfont, "pxBeginFontHeader(pxfont)");
565
0
        return code;
566
0
    }
567
393
    pxs->download_font = pxfont;
568
393
    pxs->download_bytes.data = 0;
569
393
    pxs->download_bytes.size = 0;
570
393
    return 0;
571
393
}
572
573
const byte apxReadFontHeader[] = {
574
    pxaFontHeaderLength, 0, 0
575
};
576
int
577
pxReadFontHeader(px_args_t * par, px_state_t * pxs)
578
1.86k
{
579
1.86k
    ulong len = par->pv[0]->value.i;
580
1.86k
    ulong left = len - par->source.position;
581
1.86k
    int code = pxNeedData;
582
583
1.86k
    if (left > 0) {
584
1.86k
        ulong pos;
585
586
1.86k
        if (par->source.position == 0) {        /* (Re-)allocate the downloaded data. */
587
1.86k
            void *new_data;
588
589
1.86k
            if (par->source.available == 0)
590
940
                return code;
591
928
            new_data =
592
928
                (pxs->download_bytes.size == 0 ?
593
381
                 gs_alloc_bytes(pxs->memory, len, "pxReadFontHeader") :
594
928
                 gs_resize_object(pxs->memory, pxs->download_bytes.data,
595
928
                                  pxs->download_bytes.size + len,
596
928
                                  "pxReadFontHeader"));
597
928
            if (new_data == 0)
598
0
                return_error(errorInsufficientMemory);
599
928
            pxs->download_bytes.data = new_data;
600
928
            pxs->download_bytes.size += len;
601
928
        }
602
928
        if (left > par->source.available)
603
22
            left = par->source.available;
604
906
        else
605
906
            code = 0;
606
928
        pos = pxs->download_bytes.size - len + par->source.position;
607
928
        memcpy(pxs->download_bytes.data + pos, par->source.data, left);
608
928
        par->source.position += left;
609
928
        par->source.data += left;
610
928
        par->source.available -= left;
611
928
        if (pos < 8 && pos + left >= 8) {       /* Check the font header fields now. */
612
380
            const byte *data = pxs->download_bytes.data;
613
614
380
            if (data[0] | data[5])
615
1
                return_error(errorIllegalFontHeaderFields);
616
379
            switch (data[4]) {
617
156
                case plfst_TrueType:
618
156
                    if (data[1])
619
0
                        return_error(errorIllegalFontHeaderFields);
620
156
                    break;
621
218
                case plfst_bitmap:
622
218
                    if (data[1] & ~3)
623
1
                        return_error(errorIllegalFontHeaderFields);
624
217
                    break;
625
217
                default:
626
5
                    return_error(errorIllegalFontHeaderFields);
627
379
            }
628
379
        }
629
928
    }
630
921
    return code;
631
1.86k
}
632
633
const byte apxEndFontHeader[] = { 0, 0 };
634
int
635
pxEndFontHeader(px_args_t * par, px_state_t * pxs)
636
330
{
637
330
    px_font_t *pxfont = pxs->download_font;
638
330
    int code = px_define_font(pxfont, pxs->download_bytes.data,
639
330
                              (ulong) pxs->download_bytes.size,
640
330
                              gs_next_ids(pxs->memory, 1), pxs);
641
642
        /****** HOW TO DETERMINE FONT TYPE? ******/
643
330
    pxfont->font_type = plft_16bit;
644
    /* Clear pointers for GC */
645
330
    pxs->download_font = 0;
646
330
    pxs->download_bytes.data = 0;
647
330
    return code;
648
330
}
649
650
const byte apxBeginChar[] = {
651
    pxaFontName, 0, 0
652
};
653
int
654
pxBeginChar(px_args_t * par, px_state_t * pxs)
655
294
{
656
294
    px_value_t *pfnv = par->pv[0];
657
294
    px_font_t *pxfont;
658
294
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
659
660
294
    if (code >= 0 && pxfont == 0)
661
0
        code = gs_note_error(errorFontUndefined);
662
294
    if (code < 0) {
663
24
        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
24
        return code;
668
24
    }
669
270
    if (pxfont->storage != pxfsDownLoaded)
670
0
        return_error(errorCannotReplaceCharacter);
671
270
    pxs->download_font = pxfont;
672
270
    return 0;
673
270
}
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.58k
{
681
2.58k
    uint char_code = par->pv[0]->value.i;
682
2.58k
    uint size = par->pv[1]->value.i;
683
2.58k
    uint pos = par->source.position;
684
685
2.58k
    if (pos == 0) {
686
        /* We're starting a character definition. */
687
2.49k
        byte *def;
688
689
2.49k
        if (size < 2)
690
0
            return_error(errorIllegalCharacterData);
691
2.49k
        if (par->source.available == 0)
692
1.24k
            return pxNeedData;
693
1.24k
        def = gs_alloc_bytes(pxs->memory, size, "pxReadChar");
694
1.24k
        if (def == 0)
695
0
            return_error(errorInsufficientMemory);
696
1.24k
        pxs->download_bytes.data = def;
697
1.24k
        pxs->download_bytes.size = size;
698
1.24k
    }
699
2.67k
    while (pos < size) {
700
1.47k
        uint copy = min(par->source.available, size - pos);
701
702
1.47k
        if (copy == 0)
703
139
            return pxNeedData;
704
1.33k
        memcpy(pxs->download_bytes.data + pos, par->source.data, copy);
705
1.33k
        par->source.data += copy;
706
1.33k
        par->source.available -= copy;
707
1.33k
        par->source.position = pos += copy;
708
1.33k
    }
709
    /* We have the complete character. */
710
    /* Do error checks before installing. */
711
1.20k
    {
712
1.20k
        byte *data = pxs->download_bytes.data;
713
714
1.20k
        int code = 0;
715
716
1.20k
        switch (data[0]) {
717
562
            case 0:            /* bitmap */
718
562
                if (false /* NB FIXME header[4] != plfst_bitmap */ )
719
0
                    code = gs_note_error(errorFSTMismatch);
720
562
                else if (data[1] != 0)
721
1
                    code = gs_note_error(errorUnsupportedCharacterClass);
722
561
                else if (size < 10)
723
0
                    code = gs_note_error(errorIllegalCharacterData);
724
561
                else {
725
561
                    int loff = pl_get_int16(data + 2);
726
561
                    int toff = pl_get_int16(data + 4);
727
561
                    uint width = pl_get_uint16(data + 6);
728
561
                    uint height = pl_get_uint16(data + 8);
729
561
                    uint bmp_size = ((width + 7) >> 3) * height;
730
561
                    uint bmp_offset = round_up(10, ARCH_ALIGN_PTR_MOD);
731
732
561
                    if (size != 10 + ((width + 7) >> 3) * height)
733
8
                        code = gs_note_error(errorIllegalCharacterData);
734
553
                    else if ((-16384 > toff) || (toff > 16384))
735
0
                        code = gs_note_error(errorIllegalCharacterData);
736
553
                    else if ((-16384 > loff) || (loff > 16384))
737
1
                        code = gs_note_error(errorIllegalCharacterData);
738
552
                    else if ((1 > height) || (height > 16384))
739
0
                        code = gs_note_error(errorIllegalCharacterData);
740
552
                    else if ((1 > width) || (width > 16384))
741
0
                        code = gs_note_error(errorIllegalCharacterData);
742
743
561
                    if (code >= 0) {
744
                        /* try to get the bitmap aligned */
745
552
                        data =
746
552
                            gs_resize_object(pxs->memory, data,
747
552
                                             bmp_offset + bmp_size,
748
552
                                             "pxReadChar");
749
552
                        if (data) {
750
552
                            memmove(data + bmp_offset, data + 10, bmp_size);
751
552
                            pxs->download_bytes.data = data;
752
552
                        }
753
0
                        else
754
0
                            code = gs_note_error(errorInsufficientMemory);
755
552
                    }
756
561
                }
757
562
                break;
758
633
            case 1:            /* TrueType outline */
759
633
                if (false /* NB FIXME header[4] != plfst_TrueType */ )
760
0
                    code = gs_note_error(errorFSTMismatch);
761
633
                else if (data[1] != 0 && data[1] != 1 && data[1] != 2)
762
1
                    code = gs_note_error(errorUnsupportedCharacterClass);
763
632
                else if (size < 6 || size != 2 + pl_get_uint16(data + 2))
764
1
                    code = gs_note_error(errorIllegalCharacterData);
765
633
                break;
766
5
            default:
767
5
                code = gs_note_error(errorUnsupportedCharacterFormat);
768
1.20k
        }
769
1.20k
        if (code >= 0) {
770
1.18k
            code = pl_font_add_glyph(pxs->download_font, char_code,
771
1.18k
                                    (byte *) data, pxs->download_bytes.size);     /* const cast */
772
1.18k
            if (code < 0)
773
0
                code = gs_note_error(errorInternalOverflow);
774
1.18k
        }
775
776
1.20k
        if (code < 0)
777
17
            gs_free_object(pxs->memory, pxs->download_bytes.data,
778
1.20k
                           "pxReadChar");
779
1.20k
        pxs->download_bytes.data = 0;
780
1.20k
        return code;
781
1.20k
    }
782
1.20k
}
783
784
const byte apxEndChar[] = { 0, 0 };
785
int
786
pxEndChar(px_args_t * par, px_state_t * pxs)
787
65
{
788
65
    return 0;
789
65
}
790
791
const byte apxRemoveFont[] = {
792
    pxaFontName, 0, 0
793
};
794
int
795
pxRemoveFont(px_args_t * par, px_state_t * pxs)
796
0
{
797
0
    px_value_t *pfnv = par->pv[0];
798
0
    px_font_t *pxfont;
799
0
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
800
0
    const char *error = 0;
801
802
0
    if (code < 0)
803
0
        error = "UndefinedFontNotRemoved - ";
804
0
    else if (pxfont == 0)       /* built-in font, assume internal */
805
0
        error = "InternalFontNotRemoved - ";
806
0
    else
807
0
        switch (pxfont->storage) {
808
0
            case pxfsInternal:
809
0
                error = "InternalFontNotRemoved - ";
810
0
                break;
811
0
            case pxfsMassStorage:
812
0
                error = "MassStorageFontNotRemoved - ";
813
0
                break;
814
0
            default:           /* downloaded */
815
0
                ;
816
0
        }
817
818
0
    if (error) {                /* Construct a warning message including the font name. */
819
0
        char message[px_max_error_line + 1];
820
821
0
        strcpy(message, error);
822
0
        px_concat_font_name(message, px_max_error_line, pfnv);
823
0
        code = px_record_warning(message, false, pxs);
824
0
    }
825
826
0
    if (error == NULL && pxfont != NULL) {
827
        /*
828
         * If we're deleting the current font we have to update the
829
         * graphics state.
830
         */
831
0
        if (pxfont->pfont == gs_currentfont(pxs->pgs))
832
0
            gs_setfont(pxs->pgs, NULL);
833
834
0
        px_dict_undef(&pxs->font_dict, par->pv[0]);
835
0
    }
836
837
0
    return code;
838
0
}