Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gxchar.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
/* Default implementation of text writing */
18
#include "gx.h"
19
#include "memory_.h"
20
#include "string_.h"
21
#include "gserrors.h"
22
#include "gsstruct.h"
23
#include "gxfixed.h"            /* ditto */
24
#include "gxarith.h"
25
#include "gxmatrix.h"
26
#include "gzstate.h"
27
#include "gxcoord.h"
28
#include "gxdevice.h"
29
#include "gxdevmem.h"
30
#include "gxchar.h"
31
#include "gxfont.h"
32
#include "gxfont0.h"
33
#include "gxfcache.h"
34
#include "gspath.h"
35
#include "gzpath.h"
36
#include "gxfcid.h"
37
38
/* Define whether the show operation uses the character outline data, */
39
/* as opposed to just needing the width (or nothing). */
40
#define SHOW_USES_OUTLINE(penum)\
41
42.2M
  !SHOW_IS(penum, TEXT_DO_NONE | TEXT_DO_CHARWIDTH)
42
43
/* Structure descriptors */
44
public_st_gs_show_enum();
45
extern_st(st_gs_text_enum);
46
static
47
47.7k
ENUM_PTRS_BEGIN(show_enum_enum_ptrs)
48
32.8k
     return ENUM_USING(st_gs_text_enum, vptr, size, index - 5);
49
2.98k
ENUM_PTR(0, gs_show_enum, pgs);
50
2.98k
ENUM_PTR(1, gs_show_enum, show_gstate);
51
47.7k
ENUM_PTR3(2, gs_show_enum, dev_cache, dev_cache2, dev_null);
52
47.7k
ENUM_PTRS_END
53
2.98k
static RELOC_PTRS_WITH(show_enum_reloc_ptrs, gs_show_enum *eptr)
54
2.98k
{
55
2.98k
    RELOC_USING(st_gs_text_enum, vptr, size);           /* superclass */
56
2.98k
    RELOC_VAR(eptr->pgs);
57
2.98k
    RELOC_VAR(eptr->show_gstate);
58
2.98k
    RELOC_PTR3(gs_show_enum, dev_cache, dev_cache2, dev_null);
59
2.98k
}
60
2.98k
RELOC_PTRS_END
61
62
/* Forward declarations */
63
static int continue_kshow(gs_show_enum *);
64
static int continue_show(gs_show_enum *);
65
static int continue_show_update(gs_show_enum *);
66
static void show_set_scale(const gs_show_enum *, gs_log2_scale_point *log2_scale);
67
static int show_cache_setup(gs_show_enum *);
68
static int show_state_setup(gs_show_enum *);
69
static int show_origin_setup(gs_gstate *, fixed, fixed, gs_show_enum * penum);
70
71
/* Accessors for current_char and current_glyph. */
72
2.61M
#define CURRENT_CHAR(penum) ((penum)->returned.current_char)
73
#define SET_CURRENT_CHAR(penum, chr)\
74
62.3M
  ((penum)->returned.current_char = (chr))
75
7.13M
#define CURRENT_GLYPH(penum) ((penum)->returned.current_glyph)
76
#define SET_CURRENT_GLYPH(penum, glyph)\
77
62.3M
  ((penum)->returned.current_glyph = (glyph))
78
79
/* Allocate a show enumerator. */
80
gs_show_enum *
81
gs_show_enum_alloc(gs_memory_t * mem, gs_gstate * pgs, client_name_t cname)
82
16.8M
{
83
16.8M
    gs_show_enum *penum;
84
85
16.8M
    rc_alloc_struct_1(penum, gs_show_enum, &st_gs_show_enum, mem,
86
16.8M
                      return 0, cname);
87
16.8M
    penum->rc.free = rc_free_text_enum;
88
16.8M
    penum->auto_release = true; /* old API */
89
    /* Initialize pointers for GC */
90
16.8M
    penum->text.operation = 0;  /* no pointers relevant */
91
16.8M
    penum->dev = 0;
92
16.8M
    penum->pgs = pgs;
93
16.8M
    penum->show_gstate = 0;
94
16.8M
    penum->dev_cache = 0;
95
16.8M
    penum->dev_cache2 = 0;
96
16.8M
    penum->fapi_log2_scale.x = penum->fapi_log2_scale.y = -1;
97
16.8M
    penum->fapi_glyph_shift.x = penum->fapi_glyph_shift.y = 0;
98
16.8M
    penum->dev_null = 0;
99
16.8M
    penum->fstack.depth = -1;
100
16.8M
    return penum;
101
16.8M
}
102
103
/* ------ Driver procedure ------ */
104
105
static text_enum_proc_resync(gx_show_text_resync);
106
static text_enum_proc_process(gx_show_text_process);
107
static text_enum_proc_is_width_only(gx_show_text_is_width_only);
108
static text_enum_proc_current_width(gx_show_text_current_width);
109
static text_enum_proc_set_cache(gx_show_text_set_cache);
110
static text_enum_proc_retry(gx_show_text_retry);
111
static text_enum_proc_release(gx_show_text_release); /* not default */
112
113
static const gs_text_enum_procs_t default_text_procs = {
114
    gx_show_text_resync, gx_show_text_process,
115
    gx_show_text_is_width_only, gx_show_text_current_width,
116
    gx_show_text_set_cache, gx_show_text_retry,
117
    gx_show_text_release
118
};
119
120
int
121
gx_default_text_begin(gx_device * dev, gs_gstate * pgs1,
122
                      const gs_text_params_t * text, gs_font * font,
123
                      const gx_clip_path * pcpath,
124
                      gs_text_enum_t ** ppte)
125
16.8M
{
126
16.8M
    uint operation = text->operation;
127
16.8M
    bool propagate_charpath = (operation & TEXT_DO_DRAW) != 0;
128
16.8M
    int code;
129
16.8M
    gs_gstate *pgs = (gs_gstate *)pgs1;
130
16.8M
    gs_show_enum *penum;
131
16.8M
    gs_memory_t * mem = pgs->memory;
132
133
16.8M
    penum = gs_show_enum_alloc(mem, pgs, "gx_default_text_begin");
134
16.8M
    if (!penum)
135
0
        return_error(gs_error_VMerror);
136
16.8M
    code = gs_text_enum_init((gs_text_enum_t *)penum, &default_text_procs,
137
16.8M
                             dev, pgs, text, font, pcpath, mem);
138
16.8M
    if (code < 0) {
139
0
        gs_free_object(mem, penum, "gx_default_text_begin");
140
0
        return code;
141
0
    }
142
16.8M
    penum->auto_release = false; /* new API */
143
16.8M
    penum->level = pgs->level;
144
16.8M
    penum->cc = 0;
145
16.8M
    penum->continue_proc = continue_show;
146
16.8M
    switch (penum->charpath_flag) {
147
17.5k
    case cpm_false_charpath: case cpm_true_charpath:
148
17.5k
        penum->can_cache = -1; break;
149
0
    case cpm_false_charboxpath: case cpm_true_charboxpath:
150
0
        penum->can_cache = 0; break;
151
0
    case cpm_charwidth:
152
16.8M
    default:                    /* cpm_show */
153
16.8M
        penum->can_cache = 1; break;
154
16.8M
    }
155
16.8M
    code = show_state_setup(penum);
156
16.8M
    if (code < 0) {
157
2.16k
        gs_text_release(pgs, (gs_text_enum_t *)penum, "gx_default_text_begin");
158
2.16k
        penum = NULL;
159
2.16k
        return code;
160
2.16k
    }
161
16.8M
    penum->show_gstate =
162
16.8M
        (propagate_charpath && (pgs->in_charpath != 0) ?
163
16.8M
         pgs->show_gstate : pgs);
164
16.8M
    if (!(~operation & (TEXT_DO_NONE | TEXT_RETURN_WIDTH))) {
165
        /* This is stringwidth (or a PDF with text in rendering mode 3) . */
166
198k
        gx_device_null *dev_null =
167
198k
            gs_alloc_struct(mem, gx_device_null, &st_device_null,
168
198k
                            "stringwidth(dev_null)");
169
170
198k
        if (dev_null == 0) {
171
0
            gs_text_release(pgs, (gs_text_enum_t *)penum, "gx_default_text_begin");
172
0
            penum = NULL;
173
0
            return_error(gs_error_VMerror);
174
0
        }
175
176
        /* Set up a null device that forwards xfont requests properly. */
177
        /* We have to set the device up here, so the contents are
178
           initialised, and safe to free in the event of an error.
179
         */
180
198k
        gs_make_null_device(dev_null, gs_currentdevice_inline(pgs), mem);
181
182
        /* Do an extra gsave and suppress output */
183
198k
        if ((code = gs_gsave(pgs)) < 0) {
184
0
            gs_text_release(pgs, (gs_text_enum_t *)penum, "gx_default_text_begin");
185
0
            penum = NULL;
186
0
            gs_free_object(mem, dev_null, "gx_default_text_begin");
187
0
            return code;
188
0
        }
189
198k
        penum->level = pgs->level;      /* for level check in show_update */
190
198k
        pgs->ctm_default_set = false;
191
198k
        penum->dev_null = dev_null;
192
        /* Retain this device, since it is referenced from the enumerator. */
193
198k
        gx_device_retain((gx_device *)dev_null, true);
194
198k
        gs_setdevice_no_init(pgs, (gx_device *) dev_null);
195
        /* Establish an arbitrary translation and current point. */
196
198k
        gs_newpath(pgs);
197
198k
        gx_translate_to_fixed(pgs, fixed_0, fixed_0);
198
198k
        code = gx_path_add_point(pgs->path, fixed_0, fixed_0);
199
198k
        if (code < 0) {
200
0
            gs_text_release(pgs, (gs_text_enum_t *)penum, "gx_default_text_begin");
201
0
            penum = NULL;
202
0
            gs_grestore(pgs);
203
0
            return code;
204
0
        }
205
198k
    }
206
16.8M
    *ppte = (gs_text_enum_t *)penum;
207
16.8M
    return 0;
208
16.8M
}
209
210
/* Compute the number of characters in a text. */
211
int
212
gs_text_count_chars(gs_gstate * pgs, gs_text_params_t *text, gs_memory_t * mem)
213
0
{
214
0
    font_proc_next_char_glyph((*next_proc)) = pgs->font->procs.next_char_glyph;
215
216
0
    if (next_proc == gs_default_next_char_glyph)
217
0
        return text->size;
218
0
    else {
219
        /* Do it the hard way. */
220
0
        gs_text_enum_t tenum;   /* use a separate enumerator */
221
0
        gs_char tchr;
222
0
        gs_glyph tglyph;
223
0
        int size = 0;
224
0
        int code;
225
226
0
        size = 0;
227
228
0
        code = gs_text_enum_init(&tenum, &default_text_procs,
229
0
                             NULL, NULL, text, pgs->root_font,
230
0
                             NULL, mem);
231
0
        if (code < 0)
232
0
            return code;
233
0
        while ((code = (*next_proc)(&tenum, &tchr, &tglyph)) != 2) {
234
0
            if (code < 0)
235
0
                break;
236
0
            ++size;
237
0
        }
238
0
        if (code < 0)
239
0
            return code;
240
0
        return size;
241
0
    }
242
0
}
243
244
/* An auxiliary functions for pdfwrite to process type 3 fonts. */
245
int
246
gx_hld_stringwidth_begin(gs_gstate * pgs, gx_path **path)
247
31
{
248
31
    int code;
249
250
31
    code = gs_gsave(pgs);
251
31
    if (code < 0)
252
0
        return code;
253
31
    gs_newpath(pgs);
254
31
    *path = pgs->path;
255
31
    gx_translate_to_fixed(pgs, fixed_0, fixed_0);
256
31
    return gx_path_add_point(pgs->path, fixed_0, fixed_0);
257
31
}
258
259
int
260
gx_default_text_restore_state(gs_text_enum_t *pte)
261
98.6k
{
262
98.6k
    gs_show_enum *penum;
263
98.6k
    gs_gstate *pgs;
264
265
98.6k
    if (SHOW_IS(pte, TEXT_DO_NONE))
266
23
        return 0;
267
98.5k
    penum = (gs_show_enum *)pte;
268
98.5k
    pgs = penum->pgs;
269
98.5k
    return gs_grestore(pgs);
270
98.6k
}
271
/* ------ Width/cache setting ------ */
272
273
static int
274
    set_cache_device(gs_show_enum *penum, gs_gstate *pgs,
275
                     double llx, double lly, double urx, double ury);
