Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/zchar1.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
/* Type 1 character display operator */
18
#include "memory_.h"
19
#include "ghost.h"
20
#include "oper.h"
21
#include "gsstruct.h"
22
#include "gxfixed.h"
23
#include "gxmatrix.h"
24
#include "gxdevice.h"   /* for gxfont.h */
25
#include "gxfont.h"
26
#include "gxfont1.h"
27
#include "gxtype1.h"
28
#include "gxfcid.h"
29
#include "gxchar.h"
30
#include "gxfcache.h"           /* for gs_purge_font_from_char_caches_completely */
31
#include "gzstate.h"    /* for path for gs_type1_init */
32
                                /* (should only be gsstate.h) */
33
#include "gscencs.h"
34
#include "gspaint.h"    /* for gs_fill, gs_stroke */
35
#include "gspath.h"
36
#include "gsrect.h"
37
#include "estack.h"
38
#include "ialloc.h"
39
#include "ichar.h"
40
#include "ichar1.h"
41
#include "icharout.h"
42
#include "idict.h"
43
#include "iddict.h"
44
#include "ifont.h"
45
#include "igstate.h"
46
#include "iname.h"
47
#include "iutil.h"
48
#include "store.h"
49
50
/*
51
 * Properly designed fonts, which have no self-intersecting outlines
52
 * and in which outer and inner outlines are drawn in opposite
53
 * directions, aren't affected by choice of filling rule; but some
54
 * badly designed fonts in the Genoa test suite seem to require
55
 * using the even-odd rule to match Adobe interpreters.
56
 *
57
 * Properly designed fonts will render correctly with: eofill
58
 * (required for Adobe CPSI compliant behavior
59
 */
60
/*
61
 * On April 4, 2002, we received bug report #539359
62
 * which we interpret as some Genoa test are now obsolete,
63
 * so we need to drop the bad font tolerance feature
64
 * explained above. This temporary patch changes
65
 * the even-odd rule back to non-zero rule.
66
 * This patch to be kept until we accumulate
67
 * enough information from regression testing and
68
 * from user responses.
69
 */
70
71
/* *********************************************************************
72
 * Make this dynamic via a global (somewhat better than a COMPILE option
73
 ***********************************************************************/
74
0
#define GS_CHAR_FILL gs_fill
75
76
/* ---------------- Utilities ---------------- */
77
78
/* Test whether a font is a CharString font. */
79
static bool
80
font_uses_charstrings(const gs_font *pfont)
81
0
{
82
0
    return (pfont->FontType == ft_encrypted ||
83
0
            pfont->FontType == ft_encrypted2 ||
84
0
            pfont->FontType == ft_disk_based);
85
0
}
86
87
/* Initialize a Type 1 interpreter. */
88
static int
89
type1_exec_init(gs_type1_state *pcis, gs_text_enum_t *penum,
90
                gs_gstate *pgs, gs_font_type1 *pfont1)
91
0
{
92
    /*
93
     * We have to disregard penum->pis and penum->path, and render to
94
     * the current gstate and path.  This is a design bug that we will
95
     * have to address someday!
96
     */
97
98
0
    int alpha_bits = 1;
99
0
    gs_log2_scale_point log2_subpixels;
100
101
0
    if (color_is_pure(gs_currentdevicecolor_inline(pgs))) /* Keep consistency with alpha_buffer_bits() */
102
0
        alpha_bits = (*dev_proc(pgs->device, get_alpha_bits)) (pgs->device, go_text);
103
0
    if (alpha_bits <= 1) {
104
        /* We render to cache device or the target device has no alpha bits. */
105
0
        log2_subpixels = penum->log2_scale;
106
0
    } else {
107
        /* We'll render to target device through alpha buffer. */
108
        /* Keep consistency with alpha_buffer_init() */
109
0
        log2_subpixels.x = log2_subpixels.y = ilog2(alpha_bits);
110
0
    }
111
0
    return gs_type1_interp_init(pcis, pgs, pgs->path,
112
0
                                &penum->log2_scale, &log2_subpixels,
113
0
                                (penum->text.operation & TEXT_DO_ANY_CHARPATH) != 0 ||
114
0
                                penum->device_disabled_grid_fitting,
115
0
                                pfont1->PaintType, pfont1);
116
0
}
117
118
/* ---------------- .type1execchar ---------------- */
119
120
/*
121
 * This is the workhorse for %Type1/2BuildChar, %Type1/2BuildGlyph,
122
 * CCRun, and CID fonts.  Eventually this will appear in the C API;
123
 * even now, its normal control path doesn't use any continuations.
124
 */
125
126
/*
127
 * Define the state record for this operator, which must save the metrics
128
 * separately as well as the Type 1 interpreter state.
129
 */
130
typedef struct gs_type1exec_state_s {
131
    gs_type1_state cis;   /* must be first */
132
    i_ctx_t *i_ctx_p;   /* so push/pop can access o-stack */
133
    double sbw[4];
134
    int /*metrics_present */ present;
135
    gs_rect char_bbox;
136
    bool use_FontBBox_as_Metrics2;
137
    /*
138
     * The following elements are only used locally to make the stack clean
139
     * for OtherSubrs: they don't need to be declared for the garbage
140
     * collector.
141
     */
142
    ref save_args[6];
143
    int num_args;
144
    bool AlignToPixels;
145
} gs_type1exec_state;
146
147
gs_private_st_suffix_add1(st_gs_type1exec_state, gs_type1exec_state,
148
                          "gs_type1exec_state", gs_type1exec_state_enum_ptrs,
149
                          gs_type1exec_state_reloc_ptrs, st_gs_type1_state,
150
                          i_ctx_p);
151
152
/* Forward references */
153
static int bbox_continue(i_ctx_t *);
154
static int nobbox_continue(i_ctx_t *);
155
static int type1_push_OtherSubr(i_ctx_t *, const gs_type1exec_state *,
156
                                 int (*)(i_ctx_t *), const ref *);
157
static int type1_call_OtherSubr(i_ctx_t *, const gs_type1exec_state *,
158
                                 int (*)(i_ctx_t *), const ref *);
159
static int type1_callout_dispatch(i_ctx_t *, int (*)(i_ctx_t *), int);
160
static int type1_continue_dispatch(i_ctx_t *, gs_type1exec_state *,
161
                                    const ref *, ref *, int);
