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