276
277
/* This is the default implementation of text enumerator set_cache. */
278
static int
279
gx_show_text_set_cache(gs_text_enum_t *pte, const double *pw,
280
                          gs_text_cache_control_t control)
281
16.2M
{
282
16.2M
    gs_show_enum *const penum = (gs_show_enum *)pte;
283
16.2M
    gs_gstate *pgs = penum->pgs;
284
16.2M
    gs_font *pfont = gs_rootfont(pgs);
285
286
    /* Detect zero FontMatrix now for Adobe compatibility with CET tests.
287
       Note that matrixe\\ces like [1 0 0 0 0 0] are used in comparefiles
288
       to compute a text width. See also gs_text_begin. */
289
16.2M
    if (pfont->FontMatrix.xx == 0 && pfont->FontMatrix.xy == 0 &&
290
16.2M
        pfont->FontMatrix.yx == 0 && pfont->FontMatrix.yy == 0)
291
5
        return_error(gs_error_undefinedresult); /* sic! : CPSI compatibility */
292
16.2M
    switch (control) {
293
253k
    case TEXT_SET_CHAR_WIDTH:
294
253k
        return set_char_width(penum, pgs, pw[0], pw[1]);
295
2.10M
    case TEXT_SET_CACHE_DEVICE: {
296
2.10M
        int code = set_char_width(penum, pgs, pw[0], pw[1]);    /* default is don't cache */
297
298
2.10M
        if (code < 0)
299
34
            return code;
300
2.10M
        if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) /* cshow */
301
0
            return code;
302
2.10M
        return set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
303
2.10M
    }
304
13.8M
    case TEXT_SET_CACHE_DEVICE2: {
305
13.8M
        int code;
306
13.8M
        bool retry = (penum->width_status == sws_retry);
307
308
13.8M
        if (pfont->WMode) {
309
6.69k
            float vx = pw[8], vy = pw[9];
310
6.69k
            gs_fixed_point pvxy, dvxy;
311
312
6.69k
            gs_fixed_point rewind_pvxy;
313
6.69k
            int rewind_code;
314
315
6.69k
            if ((code = gs_point_transform2fixed(&pgs->ctm, -vx, -vy, &pvxy)) < 0 ||
316
6.69k
                (code = gs_distance_transform2fixed(&pgs->ctm, vx, vy, &dvxy)) < 0
317
6.69k
                )
318
85
                return 0;               /* don't cache */
319
6.61k
            if ((code = set_char_width(penum, pgs, pw[6], pw[7])) < 0)
320
0
                return code;
321
6.61k
            if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE))
322
0
                return code;
323
            /* Adjust the origin by (vx, vy). */
324
6.61k
            gx_translate_to_fixed(pgs, pvxy.x, pvxy.y);
325
6.61k
            code = set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
326
6.61k
            if (code != 1) {
327
5.62k
                if (retry) {
328
0
                   rewind_code = gs_point_transform2fixed(&pgs->ctm, vx, vy, &rewind_pvxy);
329
0
                   if (rewind_code < 0) {
330
                       /* If the control passes here, something is wrong. */
331
0
                       return_error(gs_error_unregistered);
332
0
                   }
333
                   /* Rewind the origin by (-vx, -vy) if the cache is failed. */
334
0
                   gx_translate_to_fixed(pgs, rewind_pvxy.x, rewind_pvxy.y);
335
0
                }
336
5.62k
                return code;
337
5.62k
            }
338
            /* Adjust the character origin too. */
339
982
            (penum->cc)->offset.x += dvxy.x;
340
982
            (penum->cc)->offset.y += dvxy.y;
341
13.8M
        } else {
342
13.8M
            code = set_char_width(penum, pgs, pw[0], pw[1]);
343
13.8M
            if (code < 0)
344
0
                return code;
345
13.8M
            if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE))
346
0
                return code;
347
13.8M
            code = set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
348
13.8M
        }
349
13.8M
        return code;
350
13.8M
    }
351
0
    default:
352
0
        return_error(gs_error_rangecheck);
353
16.2M
    }
354
16.2M
}
355
356
/* Set the character width. */
357
/* Note that this returns 1 if the current show operation is */
358
/* non-displaying (stringwidth or cshow). */
359
int
360
set_char_width(gs_show_enum *penum, gs_gstate *pgs, double wx, double wy)
361
16.2M
{
362
16.2M
    int code;
363
364
16.2M
    if (penum->width_status != sws_none && penum->width_status != sws_retry)
365
37
        return_error(gs_error_undefined);
366
16.2M
    code = gs_distance_transform2fixed(&pgs->ctm, wx, wy, &penum->wxy);
367
16.2M
    if (code < 0 && penum->cc == 0) {
368
        /* Can't represent in 'fixed', use floats. */
369
349k
        code = gs_distance_transform(wx, wy, &ctm_only(pgs), &penum->wxy_float);
370
349k
        penum->wxy.x = penum->wxy.y = 0;
371
349k
        penum->use_wxy_float = true;
372
15.9M
    } else {
373
15.9M
        penum->use_wxy_float = false;
374
15.9M
        penum->wxy_float.x = penum->wxy_float.y = 0;
375
15.9M
    }
376
16.2M
    if (code < 0)
377
0
        return code;
378
    /* Check whether we're setting the scalable width */
379
    /* for a cached xfont character. */
380
16.2M
    if (penum->cc != 0) {
381
0
        penum->cc->wxy = penum->wxy;
382
0
        penum->width_status = sws_cache_width_only;
383
16.2M
    } else {
384
16.2M
        penum->width_status = sws_no_cache;
385
16.2M
    }
386
16.2M
    if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) /* cshow */
387
0
        gs_nulldevice(pgs);
388
16.2M
    return !SHOW_IS_DRAWING(penum);
389
16.2M
}
390
391
void
392
gx_compute_text_oversampling(const gs_show_enum * penum, const gs_font *pfont,
393
                             int alpha_bits, gs_log2_scale_point *p_log2_scale)
394
61.6M
{
395
61.6M
    gs_log2_scale_point log2_scale;
396
397
61.6M
    if (alpha_bits == 1)
398
61.6M
        log2_scale.x = log2_scale.y = 0;
399
0
    else if (pfont->PaintType != 0) {
400
        /* Don't oversample artificially stroked fonts. */
401
0
        log2_scale.x = log2_scale.y = 0;
402
0
    } else if (!penum->is_pure_color) {
403
        /* Don't oversample characters for rendering in non-pure color. */
404
0
        log2_scale.x = log2_scale.y = 0;
405
0
    } else {
406
0
        int excess;
407
408
        /* Get maximal scale according to cached bitmap size. */
409
0
        show_set_scale(penum, &log2_scale);
410
        /* Reduce the scale to fit into alpha bits. */
411
0
        excess = log2_scale.x + log2_scale.y - alpha_bits;
412
0
        while (excess > 0) {
413
0
            if (log2_scale.y > 0) {
414
0
                log2_scale.y --;
415
0
                excess--;
416
0
                if (excess == 0)
417
0
                    break;
418
0
            }
419
0
            if (log2_scale.x > 0) {
420
0
                log2_scale.x --;
421
0
                excess--;
422
0
            }
423
0
        }
424
0
    }
425
61.6M
    *p_log2_scale = log2_scale;
426
61.6M
}
427
428
/* Compute glyph raster parameters */
429
static int
430
compute_glyph_raster_params(gs_show_enum *penum, bool in_setcachedevice, int *alpha_bits,
431
                    int *depth,
432
                    gs_fixed_point *subpix_origin, gs_log2_scale_point *log2_scale)
