Coverage Report

Created: 2025-06-10 07:24

/src/ghostpdl/base/gstext.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2024 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
/* Driver text interface support */
18
19
#include "memory_.h"
20
#include "gstypes.h"
21
#include "gdebug.h"
22
#include "gserrors.h"
23
#include "gsmemory.h"
24
#include "gsstruct.h"
25
#include "gstypes.h"
26
#include "gxfcache.h"
27
#include "gxdevcli.h"
28
#include "gxdcolor.h"   /* for gs_gstate_color_load */
29
#include "gxfont.h"   /* for init_fstack */
30
#include "gxpath.h"
31
#include "gxtext.h"
32
#include "gzstate.h"
33
#include "gsutil.h"
34
#include "gxdevsop.h"
35
#include "gscspace.h"
36
#include "gsicc_blacktext.h"
37
38
/* GC descriptors */
39
public_st_gs_text_params();
40
public_st_gs_text_enum();
41
42
static
43
0
ENUM_PTRS_WITH(text_params_enum_ptrs, gs_text_params_t *tptr) return 0;
44
0
case 0:
45
0
if (tptr->operation & TEXT_FROM_STRING) {
46
0
    return ENUM_CONST_STRING2(tptr->data.bytes, tptr->size);
47
0
}
48
0
if (tptr->operation & TEXT_FROM_BYTES)
49
0
    return ENUM_OBJ(tptr->data.bytes);
50
0
if (tptr->operation & TEXT_FROM_CHARS)
51
0
    return ENUM_OBJ(tptr->data.chars);
52
0
if (tptr->operation & TEXT_FROM_GLYPHS)
53
0
    return ENUM_OBJ(tptr->data.glyphs);
54
0
return ENUM_OBJ(NULL);
55
0
case 1:
56
0
return ENUM_OBJ(tptr->operation & TEXT_REPLACE_WIDTHS ?
57
0
                tptr->x_widths : NULL);
58
0
case 2:
59
0
return ENUM_OBJ(tptr->operation & TEXT_REPLACE_WIDTHS ?
60
0
                tptr->y_widths : NULL);
61
0
ENUM_PTRS_END
62
0
static RELOC_PTRS_WITH(text_params_reloc_ptrs, gs_text_params_t *tptr)
63
0
{
64
0
    if (tptr->operation & TEXT_FROM_STRING) {
65
0
        gs_const_string str;
66
67
0
        str.data = tptr->data.bytes;
68
0
        str.size = tptr->size;
69
0
        RELOC_CONST_STRING_VAR(str);
70
0
        tptr->data.bytes = str.data;
71
0
    } else if (tptr->operation & TEXT_FROM_BYTES)
72
0
        RELOC_OBJ_VAR(tptr->data.bytes);
73
0
    else if (tptr->operation & TEXT_FROM_CHARS)
74
0
        RELOC_OBJ_VAR(tptr->data.chars);
75
0
    else if (tptr->operation & TEXT_FROM_GLYPHS)
76
0
        RELOC_OBJ_VAR(tptr->data.glyphs);
77
0
    if (tptr->operation & TEXT_REPLACE_WIDTHS) {
78
0
        RELOC_OBJ_VAR(tptr->x_widths);
79
0
        RELOC_OBJ_VAR(tptr->y_widths);
80
0
    }
81
0
}
82
0
RELOC_PTRS_END
83
84
0
static ENUM_PTRS_WITH(text_enum_enum_ptrs, gs_text_enum_t *eptr)
85
0
{
86
0
    if (index == 6) {
87
0
        if (eptr->pair != 0)
88
0
            ENUM_RETURN(eptr->pair - eptr->pair->index);
89
0
        else
90
0
            ENUM_RETURN(0);
91
0
    }
92
0
    index -= 7;
93
0
    if (index <= eptr->fstack.depth)
94
0
        ENUM_RETURN(eptr->fstack.items[index].font);
95
0
    index -= eptr->fstack.depth + 1;
96
0
     return ENUM_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text), index);
97
0
}
98
0
case 0: return ENUM_OBJ(gx_device_enum_ptr(eptr->dev));
99
0
case 1: return ENUM_OBJ(gx_device_enum_ptr(eptr->imaging_dev));
100
0
ENUM_PTR2(2, gs_text_enum_t, pgs, orig_font);
101
0
ENUM_PTR2(4, gs_text_enum_t, pcpath, current_font);
102
0
ENUM_PTRS_END
103
104
0
static RELOC_PTRS_WITH(text_enum_reloc_ptrs, gs_text_enum_t *eptr)
105
0
{
106
0
    int i;
107
108
0
    RELOC_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text));
109
0
    eptr->dev = gx_device_reloc_ptr(eptr->dev, gcst);
110
0
    eptr->imaging_dev = gx_device_reloc_ptr(eptr->imaging_dev, gcst);
111
0
    RELOC_PTR2(gs_text_enum_t, pgs, orig_font);
112
0
    RELOC_PTR2(gs_text_enum_t, pcpath, current_font);
113
0
    if (eptr->pair != NULL)
114
0
        eptr->pair = (cached_fm_pair *)RELOC_OBJ(eptr->pair - eptr->pair->index) +
115
0
                             eptr->pair->index;
116
0
    for (i = 0; i <= eptr->fstack.depth; i++)
