Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gxchar.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
58.0M
  !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
8.36k
ENUM_PTRS_BEGIN(show_enum_enum_ptrs)
48
5.75k
     return ENUM_USING(st_gs_text_enum, vptr, size, index - 5);
49
523
ENUM_PTR(0, gs_show_enum, pgs);
50
523
ENUM_PTR(1, gs_show_enum, show_gstate);
51
8.36k
ENUM_PTR3(2, gs_show_enum, dev_cache, dev_cache2, dev_null);
52
8.36k
ENUM_PTRS_END
53
523
static RELOC_PTRS_WITH(show_enum_reloc_ptrs, gs_show_enum *eptr)
54
523
{
55
523
    RELOC_USING(st_gs_text_enum, vptr, size);           /* superclass */
56
523
    RELOC_VAR(eptr->pgs);
57
523
    RELOC_VAR(eptr->show_gstate);
58
523
    RELOC_PTR3(gs_show_enum, dev_cache, dev_cache2, dev_null);
59
523
}
60
523
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.27M
#define CURRENT_CHAR(penum) ((penum)->returned.current_char)
73
#define SET_CURRENT_CHAR(penum, chr)\
74
68.2M
  ((penum)->returned.current_char = (chr))
75
6.25M
#define CURRENT_GLYPH(penum) ((penum)->returned.current_glyph)
76
#define SET_CURRENT_GLYPH(penum, glyph)\
77
68.2M
  ((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
39.4M
{
83
39.4M
    gs_show_enum *penum;
84
85
39.4M
    rc_alloc_struct_1(penum, gs_show_enum, &st_gs_show_enum, mem,
86
39.4M
                      return 0, cname);
87
39.4M
    penum->rc.free = rc_free_text_enum;
88
39.4M
    penum->auto_release = true; /* old API */
89
    /* Initialize pointers for GC */
90
39.4M
    penum->text.operation = 0;  /* no pointers relevant */
91
39.4M
    penum->dev = 0;
92
39.4M
    penum->pgs = pgs;
93
39.4M
    penum->show_gstate = 0;
94
39.4M
    penum->dev_cache = 0;
95
39.4M
    penum->dev_cache2 = 0;
96
39.4M
    penum->fapi_log2_scale.x = penum->fapi_log2_scale.y = -1;
97
39.4M
    penum->fapi_glyph_shift.x = penum->fapi_glyph_shift.y = 0;
98
39.4M
    penum->dev_null = 0;
99
39.4M
    penum->fstack.depth = -1;
100
39.4M
    return penum;
101
39.4M
}
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
39.4M
{
126
39.4M
    uint operation = text->operation;
127
39.4M
    bool propagate_charpath = (operation & TEXT_DO_DRAW) != 0;
128
39.4M
    int code;
129
39.4M
    gs_gstate *pgs = (gs_gstate *)pgs1;
130
39.4M
    gs_show_enum *penum;
131
39.4M
    gs_memory_t * mem = pgs->memory;
132
133
39.4M
    penum = gs_show_enum_alloc(mem, pgs, "gx_default_text_begin");
134
39.4M
    if (!penum)
135
0
        return_error(gs_error_VMerror);
136
39.4M
    code = gs_text_enum_init((gs_text_enum_t *)penum, &default_text_procs,
137
39.4M
                             dev, pgs, text, font, pcpath, mem);
138
39.4M
    if (code < 0) {
139
0
        gs_free_object(mem, penum, "gx_default_text_begin");
140
0
        return code;
141
0
    }
142
39.4M
    penum->auto_release = false; /* new API */
143
39.4M
    penum->level = pgs->level;
144
39.4M
    penum->cc = 0;
145
39.4M
    penum->continue_proc = continue_show;
146
39.4M
    switch (penum->charpath_flag) {
147
414k
    case cpm_false_charpath: case cpm_true_charpath:
148
414k
        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
39.0M
    default:                    /* cpm_show */
153
39.0M
        penum->can_cache = 1; break;
154
39.4M
    }
155
39.4M
    code = show_state_setup(penum);
156
39.4M
    if (code < 0) {
157
3.29k
        gs_text_release(pgs, (gs_text_enum_t *)penum, "gx_default_text_begin");
158
3.29k
        penum = NULL;
159
3.29k
        return code;
160
3.29k
    }
161
39.4M
    penum->show_gstate =
162
39.4M
        (propagate_charpath && (pgs->in_charpath != 0) ?
163
39.4M
         pgs->show_gstate : pgs);
164
39.4M
    if (!(~operation & (TEXT_DO_NONE | TEXT_RETURN_WIDTH))) {
165
        /* This is stringwidth (or a PDF with text in rendering mode 3) . */
166
129k
        gx_device_null *dev_null =
167
129k
            gs_alloc_struct(mem, gx_device_null, &st_device_null,
168
129k
                            "stringwidth(dev_null)");
169
170
129k
        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
129k
        gs_make_null_device(dev_null, gs_currentdevice_inline(pgs), mem);
181
182
        /* Do an extra gsave and suppress output */
183
129k
        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
129k
        penum->level = pgs->level;      /* for level check in show_update */
190
129k
        pgs->ctm_default_set = false;
191
129k
        penum->dev_null = dev_null;
192
        /* Retain this device, since it is referenced from the enumerator. */
193
129k
        gx_device_retain((gx_device *)dev_null, true);
194
129k
        gs_setdevice_no_init(pgs, (gx_device *) dev_null);
195
        /* Establish an arbitrary translation and current point. */
196
129k
        gs_newpath(pgs);
197
129k
        gx_translate_to_fixed(pgs, fixed_0, fixed_0);
198
129k
        code = gx_path_add_point(pgs->path, fixed_0, fixed_0);
199
129k
        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
129k
    }
206
39.4M
    *ppte = (gs_text_enum_t *)penum;
207
39.4M
    return 0;
208
39.4M
}
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
26
{
248
26
    int code;
249
250
26
    code = gs_gsave(pgs);
251
26
    if (code < 0)
252
0
        return code;
253
26
    gs_newpath(pgs);
254
26
    *path = pgs->path;
255
26
    gx_translate_to_fixed(pgs, fixed_0, fixed_0);
256
26
    return gx_path_add_point(pgs->path, fixed_0, fixed_0);
257
26
}
258
259
int
260
gx_default_text_restore_state(gs_text_enum_t *pte)
261
72.6k
{
262
72.6k
    gs_show_enum *penum;
263
72.6k
    gs_gstate *pgs;
264
265
72.6k
    if (SHOW_IS(pte, TEXT_DO_NONE))
266
22
        return 0;
267
72.6k
    penum = (gs_show_enum *)pte;
268
72.6k
    pgs = penum->pgs;
269
72.6k
    return gs_grestore(pgs);
270
72.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
11.9M
{
282
11.9M
    gs_show_enum *const penum = (gs_show_enum *)pte;
283
11.9M
    gs_gstate *pgs = penum->pgs;
284
11.9M
    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
11.9M
    if (pfont->FontMatrix.xx == 0 && pfont->FontMatrix.xy == 0 &&
290
38
        pfont->FontMatrix.yx == 0 && pfont->FontMatrix.yy == 0)
291
4
        return_error(gs_error_undefinedresult); /* sic! : CPSI compatibility */
292
11.9M
    switch (control) {
293
769k
    case TEXT_SET_CHAR_WIDTH:
294
769k
        return set_char_width(penum, pgs, pw[0], pw[1]);
295
3.12M
    case TEXT_SET_CACHE_DEVICE: {
296
3.12M
        int code = set_char_width(penum, pgs, pw[0], pw[1]);    /* default is don't cache */
297
298
3.12M
        if (code < 0)
299
25
            return code;
300
3.12M
        if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) /* cshow */
301
0
            return code;
302
3.12M
        return set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
303
3.12M
    }
304
8.07M
    case TEXT_SET_CACHE_DEVICE2: {
305
8.07M
        int code;
306
8.07M
        bool retry = (penum->width_status == sws_retry);
307
308
8.07M
        if (pfont->WMode) {
309
7.20k
            float vx = pw[8], vy = pw[9];
310
7.20k
            gs_fixed_point pvxy, dvxy;
311
312
7.20k
            gs_fixed_point rewind_pvxy;
313
7.20k
            int rewind_code;
314
315
7.20k
            if ((code = gs_point_transform2fixed(&pgs->ctm, -vx, -vy, &pvxy)) < 0 ||
316
7.06k
                (code = gs_distance_transform2fixed(&pgs->ctm, vx, vy, &dvxy)) < 0
317
7.20k
                )
318
136
                return 0;               /* don't cache */
319
7.06k
            if ((code = set_char_width(penum, pgs, pw[6], pw[7])) < 0)
320
0
                return code;
321
7.06k
            if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE))
322
0
                return code;
323
            /* Adjust the origin by (vx, vy). */
324
7.06k
            gx_translate_to_fixed(pgs, pvxy.x, pvxy.y);
325
7.06k
            code = set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
326
7.06k
            if (code != 1) {
327
6.06k
                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
6.06k
                return code;
337
6.06k
            }
338
            /* Adjust the character origin too. */
339
1.00k
            (penum->cc)->offset.x += dvxy.x;
340
1.00k
            (penum->cc)->offset.y += dvxy.y;
341
8.06M
        } else {
342
8.06M
            code = set_char_width(penum, pgs, pw[0], pw[1]);
343
8.06M
            if (code < 0)
344
0
                return code;
345
8.06M
            if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE))
346
0
                return code;
347
8.06M
            code = set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
348
8.06M
        }
349
8.06M
        return code;
350
8.07M
    }