433
69.1M
{
434
69.1M
    gs_gstate *pgs = penum->pgs;
435
69.1M
    gx_device *dev = gs_currentdevice_inline(pgs);
436
69.1M
    int code;
437
438
69.1M
    *alpha_bits = (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
439
69.1M
    if (in_setcachedevice) {
440
        /* current point should already be in penum->origin */
441
62.3M
    } else {
442
62.3M
        code = gx_path_current_point_inline(pgs, &penum->origin);
443
62.3M
        if (code < 0) {
444
            /* For cshow, having no current point is acceptable. */
445
0
            if (!SHOW_IS(penum, TEXT_DO_NONE))
446
0
                return code;
447
0
            penum->origin.x = penum->origin.y = 0;      /* arbitrary */
448
0
        }
449
62.3M
    }
450
69.1M
    if (penum->fapi_log2_scale.x != -1)
451
22.9M
        *log2_scale = penum->fapi_log2_scale;
452
46.2M
    else
453
46.2M
        gx_compute_text_oversampling(penum, penum->current_font, *alpha_bits, log2_scale);
454
    /*  We never oversample over the device alpha_bits,
455
     * so that we don't need to scale down. Perhaps it may happen
456
     * that we underuse alpha_bits due to a big character raster,
457
     * so we must compute log2_depth more accurately :
458
     */
459
69.1M
    *depth = (log2_scale->x + log2_scale->y == 0 ?
460
69.1M
        1 : min(log2_scale->x + log2_scale->y, *alpha_bits));
461
69.1M
    if (gs_currentaligntopixels(penum->current_font->dir) == 0) {
462
69.1M
        int scx = -(1L << (_fixed_shift - log2_scale->x));
463
69.1M
        int rdx =  1L << (_fixed_shift - 1 - log2_scale->x);
464
465
69.1M
#       if 1 /* Ever align Y to pixels to provide an uniform glyph height. */
466
69.1M
            subpix_origin->y = 0;
467
#       else
468
            int scy = -(1L << (_fixed_shift - log2_scale->y));
469
            int rdy =  1L << (_fixed_shift - 1 - log2_scale->y);
470
471
            subpix_origin->y = ((penum->origin.y + rdy) & scy) & (fixed_1 - 1);
472
#       endif
473
69.1M
        subpix_origin->x = ((penum->origin.x + rdx) & scx) & (fixed_1 - 1);
474
69.1M
    } else
475
0
        subpix_origin->x = subpix_origin->y = 0;
476
69.1M
    return 0;
477
69.1M
}
478
479
/* Set up the cache device if relevant. */
480
/* Return 1 if we just set up a cache device. */
481
/* Used by setcachedevice and setcachedevice2. */
482
static int
483
set_cache_device(gs_show_enum * penum, gs_gstate * pgs, double llx, double lly,
484
                 double urx, double ury)
485
16.0M
{
486
16.0M
    gs_glyph glyph;
487
16.0M
    int code = 0;
488
489
    /* See if we want to cache this character. */
490
16.0M
    if (pgs->in_cachedevice)    /* no recursion! */
491
8.86M
        return 0;
492
7.13M
    if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) { /* cshow */
493
0
        if_debug0m('k', penum->memory, "[k]no cache: cshow");
494
0
        code = gs_nulldevice(pgs);
495
0
        if (code < 0)
496
0
            return code;
497
0
        return 0;
498
0
    }
499
7.13M
    pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;     /* disable color/gray/image operators */
500
    /* We can only use the cache if we know the glyph. */
501
7.13M
    glyph = CURRENT_GLYPH(penum);
502
7.13M
    if (glyph == GS_NO_GLYPH)
503
0
        return 0;
504
    /* We can only use the cache if ctm is unchanged */
505
    /* (aside from a possible translation). */
506
7.13M
    if (penum->can_cache <= 0 || !pgs->char_tm_valid) {
507
3
        if_debug2m('k', penum->memory, "[k]no cache: can_cache=%d, char_tm_valid=%d\n",
508
3
                   penum->can_cache, (int)pgs->char_tm_valid);
509
3
        return 0;
510
7.13M
    } {
511
7.13M
        const gs_font *pfont = pgs->font;
512
7.13M
        gs_font_dir *dir = pfont->dir;
513
7.13M
        int alpha_bits, depth;
514
7.13M
        gs_log2_scale_point log2_scale;
515
7.13M
        gs_fixed_point subpix_origin;
516
7.13M
        static const fixed max_cdim[3] =
517
7.13M
        {
518
7.13M
#define max_cd(n)\
519
21.4M
            (fixed_1 << (ARCH_SIZEOF_SHORT * 8 - n)) - (fixed_1 >> n) * 3
520
7.13M
            max_cd(0), max_cd(1), max_cd(2)
521
7.13M
#undef max_cd
522
7.13M
        };
523
7.13M
        ushort iwidth, iheight;
524
7.13M
        cached_char *cc;
525
7.13M
        gs_fixed_rect clip_box;
526
7.13M
        gs_fixed_point cll, clr, cul, cur, cdim;
527
528
        /* Reject setcachedevice arguments that are too big and, probably, invalid */
529
        /* The threshold is arbitrary. A font from bug 692832 has a 1237340,       */
530
        /* normal fonts should have about 1000. */
531
7.13M
        if (fabs(llx) > 32000. || fabs(lly) > 32000. || fabs(urx) > 32000. || fabs(ury) >= 32000.)
532
168k
            return 0;           /* don't cache */
533
534
        /* Compute the bounding box of the transformed character. */
535
        /* Since we accept arbitrary transformations, the extrema */
536
        /* may occur in any order; however, we can save some work */
537
        /* by observing that opposite corners before transforming */
538
        /* are still opposite afterwards. */
539
540
6.96M
        if ((code = gs_distance_transform2fixed(&pgs->ctm, llx, lly, &cll)) < 0 ||
541
6.96M
            (code = gs_distance_transform2fixed(&pgs->ctm, llx, ury, &clr)) < 0 ||
542
6.96M
            (code = gs_distance_transform2fixed(&pgs->ctm, urx, lly, &cul)) < 0 ||
543
6.96M
         (code = gs_distance_transform2fixed(&pgs->ctm, urx, ury, &cur)) < 0
544
6.96M
            )
545
126k
            return 0;           /* don't cache */
546
6.84M
        {
547
6.84M
            fixed ctemp;
548
549
7.03M
#define swap(a, b) ctemp = a, a = b, b = ctemp
550
27.3M
#define make_min(a, b) if ( (a) > (b) ) swap(a, b)
551
552
6.84M
            make_min(cll.x, cur.x);
553
6.84M
            make_min(cll.y, cur.y);
554
6.84M
            make_min(clr.x, cul.x);
555
6.84M
            make_min(clr.y, cul.y);
556
6.84M
#undef make_min
557
6.84M
#undef swap
558
6.84M
        }
559
        /* Now take advantage of symmetry. */
560
6.84M
        if (clr.x < cll.x)
561
21.2k
            cll.x = clr.x, cur.x = cul.x;
562
6.84M
        if (clr.y < cll.y)
563
72.4k
            cll.y = clr.y, cur.y = cul.y;
564
        /* Now cll and cur are the extrema of the box. */
565
6.84M
        code = compute_glyph_raster_params(penum, true, &alpha_bits, &depth,
566
6.84M
           &subpix_origin, &log2_scale);
567
6.84M
        if (code < 0)
568
0
            return code;
569
#ifdef DEBUG
570
        if (gs_debug_c('k')) {
571
            dmlprintf6(pgs->memory, "[k]cbox=[%g %g %g %g] scale=%dx%d\n",
572
                       fixed2float(cll.x), fixed2float(cll.y),
573
                       fixed2float(cur.x), fixed2float(cur.y),
574
                       1 << log2_scale.x, 1 << log2_scale.y);
575
            dmlprintf6(pgs->memory, "[p]  ctm=[%g %g %g %g %g %g]\n",
576
                       pgs->ctm.xx, pgs->ctm.xy, pgs->ctm.yx, pgs->ctm.yy,
577
                       pgs->ctm.tx, pgs->ctm.ty);
578
        }
579
#endif
580
6.84M
        cdim.x = cur.x - cll.x;
581
6.84M
        cdim.y = cur.y - cll.y;
582
6.84M
        if (cdim.x > max_cdim[log2_scale.x] ||
583
6.84M
            cdim.y > max_cdim[log2_scale.y]
584
6.84M
            )
585
109k
            return 0;           /* much too big */
586
6.73M
        iwidth = ((ushort) fixed2int_var(cdim.x) + 3) << log2_scale.x;
587
6.73M
        iheight = ((ushort) fixed2int_var(cdim.y) + 3) << log2_scale.y;
588
6.73M
        if_debug3m('k', penum->memory, "[k]iwidth=%u iheight=%u dev_cache %s\n",
589
6.73M
                   (uint) iwidth, (uint) iheight,
590
6.73M
                   (penum->dev_cache == 0 ? "not set" : "set"));
591
6.73M
        if (penum->dev_cache == 0) {
592
2.61M
            code = show_cache_setup(penum);
593
2.61M
            if (code < 0)
594
0
                return code;
595
2.61M
        }
596
6.73M
        code = gx_alloc_char_bits(dir, penum->dev_cache,
597
6.73M
                                  iwidth, iheight, &log2_scale, depth, &cc);
598
6.73M
        if (code < 0)
599
52
            return code;
600
601
6.73M
        if (cc == 0) {
602
            /* too big for cache or no cache */
603
577k
            gx_path box_path;
604
605
577k
            if (penum->current_font->FontType != ft_user_defined &&
606
577k
                penum->current_font->FontType != ft_PDF_user_defined &&
607
577k
                penum->current_font->FontType != ft_PCL_user_defined &&
608
577k
                penum->current_font->FontType != ft_GL2_stick_user_defined &&
609
577k
                penum->current_font->FontType != ft_CID_user_defined) {
610
                /* Most fonts don't paint outside bbox,
611
                   so render with no clipping. */
612
311k
                return 0;
613
311k
            }
614
            /* Render with a clip. */
615
            /* show_proceed already did gsave. */
616
265k
            pgs->in_cachedevice = CACHE_DEVICE_NONE; /* Provide a correct grestore on error. */
617
265k
            clip_box.p.x = penum->origin.x - fixed_ceiling(-cll.x);
618
265k
            clip_box.p.y = penum->origin.y - fixed_ceiling(-cll.y);
619
265k
            clip_box.q.x = clip_box.p.x + int2fixed(iwidth);
620
265k
            clip_box.q.y = clip_box.p.y + int2fixed(iheight);
621
265k
            gx_path_init_local(&box_path, pgs->memory);
622
265k
            code = gx_path_add_rectangle(&box_path, clip_box.p.x, clip_box.p.y,
623
265k
                                                    clip_box.q.x, clip_box.q.y);
624
265k
            if (code < 0)
625
0
                return code;
626
265k
            code = gx_cpath_clip(pgs, pgs->clip_path, &box_path, gx_rule_winding_number);
627
265k
            if (code < 0)
628
0
                return code;
629
265k
            gx_path_free(&box_path, "set_cache_device");
630
265k
            pgs->in_cachedevice = CACHE_DEVICE_NONE_AND_CLIP;
631
265k
            return 0;
632
265k
        }
633
        /* The mins handle transposed coordinate systems.... */
634
        /* Truncate the offsets to avoid artifacts later. */
635
6.15M
        cc->offset.x = fixed_ceiling(-cll.x) + fixed_1;
636
6.15M
        cc->offset.y = fixed_ceiling(-cll.y) + fixed_1;
637
6.15M
        if_debug4m('k', penum->memory, "[k]width=%u, height=%u, offset=[%g %g]\n",
638
6.15M
                   (uint) iwidth, (uint) iheight,
639
6.15M
                   fixed2float(cc->offset.x),
640
6.15M
                   fixed2float(cc->offset.y));
641
6.15M
        pgs->in_cachedevice = CACHE_DEVICE_NONE; /* Provide correct grestore */
642
6.15M
        if ((code = gs_gsave(pgs)) < 0) {
643
0
            gx_free_cached_char(dir, cc);
644
0
            return code;
645
0
        }
646
        /* Nothing can go wrong now.... */
647
6.15M
        penum->cc = cc;
648
6.15M
        cc->code = glyph;
649
6.15M
        cc->wmode = gs_rootfont(pgs)->WMode;
650
6.15M
        cc->wxy = penum->wxy;
651
6.15M
        cc->subpix_origin = subpix_origin;
652
6.15M
        if (penum->pair != 0)
653
6.15M
            cc_set_pair(cc, penum->pair);
654
0
        else
655
0
            cc->pair = 0;
656
        /* Install the device */
657
6.15M
        gx_set_device_only(pgs, (gx_device *) penum->dev_cache);
658
6.15M
        pgs->ctm_default_set = false;
659
        /* Adjust the transformation in the graphics context */
660
        /* so that the character lines up with the cache. */
661
6.15M
        gx_translate_to_fixed(pgs,
662
6.15M
                              (cc->offset.x + subpix_origin.x) << log2_scale.x,
663
6.15M
                              (cc->offset.y + subpix_origin.y) << log2_scale.y);
664
6.15M
        if ((log2_scale.x | log2_scale.y) != 0)
665
0
            gx_scale_char_matrix(pgs, 1 << log2_scale.x,
666
0
                                 1 << log2_scale.y);
667
        /* Set the initial matrix for the cache device. */
668
6.15M
        penum->dev_cache->initial_matrix = ctm_only(pgs);
669
        /* Set the oversampling factor. */
670
6.15M
        penum->log2_scale.x = log2_scale.x;
671
6.15M
        penum->log2_scale.y = log2_scale.y;
672
        /* Reset the clipping path to match the metrics. */
673
6.15M
        clip_box.p.x = clip_box.p.y = 0;
674
6.15M
        clip_box.q.x = int2fixed(iwidth);
675
6.15M
        clip_box.q.y = int2fixed(iheight);
676
6.15M
        if ((code = gx_clip_to_rectangle(pgs, &clip_box)) < 0)
677
0
            goto fail;
678
6.15M
        code = gx_set_device_color_1(pgs);     /* write 1's */
679
6.15M
        if (code < 0)
680
0
            goto fail;
681
6.15M
        gs_swapcolors_quick(pgs);
682
6.15M
        code = gx_set_device_color_1(pgs);     /* write 1's */
683
6.15M
        if (code < 0)
684
0
            goto fail;
685
6.15M
        gs_swapcolors_quick(pgs);
686
6.15M
        pgs->in_cachedevice = CACHE_DEVICE_CACHING;
687
6.15M
    }
688
0
    penum->width_status = sws_cache;
689
6.15M
    return 1;
690
691
0
fail:
692
0
    gs_grestore(pgs);
693
0
    return code;
694
6.15M
}
695
696
/* Return the cache device status. */
697
gs_in_cache_device_t
698
gs_incachedevice(const gs_gstate *pgs)
699
589k
{
700
589k
    return pgs->in_cachedevice;
701
589k
}
702
703
/* ------ Enumerator ------ */
704
705
/*
706
 * Set the encode_char procedure in an enumerator.
707
 */
