Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/zchar.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
/* Character operators */
18
#include "ghost.h"
19
#include "oper.h"
20
#include "gsstruct.h"
21
#include "gstext.h"
22
#include "gxarith.h"
23
#include "gxfixed.h"
24
#include "gxmatrix.h"   /* for ifont.h */
25
#include "gxdevice.h"   /* for gxfont.h */
26
#include "gxfont.h"
27
#include "gxfont42.h"
28
#include "gxfont0.h"
29
#include "gzstate.h"
30
#include "dstack.h"   /* for stack depth */
31
#include "estack.h"
32
#include "ialloc.h"
33
#include "ichar.h"
34
#include "ichar1.h"
35
#include "idict.h"
36
#include "ifont.h"
37
#include "igstate.h"
38
#include "ilevel.h"
39
#include "iname.h"
40
#include "ipacked.h"
41
#include "store.h"
42
#include "zchar42.h"
43
44
/* Forward references */
45
static bool map_glyph_to_char(const gs_memory_t *mem,
46
                               const ref *, const ref *, ref *);
47
static int finish_show(i_ctx_t *);
48
static int op_show_cleanup(i_ctx_t *);
49
static int op_show_return_width(i_ctx_t *, uint, double *);
50
51
static int zawidthshow(i_ctx_t *i_ctx_p);
52
static int zwidthshow(i_ctx_t *i_ctx_p);
53
54
55
/* <string> show - */
56
static int
57
zshow(i_ctx_t *i_ctx_p)
58
513k
{
59
513k
    es_ptr ep = esp;        /* Save in case of error */
60
513k
    os_ptr op = osp;
61
513k
    gs_text_enum_t *penum = NULL;
62
513k
    int code;
63
64
513k
    check_op(1);
65
513k
    code = op_show_setup(i_ctx_p, op);
66
67
513k
    if (code != 0 ||
68
513k
        (code = gs_show_begin(igs, op->value.bytes, r_size(op), imemory_local, &penum)) < 0)
69
46
        return code;
70
513k
    *(op_proc_t *)&penum->enum_client_data = zshow;
71
513k
    if ((code = op_show_finish_setup(i_ctx_p, penum, 1, finish_show)) < 0) {
72
        /* We must restore the exec stack pointer back to the point where we entered, in case
73
         * we 'retry' the operation (eg having increased the operand stack).
74
         * We'll rely on gc to handle the enumerator.
75
         * Bug #700618.
76
         */
77
0
        esp = ep;
78
0
        return code;
79
0
    }
80
81
513k
    code = op_show_continue_pop(i_ctx_p, 1);
82
513k
    if (code < 0) {
83
        /* We must restore the exec stack pointer back to the point where we entered, in case
84
         * we 'retry' the operation (eg having increased the operand stack).
85
         * We'll rely on gc to handle the enumerator.
86
         * Bug #700618.
87
         */
88
6
        esp = ep;
89
6
    }
90
513k
    return code;
91
513k
}
92
93
/* <ax> <ay> <string> ashow - */
94
static int
95
zashow(i_ctx_t *i_ctx_p)
96
6.97k
{
97
6.97k
    es_ptr ep = esp;        /* Save in case of error */
98
6.97k
    os_ptr op = osp;
99
6.97k
    gs_text_enum_t *penum = NULL;
100
6.97k
    double axy[2];
101
6.97k
    int code;
102
103
6.97k
    check_op(3);
104
6.96k
    code = num_params(op - 1, 2, axy);
105
106
6.96k
    if (code < 0 ||
107
6.94k
        (code = op_show_setup(i_ctx_p, op)) != 0 ||
108
6.93k
        (code = gs_ashow_begin(igs, axy[0], axy[1], op->value.bytes, r_size(op), imemory_local, &penum)) < 0)
109
28
        return code;
110
6.93k
    *(op_proc_t *)&penum->enum_client_data = zashow;
111
6.93k
    if ((code = op_show_finish_setup(i_ctx_p, penum, 3, finish_show)) < 0) {
112
        /* We must restore the exec stack pointer back to the point where we entered, in case
113
         * we 'retry' the operation (eg having increased the operand stack).
114
         * We'll rely on gc to handle the enumerator.
115
         * Bug #700618.
116
         */
117
0
        esp = ep;
118
0
        return code;
119
0
    }
120
6.93k
    code = op_show_continue_pop(i_ctx_p, 3);
121
6.93k
    if (code < 0) {
122
        /* We must restore the exec stack pointer back to the point where we entered, in case
123
         * we 'retry' the operation (eg having increased the operand stack).
124
         * We'll rely on gc to handle the enumerator.
125
         * Bug #700618.
126
         */
127
0
        esp = ep;
128
0
    }
129
6.93k
    return code;
130
6.93k
}
131
132
static int
133
widthshow_aux(i_ctx_t *i_ctx_p, bool single_byte_space)
134
15
{
135
15
    es_ptr ep = esp;        /* Save in case of error */
136
15
    os_ptr op = osp;
137
15
    gs_text_enum_t *penum = NULL;
138
15
    double cxy[2];
139
15
    int code;
140
141
15
    check_op(4);
142
5
    if ((code = op_show_setup(i_ctx_p, op)) != 0 )
143
1
        return code;
144
4
    check_type(op[-1], t_integer);
145
3
    if (gs_currentfont(igs)->FontType == ft_composite) {
146
0
        if ((gs_char) (op[-1].value.intval) != op[-1].value.intval)
147
0
            return_error(gs_error_rangecheck);
148
3
    } else {
149
3
        if (op[-1].value.intval < 0 || op[-1].value.intval > 255)
150
3
            return_error(gs_error_rangecheck); /* per PLRM and CET 13-26 */
151
3
    }
152
0
    if ((code = num_params(op - 2, 2, cxy)) < 0 )
153
0
        return code;
154
0
    if ((code = gs_widthshow_begin(igs, cxy[0], cxy[1],
155
0
                                   (gs_char) op[-1].value.intval,
156
0
                                   op->value.bytes, r_size(op),
157
0
                                   imemory_local, &penum)) < 0) {
158
        /* We must restore the exec stack pointer back to the point where we entered, in case
159
         * we 'retry' the operation (eg having increased the operand stack).
160
         * We'll rely on gc to handle the enumerator.
161
         * Bug #700618.
162
         */
163
0
        esp = ep;
164
0
        return code;
165
0
    }
166
0
    *(op_proc_t *)&penum->enum_client_data = zwidthshow;
167
168
0
    penum->single_byte_space = single_byte_space;
169
170
0
    if ((code = op_show_finish_setup(i_ctx_p, penum, 4, finish_show)) < 0) {
171
        /* We must restore the exec stack pointer back to the point where we entered, in case
172
         * we 'retry' the operation (eg having increased the operand stack).
173
         * We'll rely on gc to handle the enumerator.
174
         * Bug #700618.
175
         */
176
0
        esp = ep;
177
0
        return code;
178
0
    }
179
180
0
    code = op_show_continue_pop(i_ctx_p, 4);
181
0
    if (code < 0) {
182
        /* We must restore the exec stack pointer back to the point where we entered, in case
183
         * we 'retry' the operation (eg having increased the operand stack).
184
         * We'll rely on gc to handle the enumerator.
185
         * Bug #700618.
186
         */
187
0
        esp = ep;
188
0
    }
189
0
    return code;
190
0
}
191
192
/* <cx> <cy> <char> <string> widthshow - */
193
static int
194
zwidthshow(i_ctx_t *i_ctx_p)
195
15
{
196
15
    return(widthshow_aux(i_ctx_p, false));
197
15
}
198
199
static int
200
awidthshow_aux(i_ctx_t *i_ctx_p, bool single_byte_space)
201
21
{
202
21
    es_ptr ep = esp;        /* Save in case of error */
203
21
    os_ptr op = osp;
204
21
    gs_text_enum_t *penum = NULL;
205
21
    double cxy[2], axy[2];
206
21
    int code;
207
208
21
    check_op(6);
209
10
    if ((code = op_show_setup(i_ctx_p, op)) != 0 )
210
7
        return code;
211
3
    if ((code = num_params(op - 1, 2, axy)) < 0 )
212
3
        return code;
213
0
    check_type(op[-3], t_integer);
214
0
    if (gs_currentfont(igs)->FontType == ft_composite) {
215
0
        if ((gs_char) (op[-3].value.intval) != op[-3].value.intval)
216
0
            return_error(gs_error_rangecheck);
217
0
    } else {
218
0
        if (op[-3].value.intval < 0 || op[-3].value.intval > 255)
219
0
            return_error(gs_error_rangecheck); /* per PLRM and CET 13-02 */
220
0
    }
221
0
    if ((code = num_params(op - 4, 2, cxy)) < 0 )
222
0
        return code;
223
0
    if ((code = gs_awidthshow_begin(igs, cxy[0], cxy[1],
224
0
                                    (gs_char) op[-3].value.intval,
225
0
                                    axy[0], axy[1],
226
0
                                    op->value.bytes, r_size(op),
227
0
                                    imemory_local, &penum)) < 0)
228
0
        return code;
229
0
    *(op_proc_t *)&penum->enum_client_data = zawidthshow;
230
231
0
    penum->single_byte_space = single_byte_space;
232
233
0
    if ((code = op_show_finish_setup(i_ctx_p, penum, 6, finish_show)) < 0) {
234
        /* We must restore the exec stack pointer back to the point where we entered, in case
235
         * we 'retry' the operation (eg having increased the operand stack).
236
         * We'll rely on gc to handle the enumerator.
237
         * Bug #700618.
238
         */
239
0
        esp = ep;
240
0
        return code;
241
0
    }
242
243
0
    code = op_show_continue_pop(i_ctx_p, 6);
244
0
    if (code < 0) {
245
        /* We must restore the exec stack pointer back to the point where we entered, in case
246
         * we 'retry' the operation (eg having increased the operand stack).
247
         * We'll rely on gc to handle the enumerator.
248
         * Bug #700618.
249
         */
250
0
        esp = ep;
251
0
    }
252
0
    return code;
253
0
}
254
255
/* <cx> <cy> <char> <ax> <ay> <string> awidthshow - */
256
static int
257
zawidthshow(i_ctx_t *i_ctx_p)
258
21
{
259
21
    return(awidthshow_aux(i_ctx_p, false));
260
21
}
261
262
/* <proc> <string> kshow - */
263
static int
264
zkshow(i_ctx_t *i_ctx_p)
265
6
{
266
6
    es_ptr ep = esp;        /* Save in case of error */
267
6
    os_ptr op = osp;
268
6
    gs_text_enum_t *penum = NULL;
269
6
    int code;
270
271
6
    check_op(2);
272
1
    check_read_type(*op, t_string);
273
1
    check_proc(op[-1]);
274
    /*
275
     * Per PLRM Section xx.x, kshow is illegal if the current font is a
276
     * composite font.  The graphics library does not have this limitation,
277
     * so we check for it here.
278
     */
279
0
    if (gs_currentfont(igs)->FontType == ft_composite)
280
0
        return_error(gs_error_invalidfont);
281
0
    if ((code = op_show_setup(i_ctx_p, op)) != 0 ||
282
0
        (code = gs_kshow_begin(igs, op->value.bytes, r_size(op),
283
0
                               imemory_local, &penum)) < 0)
284
0
        return code;
285
0
    *(op_proc_t *)&penum->enum_client_data = zkshow;
286
0
    if ((code = op_show_finish_setup(i_ctx_p, penum, 2, finish_show)) < 0) {
287
        /* We must restore the exec stack pointer back to the point where we entered, in case
288
         * we 'retry' the operation (eg having increased the operand stack).
289
         * We'll rely on gc to handle the enumerator.
290
         * Bug #700618.
291
         */
292
0
        esp = ep;
293
0
        return code;
294
0
    }
295
0
    sslot = op[-1];    /* save kerning proc */
296
0
    code = op_show_continue_pop(i_ctx_p, 2);
297
0
    if (code < 0) {
298
        /* We must restore the exec stack pointer back to the point where we entered, in case
299
         * we 'retry' the operation (eg having increased the operand stack).
300
         * We'll rely on gc to handle the enumerator.
301
         * Bug #700618.
302
         */
303
0
        esp = ep;
304
0
    }
305
0
    return code;
306
0
}
307
308
/* Common finish procedure for all show operations. */
309
/* Doesn't have to do anything. */
310
static int
311
finish_show(i_ctx_t *i_ctx_p)
312
522k
{
313
522k
    register es_ptr ep = esp;
314
522k
    gs_text_enum_t *penum = esenum(ep);
315
316
522k
    if (r_is_struct(ep))
317
522k
        rc_decrement(penum, "op_show_free");
318
319
522k
    return 0;
320
522k
}
321
322
/* Finishing procedure for stringwidth. */
323
/* Pushes the accumulated width. */
324
static int
325
finish_stringwidth(i_ctx_t *i_ctx_p)
326
1.05k
{
327
1.05k
    register es_ptr ep = esp;
328
1.05k
    os_ptr op = osp;
329
1.05k
    gs_point width;
330
331
1.05k
    gs_text_enum_t *penum = esenum(ep);
332
333
1.05k
    if (r_is_struct(ep))
334
1.05k
        rc_decrement(penum, "op_show_free");
335
336
1.05k
    gs_text_total_width(senum, &width);
337
1.05k
    push(2);
338
1.05k
    make_real(op - 1, width.x);
339
1.05k
    make_real(op, width.y);
340
1.05k
    return 0;
341
1.05k
}
342
343
/* <string> stringwidth <wx> <wy> */
344
static int
345
zstringwidth(i_ctx_t *i_ctx_p)
346
1.07k
{
347
1.07k
    es_ptr ep = esp;        /* Save in case of error */
348
1.07k
    os_ptr op = osp;
349
1.07k
    gs_text_enum_t *penum = NULL;
350
1.07k
    int code;
351
352
1.07k
    check_op(1);
353
1.06k
    code = op_show_setup(i_ctx_p, op);
354
355
1.06k
    if (code != 0 ||
356
1.06k
        (code = gs_stringwidth_begin(igs, op->value.bytes, r_size(op),
357
1.06k
                                     imemory, &penum)) < 0)
358
16
        return code;
359
1.05k
    *(op_proc_t *)&penum->enum_client_data = zstringwidth;
360
1.05k
    if ((code = op_show_finish_setup(i_ctx_p, penum, 1, finish_stringwidth)) < 0) {
361
0
        rc_decrement(penum, "error in zstringwidth");
362
        /* We must restore the exec stack pointer back to the point where we entered, in case
363
         * we 'retry' the operation (eg having increased the operand stack).
364
         * We'll rely on gc to handle the enumerator.
365
         * Bug #700618.
366
         */
367
0
        esp = ep;
368
0
        return code;
369
0
    }
370
1.05k
    code = op_show_continue_pop(i_ctx_p, 1);
371
1.05k
    if (code < 0) {
372
        /* We must restore the exec stack pointer back to the point where we entered, in case
373
         * we 'retry' the operation (eg having increased the operand stack).
374
         * We'll rely on gc to handle the enumerator.
375
         * Bug #700618.
376
         */
377
0
        esp = ep;
378
0
    }
379
1.05k
    return code;
380
1.05k
}
381
/* Common code for charpath and .charboxpath. */
382
static int
383
zchar_path(i_ctx_t *i_ctx_p, op_proc_t proc,
384
           int (*begin)(gs_gstate *, const byte *, uint,
385
                        bool, gs_memory_t *, gs_text_enum_t **))