117
0
        RELOC_PTR(gs_text_enum_t, fstack.items[i].font);
118
0
}
119
0
RELOC_PTRS_END
120
121
/* Begin processing text. */
122
int
123
gx_device_text_begin(gx_device * dev, gs_gstate * pgs,
124
                     const gs_text_params_t * text, gs_font * font,
125
                     const gx_clip_path * pcpath, /* DO_DRAW */
126
                     gs_text_enum_t ** ppte)
127
1.79M
{
128
1.79M
    if (TEXT_PARAMS_ARE_INVALID(text))
129
0
        return_error(gs_error_rangecheck);
130
1.79M
    {
131
1.79M
        const gx_clip_path *tcpath =
132
1.79M
            (text->operation & TEXT_DO_DRAW ? pcpath : 0);
133
134
        /* A high level device need to know an initial device color
135
           for accumulates a charstring of a Type 3 font.
136
           Since the accumulation may happen while stringwidth.
137
           we pass the device color unconditionally. */
138
1.79M
        return dev_proc(dev, text_begin)
139
1.79M
            (dev, pgs, text, font, tcpath, ppte);
140
1.79M
    }
141
1.79M
}
142
143
/*
144
 * Initialize a newly created text enumerator.  Implementations of
145
 * text_begin must call this just after allocating the enumerator.
146
 */
147
static int
148
gs_text_enum_init_dynamic(gs_text_enum_t *pte, gs_font *font)
149
2.17M
{
150
2.17M
    uint operation = pte->text.operation;
151
2.17M
    bool propagate_charpath = (operation & TEXT_DO_DRAW) != 0;
152
153
2.17M
    pte->current_font = font;
154
2.17M
    pte->index = 0;
155
2.17M
    pte->xy_index = 0;
156
2.17M
    pte->FontBBox_as_Metrics2.x = pte->FontBBox_as_Metrics2.y = 0;
157
2.17M
    pte->pair = 0;
158
2.17M
    pte->device_disabled_grid_fitting = 0;
159
2.17M
    pte->outer_CID = GS_NO_GLYPH;
160
2.17M
    pte->single_byte_space = false;
161
2.17M
    pte->cc = NULL;
162
163
    /* We need to set the charpath_flag, as the PCL interpreter calls the
164
     * graphics lib to do some measurement operations, which relies on the
165
     * charpath_flag. See bug 700577 for more details. */
166
2.17M
    if (operation & TEXT_DO_ANY_CHARPATH)
167
1.27k
        pte->charpath_flag =
168
1.27k
            (operation & TEXT_DO_FALSE_CHARPATH ? cpm_false_charpath :
169
1.27k
             operation & TEXT_DO_TRUE_CHARPATH ? cpm_true_charpath :
170
323
             operation & TEXT_DO_FALSE_CHARBOXPATH ? cpm_false_charboxpath :
171
0
             operation & TEXT_DO_TRUE_CHARBOXPATH ? cpm_true_charboxpath :
172
0
             operation & TEXT_DO_CHARWIDTH ? cpm_charwidth :
173
0
             cpm_show /* can't happen */ );
174
2.17M
    else
175
2.17M
        pte->charpath_flag =
176
2.17M
        (propagate_charpath ? (pte->pgs ? pte->pgs->in_charpath : 0) : cpm_show);
177
2.17M
    pte->is_pure_color = pte->pgs ? gs_color_writes_pure(pte->pgs) : 0;
178
179
2.17M
    return font->procs.init_fstack(pte, font);
180
2.17M
}
181
int
182
gs_text_enum_init(gs_text_enum_t *pte, const gs_text_enum_procs_t *procs,
183
                  gx_device *dev, gs_gstate *pgs,
184
                  const gs_text_params_t *text, gs_font *font,
185
                  const gx_clip_path *pcpath,
186
                  gs_memory_t *mem)
187
2.17M
{
188
2.17M
    int code;
189
190
2.17M
    pte->text = *text;
191
2.17M
    pte->dev = dev;
192
2.17M
    pte->imaging_dev = NULL;
193
2.17M
    pte->pgs = pgs;
194
2.17M
    pte->orig_font = font;
195
2.17M
    pte->pcpath = pcpath;
196
2.17M
    pte->pcpath = gx_cpath_alloc_shared(pcpath, mem, "gs_text_enum_init");
197
    /* Assign the following before potentially returning an error
198
       so there's enough there to all the cleanup
199
     */
200
2.17M
    pte->memory = mem;
201
2.17M
    pte->procs = procs;
202
2.17M
    if (pte->pcpath == NULL) {
203
0
        code = gs_note_error(gs_error_VMerror);
204
0
        goto done;
205
0
    }
206
#ifdef DEBUG
207
    pte->text_enum_id = gs_next_text_enum_id(font);
208
#else
209
2.17M
    pte->text_enum_id = 0;
210
2.17M
#endif
211
2.17M
    pte->enum_client_data = NULL;
212
    /* text_begin procedure sets rc */
213
    /* init_dynamic sets current_font */
214
215
2.17M
    pte->log2_scale.x = pte->log2_scale.y = 0;
216
    /* init_dynamic sets index, xy_index, fstack */
217
2.17M
    code = gs_text_enum_init_dynamic(pte, font);
218
2.17M
    pte->k_text_release = 0;
219
2.17M
    if (code >= 0)
220
2.17M
        rc_increment(dev);
221
2.17M
done:
222
2.17M
    return code;
223
2.17M
}
224
225
gs_text_enum_t *
226
gs_text_enum_alloc(gs_memory_t * mem, gs_gstate * pgs, client_name_t cname)
227
0
{
228
0
    gs_text_enum_t *penum;
229
230
0
    rc_alloc_struct_1(penum, gs_text_enum_t, &st_gs_text_enum, mem,
231
0
                      return 0, cname);
232
0
    penum->rc.free = rc_free_text_enum;
233
234
    /* Initialize pointers for GC */
235
0
    penum->text.operation = 0;  /* no pointers relevant */
236
0
    penum->dev = 0;
237
0
    penum->pgs = pgs;
238
0
    penum->fapi_log2_scale.x = penum->fapi_log2_scale.y = -1;
239
0
    penum->fapi_glyph_shift.x = penum->fapi_glyph_shift.y = 0;
240
0
    penum->fstack.depth = -1;
241
0
    return penum;
242
0
}
243
244
/*
245
 * Copy the dynamically changing elements from one enumerator to another.
246
 * This is useful primarily for enumerators that sometimes pass the
247
 * operation to a subsidiary enumerator.
248
 */
