Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gxchar.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* 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
12.4M
  !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
288
ENUM_PTRS_BEGIN(show_enum_enum_ptrs)
48
198
     return ENUM_USING(st_gs_text_enum, vptr, size, index - 5);
49
18
ENUM_PTR(0, gs_show_enum, pgs);
50
18
ENUM_PTR(1, gs_show_enum, show_gstate);
51
288
ENUM_PTR3(2, gs_show_enum, dev_cache, dev_cache2, dev_null);
52
288
ENUM_PTRS_END
53
18
static RELOC_PTRS_WITH(show_enum_reloc_ptrs, gs_show_enum *eptr)
54
18
{
55
18
    RELOC_USING(st_gs_text_enum, vptr, size);           /* superclass */
56
18
    RELOC_VAR(eptr->pgs);
57
18
    RELOC_VAR(eptr->show_gstate);
58
18
    RELOC_PTR3(gs_show_enum, dev_cache, dev_cache2, dev_null);
59
18
}
60
18
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
1.28M
#define CURRENT_CHAR(penum) ((penum)->returned.current_char)
73
#define SET_CURRENT_CHAR(penum, chr)\
74
23.7M
  ((penum)->returned.current_char = (chr))
75
1.99M
#define CURRENT_GLYPH(penum) ((penum)->returned.current_glyph)
76
#define SET_CURRENT_GLYPH(penum, glyph)\
77
23.7M
  ((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
5.26M
{
83
5.26M
    gs_show_enum *penum;
84
85
5.26M
    rc_alloc_struct_1(penum, gs_show_enum, &st_gs_show_enum, mem,
86
5.26M
                      return 0, cname);
87
5.26M
    penum->rc.free = rc_free_text_enum;
88
5.26M
    penum->auto_release = true; /* old API */
89
    /* Initialize pointers for GC */
90
5.26M
    penum->text.operation = 0;  /* no pointers relevant */
91
5.26M
    penum->dev = 0;
92
5.26M
    penum->pgs = pgs;
93
5.26M
    penum->show_gstate = 0;
94
5.26M
    penum->dev_cache = 0;
95
5.26M
    penum->dev_cache2 = 0;
96
5.26M
    penum->fapi_log2_scale.x = penum->fapi_log2_scale.y = -1;
97
5.26M
    penum->fapi_glyph_shift.x = penum->fapi_glyph_shift.y = 0;
98
5.26M
    penum->dev_null = 0;
99
5.26M
    penum->fstack.depth = -1;
100
5.26M
    return penum;
101
5.26M
}
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
5.26M
{
126
5.26M
    uint operation = text->operation;
127
5.26M
    bool propagate_charpath = (operation & TEXT_DO_DRAW) != 0;
128
5.26M
    int code;
129
5.26M
    gs_gstate *pgs = (gs_gstate *)pgs1;
130
5.26M
    gs_show_enum *penum;
131
5.26M
    gs_memory_t * mem = pgs->memory;
132
133
5.26M
    penum = gs_show_enum_alloc(mem, pgs, "gx_default_text_begin");
134
5.26M
    if (!penum)
135
0
        return_error(gs_error_VMerror);
136
5.26M
    code = gs_text_enum_init((gs_text_enum_t *)penum, &default_text_procs,
137
5.26M
                             dev, pgs, text, font, pcpath, mem);
138
5.26M
    if (code < 0) {
139
0
        gs_free_object(mem, penum, "gx_default_text_begin");
140
0
        return code;
141
0
    }
142
5.26M
    penum->auto_release = false; /* new API */
143
5.26M
    penum->level = pgs->level;
144
5.26M
    penum->cc = 0;
145
5.26M
    penum->continue_proc = continue_show;
146
5.26M
    switch (penum->charpath_flag) {
147
5.04k
    case cpm_false_charpath: case cpm_true_charpath:
148
5.04k
        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
5.25M
    default:                    /* cpm_show */
153
5.25M
        penum->can_cache = 1; break;
154
5.26M
    }
155
5.26M
    code = show_state_setup(penum);
156
5.26M
    if (code < 0) {
157
181
        gs_text_release(pgs, (gs_text_enum_t *)penum, "gx_default_text_begin");
158
181
        penum = NULL;
159
181
        return code;
160
181
    }
161
5.26M
    penum->show_gstate =
162
5.26M
        (propagate_charpath && (pgs->in_charpath != 0) ?
163
5.26M
         pgs->show_gstate : pgs);
164
5.26M
    if (!(~operation & (TEXT_DO_NONE | TEXT_RETURN_WIDTH))) {
165
        /* This is stringwidth (or a PDF with text in rendering mode 3) . */
166
26.0k
        gx_device_null *dev_null =
167
26.0k
            gs_alloc_struct(mem, gx_device_null, &st_device_null,
168
26.0k
                            "stringwidth(dev_null)");
169
170
26.0k
        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
26.0k
        gs_make_null_device(dev_null, gs_currentdevice_inline(pgs), mem);
181
182
        /* Do an extra gsave and suppress output */
183
26.0k
        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
26.0k
        penum->level = pgs->level;      /* for level check in show_update */
190
26.0k
        pgs->ctm_default_set = false;
191
26.0k
        penum->dev_null = dev_null;
192
        /* Retain this device, since it is referenced from the enumerator. */
193
26.0k
        gx_device_retain((gx_device *)dev_null, true);
194
26.0k
        gs_setdevice_no_init(pgs, (gx_device *) dev_null);
195
        /* Establish an arbitrary translation and current point. */
196
26.0k
        gs_newpath(pgs);
197
26.0k
        gx_translate_to_fixed(pgs, fixed_0, fixed_0);
198
26.0k
        code = gx_path_add_point(pgs->path, fixed_0, fixed_0);
199
26.0k
        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
26.0k
    }
206
5.26M
    *ppte = (gs_text_enum_t *)penum;
207
5.26M
    return 0;
208
5.26M
}
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
1
{
248
1
    int code;
249
250
1
    code = gs_gsave(pgs);
251
1
    if (code < 0)
252
0
        return code;
253
1
    gs_newpath(pgs);
254
1
    *path = pgs->path;
255
1
    gx_translate_to_fixed(pgs, fixed_0, fixed_0);
256
1
    return gx_path_add_point(pgs->path, fixed_0, fixed_0);
257
1
}
258
259
int
260
gx_default_text_restore_state(gs_text_enum_t *pte)
261
4.46k
{
262
4.46k
    gs_show_enum *penum;
263
4.46k
    gs_gstate *pgs;
264
265
4.46k
    if (SHOW_IS(pte, TEXT_DO_NONE))
266
11
        return 0;
267
4.45k
    penum = (gs_show_enum *)pte;
268
4.45k
    pgs = penum->pgs;
269
4.45k
    return gs_grestore(pgs);
270
4.46k
}
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
3.91M
{
282
3.91M
    gs_show_enum *const penum = (gs_show_enum *)pte;
283
3.91M
    gs_gstate *pgs = penum->pgs;
284
3.91M
    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
3.91M
    if (pfont->FontMatrix.xx == 0 && pfont->FontMatrix.xy == 0 &&
290
3.91M
        pfont->FontMatrix.yx == 0 && pfont->FontMatrix.yy == 0)
291
0
        return_error(gs_error_undefinedresult); /* sic! : CPSI compatibility */
292
3.91M
    switch (control) {
293
188k
    case TEXT_SET_CHAR_WIDTH:
294
188k
        return set_char_width(penum, pgs, pw[0], pw[1]);
295
970k
    case TEXT_SET_CACHE_DEVICE: {
296
970k
        int code = set_char_width(penum, pgs, pw[0], pw[1]);    /* default is don't cache */
297
298
970k
        if (code < 0)
299
0
            return code;
300
970k
        if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) /* cshow */
301
0
            return code;
302
970k
        return set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
303
970k
    }
304
2.75M
    case TEXT_SET_CACHE_DEVICE2: {
305
2.75M
        int code;
306
2.75M
        bool retry = (penum->width_status == sws_retry);
307
308
2.75M
        if (pfont->WMode) {
309
302
            float vx = pw[8], vy = pw[9];
310
302
            gs_fixed_point pvxy, dvxy;
311
312
302
            gs_fixed_point rewind_pvxy;
313
302
            int rewind_code;
314
315
302
            if ((code = gs_point_transform2fixed(&pgs->ctm, -vx, -vy, &pvxy)) < 0 ||
316
302
                (code = gs_distance_transform2fixed(&pgs->ctm, vx, vy, &dvxy)) < 0
317
302
                )
318
0
                return 0;               /* don't cache */
319
302
            if ((code = set_char_width(penum, pgs, pw[6], pw[7])) < 0)
320
0
                return code;
321
302
            if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE))
322
0
                return code;
323
            /* Adjust the origin by (vx, vy). */
324
302
            gx_translate_to_fixed(pgs, pvxy.x, pvxy.y);
325
302
            code = set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
326
302
            if (code != 1) {
327
0
                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
0
                return code;
337
0
            }
338
            /* Adjust the character origin too. */
339
302
            (penum->cc)->offset.x += dvxy.x;
340
302
            (penum->cc)->offset.y += dvxy.y;
341
2.75M
        } else {
342
2.75M
            code = set_char_width(penum, pgs, pw[0], pw[1]);
343
2.75M
            if (code < 0)
344
0
                return code;
345
2.75M
            if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE))
346
0
                return code;
347
2.75M
            code = set_cache_device(penum, pgs, pw[2], pw[3], pw[4], pw[5]);
348
2.75M
        }