162
static int op_type1_cleanup(i_ctx_t *);
163
static void op_type1_free(i_ctx_t *);
164
static int bbox_getsbw_continue(i_ctx_t *);
165
static int type1exec_bbox(i_ctx_t *, gs_text_enum_t *, gs_type1exec_state *, gs_font *, op_proc_t *exec_cont);
166
static int bbox_finish_fill(i_ctx_t *);
167
static int bbox_finish_stroke(i_ctx_t *);
168
static int bbox_fill(i_ctx_t *);
169
static int bbox_stroke(i_ctx_t *);
170
static int nobbox_finish(i_ctx_t *, gs_type1exec_state *);
171
static int nobbox_draw(i_ctx_t *, int (*)(gs_gstate *));
172
static int nobbox_fill(i_ctx_t *);
173
static int nobbox_stroke(i_ctx_t *);
174
175
/* <font> <code|name> <name> <charstring> .type1execchar - */
176
static int
177
ztype1execchar(i_ctx_t *i_ctx_p)
178
0
{
179
0
    return charstring_execchar(i_ctx_p, (1 << (int)ft_encrypted) |
180
0
                               (1 << (int)ft_disk_based));
181
0
}
182
static int
183
charstring_execchar_aux(i_ctx_t *i_ctx_p, gs_text_enum_t *penum, gs_font *pfont)
184
0
{
185
0
    os_ptr op = osp;
186
0
    gs_font_base *const pbfont = (gs_font_base *) pfont;
187
0
    gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont;
188
0
    const gs_type1_data *pdata;
189
0
    gs_type1exec_state cxs;
190
0
    gs_type1_state *const pcis = &cxs.cis;
191
0
    gs_rect FontBBox = pfont1->FontBBox;
192
0
    int code;
193
194
0
    if (penum->current_font->FontType == ft_CID_encrypted) {
195
0
        if (FontBBox.q.x <= FontBBox.p.x && FontBBox.q.y <= FontBBox.p.y) {
196
0
            gs_font_cid0 *pfcid0 = (gs_font_cid0 *)penum->current_font;
197
198
0
            FontBBox = pfcid0->FontBBox;
199
0
        }
200
0
    }
201
202
0
    pdata = &pfont1->data;
203
    /*
204
     * Any reasonable implementation would execute something like
205
     *    1 setmiterlimit 0 setlinejoin 0 setlinecap
206
     * here, but the Adobe implementations don't.
207
     *
208
     * If this is a stroked font, set the stroke width.
209
     */
210
0
    if (pfont->PaintType)
211
0
        gs_setlinewidth(igs, pfont->StrokeWidth);
212
0
    check_estack(3);   /* for continuations */
213
    /*
214
     * Execute the definition of the character.
215
     */
216
0
    if (r_is_proc(op))
217
0
        return zchar_exec_char_proc(i_ctx_p);
218
    /*
219
     * The definition must be a Type 1 CharString.
220
     * Note that we do not require read access: this is deliberate.
221
     */
222
0
    check_type(*op, t_string);
223
0
    if (r_size(op) <= max(pdata->lenIV, 0))
224
0
        return_error(gs_error_invalidfont);
225
    /*
226
     * In order to make character oversampling work, we must
227
     * set up the cache before calling .type1addpath.
228
     * To do this, we must get the bounding box from the FontBBox,
229
     * and the width from the CharString or the Metrics.
230
     * If the FontBBox isn't valid, we can't do any of this.
231
     */
232
233
0
    if ((penum->FontBBox_as_Metrics2.x == 0 &&
234
0
         penum->FontBBox_as_Metrics2.y == 0) ||
235
0
        gs_rootfont(igs)->WMode == 0 ) {
236
0
        code = zchar_get_metrics(pbfont, op - 1, cxs.sbw);
237
0
        if (code < 0)
238
0
            return code;
239
0
        cxs.present = code;
240
0
        cxs.use_FontBBox_as_Metrics2 = false;
241
0
    }  else {  /* pass here if FontType==9,11 && WMode==1*/
242
0
        cxs.sbw[0] = penum->FontBBox_as_Metrics2.x / 2;
243
0
        cxs.sbw[1] = penum->FontBBox_as_Metrics2.y;
244
0
        cxs.sbw[2] = 0;
245
0
        cxs.sbw[3] = -penum->FontBBox_as_Metrics2.x; /* Sic! */
246
0
        cxs.use_FontBBox_as_Metrics2 = true;
247
0
        cxs.present = metricsNone;
248
0
    }
249
    /* Establish a current point. */
250
0
    code = gs_moveto(igs, 0.0, 0.0);
251
0
    if (code < 0)
252
0
        return code;
253
0
    code = type1_exec_init(pcis, penum, igs, pfont1);
254
0
    if (code < 0)
255
0
        return code;
256
0
    gs_type1_set_callback_data(pcis, &cxs);
257
0
    if (FontBBox.q.x > FontBBox.p.x &&
258
0
        FontBBox.q.y > FontBBox.p.y
259
0
        ) {
260
        /* The FontBBox appears to be valid. */
261
0
        op_proc_t exec_cont = 0;
262
263
0
        cxs.char_bbox = pfont1->FontBBox;
264
0
        code = type1exec_bbox(i_ctx_p, penum, &cxs, pfont, &exec_cont);
265
0
        if (code >= 0 && exec_cont != 0)
266
0
            code = (*exec_cont)(i_ctx_p);
267
0
        return code;
268
0
    } else {
269
        /* The FontBBox is not valid */
270
0
        const ref *opstr = op;
271
0
        ref other_subr;
272
0
        const gs_matrix * pctm = &ctm_only(igs);
273
274
        /* First, check for singular CTM */
275
0
        if (pctm->xx * pctm->yy == pctm->xy * pctm->yx) {
276
           /* The code below won't be able to find the FontBBox but we
277
            * don't need it anyway. Set an empty box and consider it valid.
278
            */
279
0
            op_proc_t exec_cont = 0;
280
281
0
            cxs.char_bbox.p.x = 0;
282
0
            cxs.char_bbox.p.y = 0;
283
0
            cxs.char_bbox.q.x = 0;
284
0
            cxs.char_bbox.q.y = 0;
285
0
            code = type1exec_bbox(i_ctx_p, penum, &cxs, pfont, &exec_cont);
286
0
            if (code >= 0 && exec_cont != 0)
287
0
                code = (*exec_cont)(i_ctx_p);
288
0
            return code;
289
0
        }
290
        /* Now we create the path first, then do the setcachedevice.
291
         * If we are oversampling (in this case, only for anti-
292
         * aliasing, not just to improve quality), we have to
293
         * create the path twice, since we can't know the
294
         * oversampling factor until after setcachedevice.
295
         */
296
0
        switch (cxs.present) {
297
0
            case metricsSideBearingAndWidth: {
298
0
                gs_point pt;
299
300
0
                pt.x = cxs.sbw[0], pt.y = cxs.sbw[1];
301
0
                gs_type1_set_lsb(pcis, &pt);
302
0
            }
303
            /* fall through */
304
0
            case metricsWidthOnly: {
305
0
                gs_point pt;
306
307
0
                pt.x = cxs.sbw[2], pt.y = cxs.sbw[3];
308
0
                gs_type1_set_width(pcis, &pt);
309
0
            }
310
0
        }
311
312
        /* Continue interpreting. */
313
0
      icont:
314
0
        code = type1_continue_dispatch(i_ctx_p, &cxs, opstr, &other_subr, 4);
315
0
        op = osp;   /* OtherSubrs might change it */
316
0
        switch (code) {
317
0
            case 0:   /* all done */
318
0
                return nobbox_finish(i_ctx_p, &cxs);
319
0
            default:    /* code < 0, error */
320
0
                return code;
321
0
            case type1_result_callothersubr: /* unknown OtherSubr */
322
0
                return type1_call_OtherSubr(i_ctx_p, &cxs, nobbox_continue,
323
0
                                            &other_subr);
324
0
            case type1_result_sbw: /* [h]sbw, just continue */
325
0
                switch (cxs.present) {
326
0
                    case metricsNone:
327
0
                        cxs.sbw[0] = fixed2float(pcis->lsb.x);
328
0
                        cxs.sbw[1] = fixed2float(pcis->lsb.y);
329
                    /* fall through */
330
0
                    case metricsWidthOnly:
331
0
                        cxs.sbw[2] = fixed2float(pcis->width.x);
332
0
                        cxs.sbw[3] = fixed2float(pcis->width.y);
333
0
                }
334
0
                opstr = 0;
335
0
                goto icont;
336
0
        }
337
0
    }
338
0
}
339
340
int
341
charstring_execchar(i_ctx_t *i_ctx_p, int font_type_mask)
342
0
{
343
0
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
344
0
    gs_font *pfont;
345
0
    os_ptr op = osp;
346
0
    int code = font_param(op - 3, &pfont);
347
348
0
    if (code < 0)
349
0
        return code;
350
0
    if (penum == 0 ||
351
0
        pfont->FontType >= sizeof(font_type_mask) * 8 ||
352
0
        !(font_type_mask & (1 << (int)pfont->FontType)))
353
0
        return_error(gs_error_undefined);
354
0
    code = charstring_execchar_aux(i_ctx_p, penum, pfont);
355
0
    if (code < 0 && igs->in_cachedevice == CACHE_DEVICE_CACHING) {
356
        /* Perform the cache cleanup, when the cached character data
357
           has been allocated (gx_alloc_char_bits) but
358
           the character has not been added to the cache (gx_add_cached_char)
359
           due to a falure in the character renderer.
360
         */
361
0
        gs_show_enum *const penum_s = (gs_show_enum *)penum;
362
363
0
        if (penum_s->cc != NULL) {
364
0
            gx_free_cached_char(pfont->dir, penum_s->cc);
365
0
            penum_s->cc = NULL;
366
0
        }
367
0
    }
368
0
    return code;
369
0
}
370
371
/* -------- bbox case -------- */
372
373
/* Do all the work for the case where we have a bounding box. */
374
/* Returns exec_cont - a function, which must be called by caller after this function. */
375
static int
376
type1exec_bbox(i_ctx_t *i_ctx_p, gs_text_enum_t *penum, gs_type1exec_state * pcxs,
377
               gs_font * pfont, op_proc_t *exec_cont)