386
2.47k
{
387
2.47k
    es_ptr ep = esp;        /* Save in case of error */
388
2.47k
    os_ptr op = osp;
389
2.47k
    gs_text_enum_t *penum = NULL;
390
2.47k
    int code;
391
392
2.47k
    check_op(2);
393
2.45k
    check_type(*op, t_boolean);
394
2.45k
    code = op_show_setup(i_ctx_p, op - 1);
395
2.45k
    if (code != 0 ||
396
2.45k
        (code = begin(igs, op[-1].value.bytes, r_size(op - 1),
397
2.45k
                      op->value.boolval, imemory, &penum)) < 0)
398
8
        return code;
399
2.44k
    *(op_proc_t *)&penum->enum_client_data = proc;
400
2.44k
    if ((code = op_show_finish_setup(i_ctx_p, penum, 2, finish_show)) < 0) {
401
        /* We must restore the exec stack pointer back to the point where we entered, in case
402
         * we 'retry' the operation (eg having increased the operand stack).
403
         * We'll rely on gc to handle the enumerator.
404
         * Bug #700618.
405
         */
406
0
        esp = ep;
407
0
        return code;
408
0
    }
409
2.44k
    code = op_show_continue_pop(i_ctx_p, 2);
410
2.44k
    if (code < 0) {
411
        /* We must restore the exec stack pointer back to the point where we entered, in case
412
         * we 'retry' the operation (eg having increased the operand stack).
413
         * We'll rely on gc to handle the enumerator.
414
         * Bug #700618.
415
         */
416
5
        esp = ep;
417
5
    }
418
2.44k
    return code;
419
2.44k
}
420
/* <string> <outline_bool> charpath - */
421
static int
422
zcharpath(i_ctx_t *i_ctx_p)
423
2.47k
{
424
2.47k
    return zchar_path(i_ctx_p, zcharpath, gs_charpath_begin);
425
2.47k
}
426
/* <string> <box_bool> .charboxpath - */
427
static int
428
zcharboxpath(i_ctx_t *i_ctx_p)
429
0
{
430
0
    return zchar_path(i_ctx_p, zcharboxpath, gs_charboxpath_begin);
431
0
}
432
433
/* <wx> <wy> <llx> <lly> <urx> <ury> setcachedevice - */
434
int
435
zsetcachedevice(i_ctx_t *i_ctx_p)
436
167k
{
437
167k
    os_ptr op = osp;
438
167k
    double wbox[6];
439
167k
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
440
167k
    int code;
441
442
167k
    check_op(6);
443
167k
    code = num_params(op, 6, wbox);
444
445
167k
    if (penum == 0)
446
10
        return_error(gs_error_undefined);
447
167k
    if (code < 0)
448
2
        return code;
449
167k
    if (zchar_show_width_only(penum))
450
3.04k
        return op_show_return_width(i_ctx_p, 6, &wbox[0]);
451
164k
    code = gs_text_setcachedevice(penum, wbox);
452
164k
    if (code < 0)
453
5
        return code;
454
164k
    pop(6);
455
164k
    if (code == 1)
456
164k
        clear_pagedevice(istate);
457
164k
    return 0;
458
164k
}
459
460
/* <w0x> <w0y> <llx> <lly> <urx> <ury> <w1x> <w1y> <vx> <vy> setcachedevice2 - */
461
int
462
zsetcachedevice2(i_ctx_t *i_ctx_p)
463
24
{
464
24
    os_ptr op = osp;
465
24
    double wbox[10];
466
24
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
467
24
    int code;
468
469
24
    check_op(10);
470
13
    code = num_params(op, 10, wbox);
471
472
13
    if (penum == 0)
473
13
        return_error(gs_error_undefined);
474
0
    if (code < 0)
475
0
        return code;
476
0
    if (zchar_show_width_only(penum))
477
0
        return op_show_return_width(i_ctx_p, 10,
478
0
                                    (gs_rootfont(igs)->WMode ?
479
0
                                     &wbox[6] : &wbox[0]));
480
0
    code = gs_text_setcachedevice2(penum, wbox);
481
0
    if (code < 0)
482
0
        return code;
483
0
    pop(10);
484
0
    if (code == 1)
485
0
        clear_pagedevice(istate);
486
0
    return 0;
487
0
}
488
489
/* <wx> <wy> setcharwidth - */
490
static int
491
zsetcharwidth(i_ctx_t *i_ctx_p)
492
216k
{
493
216k
    os_ptr op = osp;
494
216k
    double width[2];
495
216k
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
496
216k
    int code;
497
498
216k
    check_op(2);
499
216k
    code = num_params(op, 2, width);
500
501
216k
    if (penum == 0)
502
85
        return_error(gs_error_undefined);
503
216k
    if (code < 0)
504
0
        return code;
505
216k
    if (zchar_show_width_only(penum))
506
0
        return op_show_return_width(i_ctx_p, 2, &width[0]);
507
216k
    code = gs_text_setcharwidth(penum, width);
508
216k
    if (code < 0)
509
0
        return code;
510
216k
    pop(2);
511
216k
    return 0;
512
216k
}
513
514
/* <dict> .fontbbox <llx> <lly> <urx> <ury> -true- */
515
/* <dict> .fontbbox -false- */
516
static int
517
zfontbbox(i_ctx_t *i_ctx_p)
518
64.5k
{
519
64.5k
    os_ptr op = osp;
520
64.5k
    double bbox[4];
521
64.5k
    int code;
522
523
64.5k
    check_op(1);
524
64.5k
    check_type(*op, t_dictionary);
525
64.5k
    check_dict_read(*op);
526
64.5k
    code = font_bbox_param(imemory, op, bbox);
527
64.5k
    if (code < 0)
528
0
        return code;
529
64.5k
    if (bbox[0] < bbox[2] && bbox[1] < bbox[3]) {
530
64.5k
        push(4);
531
64.5k
        make_reals(op - 4, bbox, 4);
532
64.5k
        make_true(op);
533
64.5k
    } else {     /* No bbox, or an empty one. */
534
0
        make_false(op);
535
0
    }
536
64.5k
    return 0;
537
64.5k
}
538
539
/* Export in_cachedevice flag for PDF interpreter, which, unlike
540
 * PS unterpreter, ignores color operations in the inappropriate context.
541
 */
