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