349
2.75M
        return code;
350
2.75M
    }
351
0
    default:
352
0
        return_error(gs_error_rangecheck);
353
3.91M
    }
354
3.91M
}
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
3.91M
{
362
3.91M
    int code;
363
364
3.91M
    if (penum->width_status != sws_none && penum->width_status != sws_retry)
365
0
        return_error(gs_error_undefined);
366
3.91M
    code = gs_distance_transform2fixed(&pgs->ctm, wx, wy, &penum->wxy);
367
3.91M
    if (code < 0 && penum->cc == 0) {
368
        /* Can't represent in 'fixed', use floats. */
369
11.8k
        code = gs_distance_transform(wx, wy, &ctm_only(pgs), &penum->wxy_float);
370
11.8k
        penum->wxy.x = penum->wxy.y = 0;
371
11.8k
        penum->use_wxy_float = true;
372
3.89M
    } else {
373
3.89M
        penum->use_wxy_float = false;
374
3.89M
        penum->wxy_float.x = penum->wxy_float.y = 0;
375
3.89M
    }
376
3.91M
    if (code < 0)
377
0
        return code;
378
    /* Check whether we're setting the scalable width */
379
    /* for a cached xfont character. */
380
3.91M
    if (penum->cc != 0) {
381
0
        penum->cc->wxy = penum->wxy;
382
0
        penum->width_status = sws_cache_width_only;
383
3.91M
    } else {
384
3.91M
        penum->width_status = sws_no_cache;
385
3.91M
    }
386
3.91M
    if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) /* cshow */
387
0
        gs_nulldevice(pgs);
388
3.91M
    return !SHOW_IS_DRAWING(penum);