378
0
{
379
0
    os_ptr op = osp;
380
0
    gs_type1_state *const pcis = &pcxs->cis;
381
0
    gs_font_base *const pbfont = (gs_font_base *) pfont;
382
0
    op_proc_t cont = (pbfont->PaintType == 0 && penum->orig_font->PaintType == 0
383
0
                        ? bbox_finish_fill : bbox_finish_stroke);
384
0
    ref *pcdevproc;
385
386
    /*
387
     * We appear to have a valid bounding box.  If we don't have Metrics for
388
     * this character, start interpreting the CharString; do the
389
     * setcachedevice as soon as we know the (side bearing and) width.
390
     */
391
0
    if ((pcxs->present == metricsNone && !pcxs->use_FontBBox_as_Metrics2) ||
392
0
         (penum->orig_font->WMode && zchar_get_CDevProc(pbfont, &pcdevproc))) {
393
        /* Get the width from the CharString,
394
         * then set the cache device. */
395
        /* We pass here when WMode==1 and the font has CDevProc,
396
         * because we do need sbw as CDevProc's argument.
397
         * A more natural way would be not setting pcxs->use_FontBBox_as_Metrics2
398
         * when the font has CDevProc, except for missing sbw in the glyph.
399
         * We prefer to pass here because we've got examples
400
         * of Tyoe 1 fonts with empty glyphs, i.e. with no sbw,
401
         * so we don't want to assume that they'll never appear in a CID font.
402
         * In that case penum->FontBBox_as_Metrics2 will go here to zchar_set_cache. */
403
0
        ref cnref;
404
0
        ref other_subr;
405
0
        int code;
406
407
        /* Since an OtherSubr callout might change osp, */
408
        /* save the character name now. */
409
0
        ref_assign(&cnref, op - 1);
410
0
        code = type1_continue_dispatch(i_ctx_p, pcxs, op, &other_subr, 4);
411
0
        op = osp;   /* OtherSubrs might change it */
412
0
        switch (code) {
413
0
            default:    /* code < 0 or done, error */
414
0
                return ((code < 0 ? code :
415
0
                         gs_note_error(gs_error_invalidfont)));
416
0
            case type1_result_callothersubr: /* unknown OtherSubr */
417
0
                return type1_call_OtherSubr(i_ctx_p, pcxs,
418
0
                                            bbox_getsbw_continue,
419
0
                                            &other_subr);
420
0
            case type1_result_sbw: /* [h]sbw, done */
421
0
                break;
422
0
        }
423
0
        type1_cis_get_metrics(pcis, pcxs->sbw);
424
0
        return zchar_set_cache(i_ctx_p, pbfont, &cnref,
425
0
                               NULL, pcxs->sbw + 2,
426
0
                               &pcxs->char_bbox,
427
0
                               cont, exec_cont, NULL);
428
0
    } else {
429
        /* We have the width and bounding box: */
430
        /* set up the cache device now. */
431
0
        return zchar_set_cache(i_ctx_p, pbfont, op - 1,
432
0
                               (pcxs->present == metricsSideBearingAndWidth
433
0
                                && !pcxs->use_FontBBox_as_Metrics2 ?
434
0
                                pcxs->sbw : NULL),
435
0
                               pcxs->sbw + 2,
436
0
                               &pcxs->char_bbox,
437
0
                               cont, exec_cont,
438
0
                               (pcxs->use_FontBBox_as_Metrics2 ? pcxs->sbw : NULL));
439
0
    }
440
0
}
441
442
/* Continue from an OtherSubr callout while getting metrics. */
443
static int
444
bbox_getsbw_continue(i_ctx_t *i_ctx_p)
445
0
{
446
0
    os_ptr op = osp;
447
0
    ref other_subr;
448
0
    gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
449
0
    gs_type1_state *const pcis = &pcxs->cis;
450
0
    int code;
451
452
0
    code = type1_continue_dispatch(i_ctx_p, pcxs, NULL, &other_subr, 4);
453
0
    op = osp;     /* in case z1_push/pop_proc was called */
454
0
    switch (code) {
455
0
        default:    /* code < 0 or done, error */
456
0
            op_type1_free(i_ctx_p);
457
0
            return ((code < 0 ? code : gs_note_error(gs_error_invalidfont)));
458
0
        case type1_result_callothersubr: /* unknown OtherSubr */
459
0
            return type1_push_OtherSubr(i_ctx_p, pcxs, bbox_getsbw_continue,
460
0
                                        &other_subr);
461
0
        case type1_result_sbw: { /* [h]sbw, done */
462
0
            double sbw[4];
463
0
            const gs_font_base *const pbfont =
464
0
                (const gs_font_base *)pcis->pfont;
465
0
            gs_rect bbox;
466
0
            op_proc_t cont = (pbfont->PaintType == 0 ? bbox_finish_fill : bbox_finish_stroke), exec_cont = 0;
467
468
            /* Get the metrics before freeing the state. */
469
0
            type1_cis_get_metrics(pcis, sbw);
470
0
            bbox = pcxs->char_bbox;
471
0
            op_type1_free(i_ctx_p);
472
0
            code = zchar_set_cache(i_ctx_p, pbfont, op - 1, sbw, sbw + 2, &bbox,
473
0
                                   cont, &exec_cont, NULL);
474
0
            if (code >= 0 && exec_cont != 0)
475
0
                code = (*exec_cont)(i_ctx_p);
476
0
            return code;
477
0
        }
478
0
    }
479
0
}
480
481
/* <font> <code|name> <name> <charstring> <sbx> <sby> %bbox_{fill|stroke} - */
482
/* <font> <code|name> <name> <charstring> %bbox_{fill|stroke} - */
483
static int bbox_finish(i_ctx_t *i_ctx_p, op_proc_t cont, op_proc_t *exec_cont);
484
static int
485
bbox_finish_fill(i_ctx_t *i_ctx_p)
486
0
{
487
0
    op_proc_t exec_cont = 0;
488
0
    int code;
489
490
0
    code = bbox_finish(i_ctx_p, bbox_fill, &exec_cont);
491
0
    if (code >= 0 && exec_cont != 0)
492
0
        code = exec_cont(i_ctx_p);
493
0
    return code;
494
0
}
495
static int
496
bbox_finish_stroke(i_ctx_t *i_ctx_p)
497
0
{
498
0
    op_proc_t exec_cont = 0;
499
0
    int code;
500
501
0
    code = bbox_finish(i_ctx_p, bbox_stroke, &exec_cont);
502
0
    if (code >= 0 && exec_cont != 0)
503
0
        code = exec_cont(i_ctx_p);
504
0
    return code;
505
0
}
506
507
static int
508
bbox_finish(i_ctx_t *i_ctx_p, op_proc_t cont, op_proc_t *exec_cont)
509
0
{   /* Returns exec_cont - a function, which must be called by caller after this function. */
510
0
    os_ptr op = osp;
511
0
    gs_font *pfont;
512
0
    int code;
513
0
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
514
0
    gs_type1exec_state cxs; /* stack allocate to avoid sandbars */
515
0
    gs_type1_state *const pcis = &cxs.cis;
516
0
    double sbxy[2];
517
0
    gs_point sbpt;
518
0
    gs_point *psbpt = 0;
519
0
    os_ptr opc = op;
520
0
    const ref *opstr;
521
0
    ref other_subr;
522
523
0
    if (!r_has_type(opc, t_string)) {
524
0
        check_op(3);
525
0
        code = num_params(op, 2, sbxy);
526
0
        if (code < 0)
527
0
            return code;
528
0
        sbpt.x = sbxy[0];
529
0
        sbpt.y = sbxy[1];
530
0
        psbpt = &sbpt;
531
0
        opc -= 2;
532
0
        check_type(*opc, t_string);
533
0
    }
534
0
    code = font_param(opc - 3, &pfont);
535
0
    if (code < 0)
536
0
        return code;
537
0
    if (penum == 0 || !font_uses_charstrings(pfont))
538
0
        return_error(gs_error_undefined);
539
0
    {
540
0
        gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont;
541
0
        int lenIV = pfont1->data.lenIV;
542
543
0
        if (lenIV > 0 && r_size(opc) <= lenIV)
544
0
            return_error(gs_error_invalidfont);
545
0
        check_estack(5); /* in case we need to do a callout */
546
0
        code = type1_exec_init(pcis, penum, igs, pfont1);
547
0
        if (code < 0)
548
0
            return code;
549
0
        if (psbpt)
550
0
            gs_type1_set_lsb(pcis, psbpt);
551
0
    }
552
0
    opstr = opc;
553
0
  icont:
554
0
    code = type1_continue_dispatch(i_ctx_p, &cxs, opstr, &other_subr,
555
0
                                   (psbpt ? 6 : 4));
556
0
    op = osp;   /* OtherSubrs might have altered it */
557
0
    switch (code) {
558
0
        case 0:   /* all done */
559
            /* Call the continuation now. */
560
0
            if (psbpt)
561
0
                ref_stack_pop(&o_stack, 2);
562
0
            *exec_cont = cont;
563
0
            return 0;
564
0
        case type1_result_callothersubr: /* unknown OtherSubr */
565
0
            push_op_estack(cont); /* call later */
566
0
            return type1_call_OtherSubr(i_ctx_p, &cxs, bbox_continue,
567
0
                                        &other_subr);
568
0
        case type1_result_sbw: /* [h]sbw, just continue */
569
0
            opstr = 0;
570
0
            goto icont;
571
0
        default:    /* code < 0, error */
572
0
            return code;
573
0
    }
574
0
}
575
576
static int
577
bbox_continue(i_ctx_t *i_ctx_p)
578
0
{
579
0
    os_ptr op = osp;
580
0
    int npop = (r_has_type(op, t_string) ? 4 : 6);
581
0
    int code = type1_callout_dispatch(i_ctx_p, bbox_continue, npop);
582
583
0
    if (code == 0) {
584
0
        op = osp;   /* OtherSubrs might have altered it */
585
0
        npop -= 4;    /* nobbox_fill/stroke handles the rest */
586
0
        pop(npop);
587
0
        op -= npop;
588
0
        op_type1_free(i_ctx_p);
589
0
    }
590
0
    return code;
591
0
}
592
593
/*
594
 * Check the path against FontBBox before drawing.  The original operands
595
 * of type1execchar are still on the o-stack.
596
 * Returns exec_cont - a function, which must be called by caller after this function.
597
 */
