Coverage Report

Created: 2025-06-10 07:17

/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
3.95M
  !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
7.76k
ENUM_PTRS_BEGIN(show_enum_enum_ptrs)
48
5.33k
     return ENUM_USING(st_gs_text_enum, vptr, size, index - 5);
49
485
ENUM_PTR(0, gs_show_enum, pgs);
50
485
ENUM_PTR(1, gs_show_enum, show_gstate);
51
7.76k
ENUM_PTR3(2, gs_show_enum, dev_cache, dev_cache2, dev_null);
52
7.76k
ENUM_PTRS_END
53
485
static RELOC_PTRS_WITH(show_enum_reloc_ptrs, gs_show_enum *eptr)
54
485
{
55
485
    RELOC_USING(st_gs_text_enum, vptr, size);           /* superclass */
56
485
    RELOC_VAR(eptr->pgs);
57
485
    RELOC_VAR(eptr->show_gstate);
58
485
    RELOC_PTR3(gs_show_enum, dev_cache, dev_cache2, dev_null);
59
485
}
60
485
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
181k
#define CURRENT_CHAR(penum) ((penum)->returned.current_char)
73
#define SET_CURRENT_CHAR(penum, chr)\
74
3.85M
  ((penum)->returned.current_char = (chr))
75
415k
#define CURRENT_GLYPH(penum) ((penum)->returned.current_glyph)
76
#define SET_CURRENT_GLYPH(penum, glyph)\
77
3.85M
  ((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
1.19M
{
83
1.19M
    gs_show_enum *penum;
84
85
1.19M
    rc_alloc_struct_1(penum, gs_show_enum, &st_gs_show_enum, mem,
86
1.19M
                      return 0, cname);
87
1.19M
    penum->rc.free = rc_free_text_enum;
88
1.19M
    penum->auto_release = true; /* old API */
89
    /* Initialize pointers for GC */
90
1.19M
    penum->text.operation = 0;  /* no pointers relevant */
91
1.19M
    penum->dev = 0;
92
1.19M
    penum->pgs = pgs;
93
1.19M
    penum->show_gstate = 0;
94
1.19M
    penum->dev_cache = 0;
95
1.19M
    penum->dev_cache2 = 0;
96
1.19M
    penum->fapi_log2_scale.x = penum->fapi_log2_scale.y = -1;
97
1.19M
    penum->fapi_glyph_shift.x = penum->fapi_glyph_shift.y = 0;
98
1.19M
    penum->dev_null = 0;
99
1.19M
    penum->fstack.depth = -1;
100
1.19M
    return penum;
101
1.19M
}
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
1.19M
{
126
1.19M
    uint operation = text->operation;
127
1.19M
    bool propagate_charpath = (operation & TEXT_DO_DRAW) != 0;
128
1.19M
    int code;
129
1.19M
    gs_gstate *pgs = (gs_gstate *)pgs1;
130
1.19M
    gs_show_enum *penum;
131
1.19M
    gs_memory_t * mem = pgs->memory;
132
133
1.19M
    penum = gs_show_enum_alloc(mem, pgs, "gx_default_text_begin");
134
1.19M
    if (!penum)
135
0
        return_error(gs_error_VMerror);
136
1.19M
    code = gs_text_enum_init((gs_text_enum_t *)penum, &default_text_procs,
137
1.19M
                             dev, pgs, text, font, pcpath, mem);
138
1.19M
    if (code < 0) {
139
0
        gs_free_object(mem, penum, "gx_default_text_begin");
140
0
        return code;
141
0
    }
142
1.19M
    penum->auto_release = false; /* new API */
143
1.19M
    penum->level = pgs->level;
144
1.19M
    penum->cc = 0;
145
1.19M
    penum->continue_proc = continue_show;
146
1.19M
    switch (penum->charpath_flag) {
147
945
    case cpm_false_charpath: case cpm_true_charpath:
148
945
        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
1.19M
    default:                    /* cpm_show */
153
1.19M
        penum->can_cache = 1; break;
154
1.19M
    }
155
1.19M
    code = show_state_setup(penum);
156
1.19M
    if (code < 0) {
157
312
        gs_text_release(pgs, (gs_text_enum_t *)penum, "gx_default_text_begin");
158
312
        penum = NULL;
159
312
        return code;
160
312
    }
161
1.19M
    penum->show_gstate =
162
1.19M
        (propagate_charpath && (pgs->in_charpath != 0) ?
163
1.19M
         pgs->show_gstate : pgs);
164
1.19M
    if (!(~operation & (TEXT_DO_NONE | TEXT_RETURN_WIDTH))) {
165
        /* This is stringwidth (or a PDF with text in rendering mode 3) . */
166
12.2k
        gx_device_null *dev_null =
167
12.2k
            gs_alloc_struct(mem, gx_device_null, &st_device_null,
168
12.2k
                            "stringwidth(dev_null)");
169
170
12.2k
        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
12.2k
        gs_make_null_device(dev_null, gs_currentdevice_inline(pgs), mem);
181
182
        /* Do an extra gsave and suppress output */
183
12.2k
        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
12.2k
        penum->level = pgs->level;      /* for level check in show_update */
190
12.2k
        pgs->ctm_default_set = false;
191
12.2k
        penum->dev_null = dev_null;
192
        /* Retain this device, since it is referenced from the enumerator. */
193
12.2k
        gx_device_retain((gx_device *)dev_null, true);
194
12.2k
        gs_setdevice_no_init(pgs, (gx_device *) dev_null);
195
        /* Establish an arbitrary translation and current point. */
196
12.2k
        gs_newpath(pgs);
197
12.2k
        gx_translate_to_fixed(pgs, fixed_0, fixed_0);
198
12.2k
        code = gx_path_add_point(pgs->path, fixed_0, fixed_0);
199
12.2k
        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
12.2k
    }
206
1.19M
    *ppte = (gs_text_enum_t *)penum;
207
1.19M
    return 0;
208
1.19M
}
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
0
{
248
0
    int code;
249
250
0
    code = gs_gsave(pgs);
251
0
    if (code < 0)
252
0
        return code;
253
0
    gs_newpath(pgs);
254
0
    *path = pgs->path;
255
0
    gx_translate_to_fixed(pgs, fixed_0, fixed_0);
256
0
    return gx_path_add_point(pgs->path, fixed_0, fixed_0);
257
0
}
258
259
int
260
gx_default_text_restore_state(gs_text_enum_t *pte)
261
0
{
262
0
    gs_show_enum *penum;
263
0
    gs_gstate *pgs;
264
265
0
    if (SHOW_IS(pte, TEXT_DO_NONE))
266
0
        return 0;
267
0
    penum = (gs_show_enum *)pte;
268
0
    pgs = penum->pgs;
269
0
    return gs_grestore(pgs);
270
0
}
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
2.20M
{
282
2.20M
    gs_show_enum *const penum = (gs_show_enum *)pte;
283
2.20M
    gs_gstate *pgs = penum->pgs;
284
2.20M
    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
2.20M
    if (pfont->FontMatrix.xx == 0 && pfont->FontMatrix.xy == 0 &&
290
2.20M
        pfont->FontMatrix.yx == 0 && pfont->FontMatrix.yy == 0)
291
1
        return_error(gs_error_undefinedresult); /* sic! : CPSI compatibility */
292
2.20M
    switch (control) {
293
3.29k
    case TEXT_SET_CHAR_WIDTH:
294
3.29k
        return set_char_width(penum, pgs, pw[0], pw[1]);
295
188k
    case TEXT_SET_CACHE_DEVICE: {
296
188k
        int code = set_char_width(penum, pgs, pw[0], pw[1]);    /* default is don't cache */
297
298
188k
        if (code < 0)
299
5
            return code;
300
188k
        if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) /* cshow */
301
0
            return code;
302
188k
        return set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
303
188k
    }
304
2.01M
    case TEXT_SET_CACHE_DEVICE2: {
305
2.01M
        int code;
306
2.01M
        bool retry = (penum->width_status == sws_retry);
307
308
2.01M
        if (pfont->WMode) {
309
543
            float vx = pw[8], vy = pw[9];
310
543
            gs_fixed_point pvxy, dvxy;
311
312
543
            gs_fixed_point rewind_pvxy;
313
543
            int rewind_code;
314
315
543
            if ((code = gs_point_transform2fixed(&pgs->ctm, -vx, -vy, &pvxy)) < 0 ||
316
543
                (code = gs_distance_transform2fixed(&pgs->ctm, vx, vy, &dvxy)) < 0
317
543
                )
318
17
                return 0;               /* don't cache */
319
526
            if ((code = set_char_width(penum, pgs, pw[6], pw[7])) < 0)
320
0
                return code;
321
526
            if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE))
322
0
                return code;
323
            /* Adjust the origin by (vx, vy). */
324
526
            gx_translate_to_fixed(pgs, pvxy.x, pvxy.y);
325
526
            code = set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
326
526
            if (code != 1) {
327
526
                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
526
                return code;
337
526
            }
338
            /* Adjust the character origin too. */
339
0
            (penum->cc)->offset.x += dvxy.x;
340
0
            (penum->cc)->offset.y += dvxy.y;
341
2.01M
        } else {
342
2.01M
            code = set_char_width(penum, pgs, pw[0], pw[1]);
343
2.01M
            if (code < 0)
344
0
                return code;
345
2.01M
            if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE))
346
0
                return code;
347
2.01M
            code = set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
348
2.01M
        }
