Coverage Report

Created: 2025-06-24 07:01

/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
11.9k
ENUM_PTRS_WITH(text_params_enum_ptrs, gs_text_params_t *tptr) return 0;
44
2.98k
case 0:
45
2.98k
if (tptr->operation & TEXT_FROM_STRING) {
46
2.98k
    return ENUM_CONST_STRING2(tptr->data.bytes, tptr->size);
47
2.98k
}
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
2.98k
case 1:
56
2.98k
return ENUM_OBJ(tptr->operation & TEXT_REPLACE_WIDTHS ?
57
0
                tptr->x_widths : NULL);
58
2.98k
case 2:
59
2.98k
return ENUM_OBJ(tptr->operation & TEXT_REPLACE_WIDTHS ?
60
11.9k
                tptr->y_widths : NULL);
61
11.9k
ENUM_PTRS_END
62
2.98k
static RELOC_PTRS_WITH(text_params_reloc_ptrs, gs_text_params_t *tptr)
63
2.98k
{
64
2.98k
    if (tptr->operation & TEXT_FROM_STRING) {
65
2.98k
        gs_const_string str;
66
67
2.98k
        str.data = tptr->data.bytes;
68
2.98k
        str.size = tptr->size;
69
2.98k
        RELOC_CONST_STRING_VAR(str);
70
2.98k
        tptr->data.bytes = str.data;
71
2.98k
    } 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
2.98k
    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
2.98k
}
82
2.98k
RELOC_PTRS_END
83
84
32.8k
static ENUM_PTRS_WITH(text_enum_enum_ptrs, gs_text_enum_t *eptr)
85
14.9k
{
86
14.9k
    if (index == 6) {
87
2.98k
        if (eptr->pair != 0)
88
2.98k
            ENUM_RETURN(eptr->pair - eptr->pair->index);
89
1
        else
90
1
            ENUM_RETURN(0);
91
2.98k
    }
92
11.9k
    index -= 7;
93
11.9k
    if (index <= eptr->fstack.depth)
94
0
        ENUM_RETURN(eptr->fstack.items[index].font);
95
11.9k
    index -= eptr->fstack.depth + 1;
96
11.9k
     return ENUM_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text), index);
97
11.9k
}
98
2.98k
case 0: return ENUM_OBJ(gx_device_enum_ptr(eptr->dev));
99
2.98k
case 1: return ENUM_OBJ(gx_device_enum_ptr(eptr->imaging_dev));
100
11.9k
ENUM_PTR2(2, gs_text_enum_t, pgs, orig_font);
101
32.8k
ENUM_PTR2(4, gs_text_enum_t, pcpath, current_font);
102
32.8k
ENUM_PTRS_END
103
104
2.98k
static RELOC_PTRS_WITH(text_enum_reloc_ptrs, gs_text_enum_t *eptr)
105
2.98k
{
106
2.98k
    int i;
107
108
2.98k
    RELOC_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text));
109
2.98k
    eptr->dev = gx_device_reloc_ptr(eptr->dev, gcst);
110
2.98k
    eptr->imaging_dev = gx_device_reloc_ptr(eptr->imaging_dev, gcst);
111
2.98k
    RELOC_PTR2(gs_text_enum_t, pgs, orig_font);
112
2.98k
    RELOC_PTR2(gs_text_enum_t, pcpath, current_font);
113
2.98k
    if (eptr->pair != NULL)
114
2.98k
        eptr->pair = (cached_fm_pair *)RELOC_OBJ(eptr->pair - eptr->pair->index) +
115
2.98k
                             eptr->pair->index;
116
2.98k
    for (i = 0; i <= eptr->fstack.depth; i++)
117
2.98k
        RELOC_PTR(gs_text_enum_t, fstack.items[i].font);