542
/* - .incachedevice <bool> */
543
static int
544
zincachedevice(i_ctx_t *i_ctx_p)
545
8
{
546
8
    os_ptr op = osp;
547
548
8
    push(1);
549
8
    make_bool(op, !!igs->in_cachedevice);
550
8
    return 0;
551
8
}
552
553
/* ------ Initialization procedure ------ */
554
555
const op_def zchar_a_op_defs[] =
556
{
557
    {"3ashow", zashow},
558
    {"6awidthshow", zawidthshow},
559
    {"2charpath", zcharpath},
560
    {"2.charboxpath", zcharboxpath},
561
    {"2kshow", zkshow},
562
    {"6setcachedevice", zsetcachedevice},
563
    {":setcachedevice2", zsetcachedevice2},
564
    {"2setcharwidth", zsetcharwidth},
565
    {"1show", zshow},
566
    {"1stringwidth", zstringwidth},
567
    {"4widthshow", zwidthshow},
568
                /* Extensions */
569
    {"1.fontbbox", zfontbbox},
570
571
                /* Internal operators */
572
    {"0%finish_show", finish_show},
573
    op_def_end(0)
574
};
575
576
const op_def zchar_b_op_defs[] =
577
{
578
    {"0%finish_stringwidth", finish_stringwidth},
579
    {"0%op_show_continue", op_show_continue},
580
    {"0.incachedevice", zincachedevice},
581
    op_def_end(0)
582
};
583
584
/* ------ Subroutines ------ */
585
586
/* Most of these are exported for zchar2.c. */
587
588
/* Convert a glyph to a ref. */
589
void
590
glyph_ref(const gs_memory_t *mem, gs_glyph glyph, ref * gref)
591
8.17M
{
592
8.17M
    if (glyph < GS_MIN_CID_GLYPH)
593
8.17M
        name_index_ref(mem, glyph, gref);
594
0
    else
595
8.17M
        make_int(gref, glyph - GS_MIN_CID_GLYPH);
596
8.17M
}
597
598
/* Prepare to set up for a text operator. */
599
/* Don't change any state yet. */
600
int
601
op_show_setup(i_ctx_t *i_ctx_p, os_ptr op)
602
524k
{
603
524k
    check_read_type(*op, t_string);
604
524k
    return op_show_enum_setup(i_ctx_p);
605
524k
}
606
int
607
op_show_enum_setup(i_ctx_t *i_ctx_p)
608
524k
{
609
524k
    check_estack(snumpush + 2);
610
524k
    return 0;
611
524k
}
612
613
/* Finish setting up a text operator. */
614
int
615
op_show_finish_setup(i_ctx_t *i_ctx_p, gs_text_enum_t * penum, int npop,
616
                     op_proc_t endproc /* end procedure */ )