351
0
    default:
352
0
        return_error(gs_error_rangecheck);
353
11.9M
    }
354
11.9M
}
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
11.9M
{
362
11.9M
    int code;
363
364
11.9M
    if (penum->width_status != sws_none && penum->width_status != sws_retry)
365
28
        return_error(gs_error_undefined);
366
11.9M
    code = gs_distance_transform2fixed(&pgs->ctm, wx, wy, &penum->wxy);
367
11.9M
    if (code < 0 && penum->cc == 0) {
368
        /* Can't represent in 'fixed', use floats. */
369
187k
        code = gs_distance_transform(wx, wy, &ctm_only(pgs), &penum->wxy_float);
370
187k
        penum->wxy.x = penum->wxy.y = 0;
371
187k
        penum->use_wxy_float = true;
372
11.7M
    } else {
373
11.7M
        penum->use_wxy_float = false;
374
11.7M
        penum->wxy_float.x = penum->wxy_float.y = 0;
375
11.7M
    }
376
11.9M
    if (code < 0)
377
0
        return code;
378
    /* Check whether we're setting the scalable width */
379
    /* for a cached xfont character. */
380
11.9M
    if (penum->cc != 0) {
381
0
        penum->cc->wxy = penum->wxy;
382
0
        penum->width_status = sws_cache_width_only;
383
11.9M
    } else {
384
11.9M
        penum->width_status = sws_no_cache;
385
11.9M
    }
386
11.9M
    if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) /* cshow */
387
0
        gs_nulldevice(pgs);
388
11.9M
    return !SHOW_IS_DRAWING(penum);
