386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / zchar.c
CommitLineData
3134ed76
WJ
1/* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
19
20/* zchar.c */
21/* Character operators for Ghostscript */
22#include "ghost.h"
23#include "errors.h"
24#include "oper.h"
25#include "gxfixed.h" /* for gstype1.h */
26#include "gxmatrix.h" /* for font.h */
27#include "gschar.h"
28#include "gstype1.h"
29#include "gxdevice.h" /* for gxfont.h */
30#include "gxfont.h"
31#include "gzpath.h" /* for type1addpath: see below */
32#include "gzstate.h"
33#include "alloc.h"
34#include "dict.h"
35#include "dstack.h" /* for systemdict */
36#include "font.h"
37#include "estack.h"
38#include "state.h"
39#include "store.h"
40
41/* All the character rendering operators use the execution stack */
42/* for loop control -- see estack.h for details. */
43/* The information pushed by these operators is as follows: */
44/* the enumerator (t_string, but points to a gs_show_enum); */
45/* a slot for the procedure for kshow, unused otherwise; */
46/* the procedure to be called at the end of the enumeration */
47/* (t_operator, but called directly, not by the interpreter); */
48/* the usual e-stack mark (t_null). */
49#define snumpush 4
50#define senum (gs_show_enum *)(esp->value.bytes)
51#define sslot esp[-1]
52#define seproc esp[-2]
53
54/* Imports */
55extern int array_get(P3(ref *, long, ref *));
56extern ref name_StandardEncoding;
57
58/* Forward references */
59private int setup_show(P3(ref *, op_proc_p, int));
60private int show_continue(P1(os_ptr));
61private int i_show_continue;
62private int finish_show(P1(os_ptr));
63private int i_finish_show;
64private int finish_stringwidth(P1(os_ptr));
65private int i_finish_stringwidth;
66private gs_show_enum *find_show(P0());
67private void free_show(P0());
68
69/* show */
70int
71zshow(register os_ptr op)
72{ int code = setup_show(op, finish_show, i_finish_show);
73 if ( code < 0 ) return code;
74 if ( (code = gs_show_n_init(senum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
75 { free_show();
76 return code;
77 }
78 pop(1); op--;
79 return show_continue(op);
80}
81
82/* ashow */
83int
84zashow(register os_ptr op)
85{ int code;
86 float axy[2];
87 if ( (code = num_params(op - 1, 2, axy)) < 0 ||
88 (code = setup_show(op, finish_show, i_finish_show)) < 0
89 )
90 return code;
91 if ( (code = gs_ashow_n_init(senum, igs, axy[0], axy[1], (char *)op->value.bytes, r_size(op))) < 0 )
92 { free_show();
93 return code;
94 }
95 pop(3); op -= 3;
96 return show_continue(op);
97}
98
99/* widthshow */
100int
101zwidthshow(register os_ptr op)
102{ int code;
103 float cxy[2];
104 check_type(op[-1], t_integer);
105 if ( (ulong)(op[-1].value.intval) > 255 ) return e_rangecheck;
106 if ( (code = num_params(op - 2, 2, cxy)) < 0 ||
107 (code = setup_show(op, finish_show, i_finish_show)) < 0
108 )
109 return code;
110 if ( (code = gs_widthshow_n_init(senum, igs, cxy[0], cxy[1],
111 (char)op[-1].value.intval,
112 (char *)op->value.bytes,
113 r_size(op))) < 0 )
114 { free_show();
115 return code;
116 }
117 pop(4); op -= 4;
118 return show_continue(op);
119}
120
121/* awidthshow */
122int
123zawidthshow(register os_ptr op)
124{ int code;
125 float cxy[2], axy[2];
126 check_type(op[-3], t_integer);
127 if ( (ulong)(op[-3].value.intval) > 255 ) return e_rangecheck;
128 if ( (code = num_params(op - 4, 2, cxy)) < 0 ||
129 (code = num_params(op - 1, 2, axy)) < 0 ||
130 (code = setup_show(op, finish_show, i_finish_show)) < 0
131 )
132 return code;
133 if ( (code = gs_awidthshow_n_init(senum, igs, cxy[0], cxy[1],
134 (char)op[-3].value.intval,
135 axy[0], axy[1],
136 (char *)op->value.bytes,
137 r_size(op))) < 0 )
138 { free_show();
139 return code;
140 }
141 pop(6); op -= 6;
142 return show_continue(op);
143}
144
145/* kshow */
146int
147zkshow(register os_ptr op)
148{ int code;
149 check_proc(op[-1]);
150 if ( (code = setup_show(op, finish_show, i_finish_show)) < 0 ) return code;
151 if ( (code = gs_kshow_n_init(senum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
152 { free_show();
153 return code;
154 }
155 sslot = op[-1]; /* save kerning proc */
156 pop(2); op -= 2;
157 return show_continue(op);
158}
159
160/* Common finish procedure for all show operations. */
161/* Doesn't have to do anything. */
162private int
163finish_show(os_ptr op)
164{ return 0;
165}
166
167/* stringwidth */
168int
169zstringwidth(register os_ptr op)
170{ int code = setup_show(op, finish_stringwidth, i_finish_stringwidth);
171 if ( code < 0 ) return code;
172 if ( (code = gs_stringwidth_n_init(senum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
173 { free_show();
174 return code;
175 }
176 pop(1); op--;
177 return show_continue(op);
178}
179/* Finishing procedure for stringwidth. */
180/* Pushes the accumulated width. */
181private int
182finish_stringwidth(register os_ptr op)
183{ gs_point width;
184 gs_show_width(senum, &width);
185 push(2);
186 make_real(op - 1, width.x);
187 make_real(op, width.y);
188 return 0;
189}
190
191/* charpath */
192int
193zcharpath(register os_ptr op)
194{ int code;
195 check_type(*op, t_boolean);
196 code = setup_show(op - 1, finish_show, i_finish_show);
197 if ( code < 0 ) return code;
198 if ( (code = gs_charpath_n_init(senum, igs, (char *)op[-1].value.bytes, r_size(op - 1), op->value.index)) < 0 )
199 { free_show();
200 return code;
201 }
202 pop(2); op -= 2;
203 return show_continue(op);
204}
205
206/* setcachedevice */
207int
208zsetcachedevice(register os_ptr op)
209{ float wbox[6];
210 int npop = 6;
211 gs_show_enum *penum = find_show();
212 int code = num_params(op, 6, wbox);
213 if ( penum == 0 ) return e_undefined;
214 if ( code < 0 )
215 { /* P*stScr*pt implementations apparently allow the */
216 /* bounding box to be specified as a 4-element array. */
217 /* Check for this here. */
218 check_array(*op);
219 if ( r_size(op) != 4 ||
220 num_params(op - 1, 2, wbox) < 0 ||
221 num_params(op->value.refs + 3, 4, wbox + 2) < 0
222 )
223 return code;
224 npop = 3;
225 }
226 if ( (code = gs_setcachedevice(penum, igs, wbox[0], wbox[1], wbox[2], wbox[3], wbox[4], wbox[5])) < 0 )
227 return code;
228 pop(npop);
229 return 0;
230}
231
232/* setcharwidth */
233int
234zsetcharwidth(register os_ptr op)
235{ float width[2];
236 gs_show_enum *penum = find_show();
237 int code = num_params(op, 2, width);
238 if ( penum == 0 ) return e_undefined;
239 if ( code < 0 ||
240 (code = gs_setcharwidth(penum, igs, width[0], width[1])) < 0
241 )
242 return code;
243 pop(2);
244 return 0;
245}
246
247/* setmetrics */
248int
249zsetmetrics(register os_ptr op)
250{ float params[4];
251 gs_point sb, w;
252 gs_show_enum *penum = find_show();
253 int code, size;
254 if ( penum == 0 ) return e_undefined;
255 switch ( r_type(op) )
256 {
257 case t_array:
258 switch ( (size = r_size(op)) )
259 {
260 case 2: case 4: break;
261 default: return e_invalidfont;
262 }
263 code = num_params(op->value.refs + size - 1, size, params);
264 if ( code < 0 ) return code;
265 sb.x = params[0];
266 if ( size == 4 )
267 sb.y = params[1], w.x = params[2], w.y = params[3];
268 else
269 sb.y = 0, w.x = params[1], w.y = 0;
270 code = gs_setmetrics(penum, igs, &sb, &w);
271 break;
272 default:
273 code = real_param(op, params);
274 if ( code < 0 ) return code;
275 w.x = params[0];
276 w.y = 0;
277 code = gs_setmetrics(penum, igs, 0, &w);
278 }
279 if ( code >= 0 ) pop(1);
280 return code;
281}
282
283/* type1addpath */
284typedef struct {
285 gs_font *pfont;
286 fixed *osptr; /* fake interpreter operand stack */
287 fixed ostack[2];
288} z1_data;
289int
290ztype1addpath(register os_ptr op)
291{ int code, value;
292 gs_show_enum *penum = find_show();
293 gs_font *pfont = gs_currentfont(igs);
294 font_data *pfdata = (font_data *)pfont->client_data;
295 gs_type1_state *pis;
296 fixed discard;
297 gs_fixed_point spt, ept;
298 int flex_path_was_open;
299 gs_type1_data tdata;
300 z1_data zdata;
301 byte *charstring = 0;
302 ref enc_entry;
303 if ( penum == 0 ) return e_undefined;
304 check_type(*op, t_string);
305 tdata = pfont->data.base.type1_data;
306 zdata.pfont = pfont;
307 zdata.osptr = zdata.ostack;
308 tdata.proc_data = (char *)&zdata;
309 if ( r_size(op) <= tdata.lenIV )
310 { /* String is empty, or too short. Just ignore it. */
311 pop(1);
312 return 0;
313 }
314 pis = (gs_type1_state *)alloc(1, gs_type1_state_sizeof, "type1addpath");
315 if ( pis == 0 ) return e_VMerror;
316 code = gs_type1_init(pis, penum,
317 gs_show_in_charpath(penum), tdata.PaintType,
318 &tdata);
319 if ( code < 0 )
320 { alloc_free((char *)pis, 1, gs_type1_state_sizeof, "type1addpath");
321 return code;
322 }
323 charstring = op->value.bytes;
324more: code = gs_type1_interpret(pis, charstring, &value);
325 charstring = 0;
326 switch ( code )
327 {
328 case type1_result_seac:
329 { ref *pstdenc, *pcstr;
330 if ( dict_find(&systemdict,
331 &name_StandardEncoding, &pstdenc) <= 0 )
332 return e_undefined;
333 code = array_get(pstdenc, (long)value, &enc_entry);
334 if ( code < 0 ) return code;
335 if ( dict_find(&pfdata->CharStrings,
336 &enc_entry, &pcstr) <= 0 )
337 return e_undefined;
338 if ( !r_has_type(pcstr, t_string) )
339 return e_invalidfont;
340 charstring = pcstr->value.bytes;
341 } goto more;
342 case type1_result_callothersubr:
343 { /* We aren't prepared to call the interpreter here, */
344 /* so we fake the Flex feature. */
345 gx_path *ppath = igs->path;
346 gs_type1_pop(pis, &discard); /* pop # of args */
347 switch ( value )
348 {
349 case 0:
350 /* We have to do something really sleazy here, */
351 /* namely, make it look as though the rmovetos */
352 /* never really happened, because we don't want */
353 /* to interrupt the current subpath. */
354 gx_path_current_point(ppath, &ept);
355 gx_path_add_point(ppath, spt.x, spt.y);
356 ppath->subpath_open = flex_path_was_open;
357 /* ^--- sleaze */
358 gx_path_add_line(ppath, ept.x, ept.y);
359 /* Transfer endpoint coordinates to 'ostack' */
360 gs_type1_pop(pis, &zdata.ostack[0]);
361 gs_type1_pop(pis, &zdata.ostack[1]);
362 gs_type1_pop(pis, &discard);
363 zdata.osptr = &zdata.ostack[2];
364 goto more;
365 case 1:
366 gx_path_current_point(ppath, &spt);
367 flex_path_was_open = ppath->subpath_open;
368 /* ^--- more sleaze */
369 goto more;
370 case 2:
371 goto more;
372 case 3:
373 gs_type1_pop(pis, &discard); /* pop subr# */
374 zdata.ostack[0] = int2fixed(3);
375 zdata.osptr = &zdata.ostack[1];
376 goto more;
377 }
378 /* Unrecognized othersubr */
379 code = e_rangecheck;
380 } break;
381 }
382 alloc_free((char *)pis, 1, gs_type1_state_sizeof, "type1addpath");
383 if ( code >= 0 ) pop(1);
384 return code;
385}
386
387/* type1imagepath */
388int
389ztype1imagepath(register os_ptr op)
390{ float woxy[4];
391 int code;
392 check_type(op[-7], t_string);
393 check_type(op[-6], t_integer);
394 check_type(op[-5], t_integer);
395 if ( (code = num_params(op - 1, 4, woxy)) < 0 ) return code;
396 check_write_type(*op, t_string);
397 code = gs_type1imagepath(igs, op[-7].value.bytes,
398 (int)op[-6].value.intval, (int)op[-5].value.intval,
399 woxy[0], woxy[1], woxy[2], woxy[3],
400 op->value.bytes, r_size(op));
401 if ( code < 0 ) return code;
402 op[-7] = *op;
403 r_set_size(op - 7, code);
404 pop(7);
405 return 0;
406}
407
408/* ------ Auxiliary procedures for type 1 fonts ------ */
409
410int
411z1_subr_proc(gs_type1_data *pdata, int index, byte **pstr)
412{ gs_font *pfont = ((z1_data *)(pdata->proc_data))->pfont;
413 font_data *pfdata = (font_data *)(pfont->client_data);
414 ref *psubr;
415 if ( index < 0 || index >= r_size(&pfdata->Subrs) )
416 return e_rangecheck;
417 psubr = pfdata->Subrs.value.refs + index;
418 check_type(*psubr, t_string);
419 *pstr = psubr->value.bytes;
420 return 0;
421}
422
423int
424z1_pop_proc(gs_type1_data *pdata, fixed *pf)
425{ *pf = *--(((z1_data *)(pdata->proc_data))->osptr);
426 return 0;
427}
428
429/* ------ Initialization procedure ------ */
430
431op_def zchar_op_defs[] = {
432 {"3ashow", zashow},
433 {"6awidthshow", zawidthshow},
434 {"2charpath", zcharpath},
435 {"2kshow", zkshow},
436 {"3setcachedevice", zsetcachedevice},
437 {"2setcharwidth", zsetcharwidth},
438 {"1.setmetrics", zsetmetrics},
439 {"1show", zshow},
440 {"1stringwidth", zstringwidth},
441 {"1type1addpath", ztype1addpath},
442 {"8type1imagepath", ztype1imagepath},
443 {"4widthshow", zwidthshow},
444 /* Internal operators */
445 {"0%finish_show", finish_show, &i_finish_show},
446 {"0%finish_stringwidth", finish_stringwidth, &i_finish_stringwidth},
447 {"0%show_continue", show_continue, &i_show_continue},
448 op_def_end(0)
449};
450
451/* ------ Internal routines ------ */
452
453/* Set up for a show operator. */
454/* The top stack element must be the string to be scanned. */
455/* The caller has already done all other argument checking. */
456private int
457setup_show(ref *op, op_proc_p endproc /* end procedure */, int proc_index)
458{ gs_show_enum *penum;
459 check_read_type(*op, t_string);
460 check_estack(snumpush + 2);
461 if ( (penum = (gs_show_enum *)alloc(1, gs_show_enum_sizeof, "setup_show")) == 0 )
462 return e_VMerror;
463 mark_estack(es_show);
464 push_op_estack(endproc, proc_index);
465 ++esp;
466 make_tv(esp, t_null, index, 0); /* reserve slot */
467 ++esp;
468 make_tasv(esp, t_string, 0, gs_show_enum_sizeof, bytes, (byte *)penum);
469 return o_push_estack;
470}
471
472/* Continuation operator for character rendering. */
473private int
474show_continue(register os_ptr op)
475{ gs_show_enum *penum = senum;
476 int code = gs_show_next(penum);
477 switch ( code )
478 {
479 case 0: /* all done */
480 code = (*real_opproc(&seproc))(op);
481 free_show();
482 return (code >= 0 ? o_pop_estack : code);
483 case gs_show_kern:
484 { ref *pslot = &sslot;
485 push(2);
486 make_int(op - 1, gs_kshow_previous_char(penum));
487 make_int(op, gs_kshow_next_char(penum));
488 push_op_estack(show_continue, i_show_continue); /* continue after kerning */
489 *++esp = *pslot; /* kerning procedure */
490 }
491 return o_push_estack;
492 case gs_show_render:
493 { font_data *pfont = (font_data *)gs_currentfont(igs)->client_data;
494 push(2);
495 op[-1] = pfont->dict; /* push the font */
496 make_int(op, gs_show_current_char(penum));
497 push_op_estack(show_continue, i_show_continue);
498 *++esp = pfont->BuildChar;
499 }
500 return o_push_estack;
501 default: /* error */
502 free_show();
503 return code;
504 }
505}
506
507/* Find the current show enumerator on the e-stack. */
508private gs_show_enum *
509find_show()
510{ es_ptr ep = esp;
511 while ( !(r_has_type(ep, t_null) && ep->value.index == es_show) )
512 { if ( --ep < esbot ) return 0; /* no mark */
513 }
514 return (gs_show_enum *)ep[snumpush - 1].value.bytes;
515}
516
517/* Discard the show record (after an error, or at the end). */
518private void
519free_show()
520{ alloc_free((char *)senum, 1, gs_show_enum_sizeof, "free_show");
521 esp -= snumpush;
522}