349
2.01M
        return code;
350
2.01M
    }
351
0
    default:
352
0
        return_error(gs_error_rangecheck);
353
2.20M
    }
354
2.20M
}
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
2.20M
{
362
2.20M
    int code;
363
364
2.20M
    if (penum->width_status != sws_none && penum->width_status != sws_retry)
365
5
        return_error(gs_error_undefined);
366
2.20M
    code = gs_distance_transform2fixed(&pgs->ctm, wx, wy, &penum->wxy);
367
2.20M
    if (code < 0 && penum->cc == 0) {
368
        /* Can't represent in 'fixed', use floats. */
369
38.5k
        code = gs_distance_transform(wx, wy, &ctm_only(pgs), &penum->wxy_float);
370
38.5k
        penum->wxy.x = penum->wxy.y = 0;
371
38.5k
        penum->use_wxy_float = true;
372
2.16M
    } else {
373
2.16M
        penum->use_wxy_float = false;
374
2.16M
        penum->wxy_float.x = penum->wxy_float.y = 0;
375
2.16M
    }
376
2.20M
    if (code < 0)
377
0
        return code;
378
    /* Check whether we're setting the scalable width */
379
    /* for a cached xfont character. */
380
2.20M
    if (penum->cc != 0) {
381
0
        penum->cc->wxy = penum->wxy;
382
0
        penum->width_status = sws_cache_width_only;
383
2.20M
    } else {
384
2.20M
        penum->width_status = sws_no_cache;
385
2.20M
    }
386
2.20M
    if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) /* cshow */
387
0
        gs_nulldevice(pgs);
388
2.20M
    return !SHOW_IS_DRAWING(penum);