708
static void
709
show_set_encode_char(gs_show_enum * penum)
710
18.6M
{
711
18.6M
    penum->encode_char =
712
18.6M
        (SHOW_IS(penum, TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH) ?
713
0
         gs_no_encode_char :
714
18.6M
         gs_show_current_font(penum)->procs.encode_char);
715
18.6M
}
716
717
/*
718
 * Resync a text operation with a different set of parameters.
719
 * Currently this is implemented only for changing the data source.
720
 */
721
static int
722
gx_show_text_resync(gs_text_enum_t *pte, const gs_text_enum_t *pfrom)
723
0
{
724
0
    gs_show_enum *const penum = (gs_show_enum *)pte;
725
0
    int old_index = pte->index;
726
727
0
    if ((pte->text.operation ^ pfrom->text.operation) & ~TEXT_FROM_ANY)
728
0
        return_error(gs_error_rangecheck);
729
0
    pte->text = pfrom->text;
730
0
    if (pte->index == old_index) {
731
0
        show_set_encode_char(penum);
732
0
        return 0;
733
0
    } else
734
0
        return show_state_setup(penum);
735
0
}
736
737
/* Do the next step of a show (or stringwidth) operation */
738
static int
739
gx_show_text_process(gs_text_enum_t *pte)
740
19.2M
{
741
19.2M
    gs_show_enum *const penum = (gs_show_enum *)pte;
742
743
19.2M
    return (*penum->continue_proc)(penum);
744
19.2M
}
745
746
/* Continuation procedures */
747
static int show_update(gs_show_enum * penum);
748
static int show_move(gs_show_enum * penum);
749
static int show_proceed(gs_show_enum * penum);
750
static int show_finish(gs_show_enum * penum);
751
static int
752
continue_show_update(gs_show_enum * penum)
753
2.32M
{
754
2.32M
    int code = show_update(penum);
755
756
2.32M
    if (code < 0)
757
0
        return code;
758
2.32M
    code = show_move(penum);
759
2.32M
    if (code != 0)
760
5
        return code;
761
2.32M
    return show_proceed(penum);
762
2.32M
}
763
static int
764
continue_show(gs_show_enum * penum)
765
16.8M
{
766
16.8M
    return show_proceed(penum);
767
16.8M
}
768
/* For kshow, the CTM or font may have changed, so we have to reestablish */
769
/* the cached values in the enumerator. */
770
static int
771
continue_kshow(gs_show_enum * penum)
772
0
{   int code;
773
0
    gs_gstate *pgs = penum->pgs;
774
775
0
    if (pgs->font != penum->orig_font)
776
0
        gs_setfont(pgs, penum->orig_font);
777
778
0
    code = show_state_setup(penum);
779
780
0
    if (code < 0)
781
0
        return code;
782
0
    return show_proceed(penum);
783
0
}
784
785
/* Update position */
786
static int
787
show_update(gs_show_enum * penum)
788
16.2M
{
789
16.2M
    gs_gstate *pgs = penum->pgs;
790
16.2M
    cached_char *cc = penum->cc;
791
16.2M
    int code;
792
793
    /* Update position for last character */
794
16.2M
    switch (penum->width_status) {
795
40.1k
        case sws_none:
796
40.1k
        case sws_retry:
797
            /* Adobe interpreters assume a character width of 0, */
798
            /* even though the documentation says this is an error.... */
799
40.1k
            penum->wxy.x = penum->wxy.y = 0;
800
40.1k
            penum->wxy_float.x = penum->wxy_float.y = 0;
801
40.1k
            penum->use_wxy_float = false;
802
40.1k
            break;
803
6.15M
        case sws_cache:
804
            /* Finish installing the cache entry. */
805
            /* If the BuildChar/BuildGlyph procedure did a save and a */
806
            /* restore, it already undid the gsave in setcachedevice. */
807
            /* We have to check for this by comparing levels. */
808
6.15M
            switch (pgs->level - penum->level) {
809
0
                default:
810
0
                    gx_free_cached_char(penum->orig_font->dir, penum->cc);
811
0
                    return_error(gs_error_invalidfont);         /* WRONG */
812
6.15M
                case 2:
813
6.15M
                    code = gs_grestore(pgs);
814
6.15M
                    if (code < 0)
815
0
                        return code;
816
6.15M
                case 1:
817
6.15M
                    ;
818
6.15M
            }
819
6.15M
            {   cached_fm_pair *pair;
820
821
6.15M
                code = gx_lookup_fm_pair(pgs->font, &char_tm_only(pgs),
822
6.15M
                            &penum->log2_scale, penum->charpath_flag != cpm_show, &pair);
823
6.15M
                if (code < 0)
824
0
                    return code;
825
6.15M
                code = gx_add_cached_char(pgs->font->dir, penum->dev_cache,
826
6.15M
                               cc, pair, &penum->log2_scale);
827
6.15M
                if (code < 0)
828
0
                    return code;
829
6.15M
            }
830
6.15M
            if (!SHOW_USES_OUTLINE(penum) ||
831
6.15M
                penum->charpath_flag != cpm_show
832
6.15M
                )
833
46.3k
                break;
834
            /* falls through */
835
6.10M
        case sws_cache_width_only:
836
            /* Copy the bits to the real output device. */
837
6.10M
            code = gs_grestore(pgs);
838
6.10M
            if (code < 0)
839
0
                return code;
840
6.10M
            code = gs_gstate_color_load(pgs);
841
6.10M
            if (code < 0)
842
0
                return code;
843
6.10M
            return gx_image_cached_char(penum, cc);
844
10.0M
        case sws_no_cache:
845
10.0M
            ;
846
16.2M
    }
847
10.1M
    if (penum->charpath_flag != cpm_show) {
848
1.01M
        if (pgs->level <= penum->level) {
849
0
            return_error(gs_error_invalidfont);
850
0
        }
851
        /* Move back to the character origin, so that */
852
        /* show_move will get us to the right place. */
853
1.01M
        code = gx_path_add_point(pgs->show_gstate->path,
854
1.01M
                                 penum->origin.x, penum->origin.y);
855
1.01M
        if (code < 0)
856
0
            return code;
857
1.01M
    }
858
10.1M
    return gs_grestore(pgs);
859
10.1M
}
860
861
/* Move to next character */
862
static inline int
863
show_fast_move(gs_gstate * pgs, gs_fixed_point * pwxy)
864
61.8M
{
865
61.8M
    return gs_moveto_aux(pgs, pgs->path,
866
61.8M
                              pgs->current_point.x + fixed2float(pwxy->x),
867
61.8M
                              pgs->current_point.y + fixed2float(pwxy->y));
868
61.8M
}
869
870
/* Get the current character code. */
871
int gx_current_char(const gs_text_enum_t * pte)
872
2.53M
{
873
2.53M
    const gs_show_enum *penum = (const gs_show_enum *)pte;
874
2.53M
    gs_char chr = CURRENT_CHAR(penum) & 0xff;
875
2.53M
    int fdepth = penum->fstack.depth;
876
877
2.53M
    if (fdepth > 0) {
878
        /* Add in the shifted font number. */
879
79.5k
        uint fidx = penum->fstack.items[fdepth - 1].index;
880
881
79.5k
        switch (((gs_font_type0 *) (penum->fstack.items[fdepth - 1].font))->data.FMapType) {
882
0
        case fmap_1_7:
883
0
        case fmap_9_7:
884
0
            chr += fidx << 7;
885
0
            break;
886
79.5k
        case fmap_CMap:
887
79.5k
            chr = CURRENT_CHAR(penum);  /* the full character */
888
79.5k
            if (!penum->cmap_code)
889
79.5k
                break;
890
            /* falls through */
891
0
        default:
892
0
            chr += fidx << 8;
893
79.5k
        }
894
79.5k
    }
895
2.53M
    return chr;
896
2.53M
}
897
898
static int
899
show_move(gs_show_enum * penum)
900
45.3M
{
901
45.3M
    gs_gstate *pgs = penum->pgs;
902
45.3M
    int code;
903
45.3M
    double dx = 0, dy = 0;
904
905
    /* Specifically for applying PDF word spacing, if single_byte_space == true
906
       we'll only apply the delta for single byte character codes == space.s_char
907
       See psi/zchar.c zpdfwidthshow and zpdfawidthshow for more detail
908
     */
909
45.3M
    if (SHOW_IS_ADD_TO_SPACE(penum)
910
45.3M
        && (!penum->single_byte_space
911
2.75M
        || penum->bytes_decoded == 1)) {
912
2.53M
        gs_char chr = gx_current_char((const gs_text_enum_t *)penum);
913
914
2.53M
        if (chr == penum->text.space.s_char) {
915
192k
            dx = penum->text.delta_space.x;
916
192k
            dy = penum->text.delta_space.y;
917
192k
        }
918
2.53M
    }
919
920
45.3M
    if (SHOW_IS(penum, TEXT_REPLACE_WIDTHS)) {
921
30.7M
        gs_point dpt;
922
923
30.7M
        code = gs_text_replaced_width(&penum->text, penum->xy_index - 1, &dpt);
924
30.7M
        if (code < 0)
925
0
            return code;
926
30.7M
        dpt.x += dx;
927
30.7M
        dpt.y += dy;
928
30.7M
        code = gs_distance_transform2fixed(&pgs->ctm, dpt.x, dpt.y, &penum->wxy);
929
30.7M
        if (code < 0)
930
2.05k
            return code;
931
30.7M
    } else {
932
14.5M
        if (SHOW_IS_ADD_TO_ALL(penum)) {
933
4.47M
            dx += penum->text.delta_all.x;
934
4.47M
            dy += penum->text.delta_all.y;
935
4.47M
        }
936
14.5M
        if (!is_fzero2(dx, dy)) {
937
4.49M
            gs_fixed_point dxy;
938
939
4.49M
            code = gs_distance_transform2fixed(&pgs->ctm, dx, dy, &dxy);
940
4.49M
            if (code < 0)
941
1.80k
                return code;
942
4.49M
            penum->wxy.x += dxy.x;
943
4.49M
            penum->wxy.y += dxy.y;
944
4.49M
        }
945
14.5M
    }
946
45.3M
    if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) {
947
        /* HACK for cshow */
948
0
        penum->continue_proc = continue_kshow;
949
0
        return TEXT_PROCESS_INTERVENE;
950
0
    }