617
524k
{
618
524k
    gs_text_enum_t *osenum = op_show_find(i_ctx_p);
619
524k
    es_ptr ep = esp + snumpush;
620
524k
    gs_glyph glyph;
621
622
524k
    if (gs_currentcpsimode(igs->memory)) {
623
        /* CET 14-03.PS page 2 emits rangecheck before rendering a character.
624
           Early check the text to font compatibility
625
           with decomposing the text into characters.*/
626
0
        int code = gs_text_count_chars(igs, gs_get_text_params(penum), imemory);
627
628
0
        if (code < 0)
629
0
            return code;
630
0
    }
631
    /*
632
     * If we are in the procedure of a cshow for a CID font and this is
633
     * a show operator, do something special, per the Red Book.
634
     */
635
524k
    if (osenum &&
636
783
        SHOW_IS_ALL_OF(osenum,
637
524k
                       TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_INTERVENE) &&
638
0
        SHOW_IS_ALL_OF(penum, TEXT_FROM_STRING | TEXT_RETURN_WIDTH) &&
639
0
        (glyph = gs_text_current_glyph(osenum)) != GS_NO_GLYPH &&
640
0
        glyph >= GS_MIN_CID_GLYPH &&
641
642
        /* According to PLRM, we don't need to raise a rangecheck error,
643
           if currentfont is changed in the proc of the operator 'cshow'. */
644
0
        gs_default_same_font (gs_text_current_font(osenum),
645
0
                              gs_text_current_font(penum), true)
646
524k
        ) {
647
0
        gs_text_params_t text;
648
649
0
        if (!(penum->text.size == 1 &&
650
0
              penum->text.data.bytes[0] ==
651
0
                (gs_text_current_char(osenum) & 0xff))
652
0
            )
653
0
            return_error(gs_error_rangecheck);
654
0
        text = penum->text;
655
0
        text.operation =
656
0
            (text.operation &
657
0
             ~(TEXT_FROM_STRING | TEXT_FROM_BYTES | TEXT_FROM_CHARS |
658
0
               TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_CHAR)) |
659
0
            TEXT_FROM_SINGLE_GLYPH;
660
0
        text.data.d_glyph = glyph;
661
0
        text.size = 1;
662
0
        gs_text_restart(penum, &text);
663
0
    }
664
524k
    if (osenum && osenum->current_font->FontType == ft_user_defined &&
665
783
        osenum->orig_font->FontType == ft_composite &&
666
0
        ((const gs_font_type0 *)osenum->orig_font)->data.FMapType == fmap_CMap) {
667
        /* A special behavior defined in PLRM3 section 5.11 page 389. */
668
0
        penum->outer_CID = osenum->returned.current_glyph;
669
0
    }
670
524k
    if (osenum == NULL && !(penum->text.operation & (TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH))) {
671
523k
        int ft = igs->root_font->FontType;
672
673
523k
        if ((ft >= ft_CID_encrypted && ft <= ft_CID_TrueType) || ft == ft_CID_bitmap)
674
0
            return_error(gs_error_typecheck);
675
523k
    }
676
524k
    make_mark_estack(ep - (snumpush - 1), es_show, op_show_cleanup);
677
524k
    if (endproc == NULL)
678
45
        endproc = finish_show;
679
524k
    make_null(&esslot(ep));
680
524k
    make_int(&esodepth(ep), ref_stack_count_inline(&o_stack) - npop); /* Save stack depth for */
681
524k
    make_int(&esddepth(ep), ref_stack_count_inline(&d_stack));        /* correct interrupt processing */
682
524k
    make_int(&esgslevel(ep), igs->level);
683
524k
    make_null(&essfont(ep));
684
524k
    make_null(&esrfont(ep));
685
524k
    make_op_estack(&eseproc(ep), endproc);
686
    /* The text enumerators are always allocated in local VM */
687
524k
    make_struct(ep, iimemory_local->space, penum);
688
524k
    rc_increment(penum);
689
524k
    esp = ep;
690
524k
    return 0;
691
524k
}
692
693
/* Continuation operator for character rendering. */
694
int
695
op_show_continue(i_ctx_t *i_ctx_p)
696
1.39M
{
697
1.39M
    int code = gs_text_update_dev_color(igs, senum);
698
699
1.39M
    if (code >= 0)
700
1.39M
        code = op_show_continue_dispatch(i_ctx_p, 0, gs_text_process(senum));
701
1.39M
    return code;
702
1.39M
}
703
int
704
op_show_continue_pop(i_ctx_t *i_ctx_p, int npop)
705
524k
{
706
524k
    return op_show_continue_dispatch(i_ctx_p, npop, gs_text_process(senum));
707
524k
}
708
/*
709
 * Note that op_show_continue_dispatch sets osp = op explicitly iff the
710
 * dispatch succeeds.  This is so that the show operators don't pop anything
711
 * from the o-stack if they don't succeed.  Note also that if it returns an
712
 * error, it has freed the enumerator.
713
 */