249
void
250
gs_text_enum_copy_dynamic(gs_text_enum_t *pto, const gs_text_enum_t *pfrom,
251
                          bool for_return)
252
3.93M
{
253
3.93M
    int depth = pfrom->fstack.depth;
254
255
3.93M
    pto->current_font = pfrom->current_font;
256
3.93M
    pto->index = pfrom->index;
257
3.93M
    pto->bytes_decoded = pfrom->bytes_decoded;
258
3.93M
    pto->xy_index = pfrom->xy_index;
259
3.93M
    pto->fstack.depth = depth;
260
3.93M
    pto->FontBBox_as_Metrics2 = pfrom->FontBBox_as_Metrics2;
261
3.93M
    pto->pair = pfrom->pair;
262
3.93M
    pto->device_disabled_grid_fitting = pfrom->device_disabled_grid_fitting;
263
3.93M
    pto->outer_CID = pfrom->outer_CID;
264
3.93M
    if (depth >= 0)
265
195k
        memcpy(pto->fstack.items, pfrom->fstack.items,
266
195k
               (depth + 1) * sizeof(pto->fstack.items[0]));
267
3.93M
    if (for_return) {
268
3.55M
        pto->cmap_code = pfrom->cmap_code;
269
3.55M
        pto->returned = pfrom->returned;
270
3.55M
    }
271
3.93M
}
272
273
/* Begin processing text based on a graphics state. */
274
int
275
gs_text_begin(gs_gstate * pgs, const gs_text_params_t * text,
276
              gs_memory_t * mem, gs_text_enum_t ** ppte)
