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