714
int
715
op_show_continue_dispatch(i_ctx_t *i_ctx_p, int npop, int code)
716
1.92M
{
717
1.92M
    os_ptr op = osp - npop;
718
1.92M
    gs_text_enum_t *penum = senum;
719
720
1.92M
    switch (code) {
721
523k
        case 0: {   /* all done */
722
523k
            os_ptr save_osp = osp;
723
724
523k
            osp = op;
725
523k
            code = (*real_opproc(&seproc)) (i_ctx_p);
726
523k
            op_show_free(i_ctx_p, code);
727
523k
            if (code < 0) {
728
0
                osp = save_osp;
729
0
                return code;
730
0
            }
731
523k
            return o_pop_estack;
732
523k
        }
733
0
        case TEXT_PROCESS_INTERVENE: {
734
0
            ref *pslot = &sslot; /* only used for kshow */
735
736
0
            push(2);
737
0
            make_int(op - 1, gs_text_current_char(penum)); /* previous char */
738
0
            make_int(op, gs_text_next_char(penum));
739
0
            push_op_estack(op_show_continue); /* continue after kerning */
740
0
            *++esp = *pslot;  /* kerning procedure */
741
0
            return o_push_estack;
742
0
        }
743
1.39M
        case TEXT_PROCESS_RENDER: {
744
1.39M
            gs_font *pfont = gs_currentfont(igs);
745
1.39M
            font_data *pfdata = pfont_data(pfont);
746
1.39M
            gs_char chr = gs_text_current_char(penum);
747
1.39M
            gs_glyph glyph = gs_text_current_glyph(penum);
748
749
1.39M
            push(2);
750
1.39M
            op[-1] = pfdata->dict;  /* push the font */
751
            /*
752
             * For Type 1 and Type 4 fonts, prefer BuildChar to BuildGlyph
753
             * if there is no glyph, or if there is both a character and a
754
             * glyph and the glyph is the one that corresponds to the
755
             * character in the Encoding, so that PostScript procedures
756
             * appearing in the CharStrings dictionary will receive the
757
             * character code rather than the character name; for Type 3
758
             * fonts, prefer BuildGlyph to BuildChar.  For other font types
759
             * (such as CID fonts), only BuildGlyph will be present.
760
             */
761
1.39M
            if (pfont->FontType == ft_user_defined) {
762
                /* Type 3 font, prefer BuildGlyph. */
763
381k
                if (level2_enabled &&
764
381k
                    !r_has_type(&pfdata->BuildGlyph, t_null) &&
765
45
                    glyph != GS_NO_GLYPH
766
381k
                    ) {
767
45
                    glyph_ref(imemory, glyph, op);
768
45
                    esp[2] = pfdata->BuildGlyph;
769
381k
                } else if (r_has_type(&pfdata->BuildChar, t_null))
770
0
                    goto err;
771
381k
                else if (chr == gs_no_char) {
772
                    /* glyphshow, reverse map the character */
773
                    /* through the Encoding */
774
0
                    ref gref;
775
0
                    const ref *pencoding = &pfdata->Encoding;
776
777
0
                    glyph_ref(imemory, glyph, &gref);
778
0
                    if (!map_glyph_to_char(imemory, &gref, pencoding,
779
0
                                           (ref *) op)
780
0
                        ) { /* Not found, try .notdef */
781
0
                        name_enter_string(imemory, ".notdef", &gref);
782
0
                        if (!map_glyph_to_char(imemory, &gref,
783
0
                                               pencoding,
784
0
                                               (ref *) op)
785
0
                            )
786
0
                            goto err;
787
0
                    }
788
0
                    esp[2] = pfdata->BuildChar;
789
381k
                } else {
790
381k
                    make_int(op, chr & 0xff);
791
381k
                    esp[2] = pfdata->BuildChar;
792
381k
                }
793
1.01M
            } else {
794
                /*
795
                 * For a Type 1 or Type 4 font, prefer BuildChar or
796
                 * BuildGlyph as described above: we know that both
797
                 * BuildChar and BuildGlyph are present.  For other font
798
                 * types, only BuildGlyph is available.
799
                 */
800
1.01M
                ref eref, gref;
801
802
1.01M
                if (chr != gs_no_char &&
803
1.01M
                    !r_has_type(&pfdata->BuildChar, t_null) &&
804
1.01M
                    (glyph == GS_NO_GLYPH ||
805
1.01M
                     (!r_has_type(&pfdata->Encoding, t_null) &&
806
1.01M
                       array_get(imemory, &pfdata->Encoding, (long)(chr & 0xff), &eref) >= 0 &&
807
1.01M
                      (glyph_ref(imemory, glyph, &gref), obj_eq(imemory, &gref, &eref))))
808
1.01M
                    ) {
809
1.01M
                    make_int(op, chr & 0xff);
810
1.01M
                    esp[2] = pfdata->BuildChar;
811
1.01M
                } else {
812
                    /* We might not have a glyph: substitute 0. **HACK** */
813
0
                    if (glyph == GS_NO_GLYPH)
814
0
                        make_int(op, 0);
815
0
                    else
816
0
                        glyph_ref(imemory, glyph, op);
817
0
                    esp[2] = pfdata->BuildGlyph;
818
0
                }
819
1.01M
            }
820
            /* Save the stack depths in case we bail out. */
821
1.39M
            sodepth.value.intval = ref_stack_count(&o_stack) - 2;
822
1.39M
            sddepth.value.intval = ref_stack_count(&d_stack);
823
1.39M
            push_op_estack(op_show_continue);
824
1.39M
            ++esp;   /* skip BuildChar or BuildGlyph proc */
825
1.39M
            return o_push_estack;
826
1.39M
        }
827
0
        case TEXT_PROCESS_CDEVPROC:
828
0
            {   gs_font *pfont = penum->current_font;
829
0
                ref cnref;
830
0
                op_proc_t cont = op_show_continue, exec_cont = 0;
831
0
                gs_glyph glyph = penum->returned.current_glyph;
832
833
0
                pop(npop);
834
0
                op = osp;
835
0
                glyph_ref(imemory, glyph, &cnref);
836
0
                if (pfont->FontType == ft_CID_TrueType) {
837
0
                    gs_font_type42 *pfont42 = (gs_font_type42 *)pfont;
838
0
                    uint glyph_index = pfont42->data.get_glyph_index(pfont42, glyph);
839
840
0
                    code = zchar42_set_cache(i_ctx_p, (gs_font_base *)pfont42,
841
0
                                    &cnref, glyph_index, cont, &exec_cont);
842
0
                } else if (pfont->FontType == ft_CID_encrypted)
843
0
                    code = z1_set_cache(i_ctx_p, (gs_font_base *)pfont,
844
0
                                    &cnref, glyph, cont, &exec_cont);
845
0
                else
846
0
                    code = gs_note_error(gs_error_unregistered); /* Unimplemented. */
847
0
                if (exec_cont != 0)
848
0
                    code = gs_note_error(gs_error_unregistered); /* Must not happen. */
849
0
                if (code < 0)
850
0
                  goto err;
851
0
                else
852
0
                  return code;
853
0
            }
854
0
        case gs_error_Remap_Color:
855
0
            {
856
0
                return code;
857
0
            }
858
15
        default:    /* error */
859
15
err:
860
15
            if (code >= 0)
861
0
                code = gs_note_error(gs_error_invalidfont);
862
15
            return op_show_free(i_ctx_p, code);
863
1.92M
    }
864
1.92M
}
865
/* Reverse-map a glyph name to a character code for glyphshow. */
866
static bool
867
map_glyph_to_char(const gs_memory_t *mem, const ref * pgref, const ref * pencoding, ref * pch)
868
0
{
869
0
    uint esize = r_size(pencoding);
870
0
    uint ch;
871
0
    ref eref;
872
873
0
    for (ch = 0; ch < esize; ch++) {
874
0
        array_get(mem, pencoding, (long)ch, &eref);
875
0
        if (obj_eq(mem, pgref, &eref)) {
876
0
            make_int(pch, ch);
877
0
            return true;
878
0
        }
879
0
    }
880
0
    return false;
881
0
}
882
883
/* Find the index of the e-stack mark for the current show enumerator. */
884
/* Return 0 if we can't find the mark. */
885
static uint
886
op_show_find_index(i_ctx_t *i_ctx_p)
887
3.09M
{
888
3.09M
    ref_stack_enum_t rsenum;
889
3.09M
    uint count = 0;
890
891
3.09M
    ref_stack_enum_begin(&rsenum, &e_stack);
892
3.09M
    do {
893
3.09M
        es_ptr ep = rsenum.ptr;
894
3.09M
        uint size = rsenum.size;
895
896
53.5M
        for (ep += size - 1; size != 0; size--, ep--, count++)
897
52.8M
            if (r_is_estack_mark(ep) && estack_mark_index(ep) == es_show)
898
2.41M
                return count;
899
3.09M
    } while (ref_stack_enum_next(&rsenum));
900
671k
    return 0;   /* no mark */
901
3.09M
}
902
903
/* Find the current show enumerator on the e-stack. */
904
gs_text_enum_t *
905
op_show_find(i_ctx_t *i_ctx_p)
906
3.08M
{
907
3.08M
    uint index = op_show_find_index(i_ctx_p);
908
3.08M
    ref *o;
909
910
3.08M
    if (index == 0)
911
671k
        return 0;    /* no mark */
912
2.41M
    o = ref_stack_index(&e_stack, index - (snumpush - 1));
913
2.41M
    if (o == NULL)
914
0
        return 0;
915
916
2.41M
    return r_ptr(o, gs_text_enum_t);
917
2.41M
}
918
919
/*
920
 * Return true if we only need the width from the rasterizer
921
 * and can short-circuit the full rendering of the character,
922
 * false if we need the actual character bits.  This is only safe if
923
 * we know the character is well-behaved, i.e., is not defined by an
924
 * arbitrary PostScript procedure.
925
 */
