xref: /plan9/sys/src/cmd/gs/src/gxchar.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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
RELOC_PTRS_WITH(show_enum_reloc_ptrs,gs_show_enum * eptr)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 *
gs_show_enum_alloc(gs_memory_t * mem,gs_state * pgs,client_name_t cname)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
gx_default_text_begin(gx_device * dev,gs_imager_state * pis,const gs_text_params_t * text,gs_font * font,gx_path * path,const gx_device_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gs_text_enum_t ** ppte)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
gx_hld_stringwidth_begin(gs_imager_state * pis,gx_path ** path)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
gx_default_text_restore_state(gs_text_enum_t * pte)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
gx_show_text_set_cache(gs_text_enum_t * pte,const double * pw,gs_text_cache_control_t control)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
set_char_width(gs_show_enum * penum,gs_state * pgs,floatp wx,floatp wy)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
gx_compute_text_oversampling(const gs_show_enum * penum,const gs_font * pfont,int alpha_bits,gs_log2_scale_point * p_log2_scale)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
compute_glyph_raster_params(gs_show_enum * penum,bool in_setcachedevice,int * alpha_bits,int * depth,gs_fixed_point * subpix_origin,gs_log2_scale_point * log2_scale)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
set_cache_device(gs_show_enum * penum,gs_state * pgs,floatp llx,floatp lly,floatp urx,floatp ury)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
gs_incachedevice(const gs_state * pgs)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
show_set_encode_char(gs_show_enum * penum)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
gx_show_text_resync(gs_text_enum_t * pte,const gs_text_enum_t * pfrom)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
gx_show_text_process(gs_text_enum_t * pte)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
continue_show_update(gs_show_enum * penum)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
continue_show(gs_show_enum * penum)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
continue_kshow(gs_show_enum * penum)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
show_update(gs_show_enum * penum)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
show_fast_move(gs_state * pgs,gs_fixed_point * pwxy)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. */
gx_current_char(const gs_text_enum_t * pte)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
show_move(gs_show_enum * penum)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
show_proceed(gs_show_enum * penum)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
gx_show_text_retry(gs_text_enum_t * pte)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
show_finish(gs_show_enum * penum)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
gx_show_text_release(gs_text_enum_t * pte,client_name_t cname)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
gs_show_in_charpath(const gs_show_enum * penum)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
gx_show_text_is_width_only(const gs_text_enum_t * pte)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
gx_show_text_current_width(const gs_text_enum_t * pte,gs_point * pwidth)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 *
gs_show_current_font(const gs_show_enum * penum)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
is_matrix_good_for_caching(const gs_matrix_fixed * m)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
show_state_setup(gs_show_enum * penum)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
show_set_scale(const gs_show_enum * penum,gs_log2_scale_point * log2_scale)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
show_cache_setup(gs_show_enum * penum)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
show_origin_setup(gs_state * pgs,fixed cpt_x,fixed cpt_y,gs_show_enum * penum)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 }
1562