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