277
1.80M
{
278
1.80M
    gx_clip_path *pcpath = 0;
279
1.80M
    int code;
280
1.80M
    gs_overprint_params_t op_params = { 0 };
281
1.80M
    bool op_active = dev_proc(pgs->device, dev_spec_op)(pgs->device, gxdso_overprint_active, NULL, 0);
282
1.80M
    bool text_op_fill = ((pgs->overprint || (!pgs->overprint && op_active)) &&
283
1.80M
        (pgs->text_rendering_mode == 0));
284
1.80M
    bool text_op_stroke = ((pgs->stroke_overprint || (!pgs->stroke_overprint && op_active)) &&
285
1.80M
        (pgs->text_rendering_mode == 1));
286
1.80M
    bool type3 = (pgs->font->FontType == ft_user_defined ||
287
1.80M
        pgs->font->FontType == ft_PDF_user_defined ||
288
1.80M
        pgs->font->FontType == ft_PCL_user_defined ||
289
1.80M
        pgs->font->FontType == ft_MicroType ||
290
1.80M
        pgs->font->FontType == ft_GL2_stick_user_defined ||
291
1.80M
        pgs->font->FontType == ft_GL2_531);
292
1.80M
    bool in_smask =
293
1.80M
        (dev_proc(pgs->device, dev_spec_op)(pgs->device, gxdso_in_smask_construction, NULL, 0)) > 0;
294
1.80M
    bool black_text = (text->operation & (TEXT_DO_DRAW | TEXT_DO_ANY_CHARPATH)) &&
295
1.80M
                        !type3 && !in_smask;
296
1.80M
    cmm_dev_profile_t *icc_struct;
297
298
1.80M
    code = dev_proc(pgs->device, get_profile)((gx_device *)pgs->device, &icc_struct);
299
1.80M
    if (code < 0)
300
0
        black_text = 0;
301
1.80M
    else
302
1.80M
        black_text = black_text && icc_struct->blacktext;
303
304
    /*
305
     * Detect nocurrentpoint now, even if the string is empty, for Adobe
306
     * compatibility.
307
     */
308
1.80M
    if (text->operation & (TEXT_DO_DRAW | TEXT_DO_ANY_CHARPATH)) {
309
1.78M
        if (!pgs->current_point_valid)
310
1
            return_error(gs_error_nocurrentpoint);
311
1.78M
    }
312
    /* Detect zero FontNatrix now for Adobe compatibility with CET tests.
313
       Note that matrixe\\ces like [1 0 0 0 0 0] are used in comparefiles
314
       to compute a text width.
315
       Note : FontType 3 throws error in setcachedevice. */
316
1.80M
    if (pgs->font->FontType != ft_user_defined &&
317
1.80M
        pgs->font->FontType != ft_PDF_user_defined &&
318
1.80M
        pgs->font->FontType != ft_GL2_stick_user_defined &&
319
1.80M
        pgs->font->FontType != ft_PCL_user_defined &&
320
1.80M
        pgs->font->FontMatrix.xx == 0 && pgs->font->FontMatrix.xy == 0 &&
321
1.80M
        pgs->font->FontMatrix.yx == 0 && pgs->font->FontMatrix.yy == 0)
322
94
        return_error(gs_error_undefinedresult); /* sic! : CPSI compatibility */
323
1.80M
    if (text->operation & TEXT_DO_DRAW) {
324
1.78M
        code = gx_effective_clip_path(pgs, &pcpath);
325
1.78M
        if (code < 0)
326
0
            return code;
327
1.78M
    }
328
    /* We must load device color even with no TEXT_DO_DRAW,
329
       because a high level device accumulates a charstring
330
       of a Type 3 font while stringwidth.
331
       Unfortunately we can't effectively know a leaf font type here,
332
       so we load the color unconditionally . */
333
    /* Processing a text object operation */
334
1.80M
    ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
335
336
1.80M
    if (black_text && pgs->black_textvec_state == NULL) {
337
0
        gsicc_setup_blacktextvec(pgs, (gx_device *)pgs->device, true);
338
0
    }
339
340
1.80M
    code = gx_set_dev_color(pgs);
341
1.80M
    if (code != 0)
342
2.19k
        return code;
343
344
1.79M
    code = gs_gstate_color_load(pgs);
345
1.79M
    if (code < 0)
346
0
        return code;
347
348
1.79M
    if (text_op_stroke) {
349
0
        if_debug0m(gs_debug_flag_overprint, pgs->memory,
350
0
            "[overprint] Stroke Text Overprint\n");
351
0
        code = gs_do_set_overprint(pgs);
352
0
        if (code < 0)
353
0
            return code;
354
1.79M
    } else if (text_op_fill) {
355
36.6k
        if_debug0m(gs_debug_flag_overprint, pgs->memory,
356
36.6k
            "[overprint] Fill Text Overprint\n");
357
36.6k
        code = gs_do_set_overprint(pgs);
358
36.6k
        if (code < 0)
359
0
            return code;
360
36.6k
    }
361
362
    /* If overprint is true, push the compositor action to set the op device state */
363
1.79M
    if ((pgs->overprint  && pgs->text_rendering_mode == 0) ||
364
1.79M
        (pgs->stroke_overprint && pgs->text_rendering_mode == 1) ||
365
1.79M
        op_active) {
366
36.6k
        gx_device* dev = pgs->device;
367
36.6k
        cmm_dev_profile_t* dev_profile;
368
369
36.6k
        dev_proc(dev, get_profile)(dev, &dev_profile);
370
        /* Previously, we used to only update overprint here if the devices default
371
         * colorspace was CMYK or NCHANNEL. This is at odds with above, where we
372
         * always gs_do_set_overprint. This meant that for RGB+Spots devices we
373
         * could arrive in overprint_fill_rectangle_hl_color without having set the
374
         * op_state to anything, causing an assert. Let's just always update_overprint. */
375
36.6k
        if (dev_profile->overprint_control != gs_overprint_control_disable) {
376
36.6k
            if (pgs->text_rendering_mode == 0) {
377
36.6k
                op_params.op_state = OP_STATE_FILL;
378
36.6k
                gs_gstate_update_overprint(pgs, &op_params);
379
36.6k
            } else if (pgs->text_rendering_mode == 1) {
380
0
                op_params.op_state = OP_STATE_STROKE;
381
0
                gs_gstate_update_overprint(pgs, &op_params);
382
0
            }
383
36.6k
        }
384
36.6k
    }
385
386
1.79M
    pgs->device->sgr.stroke_stored = false;
387
1.79M
    code = gx_device_text_begin(pgs->device, pgs,
388
1.79M
                                text, pgs->font,
389
1.79M
                                pcpath, ppte);
390
391
    /* we need to know if we are doing a highlevel device.
392
       Also we need to know if we are doing any stroke
393
       or stroke fill operations. This determines when
394
       we need to release the black_textvec_state structure. */
395
1.79M
    if (code >= 0 && *ppte != NULL) {
396
1.79M
        if (black_text) {
397
0
            if (!((*ppte)->k_text_release)) {
398
                /* Not a high level device */
399
0
                if (pgs->text_rendering_mode == 0 ||
400
0
                    pgs->text_rendering_mode == 4) {
401
                    /* No stroke */
402
0
                    (*ppte)->k_text_release = 1;
403
0
                }
404
0
            }
405
0
        } else
406
1.79M
            (*ppte)->k_text_release = 0;
407
1.79M
    }
408
409
1.79M
    return code;
410
1.79M
}
411
412
/*
413
 * Update the device color to be used with text (because a kshow or
414
 * cshow procedure may have changed the current color).
415
 */