389
3.91M
}
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
20.9M
{
395
20.9M
    gs_log2_scale_point log2_scale;
396
397
20.9M
    if (alpha_bits == 1)
398
20.9M
        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
20.9M
    *p_log2_scale = log2_scale;
426
20.9M
}
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
25.7M
{
434
25.7M
    gs_gstate *pgs = penum->pgs;
435
25.7M
    gx_device *dev = gs_currentdevice_inline(pgs);
436
25.7M
    int code;
437
438
25.7M
    *alpha_bits = (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
439
25.7M
    if (in_setcachedevice) {
440
        /* current point should already be in penum->origin */
441
23.7M
    } else {
442
23.7M
        code = gx_path_current_point_inline(pgs, &penum->origin);
443
23.7M
        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
23.7M
    }
450
25.7M
    if (penum->fapi_log2_scale.x != -1)
451
8.55M
        *log2_scale = penum->fapi_log2_scale;
452
17.2M
    else
453
17.2M
        gx_compute_text_oversampling(penum, penum->current_font, *alpha_bits, log2_scale);
454
    /*  We never oversample over the device alpha_bits,
455
     * so that we don't need to scale down. Perhaps it may happen
456
     * that we underuse alpha_bits due to a big character raster,
457
     * so we must compute log2_depth more accurately :
458
     */
459
25.7M
    *depth = (log2_scale->x + log2_scale->y == 0 ?
460
25.7M
        1 : min(log2_scale->x + log2_scale->y, *alpha_bits));
461
25.7M
    if (gs_currentaligntopixels(penum->current_font->dir) == 0) {
462
25.7M
        int scx = -1L << (_fixed_shift - log2_scale->x);
463
25.7M
        int rdx =  1L << (_fixed_shift - 1 - log2_scale->x);
464
465
25.7M
#       if 1 /* Ever align Y to pixels to provide an uniform glyph height. */
466
25.7M
            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
25.7M
        subpix_origin->x = ((penum->origin.x + rdx) & scx) & (fixed_1 - 1);
474
25.7M
    } else
475
0
        subpix_origin->x = subpix_origin->y = 0;
476
25.7M
    return 0;
477
25.7M
}
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
3.72M
{
486
3.72M
    gs_glyph glyph;
487
3.72M
    int code = 0;
488
489
    /* See if we want to cache this character. */
490
3.72M
    if (pgs->in_cachedevice)    /* no recursion! */
491
1.72M
        return 0;
492
1.99M
    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
1.99M
    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
1.99M
    glyph = CURRENT_GLYPH(penum);
502
1.99M
    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
1.99M
    if (penum->can_cache <= 0 || !pgs->char_tm_valid) {
507
0
        if_debug2m('k', penum->memory, "[k]no cache: can_cache=%d, char_tm_valid=%d\n",
508
0
                   penum->can_cache, (int)pgs->char_tm_valid);
509
0
        return 0;
510
1.99M
    } {
511
1.99M
        const gs_font *pfont = pgs->font;
512
1.99M
        gs_font_dir *dir = pfont->dir;
513
1.99M
        int alpha_bits, depth;
514
1.99M
        gs_log2_scale_point log2_scale;
515
1.99M
        gs_fixed_point subpix_origin;
516
1.99M
        static const fixed max_cdim[3] =
517
1.99M
        {
518
1.99M
#define max_cd(n)\
519
5.99M
            (fixed_1 << (ARCH_SIZEOF_SHORT * 8 - n)) - (fixed_1 >> n) * 3
520
1.99M
            max_cd(0), max_cd(1), max_cd(2)
521
1.99M
#undef max_cd
522
1.99M
        };
523
1.99M
        ushort iwidth, iheight;
524
1.99M
        cached_char *cc;
525
1.99M
        gs_fixed_rect clip_box;
526
1.99M
        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
1.99M
        if (fabs(llx) > 32000. || fabs(lly) > 32000. || fabs(urx) > 32000. || fabs(ury) >= 32000.)
532
238
            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
1.99M
        if ((code = gs_distance_transform2fixed(&pgs->ctm, llx, lly, &cll)) < 0 ||
541
1.99M
            (code = gs_distance_transform2fixed(&pgs->ctm, llx, ury, &clr)) < 0 ||
542
1.99M
            (code = gs_distance_transform2fixed(&pgs->ctm, urx, lly, &cul)) < 0 ||
543
1.99M
         (code = gs_distance_transform2fixed(&pgs->ctm, urx, ury, &cur)) < 0
544
1.99M
            )
545
4.08k
            return 0;           /* don't cache */
546
1.99M
        {
547
1.99M
            fixed ctemp;
548
549
2.31M
#define swap(a, b) ctemp = a, a = b, b = ctemp
550
7.97M
#define make_min(a, b) if ( (a) > (b) ) swap(a, b)
551
552
1.99M
            make_min(cll.x, cur.x);
553
1.99M
            make_min(cll.y, cur.y);
554
1.99M
            make_min(clr.x, cul.x);
555
1.99M
            make_min(clr.y, cul.y);
556
1.99M
#undef make_min
557
1.99M
#undef swap
558
1.99M
        }
559
        /* Now take advantage of symmetry. */
560
1.99M
        if (clr.x < cll.x)
561
24.3k
            cll.x = clr.x, cur.x = cul.x;
562
1.99M
        if (clr.y < cll.y)
563
9.71k
            cll.y = clr.y, cur.y = cul.y;
564
        /* Now cll and cur are the extrema of the box. */
565
1.99M
        code = compute_glyph_raster_params(penum, true, &alpha_bits, &depth,
566
1.99M
           &subpix_origin, &log2_scale);
567
1.99M
        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
1.99M
        cdim.x = cur.x - cll.x;
581
1.99M
        cdim.y = cur.y - cll.y;
582
1.99M
        if (cdim.x > max_cdim[log2_scale.x] ||
583
1.99M
            cdim.y > max_cdim[log2_scale.y]
584
1.99M
            )
585
12.7k
            return 0;           /* much too big */
586
1.98M
        iwidth = ((ushort) fixed2int_var(cdim.x) + 3) << log2_scale.x;
587
1.98M
        iheight = ((ushort) fixed2int_var(cdim.y) + 3) << log2_scale.y;
588
1.98M
        if_debug3m('k', penum->memory, "[k]iwidth=%u iheight=%u dev_cache %s\n",
589
1.98M
                   (uint) iwidth, (uint) iheight,
590
1.98M
                   (penum->dev_cache == 0 ? "not set" : "set"));
591
1.98M
        if (penum->dev_cache == 0) {
592
790k
            code = show_cache_setup(penum);
593
790k
            if (code < 0)
594
0
                return code;
595
790k
        }
596
1.98M
        code = gx_alloc_char_bits(dir, penum->dev_cache,
597
1.98M
                                  iwidth, iheight, &log2_scale, depth, &cc);
598
1.98M
        if (code < 0)
599
644
            return code;
600
601
1.98M
        if (cc == 0) {
602
            /* too big for cache or no cache */
603
59.7k
            gx_path box_path;
604
605
59.7k
            if (penum->current_font->FontType != ft_user_defined &&
606
59.7k
                penum->current_font->FontType != ft_PDF_user_defined &&
607
59.7k
                penum->current_font->FontType != ft_PCL_user_defined &&
608
59.7k
                penum->current_font->FontType != ft_GL2_stick_user_defined &&
609
59.7k
                penum->current_font->FontType != ft_CID_user_defined) {
610
                /* Most fonts don't paint outside bbox,
611
                   so render with no clipping. */
612
59.5k
                return 0;
613
59.5k
            }
614
            /* Render with a clip. */
615
            /* show_proceed already did gsave. */
616
129
            pgs->in_cachedevice = CACHE_DEVICE_NONE; /* Provide a correct grestore on error. */
617
129
            clip_box.p.x = penum->origin.x - fixed_ceiling(-cll.x);
618
129
            clip_box.p.y = penum->origin.y - fixed_ceiling(-cll.y);
619
129
            clip_box.q.x = clip_box.p.x + int2fixed(iwidth);
620
129
            clip_box.q.y = clip_box.p.y + int2fixed(iheight);
621
129
            gx_path_init_local(&box_path, pgs->memory);
622
129
            code = gx_path_add_rectangle(&box_path, clip_box.p.x, clip_box.p.y,
623
129
                                                    clip_box.q.x, clip_box.q.y);
624
129
            if (code < 0)
625
0
                return code;
626
129
            code = gx_cpath_clip(pgs, pgs->clip_path, &box_path, gx_rule_winding_number);
627
129
            if (code < 0)
628
0
                return code;
629
129
            gx_path_free(&box_path, "set_cache_device");
630
129
            pgs->in_cachedevice = CACHE_DEVICE_NONE_AND_CLIP;
631
129
            return 0;
632
129
        }
633
        /* The mins handle transposed coordinate systems.... */
634
        /* Truncate the offsets to avoid artifacts later. */
635
1.92M
        cc->offset.x = fixed_ceiling(-cll.x) + fixed_1;
636
1.92M
        cc->offset.y = fixed_ceiling(-cll.y) + fixed_1;
637
1.92M
        if_debug4m('k', penum->memory, "[k]width=%u, height=%u, offset=[%g %g]\n",
638
1.92M
                   (uint) iwidth, (uint) iheight,
639
1.92M
                   fixed2float(cc->offset.x),
640
1.92M
                   fixed2float(cc->offset.y));
641
1.92M
        pgs->in_cachedevice = CACHE_DEVICE_NONE; /* Provide correct grestore */
642
1.92M
        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
1.92M
        penum->cc = cc;
648
1.92M
        cc->code = glyph;
649
1.92M
        cc->wmode = gs_rootfont(pgs)->WMode;
650
1.92M
        cc->wxy = penum->wxy;
651
1.92M
        cc->subpix_origin = subpix_origin;
652
1.92M
        if (penum->pair != 0)
653
1.92M
            cc_set_pair(cc, penum->pair);
654
0
        else
655
0
            cc->pair = 0;
656
        /* Install the device */
657
1.92M
        gx_set_device_only(pgs, (gx_device *) penum->dev_cache);
658
1.92M
        pgs->ctm_default_set = false;
659
        /* Adjust the transformation in the graphics context */
660
        /* so that the character lines up with the cache. */
661
1.92M
        gx_translate_to_fixed(pgs,
662
1.92M
                              (cc->offset.x + subpix_origin.x) << log2_scale.x,
663
1.92M
                              (cc->offset.y + subpix_origin.y) << log2_scale.y);
664
1.92M
        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
1.92M
        penum->dev_cache->initial_matrix = ctm_only(pgs);
669
        /* Set the oversampling factor. */
670
1.92M
        penum->log2_scale.x = log2_scale.x;
671
1.92M
        penum->log2_scale.y = log2_scale.y;
672
        /* Reset the clipping path to match the metrics. */
673
1.92M
        clip_box.p.x = clip_box.p.y = 0;
674
1.92M
        clip_box.q.x = int2fixed(iwidth);
675
1.92M
        clip_box.q.y = int2fixed(iheight);
676
1.92M
        if ((code = gx_clip_to_rectangle(pgs, &clip_box)) < 0)
677
0
            goto fail;
678
1.92M
        code = gx_set_device_color_1(pgs);     /* write 1's */
679
1.92M
        if (code < 0)
680
0
            goto fail;
681
1.92M
        gs_swapcolors_quick(pgs);
682
1.92M
        code = gx_set_device_color_1(pgs);     /* write 1's */
683
1.92M
        if (code < 0)
684
0
            goto fail;
685
1.92M
        gs_swapcolors_quick(pgs);
686
1.92M
        pgs->in_cachedevice = CACHE_DEVICE_CACHING;
687
1.92M
    }
688
0
    penum->width_status = sws_cache;
689
1.92M
    return 1;
690
691
0
fail:
692
0
    gs_grestore(pgs);
693
0
    return code;
694
1.92M
}
695
696
/* Return the cache device status. */
697
gs_in_cache_device_t
698
gs_incachedevice(const gs_gstate *pgs)
699
1.43k
{
700
1.43k
    return pgs->in_cachedevice;
701
1.43k
}
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
5.65M
{
711
5.65M
    penum->encode_char =
712
5.65M
        (SHOW_IS(penum, TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH) ?
713
0
         gs_no_encode_char :
714
5.65M
         gs_show_current_font(penum)->procs.encode_char);
715
5.65M
}
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
6.41M
{
741
6.41M
    gs_show_enum *const penum = (gs_show_enum *)pte;
742
743
6.41M
    return (*penum->continue_proc)(penum);
744
6.41M
}
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.15M
{
754
1.15M
    int code = show_update(penum);
755
756
1.15M
    if (code < 0)
757
0
        return code;
758
1.15M
    code = show_move(penum);
759
1.15M
    if (code != 0)
760
0
        return code;
761
1.15M
    return show_proceed(penum);
762
1.15M
}
763
static int
764
continue_show(gs_show_enum * penum)
765
5.26M
{
766
5.26M
    return show_proceed(penum);
767
5.26M
}
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
3.91M
{
789
3.91M
    gs_gstate *pgs = penum->pgs;
790
3.91M
    cached_char *cc = penum->cc;
791
3.91M
    int code;
792
793
    /* Update position for last character */
794
3.91M
    switch (penum->width_status) {
795
2.64k
        case sws_none:
796
2.64k
        case sws_retry:
797
            /* Adobe interpreters assume a character width of 0, */
798
            /* even though the documentation says this is an error.... */
799
2.64k
            penum->wxy.x = penum->wxy.y = 0;
800
2.64k
            penum->wxy_float.x = penum->wxy_float.y = 0;
801
2.64k
            penum->use_wxy_float = false;
802
2.64k
            break;
803
1.92M
        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
1.92M
            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
1.92M
                case 2:
813
1.92M
                    code = gs_grestore(pgs);
814
1.92M
                    if (code < 0)
815
0
                        return code;
816
1.92M
                case 1:
817
1.92M
                    ;
818
1.92M
            }
819
1.92M
            {   cached_fm_pair *pair;
820
821
1.92M
                code = gx_lookup_fm_pair(pgs->font, &char_tm_only(pgs),
822
1.92M
                            &penum->log2_scale, penum->charpath_flag != cpm_show, &pair);
823
1.92M
                if (code < 0)
824
0
                    return code;
825
1.92M
                code = gx_add_cached_char(pgs->font->dir, penum->dev_cache,
826
1.92M
                               cc, pair, &penum->log2_scale);
827
1.92M
                if (code < 0)
828
0
                    return code;
829
1.92M
            }
830
1.92M
            if (!SHOW_USES_OUTLINE(penum) ||
831
1.92M
                penum->charpath_flag != cpm_show
832
1.92M
                )
833
4.90k
                break;
834
            /* falls through */
835
1.91M
        case sws_cache_width_only:
836
            /* Copy the bits to the real output device. */
837
1.91M
            code = gs_grestore(pgs);
838
1.91M
            if (code < 0)
839
0
                return code;
840
1.91M
            code = gs_gstate_color_load(pgs);
841
1.91M
            if (code < 0)
842
0
                return code;
843
1.91M
            return gx_image_cached_char(penum, cc);
844
1.98M
        case sws_no_cache:
845
1.98M
            ;
846
3.91M
    }
847
1.99M
    if (penum->charpath_flag != cpm_show) {
848
        /* Move back to the character origin, so that */
849
        /* show_move will get us to the right place. */
850
751k
        code = gx_path_add_point(pgs->show_gstate->path,
851
751k
                                 penum->origin.x, penum->origin.y);
852
751k
        if (code < 0)
853
0
            return code;
854
751k
    }
855
1.99M
    return gs_grestore(pgs);
856
1.99M
}
857
858
/* Move to next character */
859
static inline int
860
show_fast_move(gs_gstate * pgs, gs_fixed_point * pwxy)
861
23.7M
{
862
23.7M
    return gs_moveto_aux(pgs, pgs->path,
863
23.7M
                              pgs->current_point.x + fixed2float(pwxy->x),
864
23.7M
                              pgs->current_point.y + fixed2float(pwxy->y));
865
23.7M
}
866
867
/* Get the current character code. */
868
int gx_current_char(const gs_text_enum_t * pte)
869
1.23M
{
870
1.23M
    const gs_show_enum *penum = (const gs_show_enum *)pte;
871
1.23M
    gs_char chr = CURRENT_CHAR(penum) & 0xff;
872
1.23M
    int fdepth = penum->fstack.depth;
873
874
1.23M
    if (fdepth > 0) {
875
        /* Add in the shifted font number. */
876
47.2k
        uint fidx = penum->fstack.items[fdepth - 1].index;
877
878
47.2k
        switch (((gs_font_type0 *) (penum->fstack.items[fdepth - 1].font))->data.FMapType) {
879
0
        case fmap_1_7:
880
0
        case fmap_9_7:
881
0
            chr += fidx << 7;
882
0
            break;
883
47.2k
        case fmap_CMap:
884
47.2k
            chr = CURRENT_CHAR(penum);  /* the full character */
885
47.2k
            if (!penum->cmap_code)
886
47.2k
                break;
887
            /* falls through */
888
0
        default:
889
0
            chr += fidx << 8;
890
47.2k
        }
891
47.2k
    }
892
1.23M
    return chr;
893
1.23M
}
894
895
static int
896
show_move(gs_show_enum * penum)
897
16.9M
{
898
16.9M
    gs_gstate *pgs = penum->pgs;
899
16.9M
    int code;
900
16.9M
    double dx = 0, dy = 0;
901
902
    /* Specifically for applying PDF word spacing, if single_byte_space == true
903
       we'll only apply the delta for single byte character codes == space.s_char
904
       See psi/zchar.c zpdfwidthshow and zpdfawidthshow for more detail
905
     */
906
16.9M
    if (SHOW_IS_ADD_TO_SPACE(penum)
907
16.9M
        && (!penum->single_byte_space
908
1.30M
        || penum->bytes_decoded == 1)) {
909
1.23M
        gs_char chr = gx_current_char((const gs_text_enum_t *)penum);
910
911
1.23M
        if (chr == penum->text.space.s_char) {
912
102k
            dx = penum->text.delta_space.x;
913
102k
            dy = penum->text.delta_space.y;
914
102k
        }
915
1.23M
    }
916
917
16.9M
    if (SHOW_IS(penum, TEXT_REPLACE_WIDTHS)) {
918
13.3M
        gs_point dpt;
919
920
13.3M
        code = gs_text_replaced_width(&penum->text, penum->xy_index - 1, &dpt);
921
13.3M
        if (code < 0)
922
0
            return code;
923
13.3M
        dpt.x += dx;
924
13.3M
        dpt.y += dy;
925
13.3M
        code = gs_distance_transform2fixed(&pgs->ctm, dpt.x, dpt.y, &penum->wxy);
926
13.3M
        if (code < 0)
927
149
            return code;
928
13.3M
    } else {
929
3.67M
        if (SHOW_IS_ADD_TO_ALL(penum)) {
930
1.30M
            dx += penum->text.delta_all.x;
931
1.30M
            dy += penum->text.delta_all.y;
932
1.30M
        }
933
3.67M
        if (!is_fzero2(dx, dy)) {
934
1.31M
            gs_fixed_point dxy;
935
936
1.31M
            code = gs_distance_transform2fixed(&pgs->ctm, dx, dy, &dxy);
937
1.31M
            if (code < 0)
938
752
                return code;
939
1.30M
            penum->wxy.x += dxy.x;
940
1.30M
            penum->wxy.y += dxy.y;
941
1.30M
        }
942
3.67M
    }
943
16.9M
    if (SHOW_IS_ALL_OF(penum, TEXT_DO_NONE | TEXT_INTERVENE)) {
944
        /* HACK for cshow */
945
0
        penum->continue_proc = continue_kshow;
946
0
        return TEXT_PROCESS_INTERVENE;
947
0
    }
948
    /* wxy is in device coordinates */
949
16.9M
    {
950
16.9M
        int code;
951
952
16.9M
        if (penum->use_wxy_float)
953
11.1k
            code = gs_moveto_aux(pgs, pgs->path,
954
11.1k
                    pgs->current_point.x + penum->wxy_float.x + fixed2float(penum->wxy.x),
955
11.1k
                    pgs->current_point.y + penum->wxy_float.y + fixed2float(penum->wxy.y));
956
16.9M
        else
957
16.9M
            code = show_fast_move(pgs, &penum->wxy);
958
16.9M
        if (code < 0)
959
0
            return code;
960
16.9M
    }
961
    /* Check for kerning, but not on the last character. */
962
16.9M
    if (SHOW_IS_DO_KERN(penum) && penum->index < penum->text.size) {
963
0
        penum->continue_proc = continue_kshow;
964
0
        return TEXT_PROCESS_INTERVENE;
965
0
    }
966
16.9M
    return 0;
967
16.9M
}
968
969
static inline int
970
get_next_char_glyph(gs_show_enum * penum, gs_char *chr, gs_glyph *glyph)
971
29.0M
{
972
29.0M
    gs_font *rfont =
973
29.0M
        (penum->fstack.depth < 0 ? penum->pgs->font : penum->fstack.items[0].font);
974
29.0M
    penum->xy_index++;
975
976
29.0M
    return rfont->procs.next_char_glyph((gs_text_enum_t *)penum, chr, glyph);
977
29.0M
}
978
979
980
/* Process next character */
981
static int
982
show_proceed(gs_show_enum * penum)
983
6.41M
{
984
6.41M
    gs_gstate *pgs = penum->pgs;
985
6.41M
    gs_font *pfont;
986
6.41M
    cached_fm_pair *pair = 0;
987
6.41M
    gs_font *rfont =
988
6.41M
        (penum->fstack.depth < 0 ? pgs->font : penum->fstack.items[0].font);
989
6.41M
    int wmode = rfont->WMode;
990
6.41M
    gs_char chr;
991
6.41M
    gs_glyph glyph;
992
6.41M
    int code, start;
993
6.41M
    cached_char *cc;
994
6.41M
    gs_log2_scale_point log2_scale;
995
996
6.41M
    if (penum->charpath_flag == cpm_show && SHOW_USES_OUTLINE(penum)) {
997
5.52M
        code = gs_gstate_color_load(pgs);
998
5.52M
        if (code < 0)
999
0
            return code;
1000
5.52M
    }
1001
9.17M
  more:                 /* Proceed to next character */
1002
9.17M
    pfont = (penum->fstack.depth < 0 ? pgs->font :
1003
9.17M
             penum->fstack.items[penum->fstack.depth].font);
1004
9.17M
    penum->current_font = pfont;
1005
    /* can_cache >= 0 allows us to use cached characters, */
1006
    /* even if we can't make new cache entries. */
1007
9.17M
    if (penum->can_cache >= 0) {
1008
        /* Loop with cache */
1009
28.2M
        for (;;) {
1010
28.2M
            start = penum->index;
1011
28.2M
            switch ((code = get_next_char_glyph(penum, &chr, &glyph))) {
1012
18
                default:        /* error */
1013
18
                    return code;
1014
5.24M
                case 2: /* done */
1015
5.24M
                    return show_finish(penum);
1016
396k
                case 1: /* font change */
1017
396k
                    pfont = penum->fstack.items[penum->fstack.depth].font;
1018
396k
                    penum->current_font = pfont;
1019
396k
                    pgs->char_tm_valid = false;
1020
396k
                    show_state_setup(penum);
1021
396k
                    pair = 0;
1022
396k
                    penum->pair = 0;
1023
                    /* falls through */
1024
23.0M
                case 0: /* plain char */
1025
                    /*
1026
                     * We don't need to set penum->current_char in the
1027
                     * normal cases, but it's needed for widthshow,
1028
                     * kshow, and one strange client, so we may as well
1029
                     * do it here.
1030
                     */
1031
23.0M
                    SET_CURRENT_CHAR(penum, chr);
1032
                    /*
1033
                     * Store glyph now, because pdfwrite needs it while
1034
                     * synthezising bitmap fonts (see assign_char_code).
1035
                     */
1036
23.0M
                    if (glyph == GS_NO_GLYPH) {
1037
21.8M
                        glyph = (*penum->encode_char)(pfont, chr,
1038
21.8M
                                                      GLYPH_SPACE_NAME);
1039
21.8M
                        SET_CURRENT_GLYPH(penum, glyph);
1040
21.8M
                    } else
1041
1.19M
                        SET_CURRENT_GLYPH(penum, glyph);
1042
23.0M
                    penum->bytes_decoded = penum->index - start;
1043
23.0M
                    penum->is_pure_color = gs_color_writes_pure(penum->pgs); /* Save
1044
                                 this data for compute_glyph_raster_params to work
1045
                                 independently on the color change in BuildChar.
1046
                                 Doing it here because cshow proc may modify
1047
                                 the graphic state.
1048
                                 */
1049
23.0M
                    {
1050
23.0M
                        int alpha_bits, depth;
1051
23.0M
                        gs_fixed_point subpix_origin;
1052
1053
23.0M
                        code = compute_glyph_raster_params(penum, false,
1054
23.0M
                                    &alpha_bits, &depth, &subpix_origin, &log2_scale);
1055
23.0M
                        if (code < 0)
1056
0
                            return code;
1057
23.0M
                        if (pair == 0) {
1058
5.65M
                            code = gx_lookup_fm_pair(pfont, &char_tm_only(pgs), &log2_scale,
1059
5.65M
                                penum->charpath_flag != cpm_show, &pair);
1060
5.65M
                            if (code < 0)
1061
0
                                return code;
1062
5.65M
                        }
1063
23.0M
                        penum->pair = pair;
1064
23.0M
                        if (glyph == GS_NO_GLYPH || SHOW_IS_ALL_OF(penum, TEXT_NO_CACHE)) {
1065
92
                            cc = 0;
1066
92
                            goto no_cache;
1067
92
                        }
1068
23.0M
                        cc = gx_lookup_cached_char(pfont, pair, glyph, wmode,
1069
23.0M
                                                   depth, &subpix_origin);
1070
23.0M
                    }
1071
23.0M
                    if (cc == 0) {
1072
3.16M
                        goto no_cache;
1073
3.16M
                    }
1074
                    /* Character is in cache. */
1075
                    /* We might be doing .charboxpath or stringwidth; */
1076
                    /* check for these now. */
1077
19.8M
                    if (penum->charpath_flag == cpm_charwidth) {
1078
                        /* This is charwidth.  Just move by the width. */
1079
0
                        DO_NOTHING;
1080
19.8M
                    } else if (penum->charpath_flag != cpm_show) {
1081
                        /* This is .charboxpath. Get the bounding box */
1082
                        /* and append it to a path. */
1083
0
                        gx_path box_path;
1084
0
                        gs_fixed_point pt;
1085
0
                        fixed llx, lly, urx, ury;
1086
1087
0
                        code = gx_path_current_point(pgs->path, &pt);
1088
0
                        if (code < 0)
1089
0
                            return code;
1090
0
                        llx = fixed_rounded(pt.x - cc->offset.x) +
1091
0
                            int2fixed(penum->ftx);
1092
0
                        lly = fixed_rounded(pt.y - cc->offset.y) +
1093
0
                            int2fixed(penum->fty);
1094
0
                        urx = llx + int2fixed(cc->width),
1095
0
                            ury = lly + int2fixed(cc->height);
1096
0
                        gx_path_init_local(&box_path, pgs->memory);
1097
0
                        code =
1098
0
                            gx_path_add_rectangle(&box_path, llx, lly,
1099
0
                                                  urx, ury);
1100
0
                        if (code >= 0)
1101
0
                            code =
1102
0
                                gx_path_add_char_path(pgs->show_gstate->path,
1103
0
                                                      &box_path,
1104
0
                                                      penum->charpath_flag);
1105
0
                        if (code >= 0)
1106
0
                            code = gx_path_add_point(pgs->path, pt.x, pt.y);
1107
0
                        gx_path_free(&box_path, "show_proceed(box path)");
1108
0
                        if (code < 0)
1109
0
                            return code;
1110
19.8M
                    } else if (SHOW_IS_DRAWING(penum)) {
1111
19.8M
                        code = gx_image_cached_char(penum, cc);
1112
19.8M
                        if (code < 0)
1113
2
                            return code;
1114
19.8M
                        else if (code > 0) {
1115
0
                            cc = 0;
1116
0
                            goto no_cache;
1117
0
                        }
1118
19.8M
                    }
1119
19.8M
                    penum->use_wxy_float = false;
1120
19.8M
                    penum->wxy_float.x = penum->wxy_float.y = 0;
1121
19.8M
                    if (SHOW_IS_SLOW(penum)) {
1122
                        /* Split up the assignment so that the */
1123
                        /* Watcom compiler won't reserve esi/edi. */
1124
13.0M
                        penum->wxy.x = cc->wxy.x;
1125
13.0M
                        penum->wxy.y = cc->wxy.y;
1126
13.0M
                        code = show_move(penum);
1127
13.0M
                    } else
1128
6.78M
                        code = show_fast_move(pgs, &cc->wxy);
1129
19.8M
                    if (code) {
1130
                        /* Might be kshow, glyph is stored above. */
1131
10
                        return code;
1132
10
                    }
1133
28.2M
            }
1134
28.2M
        }
1135
8.41M
    } else {
1136
756k
        start = penum->index;
1137
        /* Can't use cache */
1138
756k
        switch ((code = get_next_char_glyph(penum, &chr, &glyph))) {
1139
0
            default:
1140
0
                return code;
1141
5.03k
            case 2:
1142
5.03k
                return show_finish(penum);
1143
627
            case 1:
1144
627
                pfont = penum->fstack.items[penum->fstack.depth].font;
1145
627
                penum->current_font = pfont;
1146
627
                show_state_setup(penum);
1147
627
                pair = 0;
1148
751k
            case 0:
1149
751k
                {   int alpha_bits, depth;
1150
751k
                    gs_log2_scale_point log2_scale;
1151
751k
                    gs_fixed_point subpix_origin;
1152
1153
751k
                    penum->bytes_decoded = penum->index - start;
1154
751k
                    code = compute_glyph_raster_params(penum, false, &alpha_bits, &depth, &subpix_origin, &log2_scale);
1155
751k
                    if (code < 0)
1156
0
                        return code;
1157
751k
                    if (pair == 0) {
1158
743k
                        code = gx_lookup_fm_pair(pfont, &char_tm_only(pgs), &log2_scale,
1159
743k
                                penum->charpath_flag != cpm_show, &pair);
1160
743k
                        if (code < 0)
1161
0
                            return code;
1162
743k
                    }
1163
751k
                    penum->pair = pair;
1164
751k
                }
1165
756k
        }
1166
751k
        SET_CURRENT_CHAR(penum, chr);
1167
751k
        if (glyph == GS_NO_GLYPH) {
1168
748k
            glyph = (*penum->encode_char)(pfont, chr, GLYPH_SPACE_NAME);
1169
748k
        }
1170
751k
        SET_CURRENT_GLYPH(penum, glyph);
1171
751k
        cc = 0;
1172
751k
    }
1173
3.92M
  no_cache:
1174
    /*
1175
     * We must call the client's rendering code.  Normally,
1176
     * we only do this if the character is not cached (cc = 0);
1177
     * however, we also must do this if we have an xfont but
1178
     * are using scalable widths.  In this case, and only this case,
1179
     * we get here with cc != 0.  penum->current_char and penum->current_glyph
1180
     * has already been set.
1181
     */
1182
3.92M
    if ((code = gs_gsave(pgs)) < 0)
1183
0
        return code;
1184
    /* Set the font to the current descendant font. */
1185
3.92M
    pgs->font = pfont;
1186
    /* Reset the in_cachedevice flag, so that a recursive show */
1187
    /* will use the cache properly. */
1188
3.92M
    pgs->in_cachedevice = CACHE_DEVICE_NONE;
1189
    /* Set the charpath data in the graphics context if necessary, */
1190
    /* so that fill and stroke will add to the path */
1191
    /* rather than having their usual effect. */
1192
3.92M
    pgs->in_charpath = penum->charpath_flag;
1193
3.92M
    pgs->show_gstate =
1194
3.92M
        (penum->show_gstate == pgs ? pgs->saved : penum->show_gstate);
1195
3.92M
    pgs->stroke_adjust = false; /* per specification */
1196
3.92M
    {
1197
3.92M
        gs_fixed_point cpt;
1198
1199
3.92M
        if ((code = gx_path_current_point_inline(pgs, &cpt)) < 0) {
1200
            /* For cshow, having no current point is acceptable. */
1201
0
            if (!SHOW_IS(penum, TEXT_DO_NONE))
1202
0
                goto rret;
1203
0
            cpt.x = cpt.y = 0;  /* arbitrary */
1204
0
        }
1205
3.92M
        penum->origin.x = cpt.x;
1206
3.92M
        penum->origin.y = cpt.y;
1207
        /* Normally, char_tm is valid because of show_state_setup, */
1208
        /* but if we're in a cshow, it may not be. */
1209
3.92M
        gs_currentcharmatrix(pgs, NULL, true);
1210
3.92M
        if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) {
1211
3.86M
            fixed tx = pgs->ctm.tx_fixed;
1212
3.86M
            fixed ty = pgs->ctm.ty_fixed;
1213
1214
3.86M
            gs_settocharmatrix(pgs);
1215
3.86M
            cpt.x += pgs->ctm.tx_fixed - tx;
1216
3.86M
            cpt.y += pgs->ctm.ty_fixed - ty;
1217
3.86M
        } else  {
1218
54.9k
            double tx = pgs->ctm.tx;
1219
54.9k
            double ty = pgs->ctm.ty;
1220
54.9k
            double fpx, fpy;
1221
1222
54.9k
            gs_settocharmatrix(pgs);
1223
54.9k
            fpx = fixed2float(cpt.x) + (pgs->ctm.tx - tx);
1224
54.9k
            fpy = fixed2float(cpt.y) + (pgs->ctm.ty - ty);
1225
54.9k
            if (!(f_fits_in_bits(fpx, fixed_int_bits)
1226
54.9k
                && f_fits_in_bits(fpy, fixed_int_bits))) {
1227
1
                gs_note_error(code = gs_error_limitcheck);
1228
1
                goto rret;
1229
1
            }
1230
54.9k
            cpt.x = float2fixed(fpx);
1231
54.9k
            cpt.y = float2fixed(fpy);
1232
54.9k
        }
1233
3.92M
        if (((code = gs_newpath(pgs)) < 0) ||
1234
3.92M
            ((code = show_origin_setup(pgs, cpt.x, cpt.y, penum)) < 0))
1235
0
            goto rret;
1236
3.92M
    }