389
2.20M
}
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
4.38M
{
395
4.38M
    gs_log2_scale_point log2_scale;
396
397
4.38M
    if (alpha_bits == 1)
398
4.38M
        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
4.38M
    *p_log2_scale = log2_scale;
426
4.38M
}
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
4.23M
{
434
4.23M
    gs_gstate *pgs = penum->pgs;
435
4.23M
    gx_device *dev = gs_currentdevice_inline(pgs);
436
4.23M
    int code;
437
438
4.23M
    *alpha_bits = (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
439
4.23M
    if (in_setcachedevice) {
440
        /* current point should already be in penum->origin */
441
3.85M
    } else {
442
3.85M
        code = gx_path_current_point_inline(pgs, &penum->origin);
443
3.85M
        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
3.85M
    }
450
4.23M
    if (penum->fapi_log2_scale.x != -1)
451
1.94M
        *log2_scale = penum->fapi_log2_scale;
452
2.29M
    else
453
2.29M
        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
4.23M
    *depth = (log2_scale->x + log2_scale->y == 0 ?
460
4.23M
        1 : min(log2_scale->x + log2_scale->y, *alpha_bits));
461
4.23M
    if (gs_currentaligntopixels(penum->current_font->dir) == 0) {
462
4.23M
        int scx = -(1L << (_fixed_shift - log2_scale->x));
463
4.23M
        int rdx =  1L << (_fixed_shift - 1 - log2_scale->x);
464
465
4.23M
#       if 1 /* Ever align Y to pixels to provide an uniform glyph height. */
466
4.23M
            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
4.23M
        subpix_origin->x = ((penum->origin.x + rdx) & scx) & (fixed_1 - 1);
474
4.23M
    } else
475
0
        subpix_origin->x = subpix_origin->y = 0;
476
4.23M
    return 0;
477
4.23M
}
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
2.20M
{
486
2.20M
    gs_glyph glyph;
487
2.20M
    int code = 0;
488
489
    /* See if we want to cache this character. */
490
2.20M
    if (pgs->in_cachedevice)    /* no recursion! */
491
1.78M
        return 0;
492
415k
    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
415k
    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
415k
    glyph = CURRENT_GLYPH(penum);
502
415k
    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
415k
    if (penum->can_cache <= 0 || !pgs->char_tm_valid) {
507
1
        if_debug2m('k', penum->memory, "[k]no cache: can_cache=%d, char_tm_valid=%d\n",
508
1
                   penum->can_cache, (int)pgs->char_tm_valid);
509
1
        return 0;
510
415k
    } {
511
415k
        const gs_font *pfont = pgs->font;
512
415k
        gs_font_dir *dir = pfont->dir;
513
415k
        int alpha_bits, depth;
514
415k
        gs_log2_scale_point log2_scale;
515
415k
        gs_fixed_point subpix_origin;
516
415k
        static const fixed max_cdim[3] =
517
415k
        {
518
415k
#define max_cd(n)\
519
1.24M
            (fixed_1 << (ARCH_SIZEOF_SHORT * 8 - n)) - (fixed_1 >> n) * 3
520
415k
            max_cd(0), max_cd(1), max_cd(2)
521
415k
#undef max_cd
522
415k
        };
523
415k
        ushort iwidth, iheight;
524
415k
        cached_char *cc;
525
415k
        gs_fixed_rect clip_box;
526
415k
        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
415k
        if (fabs(llx) > 32000. || fabs(lly) > 32000. || fabs(urx) > 32000. || fabs(ury) >= 32000.)
532
14.7k
            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
401k
        if ((code = gs_distance_transform2fixed(&pgs->ctm, llx, lly, &cll)) < 0 ||
541
401k
            (code = gs_distance_transform2fixed(&pgs->ctm, llx, ury, &clr)) < 0 ||
542
401k
            (code = gs_distance_transform2fixed(&pgs->ctm, urx, lly, &cul)) < 0 ||
543
401k
         (code = gs_distance_transform2fixed(&pgs->ctm, urx, ury, &cur)) < 0
544
401k
            )
545
18.1k
            return 0;           /* don't cache */
546
383k
        {
547
383k
            fixed ctemp;
548
549
383k
#define swap(a, b) ctemp = a, a = b, b = ctemp
550
1.53M
#define make_min(a, b) if ( (a) > (b) ) swap(a, b)
551
552
383k
            make_min(cll.x, cur.x);
553
383k
            make_min(cll.y, cur.y);
554
383k
            make_min(clr.x, cul.x);
555
383k
            make_min(clr.y, cul.y);
556
383k
#undef make_min
557
383k
#undef swap
558
383k
        }
559
        /* Now take advantage of symmetry. */
560
383k
        if (clr.x < cll.x)
561
17
            cll.x = clr.x, cur.x = cul.x;
562
383k
        if (clr.y < cll.y)
563
1.72k
            cll.y = clr.y, cur.y = cul.y;
564
        /* Now cll and cur are the extrema of the box. */
565
383k
        code = compute_glyph_raster_params(penum, true, &alpha_bits, &depth,
566
383k
           &subpix_origin, &log2_scale);
567
383k
        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
383k
        cdim.x = cur.x - cll.x;
581
383k
        cdim.y = cur.y - cll.y;
582
383k
        if (cdim.x > max_cdim[log2_scale.x] ||
583
383k
            cdim.y > max_cdim[log2_scale.y]
584
383k
            )
585
12.8k
            return 0;           /* much too big */
586
370k
        iwidth = ((ushort) fixed2int_var(cdim.x) + 3) << log2_scale.x;
587
370k
        iheight = ((ushort) fixed2int_var(cdim.y) + 3) << log2_scale.y;
588
370k
        if_debug3m('k', penum->memory, "[k]iwidth=%u iheight=%u dev_cache %s\n",
589
370k
                   (uint) iwidth, (uint) iheight,
590
370k
                   (penum->dev_cache == 0 ? "not set" : "set"));
591
370k
        if (penum->dev_cache == 0) {
592
116k
            code = show_cache_setup(penum);
593
116k
            if (code < 0)
594
0
                return code;
595
116k
        }
596
370k
        code = gx_alloc_char_bits(dir, penum->dev_cache,
597
370k
                                  iwidth, iheight, &log2_scale, depth, &cc);
598
370k
        if (code < 0)
599
0
            return code;
600
601
370k
        if (cc == 0) {
602
            /* too big for cache or no cache */
603
66.5k
            gx_path box_path;
604
605
66.5k
            if (penum->current_font->FontType != ft_user_defined &&
606
66.5k
                penum->current_font->FontType != ft_PDF_user_defined &&
607
66.5k
                penum->current_font->FontType != ft_PCL_user_defined &&
608
66.5k
                penum->current_font->FontType != ft_GL2_stick_user_defined &&
609
66.5k
                penum->current_font->FontType != ft_CID_user_defined) {
610
                /* Most fonts don't paint outside bbox,
611
                   so render with no clipping. */
612
1.68k
                return 0;
613
1.68k
            }
614
            /* Render with a clip. */
615
            /* show_proceed already did gsave. */
616
64.8k
            pgs->in_cachedevice = CACHE_DEVICE_NONE; /* Provide a correct grestore on error. */
617
64.8k
            clip_box.p.x = penum->origin.x - fixed_ceiling(-cll.x);
618
64.8k
            clip_box.p.y = penum->origin.y - fixed_ceiling(-cll.y);
619
64.8k
            clip_box.q.x = clip_box.p.x + int2fixed(iwidth);
620
64.8k
            clip_box.q.y = clip_box.p.y + int2fixed(iheight);
621
64.8k
            gx_path_init_local(&box_path, pgs->memory);
622
64.8k
            code = gx_path_add_rectangle(&box_path, clip_box.p.x, clip_box.p.y,
623
64.8k
                                                    clip_box.q.x, clip_box.q.y);
624
64.8k
            if (code < 0)
625
0
                return code;
626
64.8k
            code = gx_cpath_clip(pgs, pgs->clip_path, &box_path, gx_rule_winding_number);
627
64.8k
            if (code < 0)
628
0
                return code;
629
64.8k
            gx_path_free(&box_path, "set_cache_device");
630
64.8k
            pgs->in_cachedevice = CACHE_DEVICE_NONE_AND_CLIP;
631
64.8k
            return 0;
632
64.8k
        }
633
        /* The mins handle transposed coordinate systems.... */
634
        /* Truncate the offsets to avoid artifacts later. */
635
303k
        cc->offset.x = fixed_ceiling(-cll.x) + fixed_1;
636
303k
        cc->offset.y = fixed_ceiling(-cll.y) + fixed_1;
637
303k
        if_debug4m('k', penum->memory, "[k]width=%u, height=%u, offset=[%g %g]\n",
638
303k
                   (uint) iwidth, (uint) iheight,
639
303k
                   fixed2float(cc->offset.x),
640
303k
                   fixed2float(cc->offset.y));
641
303k
        pgs->in_cachedevice = CACHE_DEVICE_NONE; /* Provide correct grestore */
642
303k
        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
303k
        penum->cc = cc;
648
303k
        cc->code = glyph;
649
303k
        cc->wmode = gs_rootfont(pgs)->WMode;
650
303k
        cc->wxy = penum->wxy;
651
303k
        cc->subpix_origin = subpix_origin;
652
303k
        if (penum->pair != 0)
653
303k
            cc_set_pair(cc, penum->pair);
654
0
        else
655
0
            cc->pair = 0;
656
        /* Install the device */
657
303k
        gx_set_device_only(pgs, (gx_device *) penum->dev_cache);
658
303k
        pgs->ctm_default_set = false;
659
        /* Adjust the transformation in the graphics context */
660
        /* so that the character lines up with the cache. */
661
303k
        gx_translate_to_fixed(pgs,
662
303k
                              (cc->offset.x + subpix_origin.x) << log2_scale.x,
663
303k
                              (cc->offset.y + subpix_origin.y) << log2_scale.y);
664
303k
        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
303k
        penum->dev_cache->initial_matrix = ctm_only(pgs);
669
        /* Set the oversampling factor. */
670
303k
        penum->log2_scale.x = log2_scale.x;
671
303k
        penum->log2_scale.y = log2_scale.y;
672
        /* Reset the clipping path to match the metrics. */
673
303k
        clip_box.p.x = clip_box.p.y = 0;
674
303k
        clip_box.q.x = int2fixed(iwidth);
675
303k
        clip_box.q.y = int2fixed(iheight);
676
303k
        if ((code = gx_clip_to_rectangle(pgs, &clip_box)) < 0)
677
0
            goto fail;
678
303k
        code = gx_set_device_color_1(pgs);     /* write 1's */
679
303k
        if (code < 0)
680
0
            goto fail;
681
303k
        gs_swapcolors_quick(pgs);
682
303k
        code = gx_set_device_color_1(pgs);     /* write 1's */
683
303k
        if (code < 0)
684
0
            goto fail;
685
303k
        gs_swapcolors_quick(pgs);
686
303k
        pgs->in_cachedevice = CACHE_DEVICE_CACHING;
687
303k
    }
688
0
    penum->width_status = sws_cache;
689
303k
    return 1;
690
691
0
fail:
692
0
    gs_grestore(pgs);
693
0
    return code;
694
303k
}
695
696
/* Return the cache device status. */
697
gs_in_cache_device_t
698
gs_incachedevice(const gs_gstate *pgs)
699
104k
{
700
104k
    return pgs->in_cachedevice;
701
104k
}
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
1.36M
{
711
1.36M
    penum->encode_char =
712
1.36M
        (SHOW_IS(penum, TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH) ?
713
0
         gs_no_encode_char :
714
1.36M
         gs_show_current_font(penum)->procs.encode_char);
715
1.36M
}
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
1.37M
{
741
1.37M
    gs_show_enum *const penum = (gs_show_enum *)pte;
742
743
1.37M
    return (*penum->continue_proc)(penum);
744
1.37M
}
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
182k
{
754
182k
    int code = show_update(penum);
755
756
182k
    if (code < 0)
757
0
        return code;
758
182k
    code = show_move(penum);
759
182k
    if (code != 0)
760
1
        return code;
761
182k
    return show_proceed(penum);
762
182k
}
763
static int
764
continue_show(gs_show_enum * penum)
765
1.19M
{
766
1.19M
    return show_proceed(penum);
767
1.19M
}
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
2.20M
{
789
2.20M
    gs_gstate *pgs = penum->pgs;
790
2.20M
    cached_char *cc = penum->cc;
791
2.20M
    int code;
792
793
    /* Update position for last character */
794
2.20M
    switch (penum->width_status) {
795
1.00k
        case sws_none:
796
1.00k
        case sws_retry:
797
            /* Adobe interpreters assume a character width of 0, */
798
            /* even though the documentation says this is an error.... */
799
1.00k
            penum->wxy.x = penum->wxy.y = 0;
800
1.00k
            penum->wxy_float.x = penum->wxy_float.y = 0;
801
1.00k
            penum->use_wxy_float = false;
802
1.00k
            break;
803
303k
        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
303k
            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
303k
                case 2:
813
303k
                    code = gs_grestore(pgs);
814
303k
                    if (code < 0)
815
0
                        return code;
816
303k
                case 1:
817
303k
                    ;
818
303k
            }
819
303k
            {   cached_fm_pair *pair;
820
821
303k
                code = gx_lookup_fm_pair(pgs->font, &char_tm_only(pgs),
822
303k
                            &penum->log2_scale, penum->charpath_flag != cpm_show, &pair);
823
303k
                if (code < 0)
824
0
                    return code;
825
303k
                code = gx_add_cached_char(pgs->font->dir, penum->dev_cache,
826
303k
                               cc, pair, &penum->log2_scale);
827
303k
                if (code < 0)
828
0
                    return code;
829
303k
            }
830
303k
            if (!SHOW_USES_OUTLINE(penum) ||
831
303k
                penum->charpath_flag != cpm_show
832
303k
                )
833
0
                break;
834
            /* falls through */
835
303k
        case sws_cache_width_only:
836
            /* Copy the bits to the real output device. */
837
303k
            code = gs_grestore(pgs);
838
303k
            if (code < 0)
839
0
                return code;
840
303k
            code = gs_gstate_color_load(pgs);
841
303k
            if (code < 0)
842
0
                return code;
843
303k
            return gx_image_cached_char(penum, cc);
844
1.90M
        case sws_no_cache:
845
1.90M
            ;
846
2.20M
    }
847
1.90M
    if (penum->charpath_flag != cpm_show) {
848
2.69k
        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
2.69k
        code = gx_path_add_point(pgs->show_gstate->path,
854
2.69k
                                 penum->origin.x, penum->origin.y);
855
2.69k
        if (code < 0)
856
0
            return code;
857
2.69k
    }
858
1.90M
    return gs_grestore(pgs);
859
1.90M
}
860
861
/* Move to next character */
862
static inline int
863
show_fast_move(gs_gstate * pgs, gs_fixed_point * pwxy)
864
3.81M
{
865
3.81M
    return gs_moveto_aux(pgs, pgs->path,
866
3.81M
                              pgs->current_point.x + fixed2float(pwxy->x),
867
3.81M
                              pgs->current_point.y + fixed2float(pwxy->y));
868
3.81M
}
869
870
/* Get the current character code. */
871
int gx_current_char(const gs_text_enum_t * pte)
872
181k
{
873
181k
    const gs_show_enum *penum = (const gs_show_enum *)pte;
874
181k
    gs_char chr = CURRENT_CHAR(penum) & 0xff;
875
181k
    int fdepth = penum->fstack.depth;
876
877
181k
    if (fdepth > 0) {
878
        /* Add in the shifted font number. */
879
436
        uint fidx = penum->fstack.items[fdepth - 1].index;
880
881
436
        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
436
        case fmap_CMap:
887
436
            chr = CURRENT_CHAR(penum);  /* the full character */
888
436
            if (!penum->cmap_code)
889
436
                break;
890
            /* falls through */
891
0
        default:
892
0
            chr += fidx << 8;
893
436
        }
894
436
    }