416
int
417
gs_text_update_dev_color(gs_gstate * pgs, gs_text_enum_t * pte)
418
22.3k
{
419
    /* Processing a text object operation */
420
22.3k
    ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
421
422
22.3k
    if (pte->text.operation & TEXT_DO_DRAW) {
423
        /* FIXME: It feels bad that we're setting the dev color in
424
         * pgs, rather than pte->pgs. */
425
6.41k
        int code = gx_set_dev_color(pgs);
426
6.41k
        if (code != 0)
427
0
            return code;
428
6.41k
    }
429
22.3k
    return 0;
430
22.3k
}
431
432
static inline uint text_do_draw(gs_gstate * pgs)
433
1.88k
{
434
1.88k
    return (pgs->text_rendering_mode == 3 ?
435
1.88k
        TEXT_DO_NONE | TEXT_RENDER_MODE_3 : TEXT_DO_DRAW);
436
1.88k
}
437
438
/* Begin PostScript-equivalent text operations. */
439
int
440
gs_show_begin(gs_gstate * pgs, const byte * str, uint size,
441
              gs_memory_t * mem, gs_text_enum_t ** ppte)
442
1.68k
{
443
1.68k
    gs_text_params_t text;
444
445
1.68k
    text.operation = TEXT_FROM_STRING | text_do_draw(pgs) | TEXT_RETURN_WIDTH;
446
1.68k
    text.data.bytes = str, text.size = size;
447
1.68k
    return gs_text_begin(pgs, &text, mem, ppte);
448
1.68k
}
449
int
450
gs_ashow_begin(gs_gstate * pgs, double ax, double ay, const byte * str, uint size,
451
               gs_memory_t * mem, gs_text_enum_t ** ppte)
452
203
{
453
203
    gs_text_params_t text;
454
455
203
    text.operation = TEXT_FROM_STRING | TEXT_ADD_TO_ALL_WIDTHS |
456
203
        text_do_draw(pgs) | TEXT_RETURN_WIDTH;
457
203
    text.data.bytes = str, text.size = size;
458
203
    text.delta_all.x = ax;
459
203
    text.delta_all.y = ay;
460
203
    return gs_text_begin(pgs, &text, mem, ppte);
461
203
}
462
int
463
gs_widthshow_begin(gs_gstate * pgs, double cx, double cy, gs_char chr,
464
                   const byte * str, uint size,
465
                   gs_memory_t * mem, gs_text_enum_t ** ppte)
466
0
{
467
0
    gs_text_params_t text;
468
469
0
    text.operation = TEXT_FROM_STRING | TEXT_ADD_TO_SPACE_WIDTH |
470
0
        text_do_draw(pgs) | TEXT_RETURN_WIDTH;
471
0
    text.data.bytes = str, text.size = size;
472
0
    text.delta_space.x = cx;
473
0
    text.delta_space.y = cy;
474
0
    text.space.s_char = chr;
475
0
    return gs_text_begin(pgs, &text, mem, ppte);
476
0
}
477
int
478
gs_awidthshow_begin(gs_gstate * pgs, double cx, double cy, gs_char chr,
479
                    double ax, double ay, const byte * str, uint size,
480
                    gs_memory_t * mem, gs_text_enum_t ** ppte)
481
0
{
482
0
    gs_text_params_t text;
483
484
0
    text.operation = TEXT_FROM_STRING |
485
0
        TEXT_ADD_TO_ALL_WIDTHS | TEXT_ADD_TO_SPACE_WIDTH |
486
0
        text_do_draw(pgs) | TEXT_RETURN_WIDTH;
487
0
    text.data.bytes = str, text.size = size;
488
0
    text.delta_space.x = cx;
489
0
    text.delta_space.y = cy;
490
0
    text.space.s_char = chr;
491
0
    text.delta_all.x = ax;
492
0
    text.delta_all.y = ay;
493
0
    return gs_text_begin(pgs, &text, mem, ppte);
494
0
}
495
int
496
gs_kshow_begin(gs_gstate * pgs, const byte * str, uint size,
497
               gs_memory_t * mem, gs_text_enum_t ** ppte)
498
0
{
499
0
    gs_text_params_t text;
500
501
    /* Detect degenerate CTM now for Adobe compatibility with CET 13-12-4. */
502
0
    if (pgs->ctm.xx * pgs->ctm.yy - pgs->ctm.yx * pgs->ctm.xy == 0)
503
0
        return_error(gs_error_undefinedresult); /* sic! : CPSI compatibility */
504
0
    text.operation = TEXT_FROM_STRING | text_do_draw(pgs) | TEXT_INTERVENE |
505
0
        TEXT_RETURN_WIDTH;
506
0
    text.data.bytes = str, text.size = size;
507
0
    return gs_text_begin(pgs, &text, mem, ppte);
508
0
}
509
510
/* Retrieve text params from enumerator. */
511
gs_text_params_t *
512
gs_get_text_params(gs_text_enum_t *pte)
513
0
{
514
0
    return &pte->text;
515
0
}
516
517
int
518
gs_xyshow_begin(gs_gstate * pgs, const byte * str, uint size,
519
                const float *x_widths, const float *y_widths,
520
                uint widths_size, gs_memory_t * mem, gs_text_enum_t ** ppte)
