Coverage Report

Created: 2022-10-31 07:00

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