895
181k
    return chr;
896
181k
}
897
898
static int
899
show_move(gs_show_enum * penum)
900
3.27M
{
901
3.27M
    gs_gstate *pgs = penum->pgs;
902
3.27M
    int code;
903
3.27M
    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
3.27M
    if (SHOW_IS_ADD_TO_SPACE(penum)
910
3.27M
        && (!penum->single_byte_space
911
191k
        || penum->bytes_decoded == 1)) {
912
181k
        gs_char chr = gx_current_char((const gs_text_enum_t *)penum);
913
914
181k
        if (chr == penum->text.space.s_char) {
915
17.6k
            dx = penum->text.delta_space.x;
916
17.6k
            dy = penum->text.delta_space.y;
917
17.6k
        }
918
181k
    }
919
920
3.27M
    if (SHOW_IS(penum, TEXT_REPLACE_WIDTHS)) {
921
1.88M
        gs_point dpt;
922
923
1.88M
        code = gs_text_replaced_width(&penum->text, penum->xy_index - 1, &dpt);
924
1.88M
        if (code < 0)
925
0
            return code;
926
1.88M
        dpt.x += dx;
927
1.88M
        dpt.y += dy;
928
1.88M
        code = gs_distance_transform2fixed(&pgs->ctm, dpt.x, dpt.y, &penum->wxy);
929
1.88M
        if (code < 0)
930
133
            return code;
931
1.88M
    } else {
932
1.38M
        if (SHOW_IS_ADD_TO_ALL(penum)) {
933
247k
            dx += penum->text.delta_all.x;
934
247k
            dy += penum->text.delta_all.y;
935
247k
        }
936
1.38M
        if (!is_fzero2(dx, dy)) {
937
249k
            gs_fixed_point dxy;
938
939
249k
            code = gs_distance_transform2fixed(&pgs->ctm, dx, dy, &dxy);
940
249k
            if (code < 0)
941
26
                return code;
942
249k
            penum->wxy.x += dxy.x;
943
249k
            penum->wxy.y += dxy.y;
944
249k
        }
945
1.38M
    }
946
3.27M
    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
3.27M
    {
953
3.27M
        int code;
954
955
3.27M
        if (penum->use_wxy_float)
956
38.3k
            code = gs_moveto_aux(pgs, pgs->path,
957
38.3k
                    pgs->current_point.x + penum->wxy_float.x + fixed2float(penum->wxy.x),
958
38.3k
                    pgs->current_point.y + penum->wxy_float.y + fixed2float(penum->wxy.y));
959
3.23M
        else
960
3.23M
            code = show_fast_move(pgs, &penum->wxy);
961
3.27M
        if (code < 0)
962
0
            return code;
963
3.27M
    }
964
    /* Check for kerning, but not on the last character. */
965
3.27M
    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
3.27M
    return 0;
970
3.27M
}
971
972
static inline int
973
get_next_char_glyph(gs_show_enum * penum, gs_char *chr, gs_glyph *glyph)
974
5.04M
{
975
5.04M
    gs_font *rfont =
976
5.04M
        (penum->fstack.depth < 0 ? penum->pgs->font : penum->fstack.items[0].font);
977
5.04M
    penum->xy_index++;
978
979
5.04M
    return rfont->procs.next_char_glyph((gs_text_enum_t *)penum, chr, glyph);
980
5.04M
}
981
982
983
/* Process next character */
984
static int
985
show_proceed(gs_show_enum * penum)
986
1.37M
{
987
1.37M
    gs_gstate *pgs = penum->pgs;
988
1.37M
    gs_font *pfont;
989
1.37M
    cached_fm_pair *pair = 0;
990
1.37M
    gs_font *rfont =
991
1.37M
        (penum->fstack.depth < 0 ? pgs->font : penum->fstack.items[0].font);
992
1.37M
    int wmode = rfont->WMode;
993
1.37M
    gs_char chr;
994
1.37M
    gs_glyph glyph;
995
1.37M
    int code, start;
996
1.37M
    cached_char *cc;
997
1.37M
    gs_log2_scale_point log2_scale;
998
999
1.37M
    if (penum->charpath_flag == cpm_show && SHOW_USES_OUTLINE(penum)) {
1000
1.36M
        code = gs_gstate_color_load(pgs);
1001
1.36M
        if (code < 0)
1002
0
            return code;
1003
1.36M
    }
1004
3.40M
  more:                 /* Proceed to next character */
1005
3.40M
    pfont = (penum->fstack.depth < 0 ? pgs->font :
1006
3.40M
             penum->fstack.items[penum->fstack.depth].font);
1007
3.40M
    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
3.40M
    if (penum->can_cache >= 0) {
1011
        /* Loop with cache */
1012
5.04M
        for (;;) {
1013
5.04M
            start = penum->index;
1014
5.04M
            switch ((code = get_next_char_glyph(penum, &chr, &glyph))) {
1015
0
                default:        /* error */
1016
0
                    return code;
1017
1.19M
                case 2: /* done */
1018
1.19M
                    return show_finish(penum);
1019
166k
                case 1: /* font change */
1020
166k
                    pfont = penum->fstack.items[penum->fstack.depth].font;
1021
166k
                    penum->current_font = pfont;
1022
166k
                    pgs->char_tm_valid = false;
1023
166k
                    show_state_setup(penum);
1024
166k
                    pair = 0;
1025
166k
                    penum->pair = 0;
1026
                    /* falls through */
1027
3.85M
                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
3.85M
                    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
3.85M
                    if (glyph == GS_NO_GLYPH) {
1040
3.34M
                        glyph = (*penum->encode_char)(pfont, chr,
1041
3.34M
                                                      GLYPH_SPACE_NAME);
1042
3.34M
                        SET_CURRENT_GLYPH(penum, glyph);
1043
3.34M
                    } else
1044
512k
                        SET_CURRENT_GLYPH(penum, glyph);
1045
3.85M
                    penum->bytes_decoded = penum->index - start;
1046
3.85M
                    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
3.85M
                    {
1053
3.85M
                        int alpha_bits, depth;
1054
3.85M
                        gs_fixed_point subpix_origin;
1055
1056
3.85M
                        code = compute_glyph_raster_params(penum, false,
1057
3.85M
                                    &alpha_bits, &depth, &subpix_origin, &log2_scale);
1058
3.85M
                        if (code < 0)
1059
0
                            return code;
1060
3.85M
                        if (pair == 0) {
1061
1.27M
                            code = gx_lookup_fm_pair(pfont, &char_tm_only(pgs), &log2_scale,
1062
1.27M
                                penum->charpath_flag != cpm_show, &pair);
1063
1.27M
                            if (code < 0)
1064
0
                                return code;
1065
1.27M
                        }
1066
3.85M
                        penum->pair = pair;
1067
3.85M
                        if (glyph == GS_NO_GLYPH || SHOW_IS_ALL_OF(penum, TEXT_NO_CACHE)) {
1068
0
                            cc = 0;
1069
0
                            goto no_cache;
1070
0
                        }
1071
3.85M
                        cc = gx_lookup_cached_char(pfont, pair, glyph, wmode,
1072
3.85M
                                                   depth, &subpix_origin);
1073
3.85M
                    }
1074
3.85M
                    if (cc == 0) {
1075
2.20M
                        goto no_cache;
1076
2.20M
                    }
1077
                    /* Character is in cache. */
1078
                    /* We might be doing .charboxpath or stringwidth; */
1079
                    /* check for these now. */
1080
1.64M
                    if (penum->charpath_flag == cpm_charwidth) {
1081
                        /* This is charwidth.  Just move by the width. */
1082
0
                        DO_NOTHING;
1083
1.64M
                    } 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
1.64M
                    } else if (SHOW_IS_DRAWING(penum)) {
1114
1.64M
                        code = gx_image_cached_char(penum, cc);
1115
1.64M
                        if (code < 0)
1116
0
                            return code;
1117
1.64M
                        else if (code > 0) {
1118
0
                            cc = 0;
1119
0
                            goto no_cache;
1120
0
                        }
1121
1.64M
                    }
1122
1.64M
                    penum->use_wxy_float = false;
1123
1.64M
                    penum->wxy_float.x = penum->wxy_float.y = 0;
1124
1.64M
                    if (SHOW_IS_SLOW(penum)) {
1125
                        /* Split up the assignment so that the */
1126
                        /* Watcom compiler won't reserve esi/edi. */
1127
1.06M
                        penum->wxy.x = cc->wxy.x;
1128
1.06M
                        penum->wxy.y = cc->wxy.y;
1129
1.06M
                        code = show_move(penum);
1130
1.06M
                    } else
1131
581k
                        code = show_fast_move(pgs, &cc->wxy);
1132
1.64M
                    if (code) {
1133
                        /* Might be kshow, glyph is stored above. */
1134
0
                        return code;
1135
0
                    }
1136
5.04M
            }
1137
5.04M
        }
1138
3.39M
    } else {
1139
3.64k
        start = penum->index;
1140
        /* Can't use cache */
1141
3.64k
        switch ((code = get_next_char_glyph(penum, &chr, &glyph))) {
1142
0
            default:
1143
0
                return code;
1144
941
            case 2:
1145
941
                return show_finish(penum);
1146
62
            case 1:
1147
62
                pfont = penum->fstack.items[penum->fstack.depth].font;
1148
62
                penum->current_font = pfont;
1149
62
                show_state_setup(penum);
1150
62
                pair = 0;
1151
2.70k
            case 0:
1152
2.70k
                {   int alpha_bits, depth;
1153
2.70k
                    gs_log2_scale_point log2_scale;
1154
2.70k
                    gs_fixed_point subpix_origin;
1155
1156
2.70k
                    penum->bytes_decoded = penum->index - start;
1157
2.70k
                    code = compute_glyph_raster_params(penum, false, &alpha_bits, &depth, &subpix_origin, &log2_scale);
1158
2.70k
                    if (code < 0)
1159
0
                        return code;
1160
2.70k
                    if (pair == 0) {
1161
945
                        code = gx_lookup_fm_pair(pfont, &char_tm_only(pgs), &log2_scale,
1162
945
                                penum->charpath_flag != cpm_show, &pair);
1163
945
                        if (code < 0)
1164
0
                            return code;
1165
945
                    }
1166
2.70k
                    penum->pair = pair;
1167
2.70k
                }
1168
3.64k
        }
1169
2.70k
        SET_CURRENT_CHAR(penum, chr);
1170
2.70k
        if (glyph == GS_NO_GLYPH) {
1171
2.01k
            glyph = (*penum->encode_char)(pfont, chr, GLYPH_SPACE_NAME);
1172
2.01k
        }
1173
2.70k
        SET_CURRENT_GLYPH(penum, glyph);
1174
2.70k
        cc = 0;
1175
2.70k
    }
