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: gschar.c 8250 2007-09-25 13:31:24Z giles $ */
15 /* Character writing "operators" for Ghostscript library */
16 #include "gx.h"
17 #include "gserrors.h"
18 #include "gsstruct.h"
19 #include "gsmatrix.h"		/* for gscoord.h */
20 #include "gscoord.h"		/* for gs_idtransform */
21 #include "gzstate.h"
22 #include "gxdevice.h"
23 #include "gxdevmem.h"
24 #include "gxchar.h"
25 #include "gxfont.h"
26 
27 /* Forward declarations */
28 static int show_n_begin(gs_show_enum *penum, gs_state *pgs, int code,
29 			 gs_text_enum_t *pte);
30 
31 /* Structure descriptors */
32 extern_st(st_gs_show_enum);
33 
34 /* ------ String writing operators ------ */
35 
36 /* Free the contents of a show enumerator. */
37 void
gs_show_enum_release(gs_show_enum * penum,gs_memory_t * emem)38 gs_show_enum_release(gs_show_enum * penum, gs_memory_t * emem)
39 {
40     if (penum->text.operation)	/* otherwise, never initialized */
41 	penum->procs->release((gs_text_enum_t *)penum, "gs_show_enum_release");
42     if (emem != 0)
43 	gs_free_object(emem, penum, "gs_show_enum_release");
44 }
45 
46 /* show[_n] */
47 int
gs_show_n_init(gs_show_enum * penum,gs_state * pgs,const char * str,uint size)48 gs_show_n_init(gs_show_enum * penum, gs_state * pgs,
49 	       const char *str, uint size)
50 {
51     gs_text_enum_t *pte;
52     int code = gs_show_begin(pgs, (const byte *)str, size, pgs->memory, &pte);
53 
54     return show_n_begin(penum, pgs, code, pte);
55 }
56 
57 /* ashow[_n] */
58 int
gs_ashow_n_init(gs_show_enum * penum,gs_state * pgs,floatp ax,floatp ay,const char * str,uint size)59 gs_ashow_n_init(gs_show_enum * penum, gs_state * pgs,
60 		floatp ax, floatp ay, const char *str, uint size)
61 {
62     gs_text_enum_t *pte;
63     int code = gs_ashow_begin(pgs, ax, ay, (const byte *)str, size,
64 			      pgs->memory, &pte);
65 
66     return show_n_begin(penum, pgs, code, pte);
67 }
68 
69 /* widthshow[_n] */
70 int
gs_widthshow_n_init(gs_show_enum * penum,gs_state * pgs,floatp cx,floatp cy,gs_char chr,const char * str,uint size)71 gs_widthshow_n_init(gs_show_enum * penum, gs_state * pgs,
72 		    floatp cx, floatp cy, gs_char chr,
73 		    const char *str, uint size)
74 {
75     gs_text_enum_t *pte;
76     int code = gs_widthshow_begin(pgs, cx, cy, chr, (const byte *)str, size,
77 				  pgs->memory, &pte);
78 
79     return show_n_begin(penum, pgs, code, pte);
80 }
81 
82 /* awidthshow[_n] */
83 int
gs_awidthshow_n_init(gs_show_enum * penum,gs_state * pgs,floatp cx,floatp cy,gs_char chr,floatp ax,floatp ay,const char * str,uint size)84 gs_awidthshow_n_init(gs_show_enum * penum, gs_state * pgs,
85 		     floatp cx, floatp cy, gs_char chr, floatp ax, floatp ay,
86 		     const char *str, uint size)
87 {
88     gs_text_enum_t *pte;
89     int code = gs_awidthshow_begin(pgs, cx, cy, chr, ax, ay,
90 				   (const byte *)str, size, pgs->memory, &pte);
91 
92     return show_n_begin(penum, pgs, code, pte);
93 }
94 
95 /* kshow[_n] */
96 int
gs_kshow_n_init(gs_show_enum * penum,gs_state * pgs,const char * str,uint size)97 gs_kshow_n_init(gs_show_enum * penum,
98 		gs_state * pgs, const char *str, uint size)
99 {
100     gs_text_enum_t *pte;
101     int code;
102 
103     switch (pgs->font->FontType) {
104     case ft_composite:
105     case ft_CID_encrypted:
106     case ft_CID_user_defined:
107     case ft_CID_TrueType:
108     case ft_CID_bitmap:
109 	return_error(gs_error_invalidfont);
110     default:
111 	break;
112     }
113     code = gs_kshow_begin(pgs, (const byte *)str, size, pgs->memory, &pte);
114     return show_n_begin(penum, pgs, code, pte);
115 }
116 
117 /* xyshow[_n] */
118 int
gs_xyshow_n_init(gs_show_enum * penum,gs_state * pgs,const char * str,uint size)119 gs_xyshow_n_init(gs_show_enum * penum,
120 		 gs_state * pgs, const char *str, uint size)
121 {
122     gs_text_enum_t *pte;
123     int code = gs_xyshow_begin(pgs, (const byte *)str, size, NULL, NULL, 0,
124 			       pgs->memory, &pte);
125 
126     return show_n_begin(penum, pgs, code, pte);
127 }
128 
129 /* glyphshow */
130 int
gs_glyphshow_init(gs_show_enum * penum,gs_state * pgs,gs_glyph glyph)131 gs_glyphshow_init(gs_show_enum * penum, gs_state * pgs, gs_glyph glyph)
132 {
133     gs_text_enum_t *pte;
134     int code = gs_glyphshow_begin(pgs, glyph, pgs->memory, &pte);
135 
136     return show_n_begin(penum, pgs, code, pte);
137 }
138 int
gs_glyphpath_init(gs_show_enum * penum,gs_state * pgs,gs_glyph glyph,bool stroke_path)139 gs_glyphpath_init(gs_show_enum * penum, gs_state * pgs, gs_glyph glyph,
140 		  bool stroke_path)
141 {
142     gs_text_enum_t *pte;
143     int code = gs_glyphpath_begin(pgs, glyph, stroke_path, pgs->memory, &pte);
144 
145     return show_n_begin(penum, pgs, code, pte);
146 }
147 int
gs_glyphwidth_init(gs_show_enum * penum,gs_state * pgs,gs_glyph glyph)148 gs_glyphwidth_init(gs_show_enum * penum, gs_state * pgs, gs_glyph glyph)
149 {
150     gs_text_enum_t *pte;
151     int code = gs_glyphwidth_begin(pgs, glyph, pgs->memory, &pte);
152 
153     return show_n_begin(penum, pgs, code, pte);
154 }
155 
156 /* ------ Related operators ------ */
157 
158 /* cshow[_n] */
159 int
gs_cshow_n_init(gs_show_enum * penum,gs_state * pgs,const char * str,uint size)160 gs_cshow_n_init(gs_show_enum * penum,
161 		gs_state * pgs, const char *str, uint size)
162 {
163     gs_text_enum_t *pte;
164     int code = gs_cshow_begin(pgs, (const byte *)str, size, pgs->memory, &pte);
165 
166     return show_n_begin(penum, pgs, code, pte);
167 }
168 
169 /* stringwidth[_n] */
170 int
gs_stringwidth_n_init(gs_show_enum * penum,gs_state * pgs,const char * str,uint size)171 gs_stringwidth_n_init(gs_show_enum * penum, gs_state * pgs,
172 		      const char *str, uint size)
173 {
174     gs_text_enum_t *pte;
175     int code = gs_stringwidth_begin(pgs, (const byte *)str, size,
176 				    pgs->memory, &pte);
177 
178     return show_n_begin(penum, pgs, code, pte);
179 }
180 
181 /* charpath[_n] */
182 int
gs_charpath_n_init(gs_show_enum * penum,gs_state * pgs,const char * str,uint size,bool stroke_path)183 gs_charpath_n_init(gs_show_enum * penum, gs_state * pgs,
184 		   const char *str, uint size, bool stroke_path)
185 {
186     gs_text_enum_t *pte;
187     int code = gs_charpath_begin(pgs, (const byte *)str, size, stroke_path,
188 				 pgs->memory, &pte);
189 
190     return show_n_begin(penum, pgs, code, pte);
191 }
192 
193 /* charboxpath[_n] */
194 int
gs_charboxpath_n_init(gs_show_enum * penum,gs_state * pgs,const char * str,uint size,bool use_boxes)195 gs_charboxpath_n_init(gs_show_enum * penum, gs_state * pgs,
196 		      const char *str, uint size, bool use_boxes)
197 {
198     gs_text_enum_t *pte;
199     int code = gs_charboxpath_begin(pgs, (const byte *)str, size, use_boxes,
200 				    pgs->memory, &pte);
201 
202     return show_n_begin(penum, pgs, code, pte);
203 }
204 
205 /* ------ Width/cache operators ------ */
206 
207 /* setcachedevice */
208 /* The elements of pw are: wx, wy, llx, lly, urx, ury. */
209 /* Note that this returns 1 if we just set up the cache device. */
210 int
gs_setcachedevice_double(gs_show_enum * penum,gs_state * pgs,const double * pw)211 gs_setcachedevice_double(gs_show_enum *penum, gs_state *pgs, const double *pw)
212 {
213     if (penum->pgs != pgs)
214 	return_error(gs_error_rangecheck);
215     return gs_text_setcachedevice((gs_text_enum_t *)penum, pw);
216 }
217 /* The _float procedure is strictly for backward compatibility. */
218 int
gs_setcachedevice_float(gs_show_enum * penum,gs_state * pgs,const float * pw)219 gs_setcachedevice_float(gs_show_enum * penum, gs_state * pgs, const float *pw)
220 {
221     double w[6];
222     int i;
223 
224     for (i = 0; i < 6; ++i)
225 	w[i] = pw[i];
226     return gs_setcachedevice_double(penum, pgs, w);
227 }
228 
229 /* setcachedevice2 */
230 /* The elements of pw2 are: w0x, w0y, llx, lly, urx, ury, w1x, w1y, vx, vy. */
231 /* Note that this returns 1 if we just set up the cache device. */
232 int
gs_setcachedevice2_double(gs_show_enum * penum,gs_state * pgs,const double * pw2)233 gs_setcachedevice2_double(gs_show_enum * penum, gs_state * pgs,
234 			  const double *pw2)
235 {
236     if (penum->pgs != pgs)
237 	return_error(gs_error_rangecheck);
238     return gs_text_setcachedevice2((gs_text_enum_t *)penum, pw2);
239 }
240 /* The _float procedure is strictly for backward compatibility. */
241 int
gs_setcachedevice2_float(gs_show_enum * penum,gs_state * pgs,const float * pw2)242 gs_setcachedevice2_float(gs_show_enum * penum, gs_state * pgs, const float *pw2)
243 {
244     double w2[10];
245     int i;
246 
247     for (i = 0; i < 10; ++i)
248 	w2[i] = pw2[i];
249     return gs_setcachedevice2_double(penum, pgs, w2);
250 }
251 
252 /* setcharwidth */
253 /* Note that this returns 1 if the current show operation is */
254 /* non-displaying (stringwidth or cshow). */
255 int
gs_setcharwidth(gs_show_enum * penum,gs_state * pgs,floatp wx,floatp wy)256 gs_setcharwidth(gs_show_enum * penum, gs_state * pgs,
257 		floatp wx, floatp wy)
258 {
259     double w[2];
260 
261     if (penum->pgs != pgs)
262 	return_error(gs_error_rangecheck);
263     w[0] = wx, w[1] = wy;
264     return gs_text_setcharwidth((gs_text_enum_t *)penum, w);
265 }
266 
267 /* ------ Enumerator ------ */
268 
269 /* Do the next step of a show (or stringwidth) operation */
270 int
gs_show_next(gs_show_enum * penum)271 gs_show_next(gs_show_enum * penum)
272 {
273     return gs_text_process((gs_text_enum_t *)penum);
274 }
275 
276 /*
277  * Return true if we only need the width from the rasterizer
278  * and can short-circuit the full rendering of the character,
279  * false if we need the actual character bits.
280  */
281 bool
gs_show_width_only(const gs_show_enum * penum)282 gs_show_width_only(const gs_show_enum * penum)
283 {
284     return gs_text_is_width_only((const gs_text_enum_t *)penum);
285 }
286 
287 /* ------ Accessors ------ */
288 
289 /* Return the current character for rendering. */
290 gs_char
gs_show_current_char(const gs_show_enum * penum)291 gs_show_current_char(const gs_show_enum * penum)
292 {
293     return gs_text_current_char((const gs_text_enum_t *)penum);
294 }
295 
296 /* Return the current glyph for rendering. */
297 gs_glyph
gs_show_current_glyph(const gs_show_enum * penum)298 gs_show_current_glyph(const gs_show_enum * penum)
299 {
300     return gs_text_current_glyph((const gs_text_enum_t *)penum);
301 }
302 
303 /* Return the width of the just-enumerated character (for cshow). */
304 int
gs_show_current_width(const gs_show_enum * penum,gs_point * ppt)305 gs_show_current_width(const gs_show_enum * penum, gs_point * ppt)
306 {
307     return gs_text_current_width((const gs_text_enum_t *)penum, ppt);
308 }
309 
310 /* Return the just-displayed character for kerning. */
311 gs_char
gs_kshow_previous_char(const gs_show_enum * penum)312 gs_kshow_previous_char(const gs_show_enum * penum)
313 {
314     return gs_text_current_char((const gs_text_enum_t *)penum);
315 }
316 
317 /* Return the about-to-be-displayed character for kerning. */
318 gs_char
gs_kshow_next_char(const gs_show_enum * penum)319 gs_kshow_next_char(const gs_show_enum * penum)
320 {
321     return penum->text.data.bytes[penum->index];
322 }
323 
324 /* Return the accumulated width for stringwidth. */
325 void
gs_show_width(const gs_show_enum * penum,gs_point * ppt)326 gs_show_width(const gs_show_enum * penum, gs_point * ppt)
327 {
328     gs_text_total_width((const gs_text_enum_t *)penum, ppt);
329 }
330 
331 /* ------ Internal routines ------ */
332 
333 /*
334  * Force the enumerator to be a gs_show_enum *, which the current
335  * implementation code requires.
336  */
337 static int
show_n_begin(gs_show_enum * penum,gs_state * pgs,int code,gs_text_enum_t * pte)338 show_n_begin(gs_show_enum *penum, gs_state *pgs, int code, gs_text_enum_t *pte)
339 {
340     if (code < 0)
341 	return code;
342     if (gs_object_type(pgs->memory, pte) != &st_gs_show_enum) {
343 	/* Use the default implementation. */
344 	gx_device *dev = pgs->device;
345 	gs_text_params_t text;
346 	gs_memory_t *mem = pte->memory;
347 	dev_proc_text_begin((*text_begin)) = dev_proc(dev, text_begin);
348 
349 	text = pte->text;
350 	gs_text_release(pte, "show_n_begin");
351 	/* Temporarily reset the text_begin procedure to the default. */
352 	set_dev_proc(dev, text_begin, gx_default_text_begin);
353 	code = gs_text_begin(pgs, &text, mem, &pte);
354 	set_dev_proc(dev, text_begin, text_begin);
355 	if (code < 0)
356 	    return code;
357     }
358     /* Now we know pte points to a gs_show_enum. */
359     *penum = *(gs_show_enum *)pte;
360     gs_free_object(pgs->memory, pte, "show_n_begin");
361     return code;
362 }
363