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