521
0
{
522
0
    gs_text_params_t text = {0};
523
0
    uint widths_needed;
524
0
    int code;
525
526
0
    text.operation = TEXT_FROM_STRING | TEXT_REPLACE_WIDTHS |
527
0
        text_do_draw(pgs) | TEXT_RETURN_WIDTH;
528
0
    text.data.bytes = str, text.size = size;
529
0
    text.x_widths = x_widths;
530
0
    text.y_widths = y_widths;
531
0
    text.widths_size = widths_size;
532
533
    /*
534
     * Check that the widths array is large enough.  gs_text_replaced_width
535
     * checks this step-by-step, but Adobe's interpreters check it ahead of
536
     * time, and for CET compliance, we must also.  This is very easy for
537
     * font types that always have 8-bit characters, but for others, we
538
     * must use the font's next_char_glyph procedure to determine how many
539
     * characters there are in the string.
540
     */
541
0
    code = gs_text_count_chars(pgs, &text, mem);
542
0
    if (code < 0)
543
0
        return code;
544
0
    widths_needed = code;
545
0
    if (x_widths && y_widths)
546
0
        widths_needed <<= 1;
547
0
    if (widths_size < widths_needed)
548
0
        return_error(gs_error_rangecheck);
549
0
    return gs_text_begin(pgs, &text, mem, ppte);
550
0
}
551
552
static void
553
setup_FontBBox_as_Metrics2 (gs_text_enum_t * pte, gs_font * pfont)
554
0
{
555
    /* When we exec a operator like `show' that has a a chance to get
556
       a glyph from a char, we can set FontBBox_as_Metrics2 in
557
       gschar0.c:gs_type0_next_char_glyph.  In other hand, when we
558
       exec a operator like `glyphshow' that get a glyph directly from
559
       an input file, gschar0.c:gs_type0_next_char_glyph is exec'ed.
560
       For the later case, we set up FontBBox_as_Metrics2 with using
561
       this procedure.. */
562
0
    if (pfont->FontType == ft_CID_encrypted
563
0
        || pfont->FontType == ft_CID_TrueType)
564
0
        pte->FontBBox_as_Metrics2 = ((gs_font_base *)pfont)->FontBBox.q;
565
0
}
566
567
int
568
gs_glyphshow_begin(gs_gstate * pgs, gs_glyph glyph,
569
                   gs_memory_t * mem, gs_text_enum_t ** ppte)
570
0
{
571
0
    gs_text_params_t text;
572
0
    int result;
573
574
0
    text.operation = TEXT_FROM_SINGLE_GLYPH | text_do_draw(pgs) | TEXT_RETURN_WIDTH;
575
0
    text.data.d_glyph = glyph;
576
0
    text.size = 1;
577
0
    result = gs_text_begin(pgs, &text, mem, ppte);
578
0
    if (result == 0)
579
0
      setup_FontBBox_as_Metrics2(*ppte, pgs->font);
580
0
    return result;
581
0
}
582
int
583
gs_cshow_begin(gs_gstate * pgs, const byte * str, uint size,
584
               gs_memory_t * mem, gs_text_enum_t ** ppte)
585
0
{
586
0
    gs_text_params_t text;
587
588
0
    text.operation = TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_INTERVENE;
589
0
    text.data.bytes = str, text.size = size;
590
0
    return gs_text_begin(pgs, &text, mem, ppte);
591
0
}
592
int
593
gs_stringwidth_begin(gs_gstate * pgs, const byte * str, uint size,
594
                     gs_memory_t * mem, gs_text_enum_t ** ppte)
595
42
{
596
42
    gs_text_params_t text;
597
598
42
    text.operation = TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_RETURN_WIDTH;
599
42
    text.data.bytes = str, text.size = size;
600
42
    return gs_text_begin(pgs, &text, mem, ppte);
601
42
}
602
int
603
gs_charpath_begin(gs_gstate * pgs, const byte * str, uint size, bool stroke_path,
604
                  gs_memory_t * mem, gs_text_enum_t ** ppte)
605
26
{
606
26
    gs_text_params_t text;
607
608
26
    text.operation = TEXT_FROM_STRING | TEXT_RETURN_WIDTH |
609
26
        (stroke_path ? TEXT_DO_TRUE_CHARPATH : TEXT_DO_FALSE_CHARPATH);
610
26
    text.data.bytes = str, text.size = size;
611
26
    return gs_text_begin(pgs, &text, mem, ppte);
612
26
}
613
int
614
gs_charboxpath_begin(gs_gstate * pgs, const byte * str, uint size,
615
                bool stroke_path, gs_memory_t * mem, gs_text_enum_t ** ppte)
616
0
{
617
0
    gs_text_params_t text;
618
619
0
    text.operation = TEXT_FROM_STRING | TEXT_RETURN_WIDTH |
620
0
        (stroke_path ? TEXT_DO_TRUE_CHARBOXPATH : TEXT_DO_FALSE_CHARBOXPATH);
621
0
    text.data.bytes = str, text.size = size;
622
0
    return gs_text_begin(pgs, &text, mem, ppte);
623
0
}
624
int
625
gs_glyphpath_begin(gs_gstate * pgs, gs_glyph glyph, bool stroke_path,
626
                   gs_memory_t * mem, gs_text_enum_t ** ppte)