951
    /* wxy is in device coordinates */
952
45.3M
    {
953
45.3M
        int code;
954
955
45.3M
        if (penum->use_wxy_float)
956
345k
            code = gs_moveto_aux(pgs, pgs->path,
957
345k
                    pgs->current_point.x + penum->wxy_float.x + fixed2float(penum->wxy.x),
958
345k
                    pgs->current_point.y + penum->wxy_float.y + fixed2float(penum->wxy.y));
959
44.9M
        else
960
44.9M
            code = show_fast_move(pgs, &penum->wxy);
961
45.3M
        if (code < 0)
962
0
            return code;
963
45.3M
    }
964
    /* Check for kerning, but not on the last character. */
965
45.3M
    if (SHOW_IS_DO_KERN(penum) && penum->index < penum->text.size) {
966
0
        penum->continue_proc = continue_kshow;
967
0
        return TEXT_PROCESS_INTERVENE;
968
0
    }
969
45.3M
    return 0;
970
45.3M
}
971
972
static inline int
973
get_next_char_glyph(gs_show_enum * penum, gs_char *chr, gs_glyph *glyph)
974
79.1M
{
975
79.1M
    gs_font *rfont =
976
79.1M
        (penum->fstack.depth < 0 ? penum->pgs->font : penum->fstack.items[0].font);
977
79.1M
    penum->xy_index++;
978
979
79.1M
    return rfont->procs.next_char_glyph((gs_text_enum_t *)penum, chr, glyph);
980
79.1M
}
981
982
983
/* Process next character */
984
static int
985
show_proceed(gs_show_enum * penum)
986
19.2M
{
987
19.2M
    gs_gstate *pgs = penum->pgs;
988
19.2M
    gs_font *pfont;
989
19.2M
    cached_fm_pair *pair = 0;
990
19.2M
    gs_font *rfont =
991
19.2M
        (penum->fstack.depth < 0 ? pgs->font : penum->fstack.items[0].font);
992
19.2M
    int wmode = rfont->WMode;
993
19.2M
    gs_char chr;
994
19.2M
    gs_glyph glyph;
995
19.2M
    int code, start;
996
19.2M
    cached_char *cc;
997
19.2M
    gs_log2_scale_point log2_scale;
998
999
19.2M
    if (penum->charpath_flag == cpm_show && SHOW_USES_OUTLINE(penum)) {
1000
17.9M
        code = gs_gstate_color_load(pgs);
1001
17.9M
        if (code < 0)
1002
0
            return code;
1003
17.9M
    }
1004
33.1M
  more:                 /* Proceed to next character */
1005
33.1M
    pfont = (penum->fstack.depth < 0 ? pgs->font :
1006
33.1M
             penum->fstack.items[penum->fstack.depth].font);
1007
33.1M
    penum->current_font = pfont;
1008
    /* can_cache >= 0 allows us to use cached characters, */
1009
    /* even if we can't make new cache entries. */
1010
33.1M
    if (penum->can_cache >= 0) {
1011
        /* Loop with cache */
1012
78.0M
        for (;;) {
1013
78.0M
            start = penum->index;
1014
78.0M
            switch ((code = get_next_char_glyph(penum, &chr, &glyph))) {
1015
27
                default:        /* error */
1016
27
                    return code;
1017
16.7M
                case 2: /* done */
1018
16.7M
                    return show_finish(penum);
1019
1.74M
                case 1: /* font change */
1020
1.74M
                    pfont = penum->fstack.items[penum->fstack.depth].font;
1021
1.74M
                    penum->current_font = pfont;
1022
1.74M
                    pgs->char_tm_valid = false;
1023
1.74M
                    show_state_setup(penum);
1024
1.74M
                    pair = 0;
1025
1.74M
                    penum->pair = 0;
1026
                    /* falls through */
1027
61.3M
                case 0: /* plain char */
1028
                    /*
1029
                     * We don't need to set penum->current_char in the
1030
                     * normal cases, but it's needed for widthshow,
1031
                     * kshow, and one strange client, so we may as well
1032
                     * do it here.
1033
                     */
1034
61.3M
                    SET_CURRENT_CHAR(penum, chr);
1035
                    /*
1036
                     * Store glyph now, because pdfwrite needs it while
1037
                     * synthezising bitmap fonts (see assign_char_code).
1038
                     */
1039
61.3M
                    if (glyph == GS_NO_GLYPH) {
1040
56.2M
                        glyph = (*penum->encode_char)(pfont, chr,
1041
56.2M
                                                      GLYPH_SPACE_NAME);
1042
56.2M
                        SET_CURRENT_GLYPH(penum, glyph);
1043
56.2M
                    } else
1044
5.07M
                        SET_CURRENT_GLYPH(penum, glyph);
1045
61.3M
                    penum->bytes_decoded = penum->index - start;
1046
61.3M
                    penum->is_pure_color = gs_color_writes_pure(penum->pgs); /* Save
1047
                                 this data for compute_glyph_raster_params to work
1048
                                 independently on the color change in BuildChar.
1049
                                 Doing it here because cshow proc may modify
1050
                                 the graphic state.
1051
                                 */
1052
61.3M
                    {
1053
61.3M
                        int alpha_bits, depth;
1054
61.3M
                        gs_fixed_point subpix_origin;
1055
1056
61.3M
                        code = compute_glyph_raster_params(penum, false,
1057
61.3M
                                    &alpha_bits, &depth, &subpix_origin, &log2_scale);
1058
61.3M
                        if (code < 0)
1059
0
                            return code;
1060
61.3M
                        if (pair == 0) {
1061
17.6M
                            code = gx_lookup_fm_pair(pfont, &char_tm_only(pgs), &log2_scale,
1062
17.6M
                                penum->charpath_flag != cpm_show, &pair);
1063
17.6M
                            if (code < 0)
1064
0
                                return code;
1065
17.6M
                        }
1066
61.3M
                        penum->pair = pair;
1067
61.3M
                        if (glyph == GS_NO_GLYPH || SHOW_IS_ALL_OF(penum, TEXT_NO_CACHE)) {
1068
681
                            cc = 0;
1069
681
                            goto no_cache;
1070
681
                        }
1071
61.3M
                        cc = gx_lookup_cached_char(pfont, pair, glyph, wmode,
1072
61.3M
                                                   depth, &subpix_origin);
1073
61.3M
                    }
1074
61.3M
                    if (cc == 0) {
1075
15.3M
                        goto no_cache;
1076
15.3M
                    }
1077
                    /* Character is in cache. */
1078
                    /* We might be doing .charboxpath or stringwidth; */
1079
                    /* check for these now. */
1080
45.9M
                    if (penum->charpath_flag == cpm_charwidth) {
1081
                        /* This is charwidth.  Just move by the width. */
1082
0
                        DO_NOTHING;
1083
45.9M
                    } else if (penum->charpath_flag != cpm_show) {
1084
                        /* This is .charboxpath. Get the bounding box */
1085
                        /* and append it to a path. */
1086
0
                        gx_path box_path;
1087
0
                        gs_fixed_point pt;
1088
0
                        fixed llx, lly, urx, ury;
1089
1090
0
                        code = gx_path_current_point(pgs->path, &pt);
1091
0
                        if (code < 0)
1092
0
                            return code;
1093
0
                        llx = fixed_rounded(pt.x - cc->offset.x) +
1094
0
                            int2fixed(penum->ftx);
1095
0
                        lly = fixed_rounded(pt.y - cc->offset.y) +
1096
0
                            int2fixed(penum->fty);
1097
0
                        urx = llx + int2fixed(cc->width),
1098
0
                            ury = lly + int2fixed(cc->height);
1099
0
                        gx_path_init_local(&box_path, pgs->memory);
1100
0
                        code =
1101
0
                            gx_path_add_rectangle(&box_path, llx, lly,
1102
0
                                                  urx, ury);
1103
0
                        if (code >= 0)
1104
0
                            code =
1105
0
                                gx_path_add_char_path(pgs->show_gstate->path,
1106
0
                                                      &box_path,
1107
0
                                                      penum->charpath_flag);
1108
0
                        if (code >= 0)
1109
0
                            code = gx_path_add_point(pgs->path, pt.x, pt.y);
1110
0
                        gx_path_free(&box_path, "show_proceed(box path)");
1111
0
                        if (code < 0)
1112
0
                            return code;
1113
45.9M
                    } else if (SHOW_IS_DRAWING(penum)) {
1114
45.8M
                        code = gx_image_cached_char(penum, cc);
1115
45.8M
                        if (code < 0)
1116
5
                            return code;
1117
45.8M
                        else if (code > 0) {
1118
0
                            cc = 0;
1119
0
                            goto no_cache;
1120
0
                        }
1121
45.8M
                    }
1122
45.9M
                    penum->use_wxy_float = false;
1123
45.9M
                    penum->wxy_float.x = penum->wxy_float.y = 0;
1124
45.9M
                    if (SHOW_IS_SLOW(penum)) {
1125
                        /* Split up the assignment so that the */
1126
                        /* Watcom compiler won't reserve esi/edi. */
1127
29.0M
                        penum->wxy.x = cc->wxy.x;
1128
29.0M
                        penum->wxy.y = cc->wxy.y;
1129
29.0M
                        code = show_move(penum);
1130
29.0M
                    } else
1131
16.9M
                        code = show_fast_move(pgs, &cc->wxy);
1132
45.9M
                    if (code) {
1133
                        /* Might be kshow, glyph is stored above. */
1134
69
                        return code;
1135
69
                    }
1136
78.0M
            }
1137
78.0M
        }
1138
32.1M
    } else {
1139
1.03M
        start = penum->index;
1140
        /* Can't use cache */
1141
1.03M
        switch ((code = get_next_char_glyph(penum, &chr, &glyph))) {
1142
0
            default:
1143
0
                return code;
1144
17.5k
            case 2:
1145
17.5k
                return show_finish(penum);
1146
2.90k
            case 1:
1147
2.90k
                pfont = penum->fstack.items[penum->fstack.depth].font;
1148
2.90k
                penum->current_font = pfont;
1149
2.90k
                show_state_setup(penum);
1150
2.90k
                pair = 0;
1151
1.02M
            case 0:
1152
1.02M
                {   int alpha_bits, depth;
1153
1.02M
                    gs_log2_scale_point log2_scale;
1154
1.02M
                    gs_fixed_point subpix_origin;
1155
1156
1.02M
                    penum->bytes_decoded = penum->index - start;
1157
1.02M
                    code = compute_glyph_raster_params(penum, false, &alpha_bits, &depth, &subpix_origin, &log2_scale);
1158
1.02M
                    if (code < 0)
1159
0
                        return code;
1160
1.02M
                    if (pair == 0) {
1161
969k
                        code = gx_lookup_fm_pair(pfont, &char_tm_only(pgs), &log2_scale,
1162
969k
                                penum->charpath_flag != cpm_show, &pair);
1163
969k
                        if (code < 0)
1164
0
                            return code;
1165
969k
                    }
1166
1.02M
                    penum->pair = pair;
1167
1.02M
                }
1168
1.03M
        }
1169
1.02M
        SET_CURRENT_CHAR(penum, chr);
1170
1.02M
        if (glyph == GS_NO_GLYPH) {
1171
1.00M
            glyph = (*penum->encode_char)(pfont, chr, GLYPH_SPACE_NAME);
1172
1.00M
        }
1173
1.02M
        SET_CURRENT_GLYPH(penum, glyph);
1174
1.02M
        cc = 0;
1175
1.02M
    }
1176
16.3M
  no_cache:
1177
    /*
1178
     * We must call the client's rendering code.  Normally,
1179
     * we only do this if the character is not cached (cc = 0);
1180
     * however, we also must do this if we have an xfont but
1181
     * are using scalable widths.  In this case, and only this case,
1182
     * we get here with cc != 0.  penum->current_char and penum->current_glyph
1183
     * has already been set.
1184
     */
1185
16.3M
    if ((code = gs_gsave(pgs)) < 0)
1186
0
        return code;
1187
    /* Set the font to the current descendant font. */
1188
16.3M
    pgs->font = pfont;
1189
    /* Reset the in_cachedevice flag, so that a recursive show */
1190
    /* will use the cache properly. */
1191
16.3M
    pgs->in_cachedevice = CACHE_DEVICE_NONE;
1192
    /* Set the charpath data in the graphics context if necessary, */
1193
    /* so that fill and stroke will add to the path */
1194
    /* rather than having their usual effect. */
1195
16.3M
    pgs->in_charpath = penum->charpath_flag;
1196
16.3M
    pgs->show_gstate =
1197
16.3M
        (penum->show_gstate == pgs ? pgs->saved : penum->show_gstate);
1198
16.3M
    pgs->stroke_adjust = false; /* per specification */
1199
16.3M
    {
1200
16.3M
        gs_fixed_point cpt;
1201
1202
16.3M
        if ((code = gx_path_current_point_inline(pgs, &cpt)) < 0) {
1203
            /* For cshow, having no current point is acceptable. */
1204
0
            if (!SHOW_IS(penum, TEXT_DO_NONE))
1205
0
                goto rret;
1206
0
            cpt.x = cpt.y = 0;  /* arbitrary */
1207
0
        }
1208
16.3M
        penum->origin.x = cpt.x;
1209
16.3M
        penum->origin.y = cpt.y;
1210
        /* Normally, char_tm is valid because of show_state_setup, */
1211
        /* but if we're in a cshow, it may not be. */
1212
16.3M
        gs_currentcharmatrix(pgs, NULL, true);
1213
16.3M
        if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) {
1214
16.0M
            fixed tx = pgs->ctm.tx_fixed;
1215
16.0M
            fixed ty = pgs->ctm.ty_fixed;
1216
1217
16.0M
            gs_settocharmatrix(pgs);
1218
16.0M
            cpt.x += pgs->ctm.tx_fixed - tx;
1219
16.0M
            cpt.y += pgs->ctm.ty_fixed - ty;
1220
16.0M
        } else  {
1221
311k
            double tx = pgs->ctm.tx;
1222
311k
            double ty = pgs->ctm.ty;
1223
311k
            double fpx, fpy;
1224
1225
311k
            gs_settocharmatrix(pgs);
1226
311k
            fpx = fixed2float(cpt.x) + (pgs->ctm.tx - tx);
1227
311k
            fpy = fixed2float(cpt.y) + (pgs->ctm.ty - ty);
1228
311k
            if (!(f_fits_in_bits(fpx, fixed_int_bits)
1229
311k
                && f_fits_in_bits(fpy, fixed_int_bits))) {
1230
11
                gs_note_error(code = gs_error_limitcheck);
1231
11
                goto rret;
1232
11
            }
1233
311k
            cpt.x = float2fixed(fpx);
1234
311k
            cpt.y = float2fixed(fpy);
1235
311k
        }
1236
16.3M
        if (((code = gs_newpath(pgs)) < 0) ||
1237
16.3M
            ((code = show_origin_setup(pgs, cpt.x, cpt.y, penum)) < 0))
1238
0
            goto rret;
1239
16.3M
    }