389
11.9M
}
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
68.2M
{
395
68.2M
    gs_log2_scale_point log2_scale;
396
397
68.2M
    if (alpha_bits == 1)
398
68.2M
        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
68.2M
    *p_log2_scale = log2_scale;
426
68.2M
}
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
74.3M
{
434
74.3M
    gs_gstate *pgs = penum->pgs;
435
74.3M
    gx_device *dev = gs_currentdevice_inline(pgs);
436
74.3M
    int code;
437
438
74.3M
    *alpha_bits = (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
439
74.3M
    if (in_setcachedevice) {
440
        /* current point should already be in penum->origin */
441
68.2M
    } else {
442
68.2M
        code = gx_path_current_point_inline(pgs, &penum->origin);
443
68.2M
        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
68.2M
    }
450
74.3M
    if (penum->fapi_log2_scale.x != -1)
451
18.9M
        *log2_scale = penum->fapi_log2_scale;
452
55.4M
    else
453
55.4M
        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
74.3M
    *depth = (log2_scale->x + log2_scale->y == 0 ?
460
74.3M
        1 : min(log2_scale->x + log2_scale->y, *alpha_bits));
461
74.3M
    if (gs_currentaligntopixels(penum->current_font->dir) == 0) {
462
74.3M
        int scx = -(1L << (_fixed_shift - log2_scale->x));
463
74.3M
        int rdx =  1L << (_fixed_shift - 1 - log2_scale->x);
464
465
74.3M
#       if 1 /* Ever align Y to pixels to provide an uniform glyph height. */
466
74.3M
            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
74.3M
        subpix_origin->x = ((penum->origin.x + rdx) & scx) & (fixed_1 - 1);
474
74.3M
    } else
475
385
        subpix_origin->x = subpix_origin->y = 0;
476
74.3M
    return 0;
477
74.3M
}
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
11.1M
{
486
11.1M
    gs_glyph glyph;
487
11.1M
    int code = 0;
488
489
    /* See if we want to cache this character. */
490
11.1M
    if (pgs->in_cachedevice)    /* no recursion! */
491
4.94M
        return 0;
492
6.25M
    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
6.25M
    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
6.25M
    glyph = CURRENT_GLYPH(penum);
502
6.25M
    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
6.25M
    if (penum->can_cache <= 0 || !pgs->char_tm_valid) {
507
4
        if_debug2m('k', penum->memory, "[k]no cache: can_cache=%d, char_tm_valid=%d\n",
508
4
                   penum->can_cache, (int)pgs->char_tm_valid);
509
4
        return 0;
510
6.25M
    } {
511
6.25M
        const gs_font *pfont = pgs->font;
512
6.25M
        gs_font_dir *dir = pfont->dir;
513
6.25M
        int alpha_bits, depth;
514
6.25M
        gs_log2_scale_point log2_scale;
515
6.25M
        gs_fixed_point subpix_origin;
516
6.25M
        static const fixed max_cdim[3] =
517
6.25M
        {
518
6.25M
#define max_cd(n)\
519
18.7M
            (fixed_1 << (ARCH_SIZEOF_SHORT * 8 - n)) - (fixed_1 >> n) * 3
520
6.25M
            max_cd(0), max_cd(1), max_cd(2)
521
6.25M
#undef max_cd
522
6.25M
        };
523
6.25M
        ushort iwidth, iheight;
524
6.25M
        cached_char *cc;
525
6.25M
        gs_fixed_rect clip_box;
526
6.25M
        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
6.25M
        if (fabs(llx) > 32000. || fabs(lly) > 32000. || fabs(urx) > 32000. || fabs(ury) >= 32000.)
532
76.3k
            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.17M
        if ((code = gs_distance_transform2fixed(&pgs->ctm, llx, lly, &cll)) < 0 ||
541
6.16M
            (code = gs_distance_transform2fixed(&pgs->ctm, llx, ury, &clr)) < 0 ||
542
6.15M
            (code = gs_distance_transform2fixed(&pgs->ctm, urx, lly, &cul)) < 0 ||
543
6.15M
         (code = gs_distance_transform2fixed(&pgs->ctm, urx, ury, &cur)) < 0
544
6.17M
            )
545
23.7k
            return 0;           /* don't cache */
546
6.15M
        {
547
6.15M
            fixed ctemp;
548
549
6.47M
#define swap(a, b) ctemp = a, a = b, b = ctemp
550
24.6M
#define make_min(a, b) if ( (a) > (b) ) swap(a, b)
551
552
6.15M
            make_min(cll.x, cur.x);
553
6.15M
            make_min(cll.y, cur.y);
554
6.15M
            make_min(clr.x, cul.x);
555
6.15M
            make_min(clr.y, cul.y);
556
6.15M
#undef make_min
557
6.15M
#undef swap
558
6.15M
        }
559
        /* Now take advantage of symmetry. */
560
6.15M
        if (clr.x < cll.x)
561
23.0k
            cll.x = clr.x, cur.x = cul.x;
562
6.15M
        if (clr.y < cll.y)
563
56.4k
            cll.y = clr.y, cur.y = cul.y;
564
        /* Now cll and cur are the extrema of the box. */
565
6.15M
        code = compute_glyph_raster_params(penum, true, &alpha_bits, &depth,
566
6.15M
           &subpix_origin, &log2_scale);
567
6.15M
        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.15M
        cdim.x = cur.x - cll.x;
581
6.15M
        cdim.y = cur.y - cll.y;
582
6.15M
        if (cdim.x > max_cdim[log2_scale.x] ||
583
6.09M
            cdim.y > max_cdim[log2_scale.y]
584
6.15M
            )
585
73.6k
            return 0;           /* much too big */
586
6.07M
        iwidth = ((ushort) fixed2int_var(cdim.x) + 3) << log2_scale.x;
587
6.07M
        iheight = ((ushort) fixed2int_var(cdim.y) + 3) << log2_scale.y;
588
6.07M
        if_debug3m('k', penum->memory, "[k]iwidth=%u iheight=%u dev_cache %s\n",
589
6.07M
                   (uint) iwidth, (uint) iheight,
590
6.07M
                   (penum->dev_cache == 0 ? "not set" : "set"));
591
6.07M
        if (penum->dev_cache == 0) {
592
3.30M
            code = show_cache_setup(penum);
593
3.30M
            if (code < 0)
594
0
                return code;
595
3.30M
        }
596
6.07M
        code = gx_alloc_char_bits(dir, penum->dev_cache,
597
6.07M
                                  iwidth, iheight, &log2_scale, depth, &cc);
598
6.07M
        if (code < 0)
599
0
            return code;
600
601
6.07M
        if (cc == 0) {
602
            /* too big for cache or no cache */
603
275k
            gx_path box_path;
604
605
275k
            if (penum->current_font->FontType != ft_user_defined &&
606
205k
                penum->current_font->FontType != ft_PDF_user_defined &&
607
187k
                penum->current_font->FontType != ft_PCL_user_defined &&
608
187k
                penum->current_font->FontType != ft_GL2_stick_user_defined &&
609
187k
                penum->current_font->FontType != ft_CID_user_defined) {
610
                /* Most fonts don't paint outside bbox,
611
                   so render with no clipping. */
612
187k
                return 0;
613
187k
            }
614
            /* Render with a clip. */
615
            /* show_proceed already did gsave. */
616
87.6k
            pgs->in_cachedevice = CACHE_DEVICE_NONE; /* Provide a correct grestore on error. */
617
87.6k
            clip_box.p.x = penum->origin.x - fixed_ceiling(-cll.x);
618
87.6k
            clip_box.p.y = penum->origin.y - fixed_ceiling(-cll.y);
619
87.6k
            clip_box.q.x = clip_box.p.x + int2fixed(iwidth);
620
87.6k
            clip_box.q.y = clip_box.p.y + int2fixed(iheight);
621
87.6k
            gx_path_init_local(&box_path, pgs->memory);
622
87.6k
            code = gx_path_add_rectangle(&box_path, clip_box.p.x, clip_box.p.y,
623
87.6k
                                                    clip_box.q.x, clip_box.q.y);
624
87.6k
            if (code < 0)
625
0
                return code;
626
87.6k
            code = gx_cpath_clip(pgs, pgs->clip_path, &box_path, gx_rule_winding_number);
627
87.6k
            if (code < 0)
628
0
                return code;
629
87.6k
            gx_path_free(&box_path, "set_cache_device");
630
87.6k
            pgs->in_cachedevice = CACHE_DEVICE_NONE_AND_CLIP;
631
87.6k
            return 0;
632
87.6k
        }
633
        /* The mins handle transposed coordinate systems.... */
634
        /* Truncate the offsets to avoid artifacts later. */
635
5.80M
        cc->offset.x = fixed_ceiling(-cll.x) + fixed_1;
636
5.80M
        cc->offset.y = fixed_ceiling(-cll.y) + fixed_1;
637
5.80M
        if_debug4m('k', penum->memory, "[k]width=%u, height=%u, offset=[%g %g]\n",
638
5.80M
                   (uint) iwidth, (uint) iheight,
639
5.80M
                   fixed2float(cc->offset.x),
640
5.80M
                   fixed2float(cc->offset.y));
641
5.80M
        pgs->in_cachedevice = CACHE_DEVICE_NONE; /* Provide correct grestore */
642
5.80M
        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
5.80M
        penum->cc = cc;
648
5.80M
        cc->code = glyph;
649
5.80M
        cc->wmode = gs_rootfont(pgs)->WMode;
650
5.80M
        cc->wxy = penum->wxy;
651
5.80M
        cc->subpix_origin = subpix_origin;
652
5.80M
        if (penum->pair != 0)
653
5.80M
            cc_set_pair(cc, penum->pair);
654
0
        else
655
0
            cc->pair = 0;
656
        /* Install the device */
657
5.80M
        gx_set_device_only(pgs, (gx_device *) penum->dev_cache);
658
5.80M
        pgs->ctm_default_set = false;
659
        /* Adjust the transformation in the graphics context */
660
        /* so that the character lines up with the cache. */
661
5.80M
        gx_translate_to_fixed(pgs,
662
5.80M
                              (cc->offset.x + subpix_origin.x) << log2_scale.x,
663
5.80M
                              (cc->offset.y + subpix_origin.y) << log2_scale.y);
664
5.80M
        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
5.80M
        penum->dev_cache->initial_matrix = ctm_only(pgs);
669
        /* Set the oversampling factor. */
670
5.80M
        penum->log2_scale.x = log2_scale.x;
671
5.80M
        penum->log2_scale.y = log2_scale.y;
672
        /* Reset the clipping path to match the metrics. */
673
5.80M
        clip_box.p.x = clip_box.p.y = 0;
674
5.80M
        clip_box.q.x = int2fixed(iwidth);
675
5.80M
        clip_box.q.y = int2fixed(iheight);
676
5.80M
        if ((code = gx_clip_to_rectangle(pgs, &clip_box)) < 0)
677
0
            goto fail;
678
5.80M
        code = gx_set_device_color_1(pgs);     /* write 1's */
679
5.80M
        if (code < 0)
680
0
            goto fail;
681
5.80M
        gs_swapcolors_quick(pgs);
682
5.80M
        code = gx_set_device_color_1(pgs);     /* write 1's */
683
5.80M
        if (code < 0)
684
0
            goto fail;
685
5.80M
        gs_swapcolors_quick(pgs);
686
5.80M
        pgs->in_cachedevice = CACHE_DEVICE_CACHING;
687
5.80M
    }
688
0
    penum->width_status = sws_cache;
689
5.80M
    return 1;
690
691
0
fail:
692
0
    gs_grestore(pgs);
693
0
    return code;
694
5.80M
}
695
696
/* Return the cache device status. */
697
gs_in_cache_device_t
698
gs_incachedevice(const gs_gstate *pgs)
699
206k
{
700
206k
    return pgs->in_cachedevice;
701
206k
}
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
40.8M
{
711
40.8M
    penum->encode_char =
712
40.8M
        (SHOW_IS(penum, TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH) ?
713
94
         gs_no_encode_char :
714
40.8M
         gs_show_current_font(penum)->procs.encode_char);
715
40.8M
}
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
40.9M
{
741
40.9M
    gs_show_enum *const penum = (gs_show_enum *)pte;
742
743
40.9M
    return (*penum->continue_proc)(penum);
744
40.9M
}
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
1.43M
{
754
1.43M
    int code = show_update(penum);
755
756
1.43M
    if (code < 0)
757
0
        return code;
758
1.43M
    code = show_move(penum);
759
1.43M
    if (code != 0)
760
4
        return code;
761
1.43M
    return show_proceed(penum);
762
1.43M
}
763
static int
764
continue_show(gs_show_enum * penum)
765
39.4M
{
766
39.4M
    return show_proceed(penum);
767
39.4M
}
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
11.9M
{
789
11.9M
    gs_gstate *pgs = penum->pgs;
790
11.9M
    cached_char *cc = penum->cc;
791
11.9M
    int code;
792
793
    /* Update position for last character */
794
11.9M
    switch (penum->width_status) {
795
35.9k
        case sws_none:
796
35.9k
        case sws_retry:
797
            /* Adobe interpreters assume a character width of 0, */
798
            /* even though the documentation says this is an error.... */
799
35.9k
            penum->wxy.x = penum->wxy.y = 0;
800
35.9k
            penum->wxy_float.x = penum->wxy_float.y = 0;
801
35.9k
            penum->use_wxy_float = false;
802
35.9k
            break;
803
5.80M
        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
5.80M
            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
5.80M
                case 2:
813
5.80M
                    code = gs_grestore(pgs);
814
5.80M
                    if (code < 0)
815
0
                        return code;
816
5.80M
                case 1:
817
5.80M
                    ;
818
5.80M
            }
819
5.80M
            {   cached_fm_pair *pair;
820
821
5.80M
                code = gx_lookup_fm_pair(pgs->font, &char_tm_only(pgs),
822
5.80M
                            &penum->log2_scale, penum->charpath_flag != cpm_show, &pair);
823
5.80M
                if (code < 0)
824
0
                    return code;
825
5.80M
                code = gx_add_cached_char(pgs->font->dir, penum->dev_cache,
826
5.80M
                               cc, pair, &penum->log2_scale);
827
5.80M
                if (code < 0)
828
0
                    return code;
829
5.80M
            }
830
5.80M
            if (!SHOW_USES_OUTLINE(penum) ||
831
5.77M
                penum->charpath_flag != cpm_show
832
5.80M
                )
833
30.9k
                break;
834
            /* falls through */
835
5.77M
        case sws_cache_width_only:
836
            /* Copy the bits to the real output device. */
837
5.77M
            code = gs_grestore(pgs);
838
5.77M
            if (code < 0)
839
0
                return code;
840
5.77M
            code = gs_gstate_color_load(pgs);
841
5.77M
            if (code < 0)
842
0
                return code;
843
5.77M
            return gx_image_cached_char(penum, cc);
844
6.16M
        case sws_no_cache:
845
6.16M
            ;
846
11.9M
    }
847
6.22M
    if (penum->charpath_flag != cpm_show) {
848
983k
        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
983k
        code = gx_path_add_point(pgs->show_gstate->path,
854
983k
                                 penum->origin.x, penum->origin.y);
855
983k
        if (code < 0)
856
0
            return code;
857
983k
    }
858
6.22M
    return gs_grestore(pgs);
859
6.22M
}
860
861
/* Move to next character */
862
static inline int
863
show_fast_move(gs_gstate * pgs, gs_fixed_point * pwxy)
864
67.9M
{
865
67.9M
    return gs_moveto_aux(pgs, pgs->path,
866
67.9M
                              pgs->current_point.x + fixed2float(pwxy->x),
867
67.9M
                              pgs->current_point.y + fixed2float(pwxy->y));
868
67.9M
}
869
870
/* Get the current character code. */
871
int gx_current_char(const gs_text_enum_t * pte)
872
2.24M
{
873
2.24M
    const gs_show_enum *penum = (const gs_show_enum *)pte;
874
2.24M
    gs_char chr = CURRENT_CHAR(penum) & 0xff;
875
2.24M
    int fdepth = penum->fstack.depth;
876
877
2.24M
    if (fdepth > 0) {
878
        /* Add in the shifted font number. */
879
32.8k
        uint fidx = penum->fstack.items[fdepth - 1].index;
880
881
32.8k
        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
32.8k
        case fmap_CMap:
887
32.8k
            chr = CURRENT_CHAR(penum);  /* the full character */
888
32.8k
            if (!penum->cmap_code)
889
32.8k
                break;
890
            /* falls through */
891
0
        default:
892
0
            chr += fidx << 8;
893
32.8k
        }
894
32.8k
    }