1237
3.92M
    penum->width_status = sws_none;
1238
3.92M
    penum->continue_proc = continue_show_update;
1239
    /* Reset the sampling scale. */
1240
3.92M
    penum->log2_scale.x = penum->log2_scale.y = 0;
1241
    /* Try using the build procedure in the font. */
1242
    /* < 0 means error, 0 means success, 1 means failure. */
1243
3.92M
    penum->cc = cc;             /* set this now for build procedure */
1244
3.92M
    code = (*pfont->procs.build_char)(penum, pgs, pfont,
1245
3.92M
                                      chr, glyph);
1246
3.92M
    if (code < 0) {
1247
5.64k
        discard(gs_note_error(code));
1248
5.64k
        goto rret;
1249
5.64k
    }
1250
3.91M
    if (code == 0) {
1251
2.75M
        code = show_update(penum);
1252
2.75M
        if (code < 0)
1253
2
            goto rret;
1254
        /* Note that show_update does a grestore.... */
1255
2.75M
        code = show_move(penum);
1256
2.75M
        if (code)
1257
891
            return code;        /* ... so don't go to rret here. */
1258
2.75M
        goto more;
1259
2.75M
    }
1260
    /*
1261
     * Some BuildChar procedures do a save before the setcachedevice,
1262
     * and a restore at the end.  If we waited to allocate the cache
1263
     * device until the setcachedevice, we would attempt to free it
1264
     * after the restore.  Therefore, allocate it now.
1265
     */
