Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

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