Coverage Report

Created: 2022-10-31 07:00

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