1266
1.15M
    if (penum->dev_cache == 0) {
1267
25.9k
        code = show_cache_setup(penum);
1268
25.9k
        if (code < 0)
1269
0
            goto rret;
1270
25.9k
    }
1271
1.15M
    return TEXT_PROCESS_RENDER;
1272
    /* If we get an error while setting up for BuildChar, */
1273
    /* we must undo the partial setup. */
1274
5.65k
rret:
1275
11.6k
    while (pgs->level > penum->level) {
1276
5.98k
        gs_grestore(pgs);
1277
5.98k
    }
1278
5.65k
    return code;
1279
1.15M
}
1280
1281
/*
1282
 * Prepare to retry rendering of the current character.  (This is only used
1283
 * in one place in zchar1.c; a different approach may be better.)
1284
 */
1285
static int
1286
gx_show_text_retry(gs_text_enum_t *pte)
1287
0
{
1288
0
    gs_show_enum *const penum = (gs_show_enum *)pte;
1289
1290
0
    if (penum->cc) {
1291
0
        gs_font *pfont = penum->current_font;
1292
1293
0
        gx_free_cached_char(pfont->dir, penum->cc);
1294
0
        penum->cc = 0;
1295
0
    }
1296
0
    gs_grestore(penum->pgs);
1297
0
    penum->width_status = sws_retry;
1298
0
    penum->log2_scale.x = penum->log2_scale.y = 0;
1299
0
    penum->pair = 0;
1300
0
    return 0;
1301
0
}
1302
1303
/* Finish show or stringwidth */
1304
static int
1305
show_finish(gs_show_enum * penum)
1306
5.25M
{
1307
5.25M
    gs_gstate *pgs = penum->pgs;
1308
5.25M
    int code = 0, rcode;
1309
1310
5.25M
    if ((penum->text.operation & TEXT_DO_FALSE_CHARPATH) ||
1311
5.25M
        (penum->text.operation & TEXT_DO_TRUE_CHARPATH)) {
1312
5.03k
        if (pgs->path->current_subpath)
1313
4.09k
            pgs->path->last_charpath_segment = pgs->path->current_subpath->last;
1314
5.03k
    }
1315
5.25M
    if (penum->auto_release)
1316
0
        penum->procs->release((gs_text_enum_t *)penum, "show_finish");
1317
1318
5.25M
    if (!SHOW_IS_STRINGWIDTH(penum))
1319
5.22M
       return 0;
1320
1321
    /* Save the accumulated width before returning, if we are not in PDF text rendering mode 3, */
1322
    /* and undo the extra gsave. */
1323
25.9k
    if (!(penum->text.operation & TEXT_RENDER_MODE_3))
1324
407
        code = gs_currentpoint(pgs, &penum->returned.total_width);
1325
25.9k
    rcode = gs_grestore(pgs);
1326
1327
25.9k
    return (code < 0 ? code : rcode);
1328
5.25M
}
1329
1330
/* Release the structure. */
1331
static void
1332
gx_show_text_release(gs_text_enum_t *pte, client_name_t cname)
1333
5.25M
{
1334
5.25M
    gs_show_enum *const penum = (gs_show_enum *)pte;
1335
1336
5.25M
    penum->cc = 0;
1337
5.25M
    if (penum->dev_cache2) {
1338
816k
        gx_device_retain((gx_device *)penum->dev_cache2, false);
1339
816k
        penum->dev_cache2 = 0;
1340
816k
    }
1341
5.25M
    if (penum->dev_cache) {
1342
816k
        gx_device_retain((gx_device *)penum->dev_cache, false);
1343
816k
        penum->dev_cache = 0;
1344
816k
    }
1345
5.25M
    if (penum->dev_null) {
1346
26.0k
        gx_device_retain((gx_device *)penum->dev_null, false);
1347
26.0k
        penum->dev_null = 0;
1348
26.0k
    }
1349
5.25M
    gx_default_text_release(pte, cname);
1350
5.25M
}
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
4.87M
{
1370
4.87M
    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
4.87M
    return ((!SHOW_USES_OUTLINE(penum) || penum->cc != 0) &&
1375
4.87M
            penum->pgs->level == penum->level + 1);
1376
4.87M
}
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
5.65M
{
1393
5.65M
    return (penum->fstack.depth < 0 ? penum->pgs->font :
1394
5.65M
            penum->fstack.items[penum->fstack.depth].font);
1395
5.65M
}
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
5.65M
{
1406
5.65M
    gs_gstate *pgs = penum->pgs;
1407
5.65M
    gx_clip_path *pcpath;
1408
5.65M
    gs_font *pfont;
1409
1410
5.65M
    if (penum->fstack.depth <= 0) {
1411
5.26M
        pfont = pgs->font;
1412
5.26M
        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
5.26M
        } else {
1429
5.26M
            gs_currentcharmatrix(pgs, NULL, 1); /* make char_tm valid */
1430
5.26M
        }
1431
5.26M
    } else {
1432
        /* We have to concatenate the parent's FontMatrix as well. */
1433
397k
        gs_matrix mat;
1434
397k
        const gx_font_stack_item_t *pfsi =
1435
397k
            &penum->fstack.items[penum->fstack.depth];
1436
1437
397k
        pfont = pfsi->font;
1438
397k
        gs_matrix_multiply(&pfont->FontMatrix,
1439
397k
                           &pfsi[-1].font->FontMatrix, &mat);
1440
397k
        if (pfont->FontType == ft_CID_encrypted) {
1441
            /* concatenate the Type9 leaf's matrix */
1442
4.97k
            gs_matrix_multiply(&(gs_cid0_indexed_font(pfont, pfsi->index)->FontMatrix),
1443
4.97k
                                &mat, &mat);
1444
4.97k
        }
1445
397k
        gs_setcharmatrix(pgs, &mat);
1446
397k
    }
