xref: /plan9/sys/src/cmd/gs/src/gstext.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1998, 2000 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: gstext.c,v 1.19 2004/12/22 18:52:23 igor Exp $ */
18 /* Driver text interface support */
19 #include "memory_.h"
20 #include "gstypes.h"
21 #include "gdebug.h"
22 #include "gserror.h"
23 #include "gserrors.h"
24 #include "gsmemory.h"
25 #include "gsstruct.h"
26 #include "gstypes.h"
27 #include "gxfcache.h"
28 #include "gxdevcli.h"
29 #include "gxdcolor.h"		/* for gs_state_color_load */
30 #include "gxfont.h"		/* for init_fstack */
31 #include "gxpath.h"
32 #include "gxtext.h"
33 #include "gzstate.h"
34 
35 /* GC descriptors */
36 public_st_gs_text_params();
37 public_st_gs_text_enum();
38 
39 private
40 ENUM_PTRS_WITH(text_params_enum_ptrs, gs_text_params_t *tptr) return 0;
41 case 0:
42 if (tptr->operation & TEXT_FROM_STRING) {
43     return ENUM_CONST_STRING2(tptr->data.bytes, tptr->size);
44 }
45 if (tptr->operation & TEXT_FROM_BYTES)
46     return ENUM_OBJ(tptr->data.bytes);
47 if (tptr->operation & TEXT_FROM_CHARS)
48     return ENUM_OBJ(tptr->data.chars);
49 if (tptr->operation & TEXT_FROM_GLYPHS)
50     return ENUM_OBJ(tptr->data.glyphs);
51 return ENUM_OBJ(NULL);
52 case 1:
53 return ENUM_OBJ(tptr->operation & TEXT_REPLACE_WIDTHS ?
54 		tptr->x_widths : NULL);
55 case 2:
56 return ENUM_OBJ(tptr->operation & TEXT_REPLACE_WIDTHS ?
57 		tptr->y_widths : NULL);
58 ENUM_PTRS_END
RELOC_PTRS_WITH(text_params_reloc_ptrs,gs_text_params_t * tptr)59 private RELOC_PTRS_WITH(text_params_reloc_ptrs, gs_text_params_t *tptr)
60 {
61     if (tptr->operation & TEXT_FROM_STRING) {
62 	gs_const_string str;
63 
64 	str.data = tptr->data.bytes;
65 	str.size = tptr->size;
66 	RELOC_CONST_STRING_VAR(str);
67 	tptr->data.bytes = str.data;
68     } else if (tptr->operation & TEXT_FROM_BYTES)
69 	RELOC_OBJ_VAR(tptr->data.bytes);
70     else if (tptr->operation & TEXT_FROM_CHARS)
71 	RELOC_OBJ_VAR(tptr->data.chars);
72     else if (tptr->operation & TEXT_FROM_GLYPHS)
73 	RELOC_OBJ_VAR(tptr->data.glyphs);
74     if (tptr->operation & TEXT_REPLACE_WIDTHS) {
75 	RELOC_OBJ_VAR(tptr->x_widths);
76 	RELOC_OBJ_VAR(tptr->y_widths);
77     }
78 }
79 RELOC_PTRS_END
80 
ENUM_PTRS_WITH(text_enum_enum_ptrs,gs_text_enum_t * eptr)81 private ENUM_PTRS_WITH(text_enum_enum_ptrs, gs_text_enum_t *eptr)
82 {
83     if (index == 8) {
84 	if (eptr->pair != 0)
85 	    ENUM_RETURN(eptr->pair - eptr->pair->index);
86 	else
87 	    ENUM_RETURN(0);
88     }
89     index -= 9;
90     if (index <= eptr->fstack.depth)
91 	ENUM_RETURN(eptr->fstack.items[index].font);
92     index -= eptr->fstack.depth + 1;
93      return ENUM_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text), index);
94 }
95 case 0: return ENUM_OBJ(gx_device_enum_ptr(eptr->dev));
96 case 1: return ENUM_OBJ(gx_device_enum_ptr(eptr->imaging_dev));
97 ENUM_PTR3(2, gs_text_enum_t, pis, orig_font, path);
98 ENUM_PTR3(5, gs_text_enum_t, pdcolor, pcpath, current_font);
99 ENUM_PTRS_END
100 
RELOC_PTRS_WITH(text_enum_reloc_ptrs,gs_text_enum_t * eptr)101 private RELOC_PTRS_WITH(text_enum_reloc_ptrs, gs_text_enum_t *eptr)
102 {
103     int i;
104 
105     RELOC_USING(st_gs_text_params, &eptr->text, sizeof(eptr->text));
106     eptr->dev = gx_device_reloc_ptr(eptr->dev, gcst);
107     eptr->imaging_dev = gx_device_reloc_ptr(eptr->imaging_dev, gcst);
108     RELOC_PTR3(gs_text_enum_t, pis, orig_font, path);
109     RELOC_PTR3(gs_text_enum_t, pdcolor, pcpath, current_font);
110     if (eptr->pair != NULL)
111 	eptr->pair = (cached_fm_pair *)RELOC_OBJ(eptr->pair - eptr->pair->index) +
112 			     eptr->pair->index;
113     for (i = 0; i <= eptr->fstack.depth; i++)
114 	RELOC_PTR(gs_text_enum_t, fstack.items[i].font);
115 }
116 RELOC_PTRS_END
117 
118 /* Begin processing text. */
119 int
gx_device_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)120 gx_device_text_begin(gx_device * dev, gs_imager_state * pis,
121 		     const gs_text_params_t * text, gs_font * font,
122 		     gx_path * path,	/* unless DO_NONE & !RETURN_WIDTH */
123 		     const gx_device_color * pdcolor,	/* DO_DRAW */
124 		     const gx_clip_path * pcpath,	/* DO_DRAW */
125 		     gs_memory_t * mem, gs_text_enum_t ** ppte)
126 {
127     if (TEXT_PARAMS_ARE_INVALID(text))
128 	return_error(gs_error_rangecheck);
129     {
130 	gx_path *tpath =
131 	    ((text->operation & TEXT_DO_NONE) &&
132 	     !(text->operation & TEXT_RETURN_WIDTH) ? 0 : path);
133 	const gx_clip_path *tcpath =
134 	    (text->operation & TEXT_DO_DRAW ? pcpath : 0);
135 
136 	/* A high level device need to know an initial device color
137 	   for accumulates a charstring of a Type 3 font.
138 	   Since the accumulation may happen while stringwidth.
139 	   we pass the device color unconditionally. */
140 	return dev_proc(dev, text_begin)
141 	    (dev, pis, text, font, tpath, pdcolor, tcpath, mem, ppte);
142     }
143 }
144 
145 /*
146  * Initialize a newly created text enumerator.  Implementations of
147  * text_begin must call this just after allocating the enumerator.
148  */
149 private int
gs_text_enum_init_dynamic(gs_text_enum_t * pte,gs_font * font)150 gs_text_enum_init_dynamic(gs_text_enum_t *pte, gs_font *font)
151 {
152     pte->current_font = font;
153     pte->index = 0;
154     pte->xy_index = 0;
155     pte->FontBBox_as_Metrics2.x = pte->FontBBox_as_Metrics2.y = 0;
156     pte->pair = 0;
157     pte->device_disabled_grid_fitting = 0;
158     pte->outer_CID = GS_NO_GLYPH;
159     return font->procs.init_fstack(pte, font);
160 }
161 int
gs_text_enum_init(gs_text_enum_t * pte,const gs_text_enum_procs_t * procs,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)162 gs_text_enum_init(gs_text_enum_t *pte, const gs_text_enum_procs_t *procs,
163 		  gx_device *dev, gs_imager_state *pis,
164 		  const gs_text_params_t *text, gs_font *font, gx_path *path,
165 		  const gx_device_color *pdcolor, const gx_clip_path *pcpath,
166 		  gs_memory_t *mem)
167 {
168     int code;
169 
170     pte->text = *text;
171     pte->dev = dev;
172     pte->imaging_dev = NULL;
173     pte->pis = pis;
174     pte->orig_font = font;
175     pte->path = path;
176     pte->pdcolor = pdcolor;
177     pte->pcpath = pcpath;
178     pte->memory = mem;
179     pte->procs = procs;
180     /* text_begin procedure sets rc */
181     /* init_dynamic sets current_font */
182     pte->log2_scale.x = pte->log2_scale.y = 0;
183     /* init_dynamic sets index, xy_index, fstack */
184     code = gs_text_enum_init_dynamic(pte, font);
185     if (code >= 0)
186 	rc_increment(dev);
187     return code;
188 }
189 
190 /*
191  * Copy the dynamically changing elements from one enumerator to another.
192  * This is useful primarily for enumerators that sometimes pass the
193  * operation to a subsidiary enumerator.
194  */
195 void
gs_text_enum_copy_dynamic(gs_text_enum_t * pto,const gs_text_enum_t * pfrom,bool for_return)196 gs_text_enum_copy_dynamic(gs_text_enum_t *pto, const gs_text_enum_t *pfrom,
197 			  bool for_return)
198 {
199     int depth = pfrom->fstack.depth;
200 
201     pto->current_font = pfrom->current_font;
202     pto->index = pfrom->index;
203     pto->xy_index = pfrom->xy_index;
204     pto->fstack.depth = depth;
205     pto->FontBBox_as_Metrics2 = pfrom->FontBBox_as_Metrics2;
206     pto->pair = pfrom->pair;
207     pto->device_disabled_grid_fitting = pfrom->device_disabled_grid_fitting;
208     pto->outer_CID = pfrom->outer_CID;
209     if (depth >= 0)
210 	memcpy(pto->fstack.items, pfrom->fstack.items,
211 	       (depth + 1) * sizeof(pto->fstack.items[0]));
212     if (for_return) {
213 	pto->cmap_code = pfrom->cmap_code;
214 	pto->returned = pfrom->returned;
215     }
216 }
217 
218 /* Begin processing text based on a graphics state. */
219 int
gs_text_begin(gs_state * pgs,const gs_text_params_t * text,gs_memory_t * mem,gs_text_enum_t ** ppte)220 gs_text_begin(gs_state * pgs, const gs_text_params_t * text,
221 	      gs_memory_t * mem, gs_text_enum_t ** ppte)
222 {
223     gx_clip_path *pcpath = 0;
224     int code;
225 
226     if (text->operation & TEXT_DO_DRAW) {
227 	code = gx_effective_clip_path(pgs, &pcpath);
228 	if (code < 0)
229 	    return code;
230     }
231     /* We must load device color even with no TEXT_DO_DRAW,
232        because a high level device accumulates a charstring
233        of a Type 3 font while stringwidth.
234        Unfortunately we can't effectively know a leaf font type here,
235        so we load the color unconditionally . */
236     gx_set_dev_color(pgs);
237     code = gs_state_color_load(pgs);
238     if (code < 0)
239 	return code;
240     return gx_device_text_begin(pgs->device, (gs_imager_state *) pgs,
241 				text, pgs->font, pgs->path, pgs->dev_color,
242 				pcpath, mem, ppte);
243 }
244 
245 /*
246  * Update the device color to be used with text (because a kshow or
247  * cshow procedure may have changed the current color).
248  */
249 int
gs_text_update_dev_color(gs_state * pgs,gs_text_enum_t * pte)250 gs_text_update_dev_color(gs_state * pgs, gs_text_enum_t * pte)
251 {
252     /*
253      * The text enumerator holds a device color pointer, which may be a
254      * null pointer or a pointer to the same device color as the graphic
255      * state points to. In the former case the text is not to be
256      * rendered, and hence of no interest here. In the latter case the
257      * update of the graphic state color will update the text color as
258      * well.
259      */
260     if (pte->pdcolor != 0)
261         gx_set_dev_color(pgs);
262     return 0;
263 }
264 
text_do_draw(gs_state * pgs)265 private inline uint text_do_draw(gs_state * pgs)
266 {
267     return (pgs->text_rendering_mode == 3 ? TEXT_DO_NONE : TEXT_DO_DRAW);
268 }
269 
270 /* Begin PostScript-equivalent text operations. */
271 int
gs_show_begin(gs_state * pgs,const byte * str,uint size,gs_memory_t * mem,gs_text_enum_t ** ppte)272 gs_show_begin(gs_state * pgs, const byte * str, uint size,
273 	      gs_memory_t * mem, gs_text_enum_t ** ppte)
274 {
275     gs_text_params_t text;
276 
277     text.operation = TEXT_FROM_STRING | text_do_draw(pgs) | TEXT_RETURN_WIDTH;
278     text.data.bytes = str, text.size = size;
279     return gs_text_begin(pgs, &text, mem, ppte);
280 }
281 int
gs_ashow_begin(gs_state * pgs,floatp ax,floatp ay,const byte * str,uint size,gs_memory_t * mem,gs_text_enum_t ** ppte)282 gs_ashow_begin(gs_state * pgs, floatp ax, floatp ay, const byte * str, uint size,
283 	       gs_memory_t * mem, gs_text_enum_t ** ppte)
284 {
285     gs_text_params_t text;
286 
287     text.operation = TEXT_FROM_STRING | TEXT_ADD_TO_ALL_WIDTHS |
288 	text_do_draw(pgs) | TEXT_RETURN_WIDTH;
289     text.data.bytes = str, text.size = size;
290     text.delta_all.x = ax;
291     text.delta_all.y = ay;
292     return gs_text_begin(pgs, &text, mem, ppte);
293 }
294 int
gs_widthshow_begin(gs_state * pgs,floatp cx,floatp cy,gs_char chr,const byte * str,uint size,gs_memory_t * mem,gs_text_enum_t ** ppte)295 gs_widthshow_begin(gs_state * pgs, floatp cx, floatp cy, gs_char chr,
296 		   const byte * str, uint size,
297 		   gs_memory_t * mem, gs_text_enum_t ** ppte)
298 {
299     gs_text_params_t text;
300 
301     text.operation = TEXT_FROM_STRING | TEXT_ADD_TO_SPACE_WIDTH |
302 	text_do_draw(pgs) | TEXT_RETURN_WIDTH;
303     text.data.bytes = str, text.size = size;
304     text.delta_space.x = cx;
305     text.delta_space.y = cy;
306     text.space.s_char = chr;
307     return gs_text_begin(pgs, &text, mem, ppte);
308 }
309 int
gs_awidthshow_begin(gs_state * pgs,floatp cx,floatp cy,gs_char chr,floatp ax,floatp ay,const byte * str,uint size,gs_memory_t * mem,gs_text_enum_t ** ppte)310 gs_awidthshow_begin(gs_state * pgs, floatp cx, floatp cy, gs_char chr,
311 		    floatp ax, floatp ay, const byte * str, uint size,
312 		    gs_memory_t * mem, gs_text_enum_t ** ppte)
313 {
314     gs_text_params_t text;
315 
316     text.operation = TEXT_FROM_STRING |
317 	TEXT_ADD_TO_ALL_WIDTHS | TEXT_ADD_TO_SPACE_WIDTH |
318 	text_do_draw(pgs) | TEXT_RETURN_WIDTH;
319     text.data.bytes = str, text.size = size;
320     text.delta_space.x = cx;
321     text.delta_space.y = cy;
322     text.space.s_char = chr;
323     text.delta_all.x = ax;
324     text.delta_all.y = ay;
325     return gs_text_begin(pgs, &text, mem, ppte);
326 }
327 int
gs_kshow_begin(gs_state * pgs,const byte * str,uint size,gs_memory_t * mem,gs_text_enum_t ** ppte)328 gs_kshow_begin(gs_state * pgs, const byte * str, uint size,
329 	       gs_memory_t * mem, gs_text_enum_t ** ppte)
330 {
331     gs_text_params_t text;
332 
333     text.operation = TEXT_FROM_STRING | text_do_draw(pgs) | TEXT_INTERVENE |
334 	TEXT_RETURN_WIDTH;
335     text.data.bytes = str, text.size = size;
336     return gs_text_begin(pgs, &text, mem, ppte);
337 }
338 int
gs_xyshow_begin(gs_state * pgs,const byte * str,uint size,const float * x_widths,const float * y_widths,uint widths_size,gs_memory_t * mem,gs_text_enum_t ** ppte)339 gs_xyshow_begin(gs_state * pgs, const byte * str, uint size,
340 		const float *x_widths, const float *y_widths,
341 		uint widths_size, gs_memory_t * mem, gs_text_enum_t ** ppte)
342 {
343     gs_text_params_t text;
344 
345     text.operation = TEXT_FROM_STRING | TEXT_REPLACE_WIDTHS |
346 	text_do_draw(pgs) | TEXT_RETURN_WIDTH;
347     text.data.bytes = str, text.size = size;
348     text.x_widths = x_widths;
349     text.y_widths = y_widths;
350     text.widths_size = widths_size;
351     return gs_text_begin(pgs, &text, mem, ppte);
352 }
353 
354 private void
setup_FontBBox_as_Metrics2(gs_text_enum_t * pte,gs_font * pfont)355 setup_FontBBox_as_Metrics2 (gs_text_enum_t * pte, gs_font * pfont)
356 {
357     /* When we exec a operator like `show' that has a a chance to get
358        a glyph from a char, we can set FontBBox_as_Metrics2 in
359        gschar0.c:gs_type0_next_char_glyph.  In other hand, when we
360        exec a operator like `glyphshow' that get a glyph directly from
361        an input file, gschar0.c:gs_type0_next_char_glyph is exec'ed.
362        For the later case, we set up FontBBox_as_Metrics2 with using
363        this procedure.. */
364     if (pfont->FontType == ft_CID_encrypted
365 	|| pfont->FontType == ft_CID_TrueType)
366         pte->FontBBox_as_Metrics2 = ((gs_font_base *)pfont)->FontBBox.q;
367 }
368 
369 int
gs_glyphshow_begin(gs_state * pgs,gs_glyph glyph,gs_memory_t * mem,gs_text_enum_t ** ppte)370 gs_glyphshow_begin(gs_state * pgs, gs_glyph glyph,
371 		   gs_memory_t * mem, gs_text_enum_t ** ppte)
372 {
373     gs_text_params_t text;
374     int result;
375 
376     text.operation = TEXT_FROM_SINGLE_GLYPH | text_do_draw(pgs) | TEXT_RETURN_WIDTH;
377     text.data.d_glyph = glyph;
378     text.size = 1;
379     result = gs_text_begin(pgs, &text, mem, ppte);
380     if (result == 0)
381       setup_FontBBox_as_Metrics2(*ppte, pgs->font);
382     return result;
383 }
384 int
gs_cshow_begin(gs_state * pgs,const byte * str,uint size,gs_memory_t * mem,gs_text_enum_t ** ppte)385 gs_cshow_begin(gs_state * pgs, const byte * str, uint size,
386 	       gs_memory_t * mem, gs_text_enum_t ** ppte)
387 {
388     gs_text_params_t text;
389 
390     text.operation = TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_INTERVENE;
391     text.data.bytes = str, text.size = size;
392     return gs_text_begin(pgs, &text, mem, ppte);
393 }
394 int
gs_stringwidth_begin(gs_state * pgs,const byte * str,uint size,gs_memory_t * mem,gs_text_enum_t ** ppte)395 gs_stringwidth_begin(gs_state * pgs, const byte * str, uint size,
396 		     gs_memory_t * mem, gs_text_enum_t ** ppte)
397 {
398     gs_text_params_t text;
399 
400     text.operation = TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_RETURN_WIDTH;
401     text.data.bytes = str, text.size = size;
402     return gs_text_begin(pgs, &text, mem, ppte);
403 }
404 int
gs_charpath_begin(gs_state * pgs,const byte * str,uint size,bool stroke_path,gs_memory_t * mem,gs_text_enum_t ** ppte)405 gs_charpath_begin(gs_state * pgs, const byte * str, uint size, bool stroke_path,
406 		  gs_memory_t * mem, gs_text_enum_t ** ppte)
407 {
408     gs_text_params_t text;
409 
410     text.operation = TEXT_FROM_STRING | TEXT_RETURN_WIDTH |
411 	(stroke_path ? TEXT_DO_TRUE_CHARPATH : TEXT_DO_FALSE_CHARPATH);
412     text.data.bytes = str, text.size = size;
413     return gs_text_begin(pgs, &text, mem, ppte);
414 }
415 int
gs_charboxpath_begin(gs_state * pgs,const byte * str,uint size,bool stroke_path,gs_memory_t * mem,gs_text_enum_t ** ppte)416 gs_charboxpath_begin(gs_state * pgs, const byte * str, uint size,
417 		bool stroke_path, gs_memory_t * mem, gs_text_enum_t ** ppte)
418 {
419     gs_text_params_t text;
420 
421     text.operation = TEXT_FROM_STRING | TEXT_RETURN_WIDTH |
422 	(stroke_path ? TEXT_DO_TRUE_CHARBOXPATH : TEXT_DO_FALSE_CHARBOXPATH);
423     text.data.bytes = str, text.size = size;
424     return gs_text_begin(pgs, &text, mem, ppte);
425 }
426 int
gs_glyphpath_begin(gs_state * pgs,gs_glyph glyph,bool stroke_path,gs_memory_t * mem,gs_text_enum_t ** ppte)427 gs_glyphpath_begin(gs_state * pgs, gs_glyph glyph, bool stroke_path,
428 		   gs_memory_t * mem, gs_text_enum_t ** ppte)
429 {
430     gs_text_params_t text;
431     int result;
432 
433     text.operation = TEXT_FROM_SINGLE_GLYPH | TEXT_RETURN_WIDTH |
434 	(stroke_path ? TEXT_DO_TRUE_CHARPATH : TEXT_DO_FALSE_CHARPATH);
435     text.data.d_glyph = glyph;
436     text.size = 1;
437     result = gs_text_begin(pgs, &text, mem, ppte);
438     if (result == 0)
439       setup_FontBBox_as_Metrics2(*ppte, pgs->font);
440     return result;
441 }
442 int
gs_glyphwidth_begin(gs_state * pgs,gs_glyph glyph,gs_memory_t * mem,gs_text_enum_t ** ppte)443 gs_glyphwidth_begin(gs_state * pgs, gs_glyph glyph,
444 		    gs_memory_t * mem, gs_text_enum_t ** ppte)
445 {
446     gs_text_params_t text;
447     int result;
448 
449     text.operation = TEXT_FROM_SINGLE_GLYPH | TEXT_DO_NONE | TEXT_RETURN_WIDTH;
450     text.data.d_glyph = glyph;
451     text.size = 1;
452     result = gs_text_begin(pgs, &text, mem, ppte);
453     if (result == 0)
454       setup_FontBBox_as_Metrics2(*ppte, pgs->font);
455     return result;
456 }
457 
458 /* Restart processing with different parameters. */
459 int
gs_text_restart(gs_text_enum_t * pte,const gs_text_params_t * text)460 gs_text_restart(gs_text_enum_t *pte, const gs_text_params_t *text)
461 {
462     gs_text_enum_t tenum;
463 
464     tenum = *pte;
465     tenum.text = *text;
466     gs_text_enum_init_dynamic(&tenum, pte->orig_font);
467     setup_FontBBox_as_Metrics2(pte, pte->orig_font);
468     return gs_text_resync(pte, &tenum);
469 }
470 
471 /*
472  * Resync text processing with new parameters and string position.
473  */
474 int
gs_text_resync(gs_text_enum_t * pte,const gs_text_enum_t * pfrom)475 gs_text_resync(gs_text_enum_t *pte, const gs_text_enum_t *pfrom)
476 {
477     return pte->procs->resync(pte, pfrom);
478 }
479 
480 /* Process text after 'begin'. */
481 int
gs_text_process(gs_text_enum_t * pte)482 gs_text_process(gs_text_enum_t * pte)
483 {
484     return pte->procs->process(pte);
485 }
486 
487 /* Access elements of the enumerator. */
488 gs_font *
gs_text_current_font(const gs_text_enum_t * pte)489 gs_text_current_font(const gs_text_enum_t *pte)
490 {
491     return pte->current_font;
492 }
493 gs_char
gs_text_current_char(const gs_text_enum_t * pte)494 gs_text_current_char(const gs_text_enum_t *pte)
495 {
496     return pte->returned.current_char;
497 }
498 gs_char
gs_text_next_char(const gs_text_enum_t * pte)499 gs_text_next_char(const gs_text_enum_t *pte)
500 {
501     const uint operation = pte->text.operation;
502 
503     if (pte->index >= pte->text.size)
504 	return gs_no_char;	/* rangecheck */
505     if (operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES))
506 	return pte->text.data.bytes[pte->index];
507     if (operation & TEXT_FROM_CHARS)
508 	return pte->text.data.chars[pte->index];
509     return gs_no_char;		/* rangecheck */
510 }
511 gs_glyph
gs_text_current_glyph(const gs_text_enum_t * pte)512 gs_text_current_glyph(const gs_text_enum_t *pte)
513 {
514     return pte->returned.current_glyph;
515 }
516 int
gs_text_total_width(const gs_text_enum_t * pte,gs_point * pwidth)517 gs_text_total_width(const gs_text_enum_t *pte, gs_point *pwidth)
518 {
519     *pwidth = pte->returned.total_width;
520     return 0;
521 }
522 
523 /* Assuming REPLACE_WIDTHS is set, return the width of the i'th character. */
524 int
gs_text_replaced_width(const gs_text_params_t * text,uint index,gs_point * pwidth)525 gs_text_replaced_width(const gs_text_params_t *text, uint index,
526 		       gs_point *pwidth)
527 {
528     const float *x_widths = text->x_widths;
529     const float *y_widths = text->y_widths;
530 
531     if (index > text->size)
532 	return_error(gs_error_rangecheck);
533     if (x_widths == y_widths) {
534 	if (x_widths) {
535 	    index *= 2;
536 	    pwidth->x = x_widths[index];
537 	    pwidth->y = x_widths[index + 1];
538 	}
539 	else
540 	    pwidth->x = pwidth->y = 0;
541     } else {
542 	pwidth->x = (x_widths ? x_widths[index] : 0.0);
543 	pwidth->y = (y_widths ? y_widths[index] : 0.0);
544     }
545     return 0;
546 }
547 
548 /* Determine whether only the width is needed. */
549 bool
gs_text_is_width_only(const gs_text_enum_t * pte)550 gs_text_is_width_only(const gs_text_enum_t * pte)
551 {
552     return pte->procs->is_width_only(pte);
553 }
554 
555 /* Return the width of the current character. */
556 int
gs_text_current_width(const gs_text_enum_t * pte,gs_point * pwidth)557 gs_text_current_width(const gs_text_enum_t * pte, gs_point *pwidth)
558 {
559     return pte->procs->current_width(pte, pwidth);
560 }
561 
562 /* Set text metrics and optionally enable caching. */
563 int
gs_text_set_cache(gs_text_enum_t * pte,const double * values,gs_text_cache_control_t control)564 gs_text_set_cache(gs_text_enum_t * pte, const double *values,
565 		  gs_text_cache_control_t control)
566 {
567     return pte->procs->set_cache(pte, values, control);
568 }
569 int
gs_text_setcharwidth(gs_text_enum_t * pte,const double wxy[2])570 gs_text_setcharwidth(gs_text_enum_t * pte, const double wxy[2])
571 {
572     return pte->procs->set_cache(pte, wxy, TEXT_SET_CHAR_WIDTH);
573 }
574 int
gs_text_setcachedevice(gs_text_enum_t * pte,const double wbox[6])575 gs_text_setcachedevice(gs_text_enum_t * pte, const double wbox[6])
576 {
577     return pte->procs->set_cache(pte, wbox, TEXT_SET_CACHE_DEVICE);
578 }
579 int
gs_text_setcachedevice2(gs_text_enum_t * pte,const double wbox2[10])580 gs_text_setcachedevice2(gs_text_enum_t * pte, const double wbox2[10])
581 {
582     return pte->procs->set_cache(pte, wbox2, TEXT_SET_CACHE_DEVICE2);
583 }
584 
585 /* Retry processing the last character without caching. */
586 int
gs_text_retry(gs_text_enum_t * pte)587 gs_text_retry(gs_text_enum_t * pte)
588 {
589     return pte->procs->retry(pte);
590 }
591 
592 /* Release the text processing structures. */
593 void
gx_default_text_release(gs_text_enum_t * pte,client_name_t cname)594 gx_default_text_release(gs_text_enum_t *pte, client_name_t cname)
595 {
596     rc_decrement_only(pte->dev, cname);
597     rc_decrement_only(pte->imaging_dev, cname);
598 }
599 void
rc_free_text_enum(gs_memory_t * mem,void * obj,client_name_t cname)600 rc_free_text_enum(gs_memory_t * mem, void *obj, client_name_t cname)
601 {
602     gs_text_enum_t *pte = obj;
603 
604     pte->procs->release(pte, cname);
605     rc_free_struct_only(mem, obj, cname);
606 }
607 void
gs_text_release(gs_text_enum_t * pte,client_name_t cname)608 gs_text_release(gs_text_enum_t * pte, client_name_t cname)
609 {
610     rc_decrement_only(pte, cname);
611 }
612 
613 /* ---------------- Default font rendering procedures ---------------- */
614 
615 /* Default fstack initialization procedure. */
616 int
gs_default_init_fstack(gs_text_enum_t * pte,gs_font * pfont)617 gs_default_init_fstack(gs_text_enum_t *pte, gs_font *pfont)
618 {
619     pte->fstack.depth = -1;
620     return 0;
621 }
622 
623 /* Default next-glyph procedure. */
624 int
gs_default_next_char_glyph(gs_text_enum_t * pte,gs_char * pchr,gs_glyph * pglyph)625 gs_default_next_char_glyph(gs_text_enum_t *pte, gs_char *pchr, gs_glyph *pglyph)
626 {
627     if (pte->index >= pte->text.size)
628 	return 2;
629     if (pte->text.operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) {
630 	/* ordinary string */
631 	*pchr = pte->text.data.bytes[pte->index];
632 	if (pte->outer_CID != GS_NO_GLYPH)
633 	    *pglyph = pte->outer_CID;
634 	else
635 	    *pglyph = gs_no_glyph;
636     } else if (pte->text.operation & TEXT_FROM_SINGLE_GLYPH) {
637 	/* glyphshow or glyphpath */
638 	*pchr = gs_no_char;
639 	*pglyph = pte->text.data.d_glyph;
640     } else if (pte->text.operation & TEXT_FROM_GLYPHS) {
641 	*pchr = gs_no_char;
642 	*pglyph = pte->text.data.glyphs[pte->index];
643     } else if (pte->text.operation & TEXT_FROM_SINGLE_CHAR) {
644 	*pchr = pte->text.data.d_char;
645 	*pglyph = gs_no_glyph;
646     } else if (pte->text.operation & TEXT_FROM_CHARS) {
647 	*pchr = pte->text.data.chars[pte->index];
648 	*pglyph = gs_no_glyph;
649     } else
650 	return_error(gs_error_rangecheck); /* shouldn't happen */
651     pte->index++;
652     return 0;
653 }
654 
655 /* Dummy (ineffective) BuildChar/BuildGlyph procedure */
656 int
gs_no_build_char(gs_text_enum_t * pte,gs_state * pgs,gs_font * pfont,gs_char chr,gs_glyph glyph)657 gs_no_build_char(gs_text_enum_t *pte, gs_state *pgs, gs_font *pfont,
658 		 gs_char chr, gs_glyph glyph)
659 {
660     return 1;			/* failure, but not error */
661 }
662