895
2.24M
    return chr;
896
2.24M
}
897
898
static int
899
show_move(gs_show_enum * penum)
900
29.4M
{
901
29.4M
    gs_gstate *pgs = penum->pgs;
902
29.4M
    int code;
903
29.4M
    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
29.4M
    if (SHOW_IS_ADD_TO_SPACE(penum)
910
2.34M
        && (!penum->single_byte_space
911
2.24M
        || penum->bytes_decoded == 1)) {
912
2.24M
        gs_char chr = gx_current_char((const gs_text_enum_t *)penum);
913
914
2.24M
        if (chr == penum->text.space.s_char) {
915
204k
            dx = penum->text.delta_space.x;
916
204k
            dy = penum->text.delta_space.y;
917
204k
        }
918
2.24M
    }
919
920
29.4M
    if (SHOW_IS(penum, TEXT_REPLACE_WIDTHS)) {
921
18.2M
        gs_point dpt;
922
923
18.2M
        code = gs_text_replaced_width(&penum->text, penum->xy_index - 1, &dpt);
924
18.2M
        if (code < 0)
925
0
            return code;
926
18.2M
        dpt.x += dx;
927
18.2M
        dpt.y += dy;
928
18.2M
        code = gs_distance_transform2fixed(&pgs->ctm, dpt.x, dpt.y, &penum->wxy);
929
18.2M
        if (code < 0)
930
1.69k
            return code;
931
18.2M
    } else {
932
11.2M
        if (SHOW_IS_ADD_TO_ALL(penum)) {
933
3.09M
            dx += penum->text.delta_all.x;
934
3.09M
            dy += penum->text.delta_all.y;
935
3.09M
        }
936
11.2M
        if (!is_fzero2(dx, dy)) {
937
3.11M
            gs_fixed_point dxy;
938
939
3.11M
            code = gs_distance_transform2fixed(&pgs->ctm, dx, dy, &dxy);
940
3.11M
            if (code < 0)
941
1.96k
                return code;
942
3.11M
            penum->wxy.x += dxy.x;
943
3.11M
            penum->wxy.y += dxy.y;
944
3.11M
        }
945
11.2M
    }
946
29.4M
    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
29.4M
    {
953
29.4M
        int code;
954
955
29.4M
        if (penum->use_wxy_float)
956
183k
            code = gs_moveto_aux(pgs, pgs->path,
957
183k
                    pgs->current_point.x + penum->wxy_float.x + fixed2float(penum->wxy.x),
958
183k
                    pgs->current_point.y + penum->wxy_float.y + fixed2float(penum->wxy.y));
959
29.3M
        else
960
29.3M
            code = show_fast_move(pgs, &penum->wxy);
961
29.4M
        if (code < 0)
962
0
            return code;
963
29.4M
    }
964
    /* Check for kerning, but not on the last character. */
965
29.4M
    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
29.4M
    return 0;
970
29.4M
}
971
972
static inline int
973
get_next_char_glyph(gs_show_enum * penum, gs_char *chr, gs_glyph *glyph)
974
107M
{
975
107M
    gs_font *rfont =
976
107M
        (penum->fstack.depth < 0 ? penum->pgs->font : penum->fstack.items[0].font);
977
107M
    penum->xy_index++;
978
979
107M
    return rfont->procs.next_char_glyph((gs_text_enum_t *)penum, chr, glyph);
980
107M
}
981
982
983
/* Process next character */
984
static int
985
show_proceed(gs_show_enum * penum)
986
40.9M
{
987
40.9M
    gs_gstate *pgs = penum->pgs;
988
40.9M
    gs_font *pfont;
989
40.9M
    cached_fm_pair *pair = 0;
990
40.9M
    gs_font *rfont =
991
40.9M
        (penum->fstack.depth < 0 ? pgs->font : penum->fstack.items[0].font);
992
40.9M
    int wmode = rfont->WMode;
993
40.9M
    gs_char chr;
994
40.9M
    gs_glyph glyph;
995
40.9M
    int code, start;
996
40.9M
    cached_char *cc;
997
40.9M
    gs_log2_scale_point log2_scale;
998
999
40.9M
    if (penum->charpath_flag == cpm_show && SHOW_USES_OUTLINE(penum)) {
1000
39.7M
        code = gs_gstate_color_load(pgs);
1001
39.7M
        if (code < 0)
1002
0
            return code;
1003
39.7M
    }
1004
51.4M
  more:                 /* Proceed to next character */
1005
51.4M
    pfont = (penum->fstack.depth < 0 ? pgs->font :
1006
51.4M
             penum->fstack.items[penum->fstack.depth].font);
1007
51.4M
    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
51.4M
    if (penum->can_cache >= 0) {
1011
        /* Loop with cache */
1012
106M
        for (;;) {
1013
106M
            start = penum->index;
1014
106M
            switch ((code = get_next_char_glyph(penum, &chr, &glyph))) {
1015
33
                default:        /* error */
1016
33
                    return code;
1017
39.0M
                case 2: /* done */
1018
39.0M
                    return show_finish(penum);
1019
1.33M
                case 1: /* font change */
1020
1.33M
                    pfont = penum->fstack.items[penum->fstack.depth].font;
1021
1.33M
                    penum->current_font = pfont;
1022
1.33M
                    pgs->char_tm_valid = false;
1023
1.33M
                    show_state_setup(penum);
1024
1.33M
                    pair = 0;
1025
1.33M
                    penum->pair = 0;
1026
                    /* falls through */
1027
67.2M
                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
67.2M
                    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
67.2M
                    if (glyph == GS_NO_GLYPH) {
1040
64.5M
                        glyph = (*penum->encode_char)(pfont, chr,
1041
64.5M
                                                      GLYPH_SPACE_NAME);
1042
64.5M
                        SET_CURRENT_GLYPH(penum, glyph);
1043
64.5M
                    } else
1044
2.68M
                        SET_CURRENT_GLYPH(penum, glyph);
1045
67.2M
                    penum->bytes_decoded = penum->index - start;
1046
67.2M
                    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
67.2M
                    {
1053
67.2M
                        int alpha_bits, depth;
1054
67.2M
                        gs_fixed_point subpix_origin;
1055
1056
67.2M
                        code = compute_glyph_raster_params(penum, false,
1057
67.2M
                                    &alpha_bits, &depth, &subpix_origin, &log2_scale);
1058
67.2M
                        if (code < 0)
1059
0
                            return code;
1060
67.2M
                        if (pair == 0) {
1061
39.7M
                            code = gx_lookup_fm_pair(pfont, &char_tm_only(pgs), &log2_scale,
1062
39.7M
                                penum->charpath_flag != cpm_show, &pair);
1063
39.7M
                            if (code < 0)
1064
0
                                return code;
1065
39.7M
                        }
1066
67.2M
                        penum->pair = pair;
1067
67.2M
                        if (glyph == GS_NO_GLYPH || SHOW_IS_ALL_OF(penum, TEXT_NO_CACHE)) {
1068
219
                            cc = 0;
1069
219
                            goto no_cache;
1070
219
                        }
1071
67.2M
                        cc = gx_lookup_cached_char(pfont, pair, glyph, wmode,
1072
67.2M
                                                   depth, &subpix_origin);
1073
67.2M
                    }
1074
67.2M
                    if (cc == 0) {
1075
11.0M
                        goto no_cache;
1076
11.0M
                    }
1077
                    /* Character is in cache. */
1078
                    /* We might be doing .charboxpath or stringwidth; */
1079
                    /* check for these now. */
1080
56.1M
                    if (penum->charpath_flag == cpm_charwidth) {
1081
                        /* This is charwidth.  Just move by the width. */
1082
0
                        DO_NOTHING;
1083
56.1M
                    } 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
56.1M
                    } else if (SHOW_IS_DRAWING(penum)) {
1114
56.0M
                        code = gx_image_cached_char(penum, cc);
1115
56.0M
                        if (code < 0)
1116
7
                            return code;
1117
56.0M
                        else if (code > 0) {
1118
0
                            cc = 0;
1119
0
                            goto no_cache;
1120
0
                        }
1121
56.0M
                    }
1122
56.1M
                    penum->use_wxy_float = false;
1123
56.1M
                    penum->wxy_float.x = penum->wxy_float.y = 0;
1124
56.1M
                    if (SHOW_IS_SLOW(penum)) {
1125
                        /* Split up the assignment so that the */
1126
                        /* Watcom compiler won't reserve esi/edi. */
1127
17.4M
                        penum->wxy.x = cc->wxy.x;
1128
17.4M
                        penum->wxy.y = cc->wxy.y;
1129
17.4M
                        code = show_move(penum);
1130
17.4M
                    } else
1131
38.6M
                        code = show_fast_move(pgs, &cc->wxy);
1132
56.1M
                    if (code) {
1133
                        /* Might be kshow, glyph is stored above. */
1134
51
                        return code;
1135
51
                    }
1136
106M
            }
1137
106M
        }
1138
50.0M
    } else {
1139
1.40M
        start = penum->index;
1140
        /* Can't use cache */
1141
1.40M
        switch ((code = get_next_char_glyph(penum, &chr, &glyph))) {
1142
0
            default:
1143
0
                return code;
1144
414k
            case 2:
1145
414k
                return show_finish(penum);
1146
3.15k
            case 1:
1147
3.15k
                pfont = penum->fstack.items[penum->fstack.depth].font;
1148
3.15k
                penum->current_font = pfont;
1149
3.15k
                show_state_setup(penum);
1150
3.15k
                pair = 0;
1151
986k
            case 0:
1152
986k
                {   int alpha_bits, depth;
1153
986k
                    gs_log2_scale_point log2_scale;
1154
986k
                    gs_fixed_point subpix_origin;
1155
1156
986k
                    penum->bytes_decoded = penum->index - start;
1157
986k
                    code = compute_glyph_raster_params(penum, false, &alpha_bits, &depth, &subpix_origin, &log2_scale);
1158
986k
                    if (code < 0)
1159
0
                        return code;
1160
986k
                    if (pair == 0) {
1161
934k
                        code = gx_lookup_fm_pair(pfont, &char_tm_only(pgs), &log2_scale,
1162
934k
                                penum->charpath_flag != cpm_show, &pair);
1163
934k
                        if (code < 0)
1164
0
                            return code;
1165
934k
                    }
1166
986k
                    penum->pair = pair;
1167
986k
                }
1168
1.40M
        }
1169
986k
        SET_CURRENT_CHAR(penum, chr);
1170
986k
        if (glyph == GS_NO_GLYPH) {
1171
975k
            glyph = (*penum->encode_char)(pfont, chr, GLYPH_SPACE_NAME);
1172
975k
        }
1173
986k
        SET_CURRENT_GLYPH(penum, glyph);
1174
986k
        cc = 0;
1175
986k
    }