1240
16.3M
    penum->width_status = sws_none;
1241
16.3M
    penum->continue_proc = continue_show_update;
1242
    /* Reset the sampling scale. */
1243
16.3M
    penum->log2_scale.x = penum->log2_scale.y = 0;
1244
    /* Try using the build procedure in the font. */
1245
    /* < 0 means error, 0 means success, 1 means failure. */
1246
16.3M
    penum->cc = cc;             /* set this now for build procedure */
1247
16.3M
    code = (*pfont->procs.build_char)(penum, pgs, pfont,
1248
16.3M
                                      chr, glyph);
1249
16.3M
    if (code < 0) {
1250
10.7k
        discard(gs_note_error(code));
1251
10.7k
        goto rret;
1252
10.7k
    }
1253
16.3M
    if (code == 0) {
1254
13.9M
        code = show_update(penum);
1255
13.9M
        if (code < 0)
1256
7
            goto rret;
1257
        /* Note that show_update does a grestore.... */
1258
13.9M
        code = show_move(penum);
1259
13.9M
        if (code)
1260
3.78k
            return code;        /* ... so don't go to rret here. */
1261
13.9M
        goto more;
1262
13.9M
    }
1263
    /*
1264
     * Some BuildChar procedures do a save before the setcachedevice,
1265
     * and a restore at the end.  If we waited to allocate the cache
1266
     * device until the setcachedevice, we would attempt to free it
1267
     * after the restore.  Therefore, allocate it now.
1268
     */