1176
2.20M
  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
2.20M
    if ((code = gs_gsave(pgs)) < 0)
1186
0
        return code;
1187
    /* Set the font to the current descendant font. */
1188
2.20M
    pgs->font = pfont;
1189
    /* Reset the in_cachedevice flag, so that a recursive show */
1190
    /* will use the cache properly. */
1191
2.20M
    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
2.20M
    pgs->in_charpath = penum->charpath_flag;
1196
2.20M
    pgs->show_gstate =
1197
2.20M
        (penum->show_gstate == pgs ? pgs->saved : penum->show_gstate);
1198
2.20M
    pgs->stroke_adjust = false; /* per specification */
1199
2.20M
    {
1200
2.20M
        gs_fixed_point cpt;
1201
1202
2.20M
        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
2.20M
        penum->origin.x = cpt.x;
1209
2.20M
        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
2.20M
        gs_currentcharmatrix(pgs, NULL, true);
1213
2.20M
        if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) {
1214
2.17M
            fixed tx = pgs->ctm.tx_fixed;
1215
2.17M
            fixed ty = pgs->ctm.ty_fixed;
1216
1217
2.17M
            gs_settocharmatrix(pgs);
1218
2.17M
            cpt.x += pgs->ctm.tx_fixed - tx;
1219
2.17M
            cpt.y += pgs->ctm.ty_fixed - ty;
1220
2.17M
        } else  {
1221
29.3k
            double tx = pgs->ctm.tx;
1222
29.3k
            double ty = pgs->ctm.ty;
1223
29.3k
            double fpx, fpy;
1224
1225
29.3k
            gs_settocharmatrix(pgs);
1226
29.3k
            fpx = fixed2float(cpt.x) + (pgs->ctm.tx - tx);
1227
29.3k
            fpy = fixed2float(cpt.y) + (pgs->ctm.ty - ty);
1228
29.3k
            if (!(f_fits_in_bits(fpx, fixed_int_bits)
1229
29.3k
                && f_fits_in_bits(fpy, fixed_int_bits))) {
1230
1
                gs_note_error(code = gs_error_limitcheck);
1231
1
                goto rret;
1232
1
            }
1233
29.3k
            cpt.x = float2fixed(fpx);
1234
29.3k
            cpt.y = float2fixed(fpy);
1235
29.3k
        }