1447
5.65M
    penum->current_font = pfont;
1448
5.65M
    if (penum->can_cache >= 0 &&
1449
5.65M
        gx_effective_clip_path(pgs, &pcpath) >= 0
1450
5.65M
        ) {
1451
5.65M
        gs_fixed_rect cbox;
1452
1453
5.65M
        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
5.65M
        penum->ibox.p.x = fixed2int_var(cbox.p.x);
1458
5.65M
        penum->ibox.p.y = fixed2int_var(cbox.p.y);
1459
5.65M
        penum->ibox.q.x = fixed2int_var_ceiling(cbox.q.x);
1460
5.65M
        penum->ibox.q.y = fixed2int_var_ceiling(cbox.q.y);
1461
5.65M
        gx_cpath_outer_box(pcpath, &cbox);
1462
5.65M
        penum->obox.p.x = fixed2int_var(cbox.p.x);
1463
5.65M
        penum->obox.p.y = fixed2int_var(cbox.p.y);
1464
5.65M
        penum->obox.q.x = fixed2int_var_ceiling(cbox.q.x);
1465
5.65M
        penum->obox.q.y = fixed2int_var_ceiling(cbox.q.y);
1466
5.65M
        if (pgs->ctm.txy_fixed_valid && pgs->char_tm.txy_fixed_valid) {
1467
5.63M
            penum->ftx = (int)fixed2long(pgs->char_tm.tx_fixed -
1468
5.63M
                                         pgs->ctm.tx_fixed);
1469
5.63M
            penum->fty = (int)fixed2long(pgs->char_tm.ty_fixed -
1470
5.63M
                                         pgs->ctm.ty_fixed);
1471
5.63M
        } else {
1472
11.9k
            double fdx = pgs->char_tm.tx - pgs->ctm.tx;
1473
11.9k
            double fdy = pgs->char_tm.ty - pgs->ctm.ty;
1474
1475
11.9k
#define int_bits (ARCH_SIZEOF_INT * 8 - 1)
1476
11.9k
            if (!(f_fits_in_bits(fdx, int_bits) &&
1477
11.9k
                  f_fits_in_bits(fdy, int_bits))
1478
11.9k
                )
1479
181
                return_error(gs_error_limitcheck);
1480
11.8k
#undef int_bits
1481
11.8k
            penum->ftx = (int)fdx;
1482
11.8k
            penum->fty = (int)fdy;
1483
11.8k
        }
1484
5.65M
    }