926
bool
927
zchar_show_width_only(const gs_text_enum_t * penum)
928
1.40M
{
929
1.40M
    if (!gs_text_is_width_only(penum))
930
1.31M
        return false;
931
88.2k
    switch (penum->orig_font->FontType) {
932
6.09k
    case ft_encrypted:
933
6.09k
    case ft_encrypted2:
934
6.09k
    case ft_CID_encrypted:
935
6.09k
    case ft_CID_TrueType:
936
6.09k
    case ft_CID_bitmap:
937
6.09k
    case ft_TrueType:
938
6.09k
        return true;
939
82.1k
    default:
940
82.1k
        return false;
941
88.2k
    }
942
88.2k
}
943
944
/* Shortcut the BuildChar or BuildGlyph procedure at the point */
945
/* of the setcharwidth or the setcachedevice[2] if we are in */
946
/* a stringwidth or cshow, or if we are only collecting the scalable */
947
/* width for an xfont character. */
948
static int
949
op_show_return_width(i_ctx_t *i_ctx_p, uint npop, double *pwidth)
950
3.04k
{
951
3.04k
    uint index = op_show_find_index(i_ctx_p);
952
3.04k
    es_ptr ep = (es_ptr) ref_stack_index(&e_stack, index - (snumpush - 1));
953
3.04k
    int code = 0;
954
3.04k
    uint ocount, dsaved, dcount;
955
956
3.04k
    if (ep == NULL)
957
0
        return_error(gs_error_stackunderflow);
958
959
3.04k
    code = gs_text_setcharwidth(esenum(ep), pwidth);
960
3.04k
    if (code < 0)
961
0
        return code;
962
    /* Restore the operand and dictionary stacks. */
963
3.04k
    ocount = ref_stack_count(&o_stack) - (uint) esodepth(ep).value.intval;
964
3.04k
    if (ocount < npop)
965
0
        return_error(gs_error_stackunderflow);
966
3.04k
    dsaved = (uint) esddepth(ep).value.intval;
967
3.04k
    dcount = ref_stack_count(&d_stack);
968
3.04k
    if (dcount < dsaved)
969
0
        return_error(gs_error_dictstackunderflow);
970
3.04k
    while (dcount > dsaved) {
971
0
        code = zend(i_ctx_p);
972
0
        if (code < 0)
973
0
            return code;
974
0
        dcount--;
975
0
    }
976
3.04k
    ref_stack_pop(&o_stack, ocount);
977
    /* We don't want to pop the mark or the continuation */
978
    /* procedure (op_show_continue or cshow_continue). */
979
3.04k
    pop_estack(i_ctx_p, index - snumpush);
980
3.04k
    return o_pop_estack;
981
3.04k
}
982
983
/*
984
 * Restore state after finishing, or unwinding from an error within, a show
985
 * operation.  Note that we assume op == osp, and may reset osp.
986
 */
