Coverage Report

Created: 2025-06-24 07:01

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