598
static int
599
bbox_draw(i_ctx_t *i_ctx_p, int (*draw)(gs_gstate *), op_proc_t *exec_cont)
600
0
{
601
0
    os_ptr op = osp;
602
0
    gs_rect bbox;
603
0
    gs_font *pfont;
604
0
    gs_text_enum_t *penum;
605
0
    gs_font_base * pbfont;
606
0
    gs_font_type1 * pfont1;
607
0
    gs_type1exec_state cxs;
608
0
    int code;
609
610
0
    if (igs->in_cachedevice < 2) /* not caching */
611
0
        return nobbox_draw(i_ctx_p, draw);
612
0
    if ((code = font_param(op - 3, &pfont)) < 0)
613
0
        return code;
614
0
    penum = op_show_find(i_ctx_p);
615
0
    if (penum == 0 || !font_uses_charstrings(pfont))
616
0
        return_error(gs_error_undefined);
617
0
    if ((code = gs_pathbbox(igs, &bbox)) < 0) {
618
        /*
619
         * If the matrix is singular, all user coordinates map onto a
620
         * straight line.  Don't bother rendering the character at all.
621
         */
622
0
        if (code == gs_error_undefinedresult) {
623
0
            pop(4);
624
0
            gs_newpath(igs);
625
0
            return 0;
626
0
        }
627
0
        return code;
628
0
    }
629
0
    if (draw == gs_stroke) {
630
        /* Expand the bounding box by the line width. */
631
0
        float width = gs_currentlinewidth(igs) * 1.41422;
632
633
0
        bbox.p.x -= width, bbox.p.y -= width;
634
0
        bbox.q.x += width, bbox.q.y += width;
635
0
    }
636
0
    pbfont = (gs_font_base *)pfont;
637
0
    if (rect_within(bbox, pbfont->FontBBox)) /* within bounds */
638
0
        return nobbox_draw(i_ctx_p, draw);
639
    /* Enlarge the FontBBox to save work in the future. */
640
0
    rect_merge(pbfont->FontBBox, bbox);
641
    /* Dismantle everything we've done, and start over. */
642
0
    gs_text_retry(penum);
643
0
    pfont1 = (gs_font_type1 *) pfont;
644
0
    if ((penum->FontBBox_as_Metrics2.x == 0 &&
645
0
         penum->FontBBox_as_Metrics2.y == 0) ||
646
0
        gs_rootfont(igs)->WMode == 0 ) {
647
0
        code = zchar_get_metrics(pbfont, op - 1, cxs.sbw);
648
0
        if (code < 0)
649
0
            return code;
650
0
        cxs.present = code;
651
0
        cxs.use_FontBBox_as_Metrics2 = false;
652
0
    }  else {
653
0
        cxs.sbw[0] = penum->FontBBox_as_Metrics2.x / 2;
654
0
        cxs.sbw[1] = penum->FontBBox_as_Metrics2.y;
655
0
        cxs.sbw[2] = 0;
656
0
        cxs.sbw[3] = -penum->FontBBox_as_Metrics2.x; /* Sic! */
657
0
        cxs.use_FontBBox_as_Metrics2 = true;
658
0
        cxs.present = metricsSideBearingAndWidth;
659
0
    }
660
0
    code = type1_exec_init(&cxs.cis, penum, igs, pfont1);
661
0
    if (code < 0)
662
0
        return code;
663
0
    cxs.char_bbox = pfont1->FontBBox;
664
0
    code = type1exec_bbox(i_ctx_p, penum, &cxs, pfont, exec_cont);
665
0
    return code;
666
0
}
667
static int
668
bbox_fill(i_ctx_t *i_ctx_p)
669
0
{
670
0
    op_proc_t exec_cont = 0;
671
0
    int code;
672
673
    /* See above re GS_CHAR_FILL. */
674
0
    code = bbox_draw(i_ctx_p, GS_CHAR_FILL, &exec_cont);
675
0
    if (code >= 0 && exec_cont != 0)
676
0
        code = (*exec_cont)(i_ctx_p);
677
0
    return code;
678
0
}
679
static int
680
bbox_stroke(i_ctx_t *i_ctx_p)
681
0
{
682
0
    op_proc_t exec_cont = 0;
683
0
    int code;
684
685
0
    code = bbox_draw(i_ctx_p, gs_stroke, &exec_cont);
686
0
    if (code >= 0 && exec_cont != 0)
687
0
        code = (*exec_cont)(i_ctx_p);
688
0
    return code;
689
0
}
690
691
/* -------- Common code -------- */
692
693
/* Handle the results of interpreting the CharString. */
694
/* pcref points to a t_string ref. */
695
static int
696
type1_continue_dispatch(i_ctx_t *i_ctx_p, gs_type1exec_state *pcxs,
697
                        const ref * pcref, ref *pos, int num_args)
