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