1176
12.0M
  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
12.0M
    if ((code = gs_gsave(pgs)) < 0)
1186
0
        return code;
1187
    /* Set the font to the current descendant font. */
1188
12.0M
    pgs->font = pfont;
1189
    /* Reset the in_cachedevice flag, so that a recursive show */
1190
    /* will use the cache properly. */
1191
12.0M
    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
12.0M
    pgs->in_charpath = penum->charpath_flag;
1196
12.0M
    pgs->show_gstate =
1197
12.0M
        (penum->show_gstate == pgs ? pgs->saved : penum->show_gstate);
1198
12.0M
    pgs->stroke_adjust = false; /* per specification */
1199
12.0M
    {
1200
12.0M
        gs_fixed_point cpt;
1201
1202
12.0M
        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
12.0M
        penum->origin.x = cpt.x;
1209
12.0M
        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
12.0M
        gs_currentcharmatrix(pgs, NULL, true);
1213
12.0M
        if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) {
1214
11.8M
            fixed tx = pgs->ctm.tx_fixed;
1215
11.8M
            fixed ty = pgs->ctm.ty_fixed;
1216
1217
11.8M
            gs_settocharmatrix(pgs);
1218
11.8M
            cpt.x += pgs->ctm.tx_fixed - tx;
1219
11.8M
            cpt.y += pgs->ctm.ty_fixed - ty;
1220
11.8M
        } else  {
1221
253k
            double tx = pgs->ctm.tx;
1222
253k
            double ty = pgs->ctm.ty;
1223
253k
            double fpx, fpy;
1224
1225
253k
            gs_settocharmatrix(pgs);
1226
253k
            fpx = fixed2float(cpt.x) + (pgs->ctm.tx - tx);
1227
253k
            fpy = fixed2float(cpt.y) + (pgs->ctm.ty - ty);
1228
253k
            if (!(f_fits_in_bits(fpx, fixed_int_bits)
1229
253k
                && f_fits_in_bits(fpy, fixed_int_bits))) {
1230
10
                gs_note_error(code = gs_error_limitcheck);
1231
10
                goto rret;
1232
10
            }
1233
253k
            cpt.x = float2fixed(fpx);
1234
253k
            cpt.y = float2fixed(fpy);
1235
253k
        }