1485
5.65M
    show_set_encode_char(penum);
1486
5.65M
    return 0;
1487
5.65M
}
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
816k
{
1548
816k
    gs_gstate *pgs = penum->pgs;
1549
816k
    gs_memory_t *mem = penum->memory;
1550
816k
    gx_device_memory *dev =
1551
816k
        gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
1552
816k
                        "show_cache_setup(dev_cache)");
1553
816k
    gx_device_memory *dev2 =
1554
816k
        gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
1555
816k
                        "show_cache_setup(dev_cache2)");
1556
1557
816k
    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
816k
    gs_make_mem_mono_device(dev, mem, gs_currentdevice_inline(pgs));
1575
816k
    penum->dev_cache = dev;
1576
816k
    gs_make_mem_mono_device(dev2, mem, gs_currentdevice_inline(pgs));
1577
816k
    penum->dev_cache2 = dev2;
1578
816k
    dev->HWResolution[0] = pgs->device->HWResolution[0];
1579
816k
    dev->HWResolution[1] = pgs->device->HWResolution[1];
1580
    /* Retain these devices, since they are referenced from the enumerator. */
1581
816k
    gx_device_retain((gx_device *)dev, true);
1582
816k
    gx_device_retain((gx_device *)dev2, true);
1583
816k
    return 0;
1584
816k
}
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
3.92M
{
1592
3.92M
    if (penum->charpath_flag == cpm_show) {
1593
        /* Round the translation in the graphics state. */
1594
        /* This helps prevent rounding artifacts later. */
1595
3.16M
        if (gs_currentaligntopixels(penum->current_font->dir) == 0) {
1596
3.16M
            int scx = -1L << (_fixed_shift - penum->log2_scale.x);
1597
3.16M
            int scy = -1L << (_fixed_shift - penum->log2_scale.y);
1598
3.16M
            int rdx =  1L << (_fixed_shift - 1 - penum->log2_scale.x);
1599
3.16M
            int rdy =  1L << (_fixed_shift - 1 - penum->log2_scale.y);
1600
1601
3.16M
            cpt_x = (cpt_x + rdx) & scx;
1602
3.16M
            cpt_y = (cpt_y + rdy) & scy;
1603
3.16M
        } else {
1604
0
            cpt_x = fixed_rounded(cpt_x);
1605
0
            cpt_y = fixed_rounded(cpt_y);
1606
0
        }
1607
3.16M
    }
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
3.92M
    return gx_translate_to_fixed(pgs, cpt_x, cpt_y);
1613
3.92M
}