1236
2.20M
        if (((code = gs_newpath(pgs)) < 0) ||
1237
2.20M
            ((code = show_origin_setup(pgs, cpt.x, cpt.y, penum)) < 0))
1238
0
            goto rret;
1239
2.20M
    }
1240
2.20M
    penum->width_status = sws_none;
1241
2.20M
    penum->continue_proc = continue_show_update;
1242
    /* Reset the sampling scale. */
1243
2.20M
    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
2.20M
    penum->cc = cc;             /* set this now for build procedure */
1247
2.20M
    code = (*pfont->procs.build_char)(penum, pgs, pfont,
1248
2.20M
                                      chr, glyph);
1249
2.20M
    if (code < 0) {
1250
349
        discard(gs_note_error(code));
1251
349
        goto rret;
1252
349
    }
1253
2.20M
    if (code == 0) {
1254
2.02M
        code = show_update(penum);
1255
2.02M
        if (code < 0)
1256
0
            goto rret;
1257
        /* Note that show_update does a grestore.... */
1258
2.02M
        code = show_move(penum);
1259
2.02M
        if (code)
1260
158
            return code;        /* ... so don't go to rret here. */
1261
2.02M
        goto more;
1262
2.02M
    }
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
182k
    if (penum->dev_cache == 0) {
1270
104k
        code = show_cache_setup(penum);
1271
104k
        if (code < 0)
1272
0
            goto rret;
1273
104k
    }