118
2.98k
}
119
2.98k
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
21.1M
{
128
21.1M
    if (TEXT_PARAMS_ARE_INVALID(text))
129
0
        return_error(gs_error_rangecheck);
130
21.1M
    {
131
21.1M
        const gx_clip_path *tcpath =
132
21.1M
            (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
21.1M
        return dev_proc(dev, text_begin)
139
21.1M
            (dev, pgs, text, font, tcpath, ppte);
140
21.1M
    }
141
21.1M
}
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
22.1M
{
150
22.1M
    uint operation = pte->text.operation;
151
22.1M
    bool propagate_charpath = (operation & TEXT_DO_DRAW) != 0;
152
153
22.1M
    pte->current_font = font;
154
22.1M
    pte->index = 0;
155
22.1M
    pte->xy_index = 0;
156
22.1M
    pte->FontBBox_as_Metrics2.x = pte->FontBBox_as_Metrics2.y = 0;
157
22.1M
    pte->pair = 0;
158
22.1M
    pte->device_disabled_grid_fitting = 0;
159
22.1M
    pte->outer_CID = GS_NO_GLYPH;
160
22.1M
    pte->single_byte_space = false;
161
22.1M
    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
22.1M
    if (operation & TEXT_DO_ANY_CHARPATH)
167
17.9k
        pte->charpath_flag =
168
17.9k
            (operation & TEXT_DO_FALSE_CHARPATH ? cpm_false_charpath :
169
17.9k
             operation & TEXT_DO_TRUE_CHARPATH ? cpm_true_charpath :
170
5.27k
             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
22.1M
    else
175
22.1M
        pte->charpath_flag =
176
22.1M
        (propagate_charpath ? (pte->pgs ? pte->pgs->in_charpath : 0) : cpm_show);
177
22.1M
    pte->is_pure_color = pte->pgs ? gs_color_writes_pure(pte->pgs) : 0;
178
179
22.1M
    return font->procs.init_fstack(pte, font);
180
22.1M
}
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
22.1M
{
188
22.1M
    int code;
189
190
22.1M
    pte->text = *text;
191
22.1M
    pte->dev = dev;
192
22.1M
    pte->imaging_dev = NULL;
193
22.1M
    pte->pgs = pgs;
194
22.1M
    pte->orig_font = font;
195
22.1M
    pte->pcpath = pcpath;
196
22.1M
    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
22.1M
    pte->memory = mem;
201
22.1M
    pte->procs = procs;
202
22.1M
    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
22.1M
    pte->text_enum_id = 0;
210
22.1M
#endif
211
22.1M
    pte->enum_client_data = NULL;
212
    /* text_begin procedure sets rc */
213
    /* init_dynamic sets current_font */
214
215
22.1M
    pte->log2_scale.x = pte->log2_scale.y = 0;
216
    /* init_dynamic sets index, xy_index, fstack */
217
22.1M
    code = gs_text_enum_init_dynamic(pte, font);
218
22.1M
    pte->k_text_release = 0;
219
22.1M
    if (code >= 0)
220
22.1M
        rc_increment(dev);
221
22.1M
done:
222
22.1M
    return code;
223
22.1M
}
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
15.3M
{
253
15.3M
    int depth = pfrom->fstack.depth;
254
255
15.3M
    pto->current_font = pfrom->current_font;
256
15.3M
    pto->index = pfrom->index;
257
15.3M
    pto->bytes_decoded = pfrom->bytes_decoded;
258
15.3M
    pto->xy_index = pfrom->xy_index;
259
15.3M
    pto->fstack.depth = depth;
260
15.3M
    pto->FontBBox_as_Metrics2 = pfrom->FontBBox_as_Metrics2;
261
15.3M
    pto->pair = pfrom->pair;
262
15.3M
    pto->device_disabled_grid_fitting = pfrom->device_disabled_grid_fitting;
263
15.3M
    pto->outer_CID = pfrom->outer_CID;
264
15.3M
    if (depth >= 0)
265
714k
        memcpy(pto->fstack.items, pfrom->fstack.items,
266
714k
               (depth + 1) * sizeof(pto->fstack.items[0]));
267
15.3M
    if (for_return) {
268
14.4M
        pto->cmap_code = pfrom->cmap_code;
269
14.4M
        pto->returned = pfrom->returned;
270
14.4M
    }
271
15.3M
}
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
21.2M
{
278
21.2M
    gx_clip_path *pcpath = 0;
279
21.2M
    int code;
280
21.2M
    gs_overprint_params_t op_params = { 0 };
281
21.2M
    bool op_active = dev_proc(pgs->device, dev_spec_op)(pgs->device, gxdso_overprint_active, NULL, 0);
282
21.2M
    bool text_op_fill = ((pgs->overprint || (!pgs->overprint && op_active)) &&
283
21.2M
        (pgs->text_rendering_mode == 0));
284
21.2M
    bool text_op_stroke = ((pgs->stroke_overprint || (!pgs->stroke_overprint && op_active)) &&
285
21.2M
        (pgs->text_rendering_mode == 1));
286
21.2M
    bool type3 = (pgs->font->FontType == ft_user_defined ||
287
21.2M
        pgs->font->FontType == ft_PDF_user_defined ||
288
21.2M
        pgs->font->FontType == ft_PCL_user_defined ||
289
21.2M
        pgs->font->FontType == ft_MicroType ||
290
21.2M
        pgs->font->FontType == ft_GL2_stick_user_defined ||
291
21.2M
        pgs->font->FontType == ft_GL2_531);
292
21.2M
    bool in_smask =
293
21.2M
        (dev_proc(pgs->device, dev_spec_op)(pgs->device, gxdso_in_smask_construction, NULL, 0)) > 0;
294
21.2M
    bool black_text = (text->operation & (TEXT_DO_DRAW | TEXT_DO_ANY_CHARPATH)) &&
295
21.2M
                        !type3 && !in_smask;
296
21.2M
    cmm_dev_profile_t *icc_struct;
297
298
21.2M
    code = dev_proc(pgs->device, get_profile)((gx_device *)pgs->device, &icc_struct);
299
21.2M
    if (code < 0)
300
0
        black_text = 0;
301
21.2M
    else
302
21.2M
        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
21.2M
    if (text->operation & (TEXT_DO_DRAW | TEXT_DO_ANY_CHARPATH)) {
309
20.9M
        if (!pgs->current_point_valid)
310
21
            return_error(gs_error_nocurrentpoint);
311
20.9M
    }
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
21.2M
    if (pgs->font->FontType != ft_user_defined &&
317
21.2M
        pgs->font->FontType != ft_PDF_user_defined &&
318
21.2M
        pgs->font->FontType != ft_GL2_stick_user_defined &&
319
21.2M
        pgs->font->FontType != ft_PCL_user_defined &&
320
21.2M
        pgs->font->FontMatrix.xx == 0 && pgs->font->FontMatrix.xy == 0 &&
321
21.2M
        pgs->font->FontMatrix.yx == 0 && pgs->font->FontMatrix.yy == 0)
322
2.85k
        return_error(gs_error_undefinedresult); /* sic! : CPSI compatibility */
323
21.2M
    if (text->operation & TEXT_DO_DRAW) {
324
20.9M
        code = gx_effective_clip_path(pgs, &pcpath);
325
20.9M
        if (code < 0)
326
0
            return code;
327
20.9M
    }
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
21.2M
    ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
335
336
21.2M
    if (black_text && pgs->black_textvec_state == NULL) {
337
0
        gsicc_setup_blacktextvec(pgs, (gx_device *)pgs->device, true);
338
0
    }
339
340
21.2M
    code = gx_set_dev_color(pgs);
341
21.2M
    if (code != 0)
342
34.9k
        return code;
343
344
21.1M
    code = gs_gstate_color_load(pgs);
345
21.1M
    if (code < 0)
346
0
        return code;
347
348
21.1M
    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
21.1M
    } else if (text_op_fill) {
355
284k
        if_debug0m(gs_debug_flag_overprint, pgs->memory,
356
284k
            "[overprint] Fill Text Overprint\n");
357
284k
        code = gs_do_set_overprint(pgs);
358
284k
        if (code < 0)
359
0
            return code;
360
284k
    }
361
362
    /* If overprint is true, push the compositor action to set the op device state */
363
21.1M
    if ((pgs->overprint  && pgs->text_rendering_mode == 0) ||
364
21.1M
        (pgs->stroke_overprint && pgs->text_rendering_mode == 1) ||
365
21.1M
        op_active) {
366
284k
        gx_device* dev = pgs->device;
367
284k
        cmm_dev_profile_t* dev_profile;
368
369
284k
        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
284k
        if (dev_profile->overprint_control != gs_overprint_control_disable) {
376
284k
            if (pgs->text_rendering_mode == 0) {
377
284k
                op_params.op_state = OP_STATE_FILL;
378
284k
                gs_gstate_update_overprint(pgs, &op_params);
379
284k
            } 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
284k
        }
384
284k
    }
385
386
21.1M
    pgs->device->sgr.stroke_stored = false;
387
21.1M
    code = gx_device_text_begin(pgs->device, pgs,
388
21.1M
                                text, pgs->font,
389
21.1M
                                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
21.1M
    if (code >= 0 && *ppte != NULL) {
396
21.1M
        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
21.1M
            (*ppte)->k_text_release = 0;
407
21.1M
    }
408
409
21.1M
    return code;
410
21.1M
}
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
2.39M
{
419
    /* Processing a text object operation */
420
2.39M
    ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
421
422
2.39M
    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
1.27M
        int code = gx_set_dev_color(pgs);
426
1.27M
        if (code != 0)
427
0
            return code;
428
1.27M
    }
429
2.39M
    return 0;
430
2.39M
}
431
432
static inline uint text_do_draw(gs_gstate * pgs)
433
1.50M
{
434
1.50M
    return (pgs->text_rendering_mode == 3 ?
435
1.50M
        TEXT_DO_NONE | TEXT_RENDER_MODE_3 : TEXT_DO_DRAW);
436
1.50M
}
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.49M
{
443
1.49M
    gs_text_params_t text;
444
445
1.49M
    text.operation = TEXT_FROM_STRING | text_do_draw(pgs) | TEXT_RETURN_WIDTH;
446
1.49M
    text.data.bytes = str, text.size = size;
447
1.49M
    return gs_text_begin(pgs, &text, mem, ppte);
448
1.49M
}
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
8.18k
{
453
8.18k
    gs_text_params_t text;
454
455
8.18k
    text.operation = TEXT_FROM_STRING | TEXT_ADD_TO_ALL_WIDTHS |
456
8.18k
        text_do_draw(pgs) | TEXT_RETURN_WIDTH;
457
8.18k
    text.data.bytes = str, text.size = size;
458
8.18k
    text.delta_all.x = ax;
459
8.18k
    text.delta_all.y = ay;
460
8.18k
    return gs_text_begin(pgs, &text, mem, ppte);
461
8.18k
}
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
414
{
596
414
    gs_text_params_t text;
597
598
414
    text.operation = TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_RETURN_WIDTH;
599
414
    text.data.bytes = str, text.size = size;
600
414
    return gs_text_begin(pgs, &text, mem, ppte);
601
414
}
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
2.65k
{
606
2.65k
    gs_text_params_t text;
607
608
2.65k
    text.operation = TEXT_FROM_STRING | TEXT_RETURN_WIDTH |
609
2.65k
        (stroke_path ? TEXT_DO_TRUE_CHARPATH : TEXT_DO_FALSE_CHARPATH);
610
2.65k
    text.data.bytes = str, text.size = size;
611
2.65k
    return gs_text_begin(pgs, &text, mem, ppte);
612
2.65k
}
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
24.5M
{
682
24.5M
    return pte->procs->process(pte);
683
24.5M
}
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
2.40M
{
694
2.40M
    return pte->returned.current_char;
695
2.40M
}
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
2.40M
{
712
2.40M
    return pte->returned.current_glyph;
713
2.40M
}
714
int
715
gs_text_total_width(const gs_text_enum_t *pte, gs_point *pwidth)
716
407
{
717
407
    *pwidth = pte->returned.total_width;
718
407
    return 0;
719
407
}
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
51.0M
{
726
51.0M
    const float *x_widths = text->x_widths;
727
51.0M
    const float *y_widths = text->y_widths;
728
729
51.0M
    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
51.0M
    } else {
740
51.0M
        if (index >= text->widths_size)
741
0
            return_error(gs_error_rangecheck);
742
51.0M
        pwidth->x = (x_widths ? x_widths[index] : 0.0);
743
51.0M
        pwidth->y = (y_widths ? y_widths[index] : 0.0);
744
51.0M
    }
745
51.0M
    return 0;
746
51.0M
}
747
748
/* Determine whether only the width is needed. */
749
bool
750
gs_text_is_width_only(const gs_text_enum_t * pte)
751
17.8M
{
752
17.8M
    return pte->procs->is_width_only(pte);
753
17.8M
}
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
10.5k
{
767
10.5k
    return pte->procs->set_cache(pte, values, control);
768
10.5k
}
769
int
770
gs_text_setcharwidth(gs_text_enum_t * pte, const double wxy[2])
771
327k
{
772
327k
    return pte->procs->set_cache(pte, wxy, TEXT_SET_CHAR_WIDTH);
773
327k
}
774
int
775
gs_text_setcachedevice(gs_text_enum_t * pte, const double wbox[6])
776
2.11M
{
777
2.11M
    return pte->procs->set_cache(pte, wbox, TEXT_SET_CACHE_DEVICE);
778
2.11M
}
779
int
780
gs_text_setcachedevice2(gs_text_enum_t * pte, const double wbox2[10])
781
13.8M
{
782
13.8M
    return pte->procs->set_cache(pte, wbox2, TEXT_SET_CACHE_DEVICE2);
783
13.8M
}
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
22.1M
{
796
22.1M
    gx_cpath_free((gx_clip_path *)pte->pcpath, "gx_default_text_release");
797
22.1M
    pte->pcpath = NULL;
798
22.1M
    rc_decrement_only(pte->dev, cname);
799
22.1M
    rc_decrement_only(pte->imaging_dev, cname);
800
22.1M
}
801
void
802
rc_free_text_enum(gs_memory_t * mem, void *obj, client_name_t cname)
803
22.1M
{
804
22.1M
    gs_text_enum_t *pte = obj;
805
806
22.1M
    pte->procs->release(pte, cname);
807
22.1M
    rc_free_struct_only(mem, obj, cname);
808
22.1M
}
809
void
810
gs_text_release(gs_gstate *pgs, gs_text_enum_t * pte, client_name_t cname)
811
22.1M
{
812
22.1M
    if (pgs != NULL && pgs->black_textvec_state != NULL)
813
0
        gsicc_restore_blacktextvec(pgs, true);
814
22.1M
    rc_decrement_only(pte, cname);
815
22.1M
}
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
20.0M
{
823
20.0M
    pte->fstack.depth = -1;
824
20.0M
    return 0;
825
20.0M
}
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
191M
{
831
191M
    if (pte->index >= pte->text.size)
832
27.0M
        return 2;
833
164M
    if (pte->text.operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) {
834
        /* ordinary string */
835
163M
        *pchr = pte->text.data.bytes[pte->index];
836
163M
        if (pte->outer_CID != GS_NO_GLYPH)
837
0
            *pglyph = pte->outer_CID;
838
163M
        else
839
163M
            *pglyph = GS_NO_GLYPH;
840
163M
    } 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
118k
    } else if (pte->text.operation & TEXT_FROM_GLYPHS) {
845
0
        *pchr = gs_no_char;
846
0
        *pglyph = pte->text.data.glyphs[pte->index];
847
118k
    } else if (pte->text.operation & TEXT_FROM_SINGLE_CHAR) {
848
0
        *pchr = pte->text.data.d_char;
849
0
        *pglyph = GS_NO_GLYPH;
850
118k
    } else if (pte->text.operation & TEXT_FROM_CHARS) {
851
118k
        *pchr = pte->text.data.chars[pte->index];
852
118k
        *pglyph = GS_NO_GLYPH;
853
118k
    } else
854
0
        return_error(gs_error_rangecheck); /* shouldn't happen */
855
164M
    pte->index++;
856
164M
    return 0;
857
164M
}
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
2.40M
{
864
2.40M
    return 1;     /* failure, but not error */
865
2.40M
}