1236
12.0M
        if (((code = gs_newpath(pgs)) < 0) ||
1237
12.0M
            ((code = show_origin_setup(pgs, cpt.x, cpt.y, penum)) < 0))
1238
0
            goto rret;
1239
12.0M
    }
1240
12.0M
    penum->width_status = sws_none;
1241
12.0M
    penum->continue_proc = continue_show_update;
1242
    /* Reset the sampling scale. */
1243
12.0M
    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
12.0M
    penum->cc = cc;             /* set this now for build procedure */
1247
12.0M
    code = (*pfont->procs.build_char)(penum, pgs, pfont,
1248
12.0M
                                      chr, glyph);
1249
12.0M
    if (code < 0) {
1250
15.7k
        discard(gs_note_error(code));
1251
15.7k
        goto rret;
1252
15.7k
    }
1253
12.0M
    if (code == 0) {
1254
10.5M
        code = show_update(penum);
1255
10.5M
        if (code < 0)
1256
12
            goto rret;
1257
        /* Note that show_update does a grestore.... */
1258
10.5M
        code = show_move(penum);
1259
10.5M
        if (code)
1260
3.60k
            return code;        /* ... so don't go to rret here. */
1261
10.5M
        goto more;
1262
10.5M
    }
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
1.48M
    if (penum->dev_cache == 0) {
1270
304k
        code = show_cache_setup(penum);
1271
304k
        if (code < 0)
1272
0
            goto rret;
1273
304k
    }
1274
1.48M
    return TEXT_PROCESS_RENDER;
1275
    /* If we get an error while setting up for BuildChar, */
1276
    /* we must undo the partial setup. */
1277
15.7k
rret:
1278
31.6k
    while (pgs->level > penum->level) {
1279
15.8k
        gs_grestore(pgs);
1280
15.8k
    }
1281
15.7k
    return code;