1269
2.40M
    if (penum->dev_cache == 0) {
1270
683k
        code = show_cache_setup(penum);
1271
683k
        if (code < 0)
1272
0
            goto rret;
1273
683k
    }
1274
2.40M
    return TEXT_PROCESS_RENDER;
1275
    /* If we get an error while setting up for BuildChar, */
1276
    /* we must undo the partial setup. */
1277
10.7k
rret:
1278
21.7k
    while (pgs->level > penum->level) {
1279
10.9k
        gs_grestore(pgs);
1280
10.9k
    }
1281
10.7k
    return code;
1282
2.40M
}
1283
1284
/*
1285
 * Prepare to retry rendering of the current character.  (This is only used
1286
 * in one place in zchar1.c; a different approach may be better.)
1287
 */
1288
static int
1289
gx_show_text_retry(gs_text_enum_t *pte)
1290
0
{
1291
0
    gs_show_enum *const penum = (gs_show_enum *)pte;
1292
1293
0
    if (penum->cc) {
1294
0
        gs_font *pfont = penum->current_font;
1295
1296
0
        gx_free_cached_char(pfont->dir, penum->cc);
1297
0
        penum->cc = 0;
1298
0
    }
1299
0
    gs_grestore(penum->pgs);
1300
0
    penum->width_status = sws_retry;
1301
0
    penum->log2_scale.x = penum->log2_scale.y = 0;
1302
0
    penum->pair = 0;
1303
0
    return 0;
1304
0
}
1305
1306
/* Finish show or stringwidth */
1307
static int
1308
show_finish(gs_show_enum * penum)
1309
16.8M
{
1310
16.8M
    gs_gstate *pgs = penum->pgs;
1311
16.8M
    int code = 0, rcode;
1312
1313
16.8M
    if ((penum->text.operation & TEXT_DO_FALSE_CHARPATH) ||
1314
16.8M
        (penum->text.operation & TEXT_DO_TRUE_CHARPATH)) {
1315
17.4k
        if (pgs->path->current_subpath)
1316
13.9k
            pgs->path->last_charpath_segment = pgs->path->current_subpath->last;
1317
17.4k
    }
1318
16.8M
    if (penum->auto_release)
1319
0
        penum->procs->release((gs_text_enum_t *)penum, "show_finish");
1320
1321
16.8M
    if (!SHOW_IS_STRINGWIDTH(penum))
1322
16.6M
       return 0;
1323
1324
    /* Save the accumulated width before returning, if we are not in PDF text rendering mode 3, */
1325
    /* and undo the extra gsave. */
1326
198k
    if (!(penum->text.operation & TEXT_RENDER_MODE_3))
1327
376
        code = gs_currentpoint(pgs, &penum->returned.total_width);
1328
198k
    rcode = gs_grestore(pgs);
1329
1330
198k
    return (code < 0 ? code : rcode);
1331
16.8M
}
1332
1333
/* Release the structure. */
1334
static void
1335
gx_show_text_release(gs_text_enum_t *pte, client_name_t cname)
1336
16.8M
{
1337
16.8M
    gs_show_enum *const penum = (gs_show_enum *)pte;
1338
1339
16.8M
    penum->cc = 0;
1340
16.8M
    if (penum->dev_cache2) {
1341
3.30M
        gx_device_retain((gx_device *)penum->dev_cache2, false);
1342
3.30M
        penum->dev_cache2 = 0;
1343
3.30M
    }
1344
16.8M
    if (penum->dev_cache) {
1345
3.30M
        gx_device_retain((gx_device *)penum->dev_cache, false);
1346
3.30M
        penum->dev_cache = 0;
1347
3.30M
    }
1348
16.8M
    if (penum->dev_null) {
1349
198k
        gx_device_retain((gx_device *)penum->dev_null, false);
1350
198k
        penum->dev_null = 0;
1351
198k
    }
1352
16.8M
    gx_default_text_release(pte, cname);
1353
16.8M
}
1354
1355
/* ------ Miscellaneous accessors ------ */
1356
1357
/* Return the charpath mode. */
1358
gs_char_path_mode
1359
gs_show_in_charpath(const gs_show_enum * penum)
1360
0
{
1361
0
    return penum->charpath_flag;
1362
0
}
1363
1364
/* Return true if we only need the width from the rasterizer */
1365
/* and can short-circuit the full rendering of the character, */
1366
/* false if we need the actual character bits. */
1367
/* This is only meaningful just before calling gs_setcharwidth or */
1368
/* gs_setcachedevice[2]. */
1369
/* Note that we can't do this if the procedure has done any extra [g]saves. */
1370
static bool
1371
gx_show_text_is_width_only(const gs_text_enum_t *pte)
1372
17.8M
{
1373
17.8M
    const gs_show_enum *const penum = (const gs_show_enum *)pte;
1374
1375
    /* penum->cc will be non-zero iff we are calculating */
1376
    /* the scalable width for an xfont character. */
1377
17.8M
    return ((!SHOW_USES_OUTLINE(penum) || penum->cc != 0) &&
1378
17.8M
            penum->pgs->level == penum->level + 1);
1379
17.8M
}
1380
1381
/* Return the width of the just-enumerated character (for cshow). */
1382
static int
1383
gx_show_text_current_width(const gs_text_enum_t *pte, gs_point *pwidth)
1384
0
{
1385
0
    const gs_show_enum *const penum = (const gs_show_enum *)pte;
1386
1387
0
    return gs_idtransform(penum->pgs,
1388
0
                          fixed2float(penum->wxy.x),
1389
0
                          fixed2float(penum->wxy.y), pwidth);
1390
0
}
1391
1392
/* Return the current font for cshow. */
1393
gs_font *
1394
gs_show_current_font(const gs_show_enum * penum)
1395
18.6M
{
1396
18.6M
    return (penum->fstack.depth < 0 ? penum->pgs->font :
1397
18.6M
            penum->fstack.items[penum->fstack.depth].font);
1398
18.6M
}
1399
1400
/* ------ Internal routines ------ */
1401
1402
/* Initialize the gstate-derived parts of a show enumerator. */
1403
/* We do this both when starting the show operation, */
1404
/* and when returning from the kshow callout. */
1405
/* Uses only penum->pgs, penum->fstack. */
1406
static int
1407
show_state_setup(gs_show_enum * penum)
1408
18.6M
{
1409
18.6M
    gs_gstate *pgs = penum->pgs;
1410
18.6M
    gx_clip_path *pcpath;
1411
18.6M
    gs_font *pfont;
1412
1413
18.6M
    if (penum->fstack.depth <= 0) {
1414
16.8M
        pfont = pgs->font;
1415
16.8M
        if (pfont->FontType == ft_CID_encrypted) {
1416
            /* doing 'cid glyphshow',
1417
               assuming penum->operation has TEXT_FROM_SINGLE_GLYPH */
1418
0
            gs_matrix mat;
1419
0
            int fidx;
1420
0
            int code = ((gs_font_cid0 *)pfont)->cidata.glyph_data((gs_font_base *)pfont,
1421
0
                                penum->text.data.d_glyph, NULL, &fidx);
1422
0
            if (code < 0) { /* failed to load glyph data, reload glyph for CID 0 */
1423
0
               code = ((gs_font_cid0 *)pfont)->cidata.glyph_data((gs_font_base *)pfont,
1424
0
                            (gs_glyph)(GS_MIN_CID_GLYPH + 0), NULL, &fidx);
1425
0
               if (code < 0)
1426
0
                   return_error(gs_error_invalidfont);
1427
0
            }
1428
0
            gs_matrix_multiply(&(gs_cid0_indexed_font(pfont, fidx)->FontMatrix),
1429
0
                                &pfont->FontMatrix, &mat);
1430
0
            gs_setcharmatrix(pgs, &mat);
1431
16.8M
        } else {
1432
16.8M
            gs_currentcharmatrix(pgs, NULL, 1); /* make char_tm valid */
1433
16.8M
        }
1434
16.8M
    } else {
1435
        /* We have to concatenate the parent's FontMatrix as well. */
1436
1.75M
        gs_matrix mat;
1437
1.75M
        const gx_font_stack_item_t *pfsi =
1438
1.75M
            &penum->fstack.items[penum->fstack.depth];
1439
1440
1.75M
        pfont = pfsi->font;
1441
1.75M
        gs_matrix_multiply(&pfont->FontMatrix,
1442
1.75M
                           &pfsi[-1].font->FontMatrix, &mat);
1443
1.75M
        if (pfont->FontType == ft_CID_encrypted) {
1444
            /* concatenate the Type9 leaf's matrix */
1445
26.6k
            gs_matrix_multiply(&(gs_cid0_indexed_font(pfont, pfsi->index)->FontMatrix),
1446
26.6k
                                &mat, &mat);
1447
26.6k
        }
1448
1.75M
        gs_setcharmatrix(pgs, &mat);
1449
1.75M
    }
1450
18.6M
    penum->current_font = pfont;
1451
18.6M
    if (penum->can_cache >= 0 &&
1452
18.6M
        gx_effective_clip_path(pgs, &pcpath) >= 0
1453
18.6M
        ) {
1454
18.6M
        gs_fixed_rect cbox;
1455
1456
18.6M
        gx_cpath_inner_box(pcpath, &cbox);
1457
        /* Since characters occupy an integral number of pixels, */
1458
        /* we can (and should) round the inner clipping box */
1459
        /* outward rather than inward. */
1460
18.6M
        penum->ibox.p.x = fixed2int_var(cbox.p.x);
1461
18.6M
        penum->ibox.p.y = fixed2int_var(cbox.p.y);
1462
18.6M
        penum->ibox.q.x = fixed2int_var_ceiling(cbox.q.x);
1463
18.6M
        penum->ibox.q.y = fixed2int_var_ceiling(cbox.q.y);
1464
18.6M
        gx_cpath_outer_box(pcpath, &cbox);
1465
18.6M
        penum->obox.p.x = fixed2int_var(cbox.p.x);
1466
18.6M
        penum->obox.p.y = fixed2int_var(cbox.p.y);
1467
18.6M
        penum->obox.q.x = fixed2int_var_ceiling(cbox.q.x);
1468
18.6M
        penum->obox.q.y = fixed2int_var_ceiling(cbox.q.y);
1469
18.6M
        if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) {
1470
18.5M
            penum->ftx = (int)fixed2long(pgs->char_tm.tx_fixed -
1471
18.5M
                                         pgs->ctm.tx_fixed);
1472
18.5M
            penum->fty = (int)fixed2long(pgs->char_tm.ty_fixed -
1473
18.5M
                                         pgs->ctm.ty_fixed);
1474
18.5M
        } else {
1475
69.0k
            double fdx = pgs->char_tm.tx - pgs->ctm.tx;
1476
69.0k
            double fdy = pgs->char_tm.ty - pgs->ctm.ty;
1477
1478
69.0k
#define int_bits (ARCH_SIZEOF_INT * 8 - 1)
1479
69.0k
            if (!(f_fits_in_bits(fdx, int_bits) &&
1480
69.0k
                  f_fits_in_bits(fdy, int_bits))
1481
69.0k
                )
1482
2.16k
                return_error(gs_error_limitcheck);
1483
66.8k
#undef int_bits
1484
66.8k
            penum->ftx = (int)fdx;
1485
66.8k
            penum->fty = (int)fdy;
1486
66.8k
        }
1487
18.6M
    }