627
0
{
628
0
    gs_text_params_t text;
629
0
    int result;
630
631
0
    text.operation = TEXT_FROM_SINGLE_GLYPH | TEXT_RETURN_WIDTH |
632
0
        (stroke_path ? TEXT_DO_TRUE_CHARPATH : TEXT_DO_FALSE_CHARPATH);
633
0
    text.data.d_glyph = glyph;
634
0
    text.size = 1;
635
0
    result = gs_text_begin(pgs, &text, mem, ppte);
636
0
    if (result == 0)
637
0
      setup_FontBBox_as_Metrics2(*ppte, pgs->font);
638
0
    return result;
639
0
}
640
int
641
gs_glyphwidth_begin(gs_gstate * pgs, gs_glyph glyph,
642
                    gs_memory_t * mem, gs_text_enum_t ** ppte)
643
0
{
644
0
    gs_text_params_t text;
645
0
    int result;
646
647
0
    text.operation = TEXT_FROM_SINGLE_GLYPH | TEXT_DO_NONE | TEXT_RETURN_WIDTH;
648
0
    text.data.d_glyph = glyph;
649
0
    text.size = 1;
650
0
    result = gs_text_begin(pgs, &text, mem, ppte);
651
0
    if (result == 0)
652
0
      setup_FontBBox_as_Metrics2(*ppte, pgs->font);
653
0
    return result;
654
0
}
655
656
/* Restart processing with different parameters. */
657
int
658
gs_text_restart(gs_text_enum_t *pte, const gs_text_params_t *text)
659
0
{
660
0
    gs_text_enum_t tenum;
661
662
0
    tenum = *pte;
663
0
    tenum.text = *text;
664
0
    gs_text_enum_init_dynamic(&tenum, pte->orig_font);
665
0
    setup_FontBBox_as_Metrics2(pte, pte->orig_font);
666
0
    return gs_text_resync(pte, &tenum);
667
0
}
668
669
/*
670
 * Resync text processing with new parameters and string position.
671
 */
672
int
673
gs_text_resync(gs_text_enum_t *pte, const gs_text_enum_t *pfrom)
674
0
{
675
0
    return pte->procs->resync(pte, pfrom);
676
0
}
677
678
/* Process text after 'begin'. */
679
int
680
gs_text_process(gs_text_enum_t * pte)
681
2.20M
{
682
2.20M
    return pte->procs->process(pte);
683
2.20M
}
684
685
/* Access elements of the enumerator. */
686
gs_font *
687
gs_text_current_font(const gs_text_enum_t *pte)
688
0
{
689
0
    return pte->current_font;
690
0
}
691
gs_char
692
gs_text_current_char(const gs_text_enum_t *pte)
693
22.3k
{
694
22.3k
    return pte->returned.current_char;
695
22.3k
}
696
gs_char
697
gs_text_next_char(const gs_text_enum_t *pte)
698
0
{
699
0
    const uint operation = pte->text.operation;
700
701
0
    if (pte->index >= pte->text.size)
702
0
        return gs_no_char; /* rangecheck */
703
0
    if (operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES))
704
0
        return pte->text.data.bytes[pte->index];
705
0
    if (operation & TEXT_FROM_CHARS)
706
0
        return pte->text.data.chars[pte->index];
707
0
    return gs_no_char;   /* rangecheck */
708
0
}
709
gs_glyph
710
gs_text_current_glyph(const gs_text_enum_t *pte)
711
22.3k
{
712
22.3k
    return pte->returned.current_glyph;
713
22.3k
}
714
int
715
gs_text_total_width(const gs_text_enum_t *pte, gs_point *pwidth)
716
42
{
717
42
    *pwidth = pte->returned.total_width;
718
42
    return 0;
719
42
}
720
721
/* Assuming REPLACE_WIDTHS is set, return the width of the i'th character. */
722
int
723
gs_text_replaced_width(const gs_text_params_t *text, uint index,
724
                       gs_point *pwidth)
725
6.51M
{
726
6.51M
    const float *x_widths = text->x_widths;
727
6.51M
    const float *y_widths = text->y_widths;
728
729
6.51M
    if (x_widths == y_widths) {
730
0
        if (x_widths) {
731
0
            index *= 2;
732
0
            if (index + 1 >= text->widths_size)
733
0
                return_error(gs_error_rangecheck);
734
0
            pwidth->x = x_widths[index];
735
0
            pwidth->y = x_widths[index + 1];
736
0
        }
737
0
        else
738
0
            pwidth->x = pwidth->y = 0;
739
6.51M
    } else {
740
6.51M
        if (index >= text->widths_size)
741
0
            return_error(gs_error_rangecheck);
742
6.51M
        pwidth->x = (x_widths ? x_widths[index] : 0.0);
743
6.51M
        pwidth->y = (y_widths ? y_widths[index] : 0.0);
744
6.51M
    }
745
6.51M
    return 0;
746
6.51M
}
747
748
/* Determine whether only the width is needed. */
749
bool
750
gs_text_is_width_only(const gs_text_enum_t * pte)
751
375k
{
752
375k
    return pte->procs->is_width_only(pte);
753
375k
}
754
755
/* Return the width of the current character. */
756
int
757
gs_text_current_width(const gs_text_enum_t * pte, gs_point *pwidth)
758
0
{
759
0
    return pte->procs->current_width(pte, pwidth);
760
0
}
761
762
/* Set text metrics and optionally enable caching. */
763
int
764
gs_text_set_cache(gs_text_enum_t * pte, const double *values,
765
                  gs_text_cache_control_t control)