1282
1.48M
}
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
39.4M
{
1310
39.4M
    gs_gstate *pgs = penum->pgs;
1311
39.4M
    int code = 0, rcode;
1312
1313
39.4M
    if ((penum->text.operation & TEXT_DO_FALSE_CHARPATH) ||
1314
39.4M
        (penum->text.operation & TEXT_DO_TRUE_CHARPATH)) {
1315
414k
        if (pgs->path->current_subpath)
1316
406k
            pgs->path->last_charpath_segment = pgs->path->current_subpath->last;
1317
414k
    }
1318
39.4M
    if (penum->auto_release)
1319
0
        penum->procs->release((gs_text_enum_t *)penum, "show_finish");
1320
1321
39.4M
    if (!SHOW_IS_STRINGWIDTH(penum))
1322
39.2M
       return 0;
1323
1324
128k
    code = gs_currentpoint(pgs, &penum->returned.total_width);
1325
128k
    rcode = gs_grestore(pgs);
1326
1327
128k
    return (code < 0 ? code : rcode);
1328
39.4M
}
1329
1330
/* Release the structure. */
1331
static void
1332
gx_show_text_release(gs_text_enum_t *pte, client_name_t cname)
1333
39.4M
{
1334
39.4M
    gs_show_enum *const penum = (gs_show_enum *)pte;
1335
1336
39.4M
    penum->cc = 0;
1337
39.4M
    if (penum->dev_cache2) {
1338
3.60M
        gx_device_retain((gx_device *)penum->dev_cache2, false);
1339
3.60M
        penum->dev_cache2 = 0;
1340
3.60M
    }
1341
39.4M
    if (penum->dev_cache) {
1342
3.60M
        gx_device_retain((gx_device *)penum->dev_cache, false);
1343
3.60M
        penum->dev_cache = 0;
1344
3.60M
    }
1345
39.4M
    if (penum->dev_null) {
1346
129k
        gx_device_retain((gx_device *)penum->dev_null, false);
1347
129k
        penum->dev_null = 0;
1348
129k
    }
1349
39.4M
    gx_default_text_release(pte, cname);
1350
39.4M
}
1351
1352
/* ------ Miscellaneous accessors ------ */
1353
1354
/* Return the charpath mode. */
1355
gs_char_path_mode
1356
gs_show_in_charpath(const gs_show_enum * penum)
1357
0
{
1358
0
    return penum->charpath_flag;
1359
0
}
1360
1361
/* Return true if we only need the width from the rasterizer */
1362
/* and can short-circuit the full rendering of the character, */
1363
/* false if we need the actual character bits. */
1364
/* This is only meaningful just before calling gs_setcharwidth or */
1365
/* gs_setcachedevice[2]. */
1366
/* Note that we can't do this if the procedure has done any extra [g]saves. */
1367
static bool
1368
gx_show_text_is_width_only(const gs_text_enum_t *pte)
1369
12.2M
{
1370
12.2M
    const gs_show_enum *const penum = (const gs_show_enum *)pte;
1371
1372
    /* penum->cc will be non-zero iff we are calculating */
1373
    /* the scalable width for an xfont character. */
1374
12.2M
    return ((!SHOW_USES_OUTLINE(penum) || penum->cc != 0) &&
1375
686k
            penum->pgs->level == penum->level + 1);
1376
12.2M
}
1377
1378
/* Return the width of the just-enumerated character (for cshow). */
1379
static int
1380
gx_show_text_current_width(const gs_text_enum_t *pte, gs_point *pwidth)
1381
0
{
1382
0
    const gs_show_enum *const penum = (const gs_show_enum *)pte;
1383
1384
0
    return gs_idtransform(penum->pgs,
1385
0
                          fixed2float(penum->wxy.x),
1386
0
                          fixed2float(penum->wxy.y), pwidth);
1387
0
}
1388
1389
/* Return the current font for cshow. */
1390
gs_font *
1391
gs_show_current_font(const gs_show_enum * penum)
1392
40.8M
{
1393
40.8M
    return (penum->fstack.depth < 0 ? penum->pgs->font :
1394
40.8M
            penum->fstack.items[penum->fstack.depth].font);
1395
40.8M
}
1396
1397
/* ------ Internal routines ------ */
1398
1399
/* Initialize the gstate-derived parts of a show enumerator. */
1400
/* We do this both when starting the show operation, */
1401
/* and when returning from the kshow callout. */
1402
/* Uses only penum->pgs, penum->fstack. */
1403
static int
1404
show_state_setup(gs_show_enum * penum)
1405
40.8M
{
1406
40.8M
    gs_gstate *pgs = penum->pgs;
1407
40.8M
    gx_clip_path *pcpath;
1408
40.8M
    gs_font *pfont;
1409
1410
40.8M
    if (penum->fstack.depth <= 0) {
1411
39.4M
        pfont = pgs->font;
1412
39.4M
        if (pfont->FontType == ft_CID_encrypted) {
1413
            /* doing 'cid glyphshow',
1414
               assuming penum->operation has TEXT_FROM_SINGLE_GLYPH */
1415
0
            gs_matrix mat;
1416
0
            int fidx;
1417
0
            int code = ((gs_font_cid0 *)pfont)->cidata.glyph_data((gs_font_base *)pfont,
1418
0
                                penum->text.data.d_glyph, NULL, &fidx);
1419
0
            if (code < 0) { /* failed to load glyph data, reload glyph for CID 0 */
1420
0
               code = ((gs_font_cid0 *)pfont)->cidata.glyph_data((gs_font_base *)pfont,
1421
0
                            (gs_glyph)(GS_MIN_CID_GLYPH + 0), NULL, &fidx);
1422
0
               if (code < 0)
1423
0
                   return_error(gs_error_invalidfont);
1424
0
            }
1425
0
            gs_matrix_multiply(&(gs_cid0_indexed_font(pfont, fidx)->FontMatrix),
1426
0
                                &pfont->FontMatrix, &mat);
1427
0
            gs_setcharmatrix(pgs, &mat);
1428
39.4M
        } else {
1429
39.4M
            gs_currentcharmatrix(pgs, NULL, 1); /* make char_tm valid */
1430
39.4M
        }
1431
39.4M
    } else {
1432
        /* We have to concatenate the parent's FontMatrix as well. */
1433
1.33M
        gs_matrix mat;
1434
1.33M
        const gx_font_stack_item_t *pfsi =
1435
1.33M
            &penum->fstack.items[penum->fstack.depth];
1436
1437
1.33M
        pfont = pfsi->font;
1438
1.33M
        gs_matrix_multiply(&pfont->FontMatrix,
1439
1.33M
                           &pfsi[-1].font->FontMatrix, &mat);
1440
1.33M
        if (pfont->FontType == ft_CID_encrypted) {
1441
            /* concatenate the Type9 leaf's matrix */
1442
19.9k
            gs_matrix_multiply(&(gs_cid0_indexed_font(pfont, pfsi->index)->FontMatrix),
1443
19.9k
                                &mat, &mat);
1444
19.9k
        }
1445
1.33M
        gs_setcharmatrix(pgs, &mat);
1446
1.33M
    }
1447
40.8M
    penum->current_font = pfont;
1448
40.8M
    if (penum->can_cache >= 0 &&
1449
40.4M
        gx_effective_clip_path(pgs, &pcpath) >= 0
1450
40.8M
        ) {
1451
40.4M
        gs_fixed_rect cbox;
1452
1453
40.4M
        gx_cpath_inner_box(pcpath, &cbox);
1454
        /* Since characters occupy an integral number of pixels, */
1455
        /* we can (and should) round the inner clipping box */
1456
        /* outward rather than inward. */
1457
40.4M
        penum->ibox.p.x = fixed2int_var(cbox.p.x);
1458
40.4M
        penum->ibox.p.y = fixed2int_var(cbox.p.y);
1459
40.4M
        penum->ibox.q.x = fixed2int_var_ceiling(cbox.q.x);
1460
40.4M
        penum->ibox.q.y = fixed2int_var_ceiling(cbox.q.y);
1461
40.4M
        gx_cpath_outer_box(pcpath, &cbox);
1462
40.4M
        penum->obox.p.x = fixed2int_var(cbox.p.x);
1463
40.4M
        penum->obox.p.y = fixed2int_var(cbox.p.y);
1464
40.4M
        penum->obox.q.x = fixed2int_var_ceiling(cbox.q.x);
1465
40.4M
        penum->obox.q.y = fixed2int_var_ceiling(cbox.q.y);
1466
40.4M
        if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) {
1467
40.3M
            penum->ftx = (int)fixed2long(pgs->char_tm.tx_fixed -
1468
40.3M
                                         pgs->ctm.tx_fixed);
1469
40.3M
            penum->fty = (int)fixed2long(pgs->char_tm.ty_fixed -
1470
40.3M
                                         pgs->ctm.ty_fixed);
1471
40.3M
        } else {
1472
71.1k
            double fdx = pgs->char_tm.tx - pgs->ctm.tx;
1473
71.1k
            double fdy = pgs->char_tm.ty - pgs->ctm.ty;
1474
1475
71.1k
#define int_bits (ARCH_SIZEOF_INT * 8 - 1)
1476
71.1k
            if (!(f_fits_in_bits(fdx, int_bits) &&
1477
69.7k
                  f_fits_in_bits(fdy, int_bits))
1478
71.1k
                )
1479
3.29k
                return_error(gs_error_limitcheck);
1480
67.8k
#undef int_bits
1481
67.8k
            penum->ftx = (int)fdx;
1482
67.8k
            penum->fty = (int)fdy;
1483
67.8k
        }
1484
40.4M
    }
