/src/ghostpdl/psi/zfont42.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 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., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Type 42 font creation operator */ |
18 | | #include "memory_.h" |
19 | | #include "ghost.h" |
20 | | #include "oper.h" |
21 | | #include "gsccode.h" |
22 | | #include "gsmatrix.h" |
23 | | #include "gxfont.h" |
24 | | #include "gxfont42.h" |
25 | | #include "bfont.h" |
26 | | #include "icharout.h" |
27 | | #include "idict.h" |
28 | | #include "idparam.h" |
29 | | #include "ifont42.h" |
30 | | #include "ichar1.h" |
31 | | #include "iname.h" |
32 | | #include "store.h" |
33 | | |
34 | | /* Forward references */ |
35 | | static int z42_string_proc(gs_font_type42 *, ulong, uint, const byte **); |
36 | | static uint z42_get_glyph_index(gs_font_type42 *, gs_glyph); |
37 | | static int z42_gdir_get_outline(gs_font_type42 *, uint, gs_glyph_data_t *); |
38 | | static font_proc_enumerate_glyph(z42_enumerate_glyph); |
39 | | static font_proc_enumerate_glyph(z42_gdir_enumerate_glyph); |
40 | | static font_proc_encode_char(z42_encode_char); |
41 | | static font_proc_glyph_info(z42_glyph_info); |
42 | | static font_proc_glyph_outline(z42_glyph_outline); |
43 | | static font_proc_font_info(z42_font_info); |
44 | | |
45 | | /* <string|name> <font_dict> .buildfont11/42 <string|name> <font> */ |
46 | | /* Build a type 11 (TrueType CID-keyed) or 42 (TrueType) font. */ |
47 | | int |
48 | | build_gs_TrueType_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_type42 **ppfont, |
49 | | font_type ftype, gs_memory_type_ptr_t pstype, |
50 | | const char *bcstr, const char *bgstr, |
51 | | build_font_options_t options) |
52 | 25 | { |
53 | 25 | build_proc_refs build; |
54 | 25 | ref sfnts, GlyphDirectory; |
55 | 25 | gs_font_type42 *pfont; |
56 | 25 | font_data *pdata; |
57 | 25 | int code; |
58 | | |
59 | 25 | check_op(2); |
60 | 17 | code = build_proc_name_refs(imemory, &build, bcstr, bgstr); |
61 | 17 | if (code < 0) |
62 | 0 | return code; |
63 | 17 | check_type(*op, t_dictionary); |
64 | | /* |
65 | | * Since build_gs_primitive_font may resize the dictionary and cause |
66 | | * pointers to become invalid, we save sfnts and GlyphDirectory. |
67 | | */ |
68 | 17 | if ((code = font_string_array_param(imemory, op, "sfnts", &sfnts)) < 0 || |
69 | 17 | (code = font_GlyphDirectory_param(op, &GlyphDirectory)) < 0 |
70 | 17 | ) |
71 | 0 | return code; |
72 | 17 | code = build_gs_primitive_font(i_ctx_p, op, (gs_font_base **)ppfont, |
73 | 17 | ftype, pstype, &build, options); |
74 | 17 | if (code != 0) |
75 | 0 | return code; |
76 | 17 | pfont = *ppfont; |
77 | 17 | pdata = pfont_data(pfont); |
78 | 17 | ref_assign(&pdata->u.type42.sfnts, &sfnts); |
79 | 17 | pdata->u.type42.mru_sfnts_index = 0; |
80 | 17 | pdata->u.type42.mru_sfnts_pos = 0; |
81 | 17 | make_null_new(&pdata->u.type42.CIDMap); |
82 | 17 | ref_assign(&pdata->u.type42.GlyphDirectory, &GlyphDirectory); |
83 | 17 | pfont->data.string_proc = z42_string_proc; |
84 | 17 | pfont->data.proc_data = (char *)pdata; |
85 | 17 | pfont->is_resource = (options & bf_has_font_file ? true : false); |
86 | 17 | code = gs_type42_font_init(pfont, 0); |
87 | 17 | if (code < 0) |
88 | 0 | return code; |
89 | 17 | pfont->procs.font_info = z42_font_info; |
90 | | /* |
91 | | * If the font has a GlyphDictionary, this replaces loca and glyf for |
92 | | * accessing character outlines. In this case, we use alternate |
93 | | * get_outline and enumerate_glyph procedures. |
94 | | */ |
95 | 17 | if (!r_has_type(&GlyphDirectory, t_null)) { |
96 | 0 | pfont->data.get_outline = z42_gdir_get_outline; |
97 | 0 | pfont->procs.enumerate_glyph = z42_gdir_enumerate_glyph; |
98 | 0 | } else |
99 | 17 | pfont->procs.enumerate_glyph = z42_enumerate_glyph; |
100 | | /* |
101 | | * The procedures that access glyph information must accept either |
102 | | * glyph names or glyph indexes. |
103 | | */ |
104 | 17 | pfont->data.get_glyph_index = z42_get_glyph_index; |
105 | 17 | pfont->data.substitute_glyph_index_vertical = gs_type42_substitute_glyph_index_vertical; |
106 | 17 | pfont->procs.encode_char = z42_encode_char; |
107 | 17 | pfont->procs.glyph_info = z42_glyph_info; |
108 | 17 | pfont->procs.glyph_outline = z42_glyph_outline; |
109 | 17 | return 0; |
110 | 17 | } |
111 | | static int |
112 | | zbuildfont42(i_ctx_t *i_ctx_p) |
113 | 25 | { |
114 | 25 | os_ptr op = osp; |
115 | 25 | gs_font_type42 *pfont; |
116 | 25 | int code = build_gs_TrueType_font(i_ctx_p, op, &pfont, ft_TrueType, |
117 | 25 | &st_gs_font_type42, "%Type42BuildChar", |
118 | 25 | "%Type42BuildGlyph", bf_options_none); |
119 | | |
120 | 25 | if (code < 0) |
121 | 8 | return code; |
122 | 17 | return define_gs_font(i_ctx_p, (gs_font *)pfont); |
123 | 25 | } |
124 | | |
125 | | /* |
126 | | * Check a parameter for being an array of strings. Return the parameter |
127 | | * value even if it is of the wrong type. |
128 | | */ |
129 | | int |
130 | | font_string_array_param(const gs_memory_t *mem, os_ptr op, const char *kstr, ref *psa) |
131 | 17 | { |
132 | 17 | ref *pvsa; |
133 | 17 | ref rstr0; |
134 | 17 | int code; |
135 | | |
136 | 17 | if (dict_find_string(op, kstr, &pvsa) <= 0) |
137 | 0 | return_error(gs_error_invalidfont); |
138 | 17 | *psa = *pvsa; |
139 | | /* |
140 | | * We only check the first element of the array now, as a sanity test; |
141 | | * elements are checked as needed by string_array_access_proc. |
142 | | */ |
143 | 17 | if ((code = array_get(mem, pvsa, 0L, &rstr0)) < 0) |
144 | 0 | return code; |
145 | 17 | if (!r_has_type(&rstr0, t_string)) |
146 | 0 | return_error(gs_error_typecheck); |
147 | 17 | return 0; |
148 | 17 | } |
149 | | |
150 | | /* |
151 | | * Get a GlyphDirectory if present. Return 0 if present, 1 if absent, |
152 | | * or an error code. |
153 | | */ |
154 | | int |
155 | | font_GlyphDirectory_param(os_ptr op, ref *pGlyphDirectory) |
156 | 17 | { |
157 | 17 | ref *pgdir; |
158 | | |
159 | 17 | if (dict_find_string(op, "GlyphDirectory", &pgdir) <= 0) |
160 | 17 | make_null(pGlyphDirectory); |
161 | 0 | else if (!r_has_type(pgdir, t_dictionary) && !r_is_array(pgdir)) |
162 | 0 | return_error(gs_error_typecheck); |
163 | 0 | else |
164 | 0 | *pGlyphDirectory = *pgdir; |
165 | 17 | return 0; |
166 | 17 | } |
167 | | |
168 | | /* |
169 | | * Access a given byte offset and length in an array of strings. |
170 | | * This is used for sfnts and for CIDMap. The int argument is 2 for sfnts |
171 | | * (because of the strange behavior of odd-length strings), 1 for CIDMap. |
172 | | * Return code : 0 - success, <0 - error, |
173 | | * >0 - number of accessible bytes (client must cycle). |
174 | | */ |
175 | | int |
176 | | string_array_access_proc(const gs_memory_t *mem, |
177 | | const ref *psa, int modulus, ulong offset, uint length, |
178 | | uint *mru_index, ulong *mru_pos, |
179 | | const byte **pdata) |
180 | 221 | { |
181 | 221 | ulong left; |
182 | 221 | uint index; |
183 | 221 | bool backwards; |
184 | | |
185 | 221 | if (length == 0) |
186 | 0 | return 0; |
187 | 221 | if (mru_index && mru_pos && offset >= (*mru_pos >> 1)) { |
188 | | /* offset in or after mru string */ |
189 | | /* OR offset in 2nd half of the fragment before the mru string */ |
190 | 221 | backwards = (*mru_pos > offset); |
191 | 221 | if (backwards) { |
192 | 0 | index = *mru_index - 1; /* 1st string to examine */ |
193 | 0 | left = *mru_pos - offset; /* how many bytes to seek backwards */ |
194 | 221 | } else { |
195 | 221 | index = *mru_index; /* 1st string to examine */ |
196 | 221 | left = offset - *mru_pos; /* how many bytes to seek forward */ |
197 | 221 | } |
198 | 221 | } else { |
199 | | /* no mru */ |
200 | | /* OR offset in 1st half of the fragment before the mru string */ |
201 | 0 | backwards = false; |
202 | 0 | index = 0; |
203 | 0 | left = offset; |
204 | 0 | } |
205 | 323 | for (;;) { |
206 | 323 | ref rstr; |
207 | 323 | int code = array_get(mem, psa, index, &rstr); |
208 | 323 | uint size; |
209 | | |
210 | 323 | if (code < 0) |
211 | 0 | return code; |
212 | 323 | if (!r_has_type(&rstr, t_string)) |
213 | 0 | return_error(gs_error_typecheck); |
214 | | /* |
215 | | * NOTE: According to the Adobe documentation, each sfnts |
216 | | * string should have even length. If the length is odd, |
217 | | * the additional byte is padding and should be ignored. |
218 | | */ |
219 | 323 | size = r_size(&rstr) & -modulus; |
220 | 323 | if (backwards) { |
221 | 0 | if (left <= size) { |
222 | 0 | left = size - left; |
223 | 0 | backwards = false; |
224 | | /* "index" does not change */ |
225 | 0 | } else { |
226 | 0 | left -= size; |
227 | 0 | --index; |
228 | 0 | continue; |
229 | 0 | } |
230 | 0 | } |
231 | 323 | if (left < size) { |
232 | 221 | *pdata = rstr.value.const_bytes + left; |
233 | 221 | if (mru_index) |
234 | 221 | *mru_index = index; |
235 | 221 | if (mru_pos) |
236 | 221 | *mru_pos = offset - left; |
237 | 221 | if (left + length > size) |
238 | 0 | return size - left; |
239 | 221 | return 0; |
240 | 221 | } |
241 | 102 | left -= size; |
242 | 102 | ++index; |
243 | 102 | } |
244 | 221 | } |
245 | | |
246 | | /* ------ Initialization procedure ------ */ |
247 | | |
248 | | const op_def zfont42_op_defs[] = |
249 | | { |
250 | | {"2.buildfont42", zbuildfont42}, |
251 | | op_def_end(0) |
252 | | }; |
253 | | |
254 | | /* Reduce a glyph name to a glyph index if needed. */ |
255 | | static gs_glyph |
256 | | glyph_to_index(const gs_font *font, gs_glyph glyph) |
257 | 0 | { |
258 | 0 | ref gref; |
259 | 0 | ref *pcstr; |
260 | |
|
261 | 0 | if (glyph >= GS_MIN_GLYPH_INDEX) |
262 | 0 | return glyph; |
263 | 0 | name_index_ref(font->memory, glyph, &gref); |
264 | 0 | if (dict_find(&pfont_data(font)->CharStrings, &gref, &pcstr) > 0 && |
265 | 0 | r_has_type(pcstr, t_integer) |
266 | 0 | ) { |
267 | 0 | gs_glyph index_glyph = pcstr->value.intval + GS_MIN_GLYPH_INDEX; |
268 | | |
269 | | /* We don't need to check the upper limit of the value, since the |
270 | | * upper limit is the maximum value of the data type |
271 | | */ |
272 | 0 | if (index_glyph >= GS_MIN_GLYPH_INDEX) |
273 | 0 | return index_glyph; |
274 | 0 | } |
275 | 0 | return GS_MIN_GLYPH_INDEX; /* glyph 0 is notdef */ |
276 | 0 | } |
277 | | static uint |
278 | | z42_get_glyph_index(gs_font_type42 *pfont, gs_glyph glyph) |
279 | 0 | { |
280 | 0 | gs_glyph gid = glyph_to_index((gs_font *)pfont, glyph); |
281 | |
|
282 | 0 | return gid - GS_MIN_GLYPH_INDEX; |
283 | 0 | } |
284 | | |
285 | | /* |
286 | | * Get a glyph outline from GlyphDirectory. Return an empty string if |
287 | | * the glyph is missing or out of range. |
288 | | */ |
289 | | int |
290 | | font_gdir_get_outline(const gs_memory_t *mem, |
291 | | const ref *pgdir, |
292 | | long glyph_index, |
293 | | gs_glyph_data_t *pgd) |
294 | 0 | { |
295 | 0 | ref iglyph; |
296 | 0 | ref gdef; |
297 | 0 | ref *pgdef; |
298 | 0 | int code; |
299 | |
|
300 | 0 | if (r_has_type(pgdir, t_dictionary)) { |
301 | 0 | make_int(&iglyph, glyph_index); |
302 | 0 | code = dict_find(pgdir, &iglyph, &pgdef) - 1; /* 0 => not found */ |
303 | 0 | } else { |
304 | 0 | code = array_get(mem, pgdir, glyph_index, &gdef); |
305 | 0 | pgdef = &gdef; |
306 | 0 | } |
307 | 0 | if (code < 0) { |
308 | 0 | gs_glyph_data_from_null(pgd); |
309 | 0 | } else if (!r_has_type(pgdef, t_string)) { |
310 | 0 | return_error(gs_error_typecheck); |
311 | 0 | } else { |
312 | 0 | gs_glyph_data_from_string(pgd, pgdef->value.const_bytes, r_size(pgdef), |
313 | 0 | NULL); |
314 | 0 | } |
315 | 0 | return 0; |
316 | 0 | } |
317 | | static int |
318 | | z42_gdir_get_outline(gs_font_type42 * pfont, uint glyph_index, |
319 | | gs_glyph_data_t *pgd) |
320 | 0 | { |
321 | 0 | const font_data *pfdata = pfont_data(pfont); |
322 | 0 | const ref *pgdir = &pfdata->u.type42.GlyphDirectory; |
323 | |
|
324 | 0 | return font_gdir_get_outline(pfont->memory, pgdir, (long)glyph_index, pgd); |
325 | 0 | } |
326 | | |
327 | | /* Enumerate glyphs from CharStrings or loca / glyf. */ |
328 | | static int |
329 | | z42_enumerate_glyph(gs_font *font, int *pindex, gs_glyph_space_t glyph_space, |
330 | | gs_glyph *pglyph) |
331 | 0 | { |
332 | 0 | if (glyph_space == GLYPH_SPACE_INDEX) |
333 | 0 | return gs_type42_enumerate_glyph(font, pindex, glyph_space, pglyph); |
334 | 0 | else { |
335 | 0 | const ref *pcsdict = &pfont_data(font)->CharStrings; |
336 | |
|
337 | 0 | return zchar_enumerate_glyph(font->memory, pcsdict, pindex, pglyph); |
338 | 0 | } |
339 | 0 | } |
340 | | |
341 | | /* Enumerate glyphs (keys) from GlyphDirectory instead of loca / glyf. */ |
342 | | static int |
343 | | z42_gdir_enumerate_glyph(gs_font *font, int *pindex, |
344 | | gs_glyph_space_t glyph_space, gs_glyph *pglyph) |
345 | 0 | { |
346 | 0 | const ref *pgdict; |
347 | 0 | int code; |
348 | |
|
349 | 0 | if (glyph_space == GLYPH_SPACE_INDEX) { |
350 | 0 | pgdict = &pfont_data(font)->u.type42.GlyphDirectory; |
351 | 0 | if (!r_has_type(pgdict, t_dictionary)) { |
352 | 0 | ref gdef; |
353 | |
|
354 | 0 | for (;; (*pindex)++) { |
355 | 0 | if (array_get(font->memory, pgdict, (long)*pindex, &gdef) < 0) { |
356 | 0 | *pindex = 0; |
357 | 0 | return 0; |
358 | 0 | } |
359 | 0 | if (!r_has_type(&gdef, t_null)) { |
360 | 0 | *pglyph = GS_MIN_GLYPH_INDEX + (*pindex)++; |
361 | 0 | return 0; |
362 | 0 | } |
363 | 0 | } |
364 | 0 | } |
365 | 0 | } else |
366 | 0 | pgdict = &pfont_data(font)->CharStrings; |
367 | | /* A trick : use zchar_enumerate_glyph to enumerate GIDs : */ |
368 | 0 | code = zchar_enumerate_glyph(font->memory, pgdict, pindex, pglyph); |
369 | 0 | if (*pindex != 0 && *pglyph >= GS_MIN_CID_GLYPH) |
370 | 0 | *pglyph = *pglyph - GS_MIN_CID_GLYPH + GS_MIN_GLYPH_INDEX; |
371 | 0 | return code; |
372 | 0 | } |
373 | | |
374 | | /* |
375 | | * Define font procedures that accept either a character name or a glyph |
376 | | * index as the glyph. |
377 | | */ |
378 | | static gs_glyph |
379 | | z42_encode_char(gs_font *font, gs_char chr, gs_glyph_space_t glyph_space) |
380 | 0 | { |
381 | 0 | gs_glyph glyph = zfont_encode_char(font, chr, glyph_space); |
382 | |
|
383 | 0 | return (glyph_space == GLYPH_SPACE_INDEX && glyph != GS_NO_GLYPH ? |
384 | 0 | glyph_to_index(font, glyph) : glyph); |
385 | 0 | } |
386 | | static int |
387 | | z42_glyph_outline(gs_font *font, int WMode, gs_glyph glyph, const gs_matrix *pmat, |
388 | | gx_path *ppath, double sbw[4]) |
389 | 0 | { |
390 | 0 | return gs_type42_glyph_outline(font, WMode, glyph_to_index(font, glyph), |
391 | 0 | pmat, ppath, sbw); |
392 | 0 | } |
393 | | static int |
394 | | z42_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat, |
395 | | int members, gs_glyph_info_t *info) |
396 | 0 | { /* fixme : same as z1_glyph_info. */ |
397 | 0 | int wmode = font->WMode; |
398 | |
|
399 | 0 | return z1_glyph_info_generic(font, glyph, pmat, members, info, gs_type42_glyph_info, wmode); |
400 | 0 | } |
401 | | |
402 | | /* Procedure for accessing the sfnts array. |
403 | | * Return code : 0 - success, <0 - error, |
404 | | * >0 - number of accessible bytes (client must cycle). |
405 | | */ |
406 | | static int |
407 | | z42_string_proc(gs_font_type42 * pfont, ulong offset, uint length, |
408 | | const byte ** pdata) |
409 | 221 | { |
410 | 221 | return string_array_access_proc(pfont->memory, &pfont_data(pfont)->u.type42.sfnts, 2, |
411 | 221 | offset, length, &pfont_data(pfont)->u.type42.mru_sfnts_index, |
412 | 221 | &pfont_data(pfont)->u.type42.mru_sfnts_pos, pdata); |
413 | 221 | } |
414 | | |
415 | | static int |
416 | | z42_font_info(gs_font *font, const gs_point *pscale, int members, |
417 | | gs_font_info_t *info) |
418 | 0 | { |
419 | 0 | int code = zfont_info(font, pscale, members, info); |
420 | |
|
421 | 0 | if (code < 0) |
422 | 0 | return code; |
423 | 0 | return gs_truetype_font_info(font, pscale, members, info); |
424 | 0 | } |