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: zfont0.c 9043 2008-08-28 22:48:19Z giles $ */
15 /* Composite font creation operator */
16 #include "ghost.h"
17 #include "oper.h"
18 #include "gsstruct.h"
19 /*
20  * The following lines used to say:
21  *      #include "gsmatrix.h"
22  *      #include "gxdevice.h"           /. for gxfont.h ./
23  * Tony Li says the longer list is necessary to keep the GNU compiler
24  * happy, but this is pretty hard to understand....
25  */
26 #include "gxfixed.h"
27 #include "gxmatrix.h"
28 #include "gzstate.h"		/* must precede gxdevice */
29 #include "gxdevice.h"		/* must precede gxfont */
30 #include "gxfcmap.h"
31 #include "gxfont.h"
32 #include "gxfont0.h"
33 #include "bfont.h"
34 #include "ialloc.h"
35 #include "iddict.h"
36 #include "idparam.h"
37 #include "igstate.h"
38 #include "iname.h"
39 #include "store.h"
40 
41 /* Imported from zfcmap.c */
42 int ztype0_get_cmap(const gs_cmap_t ** ppcmap, const ref * pfdepvector,
43 		    const ref * op, gs_memory_t *imem);
44 
45 /* Forward references */
46 static font_proc_define_font(ztype0_define_font);
47 static font_proc_make_font(ztype0_make_font);
48 static int ensure_char_entry(i_ctx_t *, os_ptr, const char *, byte *, int);
49 
50 /* <string|name> <font_dict> .buildfont0 <string|name> <font> */
51 /* Build a type 0 (composite) font. */
52 static int
zbuildfont0(i_ctx_t * i_ctx_p)53 zbuildfont0(i_ctx_t *i_ctx_p)
54 {
55     os_ptr op = osp;
56     gs_type0_data data;
57     ref fdepvector;
58     ref *pprefenc;
59     gs_font_type0 *pfont;
60     font_data *pdata;
61     ref save_FID;
62     int i;
63     int code = 0;
64 
65     check_type(*op, t_dictionary);
66     {
67 	ref *pfmaptype;
68 	ref *pfdepvector;
69 
70 	if (dict_find_string(op, "FMapType", &pfmaptype) <= 0 ||
71 	    !r_has_type(pfmaptype, t_integer) ||
72 	    pfmaptype->value.intval < (int)fmap_type_min ||
73 	    pfmaptype->value.intval > (int)fmap_type_max ||
74 	    dict_find_string(op, "FDepVector", &pfdepvector) <= 0 ||
75 	    !r_is_array(pfdepvector)
76 	    )
77 	    return_error(e_invalidfont);
78 	data.FMapType = (fmap_type) pfmaptype->value.intval;
79 	/*
80 	 * Adding elements below could cause the font dictionary to be
81 	 * resized, which would invalidate pfdepvector.
82 	 */
83 	fdepvector = *pfdepvector;
84     }
85     /* Check that every element of the FDepVector is a font. */
86     data.fdep_size = r_size(&fdepvector);
87     for (i = 0; i < data.fdep_size; i++) {
88 	ref fdep;
89 	gs_font *psub;
90 
91 	array_get(imemory, &fdepvector, i, &fdep);
92 	if ((code = font_param(&fdep, &psub)) < 0)
93 	    return code;
94 	/*
95 	 * Check the inheritance rules.  Allowed configurations
96 	 * (paths from root font) are defined by the regular
97 	 * expression:
98 	 *      (shift | double_escape escape* | escape*)
99 	 *        non_modal* non_composite
100 	 */
101 	if (psub->FontType == ft_composite) {
102 	    const gs_font_type0 *const psub0 = (const gs_font_type0 *)psub;
103 	    fmap_type fmt = psub0->data.FMapType;
104 
105 	    if (fmt == fmap_double_escape ||
106 		fmt == fmap_shift ||
107 		(fmt == fmap_escape &&
108 		 !(data.FMapType == fmap_escape ||
109 		   data.FMapType == fmap_double_escape))
110 		)
111 		return_error(e_invalidfont);
112 	}
113     }
114     switch (data.FMapType) {
115 	case fmap_escape:
116 	case fmap_double_escape:	/* need EscChar */
117 	    code = ensure_char_entry(i_ctx_p, op, "EscChar", &data.EscChar, 255);
118 	    break;
119 	case fmap_shift:	/* need ShiftIn & ShiftOut */
120 	    code = ensure_char_entry(i_ctx_p, op, "ShiftIn", &data.ShiftIn, 15);
121 	    if (code >= 0)
122 		code = ensure_char_entry(i_ctx_p, op, "ShiftOut", &data.ShiftOut, 14);
123 	    break;
124 	case fmap_SubsVector:	/* need SubsVector */
125 	    {
126 		ref *psubsvector;
127 		uint svsize;
128 
129 		if (dict_find_string(op, "SubsVector", &psubsvector) <= 0 ||
130 		    !r_has_type(psubsvector, t_string) ||
131 		    (svsize = r_size(psubsvector)) == 0 ||
132 		(data.subs_width = (int)*psubsvector->value.bytes + 1) > 4 ||
133 		    (svsize - 1) % data.subs_width != 0
134 		    )
135 		    return_error(e_invalidfont);
136 		data.subs_size = (svsize - 1) / data.subs_width;
137 		data.SubsVector.data = psubsvector->value.bytes + 1;
138 		data.SubsVector.size = svsize - 1;
139 	    } break;
140 	case fmap_CMap:	/* need CMap */
141 	    code = ztype0_get_cmap(&data.CMap, (const ref *)&fdepvector,
142 				   (const ref *)op, imemory);
143 	    break;
144 	default:
145 	    ;
146     }
147     if (code < 0)
148 	return code;
149     /*
150      * Save the old FID in case we have to back out.
151      * build_gs_font will return an error if there is a FID entry
152      * but it doesn't reference a valid font.
153      */
154     {
155 	ref *pfid;
156 
157 	if (dict_find_string(op, "FID", &pfid) <= 0)
158 	    make_null(&save_FID);
159 	else
160 	    save_FID = *pfid;
161     }
162     {
163 	build_proc_refs build;
164 
165 	code = build_proc_name_refs(imemory, &build,
166 				    "%Type0BuildChar", "%Type0BuildGlyph");
167 	if (code < 0)
168 	    return code;
169 	code = build_gs_font(i_ctx_p, op, (gs_font **) & pfont,
170 			     ft_composite, &st_gs_font_type0, &build,
171 			     bf_options_none);
172     }
173     if (code != 0)
174 	return code;
175     /* Fill in the rest of the basic font data. */
176     pfont->procs.init_fstack = gs_type0_init_fstack;
177     pfont->procs.define_font = ztype0_define_font;
178     pfont->procs.make_font = ztype0_make_font;
179     pfont->procs.next_char_glyph = gs_type0_next_char_glyph;
180     pfont->procs.decode_glyph = gs_font_map_glyph_to_unicode; /* PDF needs. */
181     if (dict_find_string(op, "PrefEnc", &pprefenc) <= 0) {
182 	ref nul;
183 
184 	make_null_new(&nul);
185 	if ((code = idict_put_string(op, "PrefEnc", &nul)) < 0)
186 	    goto fail;
187     }
188     get_GlyphNames2Unicode(i_ctx_p, (gs_font *)pfont, op);
189     /* Fill in the font data */
190     pdata = pfont_data(pfont);
191     data.encoding_size = r_size(&pdata->Encoding);
192     /*
193      * Adobe interpreters apparently require that Encoding.size >= subs_size
194      * +1 (not sure whether the +1 only applies if the sum of the range
195      * sizes is less than the size of the code space).  The gs library
196      * doesn't require this -- it only gives an error if a show operation
197      * actually would reference beyond the end of the Encoding -- so we
198      * check this here rather than in the library.
199      */
200     if (data.FMapType == fmap_SubsVector) {
201 	if (data.subs_size >= r_size(&pdata->Encoding)) {
202 	    code = gs_note_error(e_rangecheck);
203 	    goto fail;
204 	}
205     }
206     data.Encoding =
207 	(uint *) ialloc_byte_array(data.encoding_size, sizeof(uint),
208 				   "buildfont0(Encoding)");
209     if (data.Encoding == 0) {
210 	code = gs_note_error(e_VMerror);
211 	goto fail;
212     }
213     /* Fill in the encoding vector, checking to make sure that */
214     /* each element is an integer between 0 and fdep_size-1. */
215     for (i = 0; i < data.encoding_size; i++) {
216 	ref enc;
217 
218 	array_get(imemory, &pdata->Encoding, i, &enc);
219 	if (!r_has_type(&enc, t_integer)) {
220 	    code = gs_note_error(e_typecheck);
221 	    goto fail;
222 	}
223 	if ((ulong) enc.value.intval >= data.fdep_size) {
224 	    code = gs_note_error(e_rangecheck);
225 	    goto fail;
226 	}
227 	data.Encoding[i] = (uint) enc.value.intval;
228     }
229     data.FDepVector =
230 	ialloc_struct_array(data.fdep_size, gs_font *,
231 			    &st_gs_font_ptr_element,
232 			    "buildfont0(FDepVector)");
233     if (data.FDepVector == 0) {
234 	code = gs_note_error(e_VMerror);
235 	goto fail;
236     }
237     for (i = 0; i < data.fdep_size; i++) {
238 	ref fdep;
239 	ref *pfid;
240 
241 	array_get(pfont->memory, &fdepvector, i, &fdep);
242 	/* The lookup can't fail, because of the pre-check above. */
243 	dict_find_string(&fdep, "FID", &pfid);
244 	data.FDepVector[i] = r_ptr(pfid, gs_font);
245     }
246     pfont->data = data;
247     code = define_gs_font((gs_font *) pfont);
248     if (code >= 0)
249 	return code;
250 fail:
251 	/*
252 	 * Undo the insertion of the FID entry in the dictionary.  Note that
253 	 * some allocations (Encoding, FDepVector) are not undone.
254 	 */
255     if (r_has_type(&save_FID, t_null)) {
256 	ref rnfid;
257 
258 	name_enter_string(pfont->memory, "FID", &rnfid);
259 	idict_undef(op, &rnfid);
260     } else
261 	idict_put_string(op, "FID", &save_FID);
262     gs_free_object(pfont->memory, pfont, "buildfont0(font)");
263     return code;
264 }
265 /* If a newly defined or scaled composite font had to scale */
266 /* any composite sub-fonts, adjust the parent font's FDepVector. */
267 /* This is called only if gs_type0_define/make_font */
268 /* actually changed the FDepVector. */
269 static int
ztype0_adjust_FDepVector(gs_font_type0 * pfont)270 ztype0_adjust_FDepVector(gs_font_type0 * pfont)
271 {
272     gs_memory_t *mem = pfont->memory;
273     /* HACK: We know the font was allocated by the interpreter. */
274     gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
275     gs_font **pdep = pfont->data.FDepVector;
276     ref newdep;
277     uint fdep_size = pfont->data.fdep_size;
278     ref *prdep;
279     uint i;
280     int code = gs_alloc_ref_array(imem, &newdep, a_readonly, fdep_size,
281 				  "ztype0_adjust_matrix");
282 
283     if (code < 0)
284 	return code;
285     for (prdep = newdep.value.refs, i = 0; i < fdep_size; i++, prdep++) {
286 	const ref *pdict = pfont_dict(pdep[i]);
287 
288 	ref_assign(prdep, pdict);
289 	r_set_attrs(prdep, imemory_new_mask(imem));
290     }
291     /*
292      * The FDepVector is an existing key in the parent's dictionary,
293      * so it's safe to pass NULL as the dstack pointer to dict_put_string.
294      */
295     return dict_put_string(pfont_dict(pfont), "FDepVector", &newdep, NULL);
296 }
297 static int
ztype0_define_font(gs_font_dir * pdir,gs_font * pfont)298 ztype0_define_font(gs_font_dir * pdir, gs_font * pfont)
299 {
300     gs_font_type0 *const pfont0 = (gs_font_type0 *)pfont;
301     gs_font **pdep = pfont0->data.FDepVector;
302     int code = gs_type0_define_font(pdir, pfont);
303 
304     if (code < 0 || pfont0->data.FDepVector == pdep)
305 	return code;
306     return ztype0_adjust_FDepVector(pfont0);
307 }
308 static int
ztype0_make_font(gs_font_dir * pdir,const gs_font * pfont,const gs_matrix * pmat,gs_font ** ppfont)309 ztype0_make_font(gs_font_dir * pdir, const gs_font * pfont,
310 		 const gs_matrix * pmat, gs_font ** ppfont)
311 {
312     gs_font_type0 **const ppfont0 = (gs_font_type0 **)ppfont;
313     gs_font **pdep = (*ppfont0)->data.FDepVector;
314     int code;
315 
316     code = zdefault_make_font(pdir, pfont, pmat, ppfont);
317     if (code < 0)
318 	return code;
319     code = gs_type0_make_font(pdir, pfont, pmat, ppfont);
320     if (code < 0)
321 	return code;
322     if ((*ppfont0)->data.FDepVector == pdep)
323 	return 0;
324     return ztype0_adjust_FDepVector(*ppfont0);
325 }
326 
327 /* ------ Internal routines ------ */
328 
329 /* Find or add a character entry in a font dictionary. */
330 static int
ensure_char_entry(i_ctx_t * i_ctx_p,os_ptr op,const char * kstr,byte * pvalue,int default_value)331 ensure_char_entry(i_ctx_t *i_ctx_p, os_ptr op, const char *kstr,
332 		  byte * pvalue, int default_value)
333 {
334     ref *pentry;
335 
336     if (dict_find_string(op, kstr, &pentry) <= 0) {
337 	ref ent;
338 
339 	make_int(&ent, default_value);
340 	*pvalue = (byte) default_value;
341 	return idict_put_string(op, kstr, &ent);
342     } else {
343 	check_int_leu_only(*pentry, 255);
344 	*pvalue = (byte) pentry->value.intval;
345 	return 0;
346     }
347 }
348 
349 /* ------ Initialization procedure ------ */
350 
351 const op_def zfont0_op_defs[] =
352 {
353     {"2.buildfont0", zbuildfont0},
354     op_def_end(0)
355 };
356