1274
182k
    return TEXT_PROCESS_RENDER;
1275
    /* If we get an error while setting up for BuildChar, */
1276
    /* we must undo the partial setup. */
1277
350
rret:
1278
700
    while (pgs->level > penum->level) {
1279
350
        gs_grestore(pgs);
1280
350
    }
1281
350
    return code;
1282
182k
}
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
1.19M
{
1310
1.19M
    gs_gstate *pgs = penum->pgs;
1311
1.19M
    int code = 0, rcode;
1312
1313
1.19M
    if ((penum->text.operation & TEXT_DO_FALSE_CHARPATH) ||
1314
1.19M
        (penum->text.operation & TEXT_DO_TRUE_CHARPATH)) {
1315
941
        if (pgs->path->current_subpath)
1316
756
            pgs->path->last_charpath_segment = pgs->path->current_subpath->last;
1317
941
    }
1318
1.19M
    if (penum->auto_release)
1319
0
        penum->procs->release((gs_text_enum_t *)penum, "show_finish");
1320
1321
1.19M
    if (!SHOW_IS_STRINGWIDTH(penum))
1322
1.18M
       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
12.2k
    if (!(penum->text.operation & TEXT_RENDER_MODE_3))
1327
15
        code = gs_currentpoint(pgs, &penum->returned.total_width);
1328
12.2k
    rcode = gs_grestore(pgs);
1329
1330
12.2k
    return (code < 0 ? code : rcode);
1331
1.19M
}
1332
1333
/* Release the structure. */
1334
static void
1335
gx_show_text_release(gs_text_enum_t *pte, client_name_t cname)
1336
1.19M
{
1337
1.19M
    gs_show_enum *const penum = (gs_show_enum *)pte;
1338
1339
1.19M
    penum->cc = 0;
1340
1.19M
    if (penum->dev_cache2) {
1341
221k
        gx_device_retain((gx_device *)penum->dev_cache2, false);
1342
221k
        penum->dev_cache2 = 0;
1343
221k
    }
1344
1.19M
    if (penum->dev_cache) {
1345
221k
        gx_device_retain((gx_device *)penum->dev_cache, false);
1346
221k
        penum->dev_cache = 0;
1347
221k
    }
1348
1.19M
    if (penum->dev_null) {
1349
12.2k
        gx_device_retain((gx_device *)penum->dev_null, false);
1350
12.2k
        penum->dev_null = 0;
1351
12.2k
    }
1352
1.19M
    gx_default_text_release(pte, cname);
1353
1.19M
}
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
2.27M
{
1373
2.27M
    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
2.27M
    return ((!SHOW_USES_OUTLINE(penum) || penum->cc != 0) &&
1378
2.27M
            penum->pgs->level == penum->level + 1);
1379
2.27M
}
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
1.36M
{
1396
1.36M
    return (penum->fstack.depth < 0 ? penum->pgs->font :
1397
1.36M
            penum->fstack.items[penum->fstack.depth].font);
1398
1.36M
}
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
1.36M
{
1409
1.36M
    gs_gstate *pgs = penum->pgs;
1410
1.36M
    gx_clip_path *pcpath;
1411
1.36M
    gs_font *pfont;
1412
1413
1.36M
    if (penum->fstack.depth <= 0) {
1414
1.19M
        pfont = pgs->font;
1415
1.19M
        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
1.19M
        } else {
1432
1.19M
            gs_currentcharmatrix(pgs, NULL, 1); /* make char_tm valid */
1433
1.19M
        }
1434
1.19M
    } else {
1435
        /* We have to concatenate the parent's FontMatrix as well. */
1436
166k
        gs_matrix mat;
1437
166k
        const gx_font_stack_item_t *pfsi =
1438
166k
            &penum->fstack.items[penum->fstack.depth];
1439
1440
166k
        pfont = pfsi->font;
1441
166k
        gs_matrix_multiply(&pfont->FontMatrix,
1442
166k
                           &pfsi[-1].font->FontMatrix, &mat);
1443
166k
        if (pfont->FontType == ft_CID_encrypted) {
1444
            /* concatenate the Type9 leaf's matrix */
1445
963
            gs_matrix_multiply(&(gs_cid0_indexed_font(pfont, pfsi->index)->FontMatrix),
1446
963
                                &mat, &mat);
1447
963
        }
1448
166k
        gs_setcharmatrix(pgs, &mat);
1449
166k
    }
