xref: /plan9/sys/src/cmd/gs/src/zcharout.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1996, 1997, 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: zcharout.c,v 1.13 2004/09/22 13:52:33 igor Exp $ */
18 /* Common code for outline (Type 1 / 4 / 42) fonts */
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "gscrypt1.h"
23 #include "gstext.h"
24 #include "gxdevice.h"		/* for gxfont.h */
25 #include "gxfont.h"
26 #include "gxfont1.h"
27 #include "dstack.h"		/* only for systemdict */
28 #include "estack.h"
29 #include "ichar.h"
30 #include "icharout.h"
31 #include "idict.h"
32 #include "ifont.h"
33 #include "igstate.h"
34 #include "iname.h"
35 #include "store.h"
36 
37 /*
38  * Execute an outline defined by a PostScript procedure.
39  * The top elements of the stack are:
40  *      <font> <code|name> <name> <outline_id>
41  */
42 int
zchar_exec_char_proc(i_ctx_t * i_ctx_p)43 zchar_exec_char_proc(i_ctx_t *i_ctx_p)
44 {
45     os_ptr op = osp;
46 	/*
47 	 * The definition is a PostScript procedure.  Execute
48 	 *      <code|name> proc
49 	 * within a systemdict begin/end and a font begin/end.
50 	 */
51     es_ptr ep;
52 
53     check_estack(5);
54     ep = esp += 5;
55     make_op_estack(ep - 4, zend);
56     make_op_estack(ep - 3, zend);
57     ref_assign(ep - 2, op);
58     make_op_estack(ep - 1, zbegin);
59     make_op_estack(ep, zbegin);
60     ref_assign(op - 1, systemdict);
61     {
62 	ref rfont;
63 
64 	ref_assign(&rfont, op - 3);
65 	ref_assign(op - 3, op - 2);
66 	ref_assign(op - 2, &rfont);
67     }
68     pop(1);
69     return o_push_estack;
70 }
71 
72 /*
73  * Get the metrics for a character from the Metrics dictionary of a base
74  * font.  If present, store the l.s.b. in psbw[0,1] and the width in
75  * psbw[2,3].
76  */
77 int				/*metrics_present*/
zchar_get_metrics(const gs_font_base * pbfont,const ref * pcnref,double psbw[4])78 zchar_get_metrics(const gs_font_base * pbfont, const ref * pcnref,
79 		  double psbw[4])
80 {
81     const ref *pfdict = &pfont_data(gs_font_parent(pbfont))->dict;
82     ref *pmdict;
83 
84     if (dict_find_string(pfdict, "Metrics", &pmdict) > 0) {
85 	ref *pmvalue;
86 
87 	check_type_only(*pmdict, t_dictionary);
88 	check_dict_read(*pmdict);
89 	if (dict_find(pmdict, pcnref, &pmvalue) > 0) {
90 	    if (num_params(pmvalue, 1, psbw + 2) >= 0) {	/* <wx> only */
91 		psbw[3] = 0;
92 		return metricsWidthOnly;
93 	    } else {
94 		int code;
95 
96 		check_read_type_only(*pmvalue, t_array);
97 		switch (r_size(pmvalue)) {
98 		    case 2:	/* [<sbx> <wx>] */
99 			code = num_params(pmvalue->value.refs + 1,
100 					  2, psbw);
101 			psbw[2] = psbw[1];
102 			psbw[1] = psbw[3] = 0;
103 			break;
104 		    case 4:	/* [<sbx> <sby> <wx> <wy>] */
105 			code = num_params(pmvalue->value.refs + 3,
106 					  4, psbw);
107 			break;
108 		    default:
109 			return_error(e_rangecheck);
110 		}
111 		if (code < 0)
112 		    return code;
113 		return metricsSideBearingAndWidth;
114 	    }
115 	}
116     }
117     return metricsNone;
118 }
119 
120 /* Get the vertical metrics for a character from Metrics2, if present. */
121 int
zchar_get_metrics2(const gs_font_base * pbfont,const ref * pcnref,double pwv[4])122 zchar_get_metrics2(const gs_font_base * pbfont, const ref * pcnref,
123 		   double pwv[4])
124 {
125     const ref *pfdict = &pfont_data(gs_font_parent(pbfont))->dict;
126     ref *pmdict;
127 
128     if (dict_find_string(pfdict, "Metrics2", &pmdict) > 0) {
129 	ref *pmvalue;
130 
131 	check_type_only(*pmdict, t_dictionary);
132 	check_dict_read(*pmdict);
133 	if (dict_find(pmdict, pcnref, &pmvalue) > 0) {
134 	    check_read_type_only(*pmvalue, t_array);
135 	    if (r_size(pmvalue) == 4) {
136 		int code = num_params(pmvalue->value.refs + 3, 4, pwv);
137 
138 		return (code < 0 ? code : metricsSideBearingAndWidth);
139 	    }
140 	}
141     }
142     return metricsNone;
143 }
144 
145 /*
146  * Get CDevProc.
147  */
148 bool
zchar_get_CDevProc(const gs_font_base * pbfont,ref ** ppcdevproc)149 zchar_get_CDevProc(const gs_font_base * pbfont, ref **ppcdevproc)
150 {
151     const ref *pfdict = &pfont_data(gs_font_parent(pbfont))->dict;
152 
153     return dict_find_string(pfdict, "CDevProc", ppcdevproc) > 0;
154 }
155 
156 /*
157  * Consult Metrics2 and CDevProc, and call setcachedevice[2].  Return
158  * o_push_estack if we had to call a CDevProc, or if we are skipping the
159  * rendering process (only getting the metrics).
160  * Returns exec_cont - a function, which must be called by caller after this function.
161  */
162 int
zchar_set_cache(i_ctx_t * i_ctx_p,const gs_font_base * pbfont,const ref * pcnref,const double psb[2],const double pwidth[2],const gs_rect * pbbox,op_proc_t cont,op_proc_t * exec_cont,const double Metrics2_sbw_default[4])163 zchar_set_cache(i_ctx_t *i_ctx_p, const gs_font_base * pbfont,
164 		const ref * pcnref, const double psb[2],
165 		const double pwidth[2], const gs_rect * pbbox,
166 		op_proc_t cont, op_proc_t *exec_cont,
167 		const double Metrics2_sbw_default[4])
168 {
169     os_ptr op = osp;
170     ref *pcdevproc;
171     int have_cdevproc;
172     ref rpop;
173     bool metrics2;
174     bool metrics2_use_default = false;
175     double w2[10];
176     gs_text_enum_t *penum = op_show_find(i_ctx_p);
177 
178     w2[0] = pwidth[0], w2[1] = pwidth[1];
179 
180     /* Adjust the bounding box for stroking if needed. */
181 
182     w2[2] = pbbox->p.x, w2[3] = pbbox->p.y;
183     w2[4] = pbbox->q.x, w2[5] = pbbox->q.y;
184     if (pbfont->PaintType != 0) {
185 	double expand = max(1.415, gs_currentmiterlimit(igs)) *
186 	gs_currentlinewidth(igs) / 2;
187 
188 	w2[2] -= expand, w2[3] -= expand;
189 	w2[4] += expand, w2[5] += expand;
190     }
191 
192     /* Check for Metrics2. */
193 
194     {
195 	int code = zchar_get_metrics2(pbfont, pcnref, w2 + 6);
196 
197 	if (code < 0)
198 	    return code;
199 	metrics2 = code > 0;
200     }
201 
202     /*
203      * For FontType 9 and 11, if Metrics2 is missing, the caller provides
204      * default Metrics2 values derived from the FontBBox.
205      */
206     if (!metrics2 && Metrics2_sbw_default != NULL) {
207         w2[6] = Metrics2_sbw_default[2];
208         w2[7] = Metrics2_sbw_default[3];
209         w2[8] = Metrics2_sbw_default[0];
210         w2[9] = Metrics2_sbw_default[1];
211 	metrics2 = true;
212 	metrics2_use_default = true;
213     }
214 
215     /* Check for CDevProc or "short-circuiting". */
216 
217     have_cdevproc = zchar_get_CDevProc(pbfont, &pcdevproc);
218     if (have_cdevproc || zchar_show_width_only(penum)) {
219 	int i;
220 	op_proc_t zsetc;
221 	int nparams;
222 
223 	if (have_cdevproc) {
224 	    check_proc_only(*pcdevproc);
225 	    zsetc = zsetcachedevice2;
226 
227 	    /* If we have cdevproc and the font type is CID type 0,
228 	       we'll throw away Metrics2_sbw_default that is calculated
229 	       from FontBBox. */
230 	    if (!metrics2
231 		|| (penum->current_font->FontType == ft_CID_encrypted
232 		    && metrics2_use_default)) {
233 		w2[6] = w2[0], w2[7] = w2[1];
234 		w2[8] = w2[9] = 0;
235 	    }
236 	    nparams = 10;
237 	} else {
238 	    make_oper(&rpop, 0, zpop);
239 	    pcdevproc = &rpop;
240 	    if (metrics2)
241 		zsetc = zsetcachedevice2, nparams = 10;
242 	    else
243 		zsetc = zsetcachedevice, nparams = 6;
244 	}
245 	check_estack(3);
246 	/* Push the l.s.b. for .type1addpath if necessary. */
247 	if (psb != 0) {
248 	    push(nparams + 3);
249 	    make_real(op - (nparams + 2), psb[0]);
250 	    make_real(op - (nparams + 1), psb[1]);
251 	} else {
252 	    push(nparams + 1);
253 	}
254 	for (i = 0; i < nparams; ++i)
255 	    make_real(op - nparams + i, w2[i]);
256 	ref_assign(op, pcnref);
257 	push_op_estack(cont);
258 	push_op_estack(zsetc);
259 	++esp;
260 	ref_assign(esp, pcdevproc);
261 	return o_push_estack;
262     } {
263 	int code =
264 	    (metrics2 ? gs_text_setcachedevice2(penum, w2) :
265 	     gs_text_setcachedevice(penum, w2));
266 
267 	if (code < 0)
268 	    return code;
269     }
270 
271     /* No metrics modification, do the stroke or fill now. */
272 
273     /* Push the l.s.b. for .type1addpath if necessary. */
274     if (psb != 0) {
275 	push(2);
276 	make_real(op - 1, psb[0]);
277 	make_real(op, psb[1]);
278     }
279     *exec_cont = cont;
280     return 0;
281 }
282 
283 /*
284  * Get the CharString data corresponding to a glyph.  Return typecheck
285  * if it isn't a string.
286  */
287 private bool charstring_is_notdef_proc(const gs_memory_t *mem, const ref *);
288 private int charstring_make_notdef(gs_glyph_data_t *, gs_font *);
289 int
zchar_charstring_data(gs_font * font,const ref * pgref,gs_glyph_data_t * pgd)290 zchar_charstring_data(gs_font *font, const ref *pgref, gs_glyph_data_t *pgd)
291 {
292     ref *pcstr;
293 
294     if (dict_find(&pfont_data(font)->CharStrings, pgref, &pcstr) <= 0)
295 	return_error(e_undefined);
296     if (!r_has_type(pcstr, t_string)) {
297 	/*
298 	 * The ADOBEPS4 Windows driver replaces the .notdef entry of
299 	 * otherwise normal Type 1 fonts with the procedure
300 	 *	{pop 0 0 setcharwidth}
301 	 * To prevent this from making the font unembeddable in PDF files
302 	 * (with our present font-writing code), we recognize this as a
303 	 * special case and return a Type 1 CharString consisting of
304 	 *	0 0 hsbw endchar
305 	 */
306 	if (font->FontType == ft_encrypted &&
307 	    charstring_is_notdef_proc(font->memory, pcstr)
308 	    )
309 	    return charstring_make_notdef(pgd, font);
310 	else
311 	    return_error(e_typecheck);
312     }
313     gs_glyph_data_from_string(pgd, pcstr->value.const_bytes, r_size(pcstr),
314 			      NULL);
315     return 0;
316 }
317 private bool
charstring_is_notdef_proc(const gs_memory_t * mem,const ref * pcstr)318 charstring_is_notdef_proc(const gs_memory_t *mem, const ref *pcstr)
319 {
320     if (r_is_array(pcstr) && r_size(pcstr) == 4) {
321 	ref elts[4];
322 	long i;
323 
324 	for (i = 0; i < 4; ++i)
325 	    array_get(mem, pcstr, i, &elts[i]);
326 	if (r_has_type(&elts[0], t_name) &&
327 	    r_has_type(&elts[1], t_integer) && elts[1].value.intval == 0 &&
328 	    r_has_type(&elts[2], t_integer) && elts[2].value.intval == 0 &&
329 	    r_has_type(&elts[3], t_name)
330 	    ) {
331 	    ref nref;
332 
333 	    name_enter_string(mem, "pop", &nref);
334 	    if (name_eq(&elts[0], &nref)) {
335 	        name_enter_string(mem, "setcharwidth", &nref);
336 		if (name_eq(&elts[3], &nref))
337 		    return true;
338 	    }
339 	}
340     }
341     return false;
342 }
343 private int
charstring_make_notdef(gs_glyph_data_t * pgd,gs_font * font)344 charstring_make_notdef(gs_glyph_data_t *pgd, gs_font *font)
345 {
346     gs_font_type1 *const pfont = (gs_font_type1 *)font;
347     static const byte char_data[4] = {
348 	139,			/* 0 */
349 	139,			/* 0 */
350 	c1_hsbw,
351 	cx_endchar
352     };
353     uint len = max(pfont->data.lenIV, 0) + sizeof(char_data);
354     byte *chars = gs_alloc_string(font->memory, len, "charstring_make_notdef");
355 
356     if (chars == 0)
357 	return_error(e_VMerror);
358     gs_glyph_data_from_string(pgd, chars, len, font);
359     if (pfont->data.lenIV < 0)
360 	memcpy(chars, char_data, sizeof(char_data));
361     else {
362 	crypt_state state = crypt_charstring_seed;
363 
364 	memcpy(chars + pfont->data.lenIV, char_data, sizeof(char_data));
365 	gs_type1_encrypt(chars, chars, len, &state);
366     }
367     return 0;
368 }
369 
370 /*
371  * Enumerate the next glyph from a directory.  This is essentially a
372  * wrapper around dict_first/dict_next to implement the enumerate_glyph
373  * font procedure.
374  *
375  * Note that *prdict will be null if the font is a subfont of a
376  * CIDFontType 0 CIDFont.
377  */
378 int
zchar_enumerate_glyph(const gs_memory_t * mem,const ref * prdict,int * pindex,gs_glyph * pglyph)379 zchar_enumerate_glyph(const gs_memory_t *mem, const ref *prdict, int *pindex, gs_glyph *pglyph)
380 {
381     int index = *pindex - 1;
382     ref elt[2];
383 
384     if (!r_has_type(prdict, t_dictionary))
385 	return 0;		/* *pindex was 0, is still 0 */
386     if (index < 0)
387 	index = dict_first(prdict);
388 next:
389     index = dict_next(prdict, index, elt);
390     *pindex = index + 1;
391     if (index >= 0) {
392 	switch (r_type(elt)) {
393 	    case t_integer:
394 		*pglyph = gs_min_cid_glyph + elt[0].value.intval;
395 		break;
396 	    case t_name:
397 	        *pglyph = name_index(mem, elt);
398 		break;
399 	    default:		/* can't handle it */
400 		goto next;
401 	}
402     }
403     return 0;
404 }
405