1488
18.6M
    show_set_encode_char(penum);
1489
18.6M
    return 0;
1490
18.6M
}
1491
1492
/* Set the suggested oversampling scale for character rendering. */
1493
static void
1494
show_set_scale(const gs_show_enum * penum, gs_log2_scale_point *log2_scale)
1495
0
{
1496
    /*
1497
     * Decide whether to oversample.
1498
     * We have to decide this each time setcachedevice is called.
1499
     */
1500
0
    const gs_gstate *pgs = NULL;
1501
1502
0
    if (gs_object_type(penum->pgs->memory, penum) == &st_gs_show_enum) {
1503
0
        pgs = penum->pgs;
1504
0
    } else {
1505
0
            pgs = (gs_gstate *)penum->pgs;
1506
0
    }
1507
1508
0
    if (pgs != NULL && (penum->charpath_flag == cpm_show ||
1509
0
         penum->charpath_flag == cpm_charwidth) &&
1510
0
        SHOW_USES_OUTLINE(penum)
1511
        /* && gx_path_is_void_inline(pgs->path) */
1512
0
        ) {
1513
0
        const gs_font_base *pfont = (const gs_font_base *)penum->current_font;
1514
0
        gs_fixed_point extent;
1515
0
        int code = gs_distance_transform2fixed(&pgs->char_tm,
1516
0
                                  pfont->FontBBox.q.x - pfont->FontBBox.p.x,
1517
0
                                  pfont->FontBBox.q.y - pfont->FontBBox.p.y,
1518
0
                                               &extent);
1519
1520
0
        if (code >= 0) {
1521
0
            int sx =
1522
0
            (any_abs(extent.x) < int2fixed(60) ? 2 :
1523
0
             any_abs(extent.x) < int2fixed(200) ? 1 :
1524
0
             0);
1525
0
            int sy =
1526
0
            (any_abs(extent.y) < int2fixed(60) ? 2 :
1527
0
             any_abs(extent.y) < int2fixed(200) ? 1 :
1528
0
             0);
1529
1530
            /* If we oversample at all, make sure we do it */
1531
            /* in both X and Y. */
1532
0
            if (sx == 0 && sy != 0)
1533
0
                sx = 1;
1534
0
            else if (sy == 0 && sx != 0)
1535
0
                sy = 1;
1536
0
            log2_scale->x = sx;
1537
0
            log2_scale->y = sy;
1538
0
            return;
1539
0
        }
1540
0
    }
1541
    /* By default, don't scale. */
1542
0
    log2_scale->x = log2_scale->y = 0;
1543
0
}
1544
1545
/* Set up the cache device and related information. */
1546
/* Note that we always allocate both cache devices, */
1547
/* even if we only use one of them. */
1548
static int
1549
show_cache_setup(gs_show_enum * penum)
1550
3.30M
{
1551
3.30M
    gs_gstate *pgs = penum->pgs;
1552
3.30M
    gs_memory_t *mem = penum->memory;
1553
3.30M
    gx_device_memory *dev =
1554
3.30M
        gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory,
1555
3.30M
                        "show_cache_setup(dev_cache)");
1556
3.30M
    gx_device_memory *dev2 =
1557
3.30M
        gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory,
1558
3.30M
                        "show_cache_setup(dev_cache2)");
1559
1560
3.30M
    if (dev == 0 || dev2 == 0) {
1561
        /*
1562
         * The structure is full of garbage so must not call the
1563
         * finalize method but still need to free the structure
1564
         */
1565
0
        gs_set_object_type(mem, dev2, &st_bytes);
1566
0
        gs_set_object_type(mem, dev, &st_bytes);
1567
0
        gs_free_object(mem, dev2, "show_cache_setup(dev_cache2)");
1568
0
        gs_free_object(mem, dev, "show_cache_setup(dev_cache)");
1569
0
        return_error(gs_error_VMerror);
1570
0
    }
1571
    /*
1572
     * We only initialize the devices for the sake of the GC,
1573
     * (since we have to re-initialize dev as either a mem_mono
1574
     * or a mem_abuf device before actually using it) and also
1575
     * to set its memory pointer.
1576
     */
1577
3.30M
    gs_make_mem_mono_device(dev, mem, gs_currentdevice_inline(pgs));
1578
3.30M
    penum->dev_cache = dev;
1579
3.30M
    gs_make_mem_mono_device(dev2, mem, gs_currentdevice_inline(pgs));
1580
3.30M
    penum->dev_cache2 = dev2;
1581
3.30M
    dev->HWResolution[0] = pgs->device->HWResolution[0];
1582
3.30M
    dev->HWResolution[1] = pgs->device->HWResolution[1];
1583
    /* Retain these devices, since they are referenced from the enumerator. */
1584
3.30M
    gx_device_retain((gx_device *)dev, true);
1585
3.30M
    gx_device_retain((gx_device *)dev2, true);
1586
3.30M
    return 0;
1587
3.30M
}
1588
1589
/* Set the character origin as the origin of the coordinate system. */
1590
/* Used before rendering characters, and for moving the origin */
1591
/* in setcachedevice2 when WMode=1. */
1592
static int
1593
show_origin_setup(gs_gstate * pgs, fixed cpt_x, fixed cpt_y, gs_show_enum * penum)
1594
16.3M
{
1595
16.3M
    if (penum->charpath_flag == cpm_show) {
1596
        /* Round the translation in the graphics state. */
1597
        /* This helps prevent rounding artifacts later. */
1598
15.3M
        if (gs_currentaligntopixels(penum->current_font->dir) == 0) {
1599
15.3M
            int scx = -(1L << (_fixed_shift - penum->log2_scale.x));
1600
15.3M
            int scy = -(1L << (_fixed_shift - penum->log2_scale.y));
1601
15.3M
            int rdx =  1L << (_fixed_shift - 1 - penum->log2_scale.x);
1602
15.3M
            int rdy =  1L << (_fixed_shift - 1 - penum->log2_scale.y);
1603
1604
15.3M
            cpt_x = (cpt_x + rdx) & scx;
1605
15.3M
            cpt_y = (cpt_y + rdy) & scy;
1606
15.3M
        } else {
1607
0
            cpt_x = fixed_rounded(cpt_x);
1608
0
            cpt_y = fixed_rounded(cpt_y);
1609
0
        }
1610
15.3M
    }
1611
    /*
1612
     * BuildChar procedures expect the current point to be undefined,
1613
     * so we omit the gx_path_add_point with ctm.t*_fixed.
1614
     */
1615
16.3M
    return gx_translate_to_fixed(pgs, cpt_x, cpt_y);
1616
16.3M
}