987
static int
988
op_show_restore(i_ctx_t *i_ctx_p, bool for_error)
989
524k
{
990
524k
    register es_ptr ep = esp + snumpush;
991
524k
    gs_text_enum_t *penum = esenum(ep);
992
524k
    int saved_level = esgslevel(ep).value.intval;
993
524k
    int code = 0;
994
995
524k
    if (for_error) {
996
#if 0 /* Disabled for CPSI compatibility for 13-12-4.
997
         CPSI doesn't remove cshow, kshow proc operands. */
998
        uint saved_count = esodepth(ep).value.intval;
999
        uint count = ref_stack_count(&o_stack);
1000
1001
        if (count > saved_count)  /* if <, we're in trouble */
1002
            ref_stack_pop(&o_stack, count - saved_count);
1003
#endif
1004
995
        if (ep[1].value.opproc == op_show_continue && penum->enum_client_data != NULL) {
1005
            /* Replace the continuation operaton on estack with the right operator : */
1006
984
            op_proc_t proc;
1007
1008
984
            *(void **)&proc = penum->enum_client_data;
1009
984
            make_op_estack(ep + 1, proc);
1010
984
        }
1011
995
    }
1012
524k
    if (SHOW_IS_STRINGWIDTH(penum) && igs->text_rendering_mode != 3) {
1013
        /* stringwidth does an extra gsave */
1014
1.05k
        --saved_level;
1015
1.05k
    }
1016
524k
    if (penum->text.operation & TEXT_REPLACE_WIDTHS) {
1017
0
        gs_free_const_object(penum->memory, penum->text.y_widths, "y_widths");
1018
0
        if (penum->text.x_widths != penum->text.y_widths)
1019
0
            gs_free_const_object(penum->memory, penum->text.x_widths, "x_widths");
1020
0
    }
1021
    /*
1022
     * We might have been inside a cshow, in which case currentfont was
1023
     * reset temporarily, as though we were inside a BuildChar/ BuildGlyph
1024
     * procedure.  To handle this case, set currentfont back to its original
1025
     * state.  NOTE: this code previously used fstack[0] in the enumerator
1026
     * for the root font: we aren't sure that this change is correct.
1027
     */
1028
524k
    gs_set_currentfont(igs, penum->orig_font);
1029
525k
    while (igs->level > saved_level && code >= 0) {
1030
1.11k
        if (igs->saved == 0 || igs->saved->saved == 0) {
1031
            /*
1032
             * Bad news: we got an error inside a save inside a BuildChar or
1033
             * BuildGlyph.  Don't attempt to recover.
1034
             */
1035
0
            code = gs_note_error(gs_error_Fatal);
1036
0
        } else
1037
1.11k
            code = gs_grestore(igs);
1038
1.11k
    }
1039
1040
    /* Possibly restore color. This occurs if we are going to a high
1041
       level device or if we were only doing a fill.
1042
       If we are going to be doing the stroke
1043
       operation through zstroke then we do not want to restore yet. */
1044
524k
    if (penum->k_text_release) {
1045
0
        gsicc_restore_blacktextvec(igs, true);
1046
0
    }
1047
    /* Because the garbager, in most places, works on clumps, taking no
1048
       account of where the top of the exec stack is, we can't leave a
1049
       dangling pointer to this enumerator when we're about to free it.
1050
     */
1051
524k
    make_null(ep);
1052
524k
    gs_text_release(NULL, penum, "op_show_restore");
1053
524k
    return code;
1054
524k
}
1055
/* Clean up after an error. */
1056
static int
1057
op_show_cleanup(i_ctx_t *i_ctx_p)
1058
980
{
1059
980
    return op_show_restore(i_ctx_p, true);
1060
980
}
1061
/* Clean up after termination of a show operation. */
1062
int
1063
op_show_free(i_ctx_t *i_ctx_p, int code)
1064
523k
{
1065
523k
    int rcode;
1066
1067
523k
    esp -= snumpush;
1068
523k
    rcode = op_show_restore(i_ctx_p, code < 0);
1069
523k
    return (rcode < 0 ? rcode : code);
1070
523k
}
1071
1072
/* Get a FontBBox parameter from a font dictionary. */
1073
int
1074
font_bbox_param(const gs_memory_t *mem, const ref * pfdict, double bbox[4])
1075
277k
{
1076
277k
    ref *pbbox;
1077
1078
    /*
1079
     * Pre-clear the bbox in case it's invalid.  The Red Books say that
1080
     * FontBBox is required, but old Adobe interpreters don't require
1081
     * it, and a few user-written fonts don't supply it, or supply one
1082
     * of the wrong size (!); also, PageMaker 5.0 (an Adobe product!)
1083
     * sometimes emits an absurd bbox for Type 1 fonts converted from
1084
     * TrueType.
1085
     */
1086
277k
    bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
1087
277k
    if (dict_find_string(pfdict, "FontBBox", &pbbox) > 0) {
1088
277k
        if (!r_is_array(pbbox))
1089
0
            return_error(gs_error_typecheck);
1090
277k
        if (r_size(pbbox) == 4) {
1091
277k
            const ref_packed *pbe = pbbox->value.packed;
1092
277k
            ref rbe[4];
1093
277k
            int i;
1094
277k
            int code;
1095
277k
            float dx, dy, ratio;
1096
277k
            const float max_ratio = 12; /* From the bug 687594. */
1097
1098
1.38M
            for (i = 0; i < 4; i++) {
1099
1.10M
                packed_get(mem, pbe, rbe + i);
1100
1.10M
                pbe = packed_next(pbe);
1101
1.10M
            }
1102
277k
            if ((code = num_params(rbe + 3, 4, bbox)) < 0)
1103
1
                return code;
1104
            /* Require "reasonable" values. */
1105
277k
            dx = bbox[2] - bbox[0];
1106
277k
            dy = bbox[3] - bbox[1];
1107
277k
            if (dx <= 0 || dy <= 0 ||
1108
129k
                (ratio = dy / dx) < 1 / max_ratio || ratio > max_ratio
1109
277k
                )
1110
147k
                bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
1111
277k
        }
1112
277k
    } else if (gs_currentcpsimode(mem)) {
1113
0
        return_error(gs_error_invalidfont); /* CPSI requires FontBBox */
1114
0
    }
1115
277k
    return 0;
1116
277k
}