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