698
0
{
699
0
    int value;
700
0
    int code;
701
0
    gs_glyph_data_t cs_data;
702
0
    gs_glyph_data_t *pcsd;
703
704
0
    cs_data.memory = imemory;
705
0
    if (pcref == 0) {
706
0
        pcsd = 0;
707
0
    } else {
708
0
        gs_glyph_data_from_string(&cs_data, pcref->value.const_bytes,
709
0
                                  r_size(pcref), NULL);
710
0
        pcsd = &cs_data;
711
0
    }
712
    /*
713
     * Since OtherSubrs may push or pop values on the PostScript operand
714
     * stack, remove the arguments of .type1execchar before calling the
715
     * Type 1 interpreter, and put them back afterwards unless we're
716
     * about to execute an OtherSubr procedure.  Also, we must set up
717
     * the callback data for pushing OtherSubrs arguments.
718
     */
719
0
    pcxs->i_ctx_p = i_ctx_p;
720
0
    pcxs->num_args = num_args;
721
0
    memcpy(pcxs->save_args, osp - (num_args - 1), num_args * sizeof(ref));
722
0
    osp -= num_args;
723
0
    gs_type1_set_callback_data(&pcxs->cis, pcxs);
724
0
    code = pcxs->cis.pfont->data.interpret(&pcxs->cis, pcsd, &value);
725
0
    switch (code) {
726
0
        case type1_result_callothersubr: {
727
            /*
728
             * The Type 1 interpreter handles all known OtherSubrs,
729
             * so this must be an unknown one.
730
             */
731
0
            const font_data *pfdata = pfont_data(gs_currentfont(igs));
732
733
0
            code = array_get(imemory, &pfdata->u.type1.OtherSubrs, (long)value, pos);
734
0
            if (code >= 0)
735
0
                return type1_result_callothersubr;
736
0
        }
737
0
    }
738
    /* Put back the arguments removed above. */
739
0
    memcpy(osp + 1, pcxs->save_args, num_args * sizeof(ref));
740
0
    osp += num_args;
741
0
    return code;
742
0
}
743
744
/*
745
 * Push a continuation, the arguments removed for the OtherSubr, and
746
 * the OtherSubr procedure.
747
 */
748
static int
749
type1_push_OtherSubr(i_ctx_t *i_ctx_p, const gs_type1exec_state *pcxs,
750
                     int (*cont)(i_ctx_t *), const ref *pos)
751
0
{
752
0
    int i, n = pcxs->num_args;
753
754
0
    push_op_estack(cont);
755
    /*
756
     * Push the saved arguments (in reverse order, so they will get put
757
     * back on the operand stack in the correct order) on the e-stack.
758
     */
759
0
    for (i = n; --i >= 0; ) {
760
0
        *++esp = pcxs->save_args[i];
761
0
        r_clear_attrs(esp, a_executable);  /* just in case */
762
0
    }
763
0
    ++esp;
764
0
    *esp = *pos;
765
0
    return o_push_estack;
766
0
}
767
768
/*
769
 * Do a callout to an OtherSubr implemented in PostScript.
770
 * The caller must have done a check_estack(4 + num_args).
771
 */
772
static int
773
type1_call_OtherSubr(i_ctx_t *i_ctx_p, const gs_type1exec_state * pcxs,
774
                     int (*cont) (i_ctx_t *),
775
                     const ref * pos)
776
0
{
777
    /* Move the Type 1 interpreter state to the heap. */
778
0
    gs_type1exec_state *hpcxs =
779
0
        ialloc_struct(gs_type1exec_state, &st_gs_type1exec_state,
780
0
                      "type1_call_OtherSubr");
781
782
0
    if (hpcxs == 0)
783
0
        return_error(gs_error_VMerror);
784
0
    *hpcxs = *pcxs;
785
0
    gs_type1_set_callback_data(&hpcxs->cis, hpcxs);
786
0
    push_mark_estack(es_show, op_type1_cleanup);
787
0
    ++esp;
788
0
    make_istruct(esp, 0, hpcxs);
789
0
    return type1_push_OtherSubr(i_ctx_p, pcxs, cont, pos);
790
0
}
791
792
/* Continue from an OtherSubr callout while building the path. */
793
static int
794
type1_callout_dispatch(i_ctx_t *i_ctx_p, int (*cont)(i_ctx_t *),
795
                       int num_args)