1485
40.8M
    show_set_encode_char(penum);
1486
40.8M
    return 0;
1487
40.8M
}
1488
1489
/* Set the suggested oversampling scale for character rendering. */
1490
static void
1491
show_set_scale(const gs_show_enum * penum, gs_log2_scale_point *log2_scale)
1492
0
{
1493
    /*
1494
     * Decide whether to oversample.
1495
     * We have to decide this each time setcachedevice is called.
1496
     */
1497
0
    const gs_gstate *pgs = NULL;
1498
1499
0
    if (gs_object_type(penum->pgs->memory, penum) == &st_gs_show_enum) {
1500
0
        pgs = penum->pgs;
1501
0
    } else {
1502
0
            pgs = (gs_gstate *)penum->pgs;
1503
0
    }
1504
1505
0
    if (pgs != NULL && (penum->charpath_flag == cpm_show ||
1506
0
         penum->charpath_flag == cpm_charwidth) &&
1507
0
        SHOW_USES_OUTLINE(penum)
1508
        /* && gx_path_is_void_inline(pgs->path) */
1509
0
        ) {
1510
0
        const gs_font_base *pfont = (const gs_font_base *)penum->current_font;
1511
0
        gs_fixed_point extent;
1512
0
        int code = gs_distance_transform2fixed(&pgs->char_tm,
1513
0
                                  pfont->FontBBox.q.x - pfont->FontBBox.p.x,
1514
0
                                  pfont->FontBBox.q.y - pfont->FontBBox.p.y,
1515
0
                                               &extent);
1516
1517
0
        if (code >= 0) {
1518
0
            int sx =
1519
0
            (any_abs(extent.x) < int2fixed(60) ? 2 :
1520
0
             any_abs(extent.x) < int2fixed(200) ? 1 :
1521
0
             0);
1522
0
            int sy =
1523
0
            (any_abs(extent.y) < int2fixed(60) ? 2 :
1524
0
             any_abs(extent.y) < int2fixed(200) ? 1 :
1525
0
             0);
1526
1527
            /* If we oversample at all, make sure we do it */
1528
            /* in both X and Y. */
1529
0
            if (sx == 0 && sy != 0)
1530
0
                sx = 1;
1531
0
            else if (sy == 0 && sx != 0)
1532
0
                sy = 1;
1533
0
            log2_scale->x = sx;
1534
0
            log2_scale->y = sy;
1535
0
            return;
1536
0
        }
1537
0
    }
1538
    /* By default, don't scale. */
1539
0
    log2_scale->x = log2_scale->y = 0;
1540
0
}
1541
1542
/* Set up the cache device and related information. */
1543
/* Note that we always allocate both cache devices, */
1544
/* even if we only use one of them. */
1545
static int
1546
show_cache_setup(gs_show_enum * penum)
1547
3.60M
{
1548
3.60M
    gs_gstate *pgs = penum->pgs;
1549
3.60M
    gs_memory_t *mem = penum->memory;
1550
3.60M
    gx_device_memory *dev =
1551
3.60M
        gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory,
1552
3.60M
                        "show_cache_setup(dev_cache)");
1553
3.60M
    gx_device_memory *dev2 =
1554
3.60M
        gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory,
1555
3.60M
                        "show_cache_setup(dev_cache2)");
1556
1557
3.60M
    if (dev == 0 || dev2 == 0) {
1558
        /*
1559
         * The structure is full of garbage so must not call the
1560
         * finalize method but still need to free the structure
1561
         */
1562
0
        gs_set_object_type(mem, dev2, &st_bytes);
1563
0
        gs_set_object_type(mem, dev, &st_bytes);
1564
0
        gs_free_object(mem, dev2, "show_cache_setup(dev_cache2)");
1565
0
        gs_free_object(mem, dev, "show_cache_setup(dev_cache)");
1566
0
        return_error(gs_error_VMerror);
1567
0
    }
1568
    /*
1569
     * We only initialize the devices for the sake of the GC,
1570
     * (since we have to re-initialize dev as either a mem_mono
1571
     * or a mem_abuf device before actually using it) and also
1572
     * to set its memory pointer.
1573
     */
1574
3.60M
    gs_make_mem_mono_device(dev, mem, gs_currentdevice_inline(pgs));
1575
3.60M
    penum->dev_cache = dev;
1576
3.60M
    gs_make_mem_mono_device(dev2, mem, gs_currentdevice_inline(pgs));
1577
3.60M
    penum->dev_cache2 = dev2;
1578
3.60M
    dev->HWResolution[0] = pgs->device->HWResolution[0];
1579
3.60M
    dev->HWResolution[1] = pgs->device->HWResolution[1];
1580
    /* Retain these devices, since they are referenced from the enumerator. */
1581
3.60M
    gx_device_retain((gx_device *)dev, true);
1582
3.60M
    gx_device_retain((gx_device *)dev2, true);
1583
3.60M
    return 0;
1584
3.60M
}
1585
1586
/* Set the character origin as the origin of the coordinate system. */
1587
/* Used before rendering characters, and for moving the origin */
1588
/* in setcachedevice2 when WMode=1. */
1589
static int
1590
show_origin_setup(gs_gstate * pgs, fixed cpt_x, fixed cpt_y, gs_show_enum * penum)
1591
12.0M
{
1592
12.0M
    if (penum->charpath_flag == cpm_show) {
1593
        /* Round the translation in the graphics state. */
1594
        /* This helps prevent rounding artifacts later. */
1595
11.0M
        if (gs_currentaligntopixels(penum->current_font->dir) == 0) {
1596
11.0M
            int scx = -(1L << (_fixed_shift - penum->log2_scale.x));
1597
11.0M
            int scy = -(1L << (_fixed_shift - penum->log2_scale.y));
1598
11.0M
            int rdx =  1L << (_fixed_shift - 1 - penum->log2_scale.x);
1599
11.0M
            int rdy =  1L << (_fixed_shift - 1 - penum->log2_scale.y);
1600
1601
11.0M
            cpt_x = (cpt_x + rdx) & scx;
1602
11.0M
            cpt_y = (cpt_y + rdy) & scy;
1603
11.0M
        } else {
1604
154
            cpt_x = fixed_rounded(cpt_x);
1605
154
            cpt_y = fixed_rounded(cpt_y);
1606
154
        }
1607
11.0M
    }
1608
    /*
1609
     * BuildChar procedures expect the current point to be undefined,
1610
     * so we omit the gx_path_add_point with ctm.t*_fixed.
1611
     */
1612
12.0M
    return gx_translate_to_fixed(pgs, cpt_x, cpt_y);
1613
12.0M
}