766
1.11k
{
767
1.11k
    return pte->procs->set_cache(pte, values, control);
768
1.11k
}
769
int
770
gs_text_setcharwidth(gs_text_enum_t * pte, const double wxy[2])
771
22.4k
{
772
22.4k
    return pte->procs->set_cache(pte, wxy, TEXT_SET_CHAR_WIDTH);
773
22.4k
}
774
int
775
gs_text_setcachedevice(gs_text_enum_t * pte, const double wbox[6])
776
1.76k
{
777
1.76k
    return pte->procs->set_cache(pte, wbox, TEXT_SET_CACHE_DEVICE);
778
1.76k
}
779
int
780
gs_text_setcachedevice2(gs_text_enum_t * pte, const double wbox2[10])
781
329k
{
782
329k
    return pte->procs->set_cache(pte, wbox2, TEXT_SET_CACHE_DEVICE2);
783
329k
}
784
785
/* Retry processing the last character without caching. */
786
int
787
gs_text_retry(gs_text_enum_t * pte)
788
0
{
789
0
    return pte->procs->retry(pte);
790
0
}
791
792
/* Release the text processing structures. */
793
void
794
gx_default_text_release(gs_text_enum_t *pte, client_name_t cname)
795
2.17M
{
796
2.17M
    gx_cpath_free((gx_clip_path *)pte->pcpath, "gx_default_text_release");
797
2.17M
    pte->pcpath = NULL;
798
2.17M
    rc_decrement_only(pte->dev, cname);
799
2.17M
    rc_decrement_only(pte->imaging_dev, cname);
800
2.17M
}
801
void
802
rc_free_text_enum(gs_memory_t * mem, void *obj, client_name_t cname)
803
2.17M
{
804
2.17M
    gs_text_enum_t *pte = obj;
805
806
2.17M
    pte->procs->release(pte, cname);
807
2.17M
    rc_free_struct_only(mem, obj, cname);
808
2.17M
}
809
void
810
gs_text_release(gs_gstate *pgs, gs_text_enum_t * pte, client_name_t cname)
811
2.17M
{
812
2.17M
    if (pgs != NULL && pgs->black_textvec_state != NULL)
813
0
        gsicc_restore_blacktextvec(pgs, true);
814
2.17M
    rc_decrement_only(pte, cname);
815
2.17M
}
816
817
/* ---------------- Default font rendering procedures ---------------- */
818
819
/* Default fstack initialization procedure. */
820
int
821
gs_default_init_fstack(gs_text_enum_t *pte, gs_font *pfont)
822
1.94M
{
823
1.94M
    pte->fstack.depth = -1;
824
1.94M
    return 0;
825
1.94M
}
826
827
/* Default next-glyph procedure. */
828
int
829
gs_default_next_char_glyph(gs_text_enum_t *pte, gs_char *pchr, gs_glyph *pglyph)
830
31.7M
{
831
31.7M
    if (pte->index >= pte->text.size)
832
3.66M
        return 2;
833
28.0M
    if (pte->text.operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) {
834
        /* ordinary string */
835
28.0M
        *pchr = pte->text.data.bytes[pte->index];
836
28.0M
        if (pte->outer_CID != GS_NO_GLYPH)
837
0
            *pglyph = pte->outer_CID;
838
28.0M
        else
839
28.0M
            *pglyph = GS_NO_GLYPH;
840
28.0M
    } else if (pte->text.operation & TEXT_FROM_SINGLE_GLYPH) {
841
        /* glyphshow or glyphpath */
842
0
        *pchr = gs_no_char;
843
0
        *pglyph = pte->text.data.d_glyph;
844
5.13k
    } else if (pte->text.operation & TEXT_FROM_GLYPHS) {
845
0
        *pchr = gs_no_char;
846
0
        *pglyph = pte->text.data.glyphs[pte->index];
847
5.13k
    } else if (pte->text.operation & TEXT_FROM_SINGLE_CHAR) {
848
0
        *pchr = pte->text.data.d_char;
849
0
        *pglyph = GS_NO_GLYPH;
850
5.13k
    } else if (pte->text.operation & TEXT_FROM_CHARS) {
851
5.13k
        *pchr = pte->text.data.chars[pte->index];
852
5.13k
        *pglyph = GS_NO_GLYPH;
853
5.13k
    } else
854
0
        return_error(gs_error_rangecheck); /* shouldn't happen */
855
28.0M
    pte->index++;
856
28.0M
    return 0;
857
28.0M
}
858
859
/* Dummy (ineffective) BuildChar/BuildGlyph procedure */
860
int
861
gs_no_build_char(gs_show_enum *pte, gs_gstate *pgs, gs_font *pfont,
862
                 gs_char chr, gs_glyph glyph)
863
22.3k
{
864
22.3k
    return 1;     /* failure, but not error */
865
22.3k
}