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