796
0
{
797
0
    ref other_subr;
798
0
    gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
799
0
    int code;
800
801
0
  icont:
802
0
    code = type1_continue_dispatch(i_ctx_p, pcxs, NULL, &other_subr,
803
0
                                   num_args);
804
0
    switch (code) {
805
0
        case 0:   /* callout done, cont is on e-stack */
806
0
            return 0;
807
0
        default:    /* code < 0 or done, error */
808
0
            op_type1_free(i_ctx_p);
809
0
            return ((code < 0 ? code : gs_note_error(gs_error_invalidfont)));
810
0
        case type1_result_callothersubr: /* unknown OtherSubr */
811
0
            return type1_push_OtherSubr(i_ctx_p, pcxs, cont, &other_subr);
812
0
        case type1_result_sbw: /* [h]sbw, just continue */
813
0
            goto icont;
814
0
    }
815
0
}
816
817
/* Clean up after a Type 1 callout. */
818
static int
819
op_type1_cleanup(i_ctx_t *i_ctx_p)
820
0
{
821
0
    ifree_object(r_ptr(esp + 2, void), "op_type1_cleanup");
822
0
    return 0;
823
0
}
824
static void
825
op_type1_free(i_ctx_t *i_ctx_p)
826
0
{
827
0
    ifree_object(r_ptr(esp, void), "op_type1_free");
828
    /*
829
     * In order to avoid popping from the e-stack and then pushing onto
830
     * it, which would violate an interpreter invariant, we simply
831
     * overwrite the two e-stack items being discarded (hpcxs and the
832
     * cleanup operator) with empty procedures.
833
     */
834
0
    make_empty_const_array(esp - 1, a_readonly + a_executable);
835
0
    make_empty_const_array(esp, a_readonly + a_executable);
836
0
}
837
838
/* -------- no-bbox case -------- */
839
840
static int
841
nobbox_continue(i_ctx_t *i_ctx_p)
842
0
{
843
0
    int code = type1_callout_dispatch(i_ctx_p, nobbox_continue, 4);
844
845
0
    if (code)
846
0
        return code;
847
0
    {
848
0
        gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
849
0
        gs_type1exec_state cxs;
850
851
0
        cxs = *pcxs;
852
0
        gs_type1_set_callback_data(&cxs.cis, &cxs);
853
0
        op_type1_free(i_ctx_p);
854
0
        return nobbox_finish(i_ctx_p, &cxs);
855
0
    }
856
0
}
857
858
/* Finish the no-FontBBox case after constructing the path. */
859
/* If we are oversampling for anti-aliasing, we have to go around again. */
860
/* <font> <code|name> <name> <charstring> %nobbox_continue - */
861
static int
862
nobbox_finish(i_ctx_t *i_ctx_p, gs_type1exec_state * pcxs)
863
0
{
864
0
    os_ptr op = osp;
865
0
    int code;
866
0
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
867
0
    gs_font *pfont;
868
869
0
    if ((code = gs_pathbbox(igs, &pcxs->char_bbox)) < 0 ||
870
0
        (code = font_param(op - 3, &pfont)) < 0
871
0
        )
872
0
        return code;
873
0
    if (penum == 0 || !font_uses_charstrings(pfont))
874
0
        return_error(gs_error_undefined);
875
0
    {
876
0
        gs_font_base *const pbfont = (gs_font_base *) pfont;
877
0
        gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont;
878
0
        op_proc_t cont, exec_cont = 0;
879
880
0
        if (pcxs->present == metricsNone) {
881
0
            gs_point endpt;
882
883
0
            if ((code = gs_currentpoint(igs, &endpt)) < 0)
884
0
                return code;
885
0
            pcxs->sbw[2] = endpt.x, pcxs->sbw[3] = endpt.y;
886
0
            pcxs->present = metricsSideBearingAndWidth;
887
0
        }
888
        /*
889
         * We only need to rebuild the path from scratch if we might
890
         * oversample for anti-aliasing.
891
         */
892
0
        if ((*dev_proc(igs->device, get_alpha_bits))(igs->device, go_text) > 1
893
0
            ) {
894
0
            gs_newpath(igs);
895
0
            gs_moveto(igs, 0.0, 0.0);
896
0
            code = type1_exec_init(&pcxs->cis, penum, igs, pfont1);
897
0
            if (code < 0)
898
0
                return code;
899
0
            code = type1exec_bbox(i_ctx_p, penum, pcxs, pfont, &exec_cont);
900
0
        } else {
901
0
            cont = (pbfont->PaintType == 0 && penum->orig_font->PaintType == 0
902
0
                        ? nobbox_fill : nobbox_stroke);
903
0
            exec_cont = 0;
904
0
            code = zchar_set_cache(i_ctx_p, pbfont, op - 1, NULL,
905
0
                                   pcxs->sbw + 2,
906
0
                                   &pcxs->char_bbox,
907
0
                                   cont, &exec_cont,
908
0
                                   (pcxs->use_FontBBox_as_Metrics2 ? pcxs->sbw : NULL));
909
0
        }
910
0
        if (code >= 0 && exec_cont != 0)
911
0
            code = (*exec_cont)(i_ctx_p);
912
0
        return code;
913
0
    }
914
0
}
915
/* Finish by popping the operands and filling or stroking. */
916
static int
917
nobbox_draw(i_ctx_t *i_ctx_p, int (*draw)(gs_gstate *))
918
0
{
919
0
    int code = draw(igs);
920
921
0
    if (code >= 0)
922
0
        pop(4);
923
0
    return code;
924
0
}
925
static int
926
nobbox_fill(i_ctx_t *i_ctx_p)
927
0
{
928
    /* See above re GS_CHAR_FILL. */
929
0
    return nobbox_draw(i_ctx_p, GS_CHAR_FILL);
930
0
}
931
static int
932
nobbox_stroke(i_ctx_t *i_ctx_p)
933
0
{
934
    /* As a compatibility to Adobe, use the exact "StrokeWidth".
935
       Reset fill_adjust for that. */
936
0
    int code;
937
0
    gs_fixed_point fa = i_ctx_p->pgs->fill_adjust;
938
939
0
    i_ctx_p->pgs->fill_adjust.x = i_ctx_p->pgs->fill_adjust.y = 0;
940
0
    code = nobbox_draw(i_ctx_p, gs_stroke);
941
0
    i_ctx_p->pgs->fill_adjust = fa;
942
0
    return code;
943
0
}
944
945
/* <font> <array> setweightvector -
946
 * setweightvector is an undocumented procedure that force writes
947
 * weight vector to the font.
948
 */
949
static int
950
zsetweightvector(i_ctx_t *i_ctx_p)
951
0
{
952
0
    os_ptr op = osp;
953
0
    gs_font *pfont;
954
0
    int code = font_param(op - 1, &pfont);
955
0
    gs_font_type1 *pfont1;
956
0
    int size;
957
0
    float wv[max_WeightVector];
958
959
0
    if (code < 0) {
960
        /* The font was not defined yet. Just ignore. See lib/gs_type1.ps . */
961
0
        pop(2);
962
0
        return 0;
963
0
    }
964
0
    if (!r_is_array(op)) {
965
0
        return_error(gs_error_typecheck);
966
0
    }
967
0
    if (pfont->FontType != ft_encrypted && pfont->FontType != ft_encrypted2)
968
0
        return_error(gs_error_invalidfont);
969
0
    pfont1 = (gs_font_type1 *)pfont;
970
0
    size = r_size(op);
971
0
    if (size != pfont1->data.WeightVector.count)
972
0
        return_error(gs_error_invalidfont);
973
974
    /* We know op - 1 is a dictionary because of font_param() above */
975
0
    if ((code = idict_put_string_copy(op - 1, "WeightVector", op)) < 0)
976
0
        return code;
977
978
0
    code = process_float_array(imemory, op, size, wv);
979
0
    if (code < 0)
980
0
        return code;
981
0
    if (memcmp(wv, pfont1->data.WeightVector.values,
982
0
        sizeof(pfont1->data.WeightVector.values[0]) * size) != 0) {
983
0
        memcpy(pfont1->data.WeightVector.values, wv, size);
984
0
        gs_purge_font_from_char_caches_completely(pfont);
985
0
    }
986
0
    pop(2);
987
0
    return 0;
988
0
}
989
990
/* ------ Initialization procedure ------ */
991
992
const op_def zchar1_op_defs[] =
993
{
994
    {"4.type1execchar", ztype1execchar},
995
                /* Internal operators */
996
    {"4%bbox_getsbw_continue", bbox_getsbw_continue},
997
    {"4%bbox_continue", bbox_continue},
998
    {"4%bbox_finish_fill", bbox_finish_fill},
999
    {"4%bbox_finish_stroke", bbox_finish_stroke},
1000
    {"4%nobbox_continue", nobbox_continue},
1001
    {"4%nobbox_fill", nobbox_fill},
1002
    {"4%nobbox_stroke", nobbox_stroke},
1003
    {"4.setweightvector", zsetweightvector},
1004
    op_def_end(0)
1005
};
1006
1007
/* ------ Auxiliary procedures for type 1 fonts ------ */
1008
1009
static int
1010
z1_glyph_data(gs_font_type1 * pfont, gs_glyph glyph, gs_glyph_data_t *pgd)
1011
6.36M
{
1012
6.36M
    ref gref;
1013
1014
6.36M
    glyph_ref(pfont->memory, glyph, &gref);
1015
6.36M
    return zchar_charstring_data((gs_font *)pfont, &gref, pgd);
1016
6.36M
}
1017
1018
static int
1019
z1_subr_data(gs_font_type1 * pfont, int index, bool global,
1020
             gs_glyph_data_t *pgd)