1450
1.36M
    penum->current_font = pfont;
1451
1.36M
    if (penum->can_cache >= 0 &&
1452
1.36M
        gx_effective_clip_path(pgs, &pcpath) >= 0
1453
1.36M
        ) {
1454
1.36M
        gs_fixed_rect cbox;
1455
1456
1.36M
        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
1.36M
        penum->ibox.p.x = fixed2int_var(cbox.p.x);
1461
1.36M
        penum->ibox.p.y = fixed2int_var(cbox.p.y);
1462
1.36M
        penum->ibox.q.x = fixed2int_var_ceiling(cbox.q.x);
1463
1.36M
        penum->ibox.q.y = fixed2int_var_ceiling(cbox.q.y);
1464
1.36M
        gx_cpath_outer_box(pcpath, &cbox);
1465
1.36M
        penum->obox.p.x = fixed2int_var(cbox.p.x);
1466
1.36M
        penum->obox.p.y = fixed2int_var(cbox.p.y);
1467
1.36M
        penum->obox.q.x = fixed2int_var_ceiling(cbox.q.x);
1468
1.36M
        penum->obox.q.y = fixed2int_var_ceiling(cbox.q.y);
1469
1.36M
        if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) {
1470
1.35M
            penum->ftx = (int)fixed2long(pgs->char_tm.tx_fixed -
1471
1.35M
                                         pgs->ctm.tx_fixed);
1472
1.35M
            penum->fty = (int)fixed2long(pgs->char_tm.ty_fixed -
1473
1.35M
                                         pgs->ctm.ty_fixed);
1474
1.35M
        } else {
1475
3.74k
            double fdx = pgs->char_tm.tx - pgs->ctm.tx;
1476
3.74k
            double fdy = pgs->char_tm.ty - pgs->ctm.ty;
1477
1478
3.74k
#define int_bits (ARCH_SIZEOF_INT * 8 - 1)
1479
3.74k
            if (!(f_fits_in_bits(fdx, int_bits) &&
1480
3.74k
                  f_fits_in_bits(fdy, int_bits))
1481
3.74k
                )
1482
312
                return_error(gs_error_limitcheck);
1483
3.43k
#undef int_bits
1484
3.43k
            penum->ftx = (int)fdx;
1485
3.43k
            penum->fty = (int)fdy;
1486
3.43k
        }
1487
1.36M
    }
1488
1.36M
    show_set_encode_char(penum);
1489
1.36M
    return 0;
1490
1.36M
}
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
221k
{
1551
221k
    gs_gstate *pgs = penum->pgs;
1552
221k
    gs_memory_t *mem = penum->memory;
1553
221k
    gx_device_memory *dev =
1554
221k
        gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory,
1555
221k
                        "show_cache_setup(dev_cache)");
1556
221k
    gx_device_memory *dev2 =
1557
221k
        gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory,
1558
221k
                        "show_cache_setup(dev_cache2)");
1559
1560
221k
    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
221k
    gs_make_mem_mono_device(dev, mem, gs_currentdevice_inline(pgs));
1578
221k
    penum->dev_cache = dev;
1579
221k
    gs_make_mem_mono_device(dev2, mem, gs_currentdevice_inline(pgs));
1580
221k
    penum->dev_cache2 = dev2;
1581
221k
    dev->HWResolution[0] = pgs->device->HWResolution[0];
1582
221k
    dev->HWResolution[1] = pgs->device->HWResolution[1];
1583
    /* Retain these devices, since they are referenced from the enumerator. */
1584
221k
    gx_device_retain((gx_device *)dev, true);
1585
221k
    gx_device_retain((gx_device *)dev2, true);
1586
221k
    return 0;
1587
221k
}
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
2.20M
{
1595
2.20M
    if (penum->charpath_flag == cpm_show) {
1596
        /* Round the translation in the graphics state. */
1597
        /* This helps prevent rounding artifacts later. */
1598
2.20M
        if (gs_currentaligntopixels(penum->current_font->dir) == 0) {
1599
2.20M
            int scx = -(1L << (_fixed_shift - penum->log2_scale.x));
1600
2.20M
            int scy = -(1L << (_fixed_shift - penum->log2_scale.y));
1601
2.20M
            int rdx =  1L << (_fixed_shift - 1 - penum->log2_scale.x);
1602
2.20M
            int rdy =  1L << (_fixed_shift - 1 - penum->log2_scale.y);
1603
1604
2.20M
            cpt_x = (cpt_x + rdx) & scx;
1605
2.20M
            cpt_y = (cpt_y + rdy) & scy;
1606
2.20M
        } else {
1607
0
            cpt_x = fixed_rounded(cpt_x);
1608
0
            cpt_y = fixed_rounded(cpt_y);
1609
0
        }
1610
2.20M
    }
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
2.20M
    return gx_translate_to_fixed(pgs, cpt_x, cpt_y);
1616
2.20M
}