1021
3.07M
{
1022
3.07M
    const font_data *pfdata = pfont_data(pfont);
1023
3.07M
    ref subr;
1024
3.07M
    int code;
1025
1026
3.07M
    code = array_get(pfont->memory, (global ? &pfdata->u.type1.GlobalSubrs :
1027
3.07M
                      &pfdata->u.type1.Subrs),
1028
3.07M
                     index, &subr);
1029
3.07M
    if (code < 0)
1030
11.4k
        return code;
1031
3.07M
    check_type_only(subr, t_string);
1032
3.06M
    gs_glyph_data_from_string(pgd, subr.value.const_bytes, r_size(&subr),
1033
3.06M
                              NULL);
1034
3.06M
    return 0;
1035
3.06M
}
1036
1037
static int
1038
z1_seac_data(gs_font_type1 *pfont, int ccode, gs_glyph *pglyph,
1039
             gs_const_string *gstr, gs_glyph_data_t *pgd)
1040
0
{
1041
0
    gs_glyph glyph = gs_c_known_encode((gs_char)ccode,
1042
0
                                       ENCODING_INDEX_STANDARD);
1043
0
    int code;
1044
0
    ref rglyph;
1045
1046
0
    if (glyph == GS_NO_GLYPH)
1047
0
        return_error(gs_error_rangecheck);
1048
0
    if ((code = gs_c_glyph_name(glyph, gstr)) < 0 ||
1049
0
        (code = name_ref(pfont->memory, gstr->data, gstr->size, &rglyph, 0)) < 0
1050
0
        )
1051
0
        return code;
1052
0
    if (pglyph)
1053
0
        *pglyph = name_index(pfont->memory, &rglyph);
1054
0
    if (pgd)
1055
0
        code = zchar_charstring_data((gs_font *)pfont, &rglyph, pgd);
1056
0
    return code;
1057
0
}
1058
1059
static int
1060
z1_push(void *callback_data, const fixed * pf, int count)
1061
0
{
1062
0
    gs_type1exec_state *pcxs = callback_data;
1063
0
    i_ctx_t *i_ctx_p = pcxs->i_ctx_p;
1064
0
    const fixed *p = pf + count - 1;
1065
0
    int i;
1066
1067
0
    check_ostack(count);
1068
0
    for (i = 0; i < count; i++, p--) {
1069
0
        osp++;
1070
0
        make_real(osp, fixed2float(*p));
1071
0
    }
1072
0
    return 0;
1073
0
}
1074
1075
static int
1076
z1_pop(void *callback_data, fixed * pf)
1077
0
{
1078
0
    gs_type1exec_state *pcxs = callback_data;
1079
0
    i_ctx_t *i_ctx_p = pcxs->i_ctx_p;
1080
0
    double val;
1081
0
    int code = real_param(osp, &val);
1082
1083
0
    if (code < 0)
1084
0
        return code;
1085
0
    *pf = float2fixed(val);
1086
0
    osp--;
1087
0
    return 0;
1088
0
}
1089
1090
/* Define the Type 1 procedure vector. */
1091
const gs_type1_data_procs_t z1_data_procs = {
1092
    z1_glyph_data, z1_subr_data, z1_seac_data, z1_push, z1_pop
1093
};
1094
1095
/* ------ Font procedures for Type 1 fonts ------ */
1096
1097
/*
1098
 * Get a Type 1 or Type 2 glyph outline.  This is the glyph_outline
1099
 * procedure for the font.
1100
 */
1101
int
1102
zchar1_glyph_outline(gs_font *font, int WMode, gs_glyph glyph, const gs_matrix *pmat,
1103
                     gx_path *ppath, double sbw[4])
1104
32
{
1105
32
    gs_font_type1 *const pfont1 = (gs_font_type1 *)font;
1106
32
    ref gref;
1107
32
    gs_glyph_data_t gdata;
1108
32
    int code;
1109
1110
32
    glyph_ref(font->memory, glyph, &gref);
1111
32
    gdata.memory = font->memory;
1112
32
    code = zchar_charstring_data(font, &gref, &gdata);
1113
32
    if (code < 0)
1114
0
        return code;
1115
32
    return zcharstring_outline(pfont1, WMode, &gref, &gdata, pmat, ppath, sbw);
1116
32
}
1117
/*
1118
 * Get a glyph outline given a CharString.  The glyph_outline procedure
1119
 * for CIDFontType 0 fonts uses this.
1120
 */
1121
int
1122
zcharstring_outline(gs_font_type1 *pfont1, int WMode, const ref *pgref,
1123
                    const gs_glyph_data_t *pgd_orig,
1124
                    const gs_matrix *pmat, gx_path *ppath, double sbw[4])
1125
32
{
1126
32
    const gs_glyph_data_t *pgd = pgd_orig;
1127
32
    int code;
1128
32
    gs_type1exec_state cxs;
1129
32
    gs_type1_state *const pcis = &cxs.cis;
1130
32
    const gs_type1_data *pdata;
1131
32
    int value;
1132
32
    gs_gstate gs;
1133
32
    double wv[4];
1134
32
    gs_point mpt;
1135
1136
32
    pdata = &pfont1->data;
1137
32
    if (pgd->bits.size <= max(pdata->lenIV, 0))
1138
0
        return_error(gs_error_invalidfont);
1139
#if 0 /* Ignore CDevProc for now. */
1140
    if (zchar_get_CDevProc((const gs_font_base *)pfont1, &pcdevproc))
1141
        return_error(gs_error_rangecheck); /* can't call CDevProc from here */
1142
#endif
1143
32
    switch (WMode) {
1144
0
    default:
1145
0
        code = zchar_get_metrics2((gs_font_base *)pfont1, pgref, wv);
1146
0
        if (code) {
1147
0
            sbw[0] = wv[2];
1148
0
            sbw[1] = wv[3];
1149
0
            sbw[2] = wv[0];
1150
0
            sbw[3] = wv[1];
1151
0
            break;
1152
0
        }
1153
        /* falls through */
1154
32
    case 0:
1155
32
        code = zchar_get_metrics((gs_font_base *)pfont1, pgref, sbw);
1156
32
    }
1157
32
    if (code < 0)
1158
0
        return code;
1159
32
    cxs.present = code;
1160
    /* Initialize just enough of the imager state. */
1161
32
    if (pmat)
1162
0
        gs_matrix_fixed_from_matrix(&gs.ctm, pmat);
1163
32
    else {
1164
32
        gs_matrix imat;
1165
1166
32
        gs_make_identity(&imat);
1167
32
        gs_matrix_fixed_from_matrix(&gs.ctm, &imat);
1168
32
    }
1169
32
    gs.flatness = 0;
1170
32
    code = gs_type1_interp_init(&cxs.cis, &gs, ppath, NULL, NULL, true, 0,
1171
32
                                pfont1);
1172
32
    if (code < 0)
1173
0
        return code;
1174
32
    cxs.cis.no_grid_fitting = true;
1175
32
    gs_type1_set_callback_data(pcis, &cxs);
1176
32
    switch (cxs.present) {
1177
0
    case metricsSideBearingAndWidth:
1178
0
        mpt.x = sbw[0], mpt.y = sbw[1];
1179
0
        gs_type1_set_lsb(pcis, &mpt);
1180
        /* falls through */
1181
0
    case metricsWidthOnly:
1182
0
        mpt.x = sbw[2], mpt.y = sbw[3];
1183
0
        gs_type1_set_width(pcis, &mpt);
1184
32
    case metricsNone:
1185
32
        ;
1186
32
    }
1187
    /* Continue interpreting. */
1188
64
icont:
1189
64
    code = pfont1->data.interpret(pcis, pgd, &value);
1190
64
    switch (code) {
1191
32
    case 0:   /* all done */
1192
        /* falls through */
1193
32
    default:    /* code < 0, error */
1194
32
        return code;
1195
0
    case type1_result_callothersubr: /* unknown OtherSubr */
1196
0
        return_error(gs_error_rangecheck); /* can't handle it */
1197
32
    case type1_result_sbw: /* [h]sbw, just continue */
1198
32
        type1_cis_get_metrics(pcis, cxs.sbw);
1199
32
        type1_cis_get_metrics(pcis, sbw);
1200
32
        pgd = 0;
1201
32
        goto icont;
1202
64
    }
1203
64
}
1204
1205
/*
1206
 * Redefine glyph_info to take Metrics[2] and CDevProc into account (unless
1207
 * GLYPH_INFO_OUTLINE_WIDTHS is set).  If CDevProc is present, return
1208
 * gs_error_rangecheck, since we can't call the interpreter from here.
1209
 */
1210
int
1211
z1_glyph_info_generic(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
1212
              int members, gs_glyph_info_t *info, font_proc_glyph_info((*proc)), int wmode)
1213
4.81M
{
1214
4.81M
    ref gref;
1215
4.81M
    ref *pcdevproc;
1216
4.81M
    gs_font_base *const pbfont = (gs_font_base *)font;
1217
4.81M
    int width_members = members & (GLYPH_INFO_WIDTH0 << wmode);
1218
4.81M
    int outline_widths = members & GLYPH_INFO_OUTLINE_WIDTHS;
1219
4.81M
    bool modified_widths = false;
1220
4.81M
    int default_members = members & ~(width_members + outline_widths +
1221
4.81M
                                      GLYPH_INFO_VVECTOR0 + GLYPH_INFO_VVECTOR1 +
1222
4.81M
                                      GLYPH_INFO_CDEVPROC);
1223
4.81M
    int done_members = 0;
1224
4.81M
    int code;
1225
1226
4.81M
    if (!width_members)
1227
2.95M
        return (*proc)(font, glyph, pmat, members, info);
1228
1.86M
    if (!outline_widths && zchar_get_CDevProc(pbfont, &pcdevproc)) {
1229
0
        done_members |= GLYPH_INFO_CDEVPROC;
1230
0
        if (members & GLYPH_INFO_CDEVPROC) {
1231
0
            info->members = done_members;
1232
0
            return_error(gs_error_rangecheck);
1233
0
        } else {
1234
            /* Ignore CDevProc. Used to compure MissingWidth.*/
1235
0
        }
1236
0
    }
1237
1.86M
    glyph_ref(pbfont->memory, glyph, &gref);
1238
1.86M
    if (width_members == GLYPH_INFO_WIDTH1) {
1239
0
        double wv[4];
1240
0
        code = zchar_get_metrics2(pbfont, &gref, wv);
1241
0
        if (code > 0) {
1242
0
            modified_widths = true;
1243
0
            info->width[1].x = wv[0];
1244
0
            info->width[1].y = wv[1];
1245
0
            info->v.x = wv[2];
1246
0
            info->v.y = wv[3];
1247
0
            done_members = width_members | GLYPH_INFO_VVECTOR1;
1248
0
            width_members = 0;
1249
0
        }
1250
0
    }
1251
1.86M
    if (width_members) {
1252
1.86M
        double sbw[4];
1253
1.86M
        code = zchar_get_metrics(pbfont, &gref, sbw);
1254
1.86M
        if (code > 0) {
1255
0
            modified_widths = true;
1256
0
            info->width[wmode].x = sbw[2];
1257
0
            info->width[wmode].y = sbw[3];
1258
0
            if (code == metricsSideBearingAndWidth) {
1259
0
                info->v.x = sbw[0];
1260
0
                info->v.y = sbw[1];
1261
0
                width_members |= GLYPH_INFO_VVECTOR0;
1262
0
            } else {
1263
0
                info->v.x = 0;
1264
0
                info->v.y = 0;
1265
0
            }
1266
0
            done_members = width_members;
1267
0
            width_members = 0;
1268
0
        }
1269
1.86M
    }
1270
1271
1.86M
    if (outline_widths) {
1272
48.0k
        if (modified_widths || zchar_get_CDevProc(pbfont, &pcdevproc)) {
1273
            /* Discard the modified widths, but indicate they exist. */
1274
0
            width_members |= done_members;
1275
0
            done_members = outline_widths;
1276
0
        }
1277
48.0k
    }
1278
1.86M
    default_members |= width_members;
1279
1.86M
    if (default_members) {
1280
1.86M
        code = (*proc)(font, glyph, pmat, default_members, info);
1281
1282
1.86M
        if (code < 0)
1283
0
            return code;
1284
1.86M
    } else
1285
0
        info->members = 0;
1286
1.86M
    info->members |= done_members;
1287
1.86M
    return 0;
1288
1.86M
}
1289
1290
int
1291
z1_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
1292
              int members, gs_glyph_info_t *info)
1293
4.81M
{
1294
4.81M
    int wmode = font->WMode;
1295
1296
4.81M
    return z1_glyph_info_generic(font, glyph, pmat, members, info,
1297
4.81M
                                    &gs_type1_glyph_info, wmode);
1298
4.81M
}
1299
1300
/* Get a Type 1 or Type 9 character metrics and set the cache device. */
1301
int
1302
z1_set_cache(i_ctx_t *i_ctx_p, gs_font_base *pbfont, ref *cnref,
1303
            gs_glyph glyph, op_proc_t cont, op_proc_t *exec_cont)
1304
0
{   /* This function is similar to zchar42_set_cache. */
1305
0
    double sbw[4];
1306
0
    gs_glyph_info_t info;
1307
0
    int wmode = gs_rootfont(igs)->WMode;
1308
0
    int code;
1309
0
    gs_matrix id_matrix = { identity_matrix_body };
1310
1311
0
    code = gs_default_glyph_info((gs_font *)pbfont, glyph, &id_matrix,
1312
0
                ((GLYPH_INFO_WIDTH0 | GLYPH_INFO_VVECTOR0) << wmode) | GLYPH_INFO_BBOX,
1313
0
                &info);
1314
0
    if (code < 0)
1315
0
        return code;
1316
0
    sbw[0] = info.v.x;
1317
0
    sbw[1] = info.v.y;
1318
0
    sbw[2] = info.width[wmode].x;
1319
0
    sbw[3] = info.width[wmode].y;
1320
0
    return zchar_set_cache(i_ctx_p, pbfont, cnref, NULL,
1321
0
                           sbw + 2, &info.bbox,
1322
0
                           cont, exec_cont,
1323
0
                           wmode ? sbw : NULL);
1324
0
}