/src/ghostpdl/psi/zfont1.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 1 and Type 4 font creation operators */ |
18 | | #include "memory_.h" |
19 | | #include "ghost.h" |
20 | | #include "oper.h" |
21 | | #include "gxfixed.h" |
22 | | #include "gsmatrix.h" |
23 | | #include "gxdevice.h" |
24 | | #include "gxfont.h" |
25 | | #include "gxfont1.h" |
26 | | #include "bfont.h" |
27 | | #include "ialloc.h" |
28 | | #include "icharout.h" |
29 | | #include "ichar1.h" |
30 | | #include "idict.h" |
31 | | #include "idparam.h" |
32 | | #include "ifont1.h" |
33 | | #include "iname.h" /* for name_index in enumerate_glyph */ |
34 | | #include "store.h" |
35 | | |
36 | | /* Type 1 font procedures (defined in zchar1.c) */ |
37 | | extern const gs_type1_data_procs_t z1_data_procs; |
38 | | font_proc_glyph_info(z1_glyph_info); |
39 | | /* Font procedures defined here */ |
40 | | static font_proc_same_font(z1_same_font); |
41 | | |
42 | | /* ------ Private utilities ------ */ |
43 | | |
44 | | static void |
45 | | find_zone_height(float *pmax_height, int count, const float *values) |
46 | 493k | { |
47 | 493k | int i; |
48 | 493k | float zone_height; |
49 | | |
50 | 974k | for (i = 0; i < count; i += 2) |
51 | 480k | if ((zone_height = values[i + 1] - values[i]) > *pmax_height) |
52 | 123k | *pmax_height = zone_height; |
53 | 493k | } |
54 | | |
55 | | /* ------ Font procedures ------ */ |
56 | | |
57 | | static int |
58 | | z1_enumerate_glyph(gs_font * pfont, int *pindex, gs_glyph_space_t ignored, |
59 | | gs_glyph * pglyph) |
60 | 6.79M | { |
61 | 6.79M | const gs_font_type1 *const pfont1 = (gs_font_type1 *)pfont; |
62 | 6.79M | const ref *pcsdict = &pfont_data(pfont1)->CharStrings; |
63 | | |
64 | 6.79M | return zchar_enumerate_glyph(pfont->memory, pcsdict, pindex, pglyph); |
65 | 6.79M | } |
66 | | |
67 | | /* ------ Public procedures ------ */ |
68 | | |
69 | | /* Extract pointers to internal structures. */ |
70 | | int |
71 | | charstring_font_get_refs(const_os_ptr op, charstring_font_refs_t *pfr) |
72 | 123k | { |
73 | 123k | check_type(*op, t_dictionary); |
74 | 123k | if (dict_find_string(op, "Private", &pfr->Private) <= 0 || |
75 | 123k | !r_has_type(pfr->Private, t_dictionary) |
76 | 123k | ) |
77 | 10 | return_error(gs_error_invalidfont); |
78 | 123k | make_empty_array(&pfr->no_subrs, 0); |
79 | 123k | if (dict_find_string(pfr->Private, "OtherSubrs", &pfr->OtherSubrs) > 0) { |
80 | 123k | if (!r_is_array(pfr->OtherSubrs)) |
81 | 0 | return_error(gs_error_typecheck); |
82 | 123k | } else |
83 | 0 | pfr->OtherSubrs = &pfr->no_subrs; |
84 | 123k | if (dict_find_string(pfr->Private, "Subrs", &pfr->Subrs) > 0) { |
85 | 123k | if (!r_is_array(pfr->Subrs)) |
86 | 0 | return_error(gs_error_typecheck); |
87 | 123k | } else |
88 | 0 | pfr->Subrs = &pfr->no_subrs; |
89 | 123k | pfr->GlobalSubrs = &pfr->no_subrs; |
90 | 123k | return 0; |
91 | 123k | } |
92 | | |
93 | | static int |
94 | | charstring_check_mm_params(ref *fdict, unsigned int ndesigns) |
95 | 1 | { |
96 | 1 | ref *p1; |
97 | 1 | ref p2, p3; |
98 | 1 | ref *Blend, *FInfo, *BFInfo, *BPriv; |
99 | 1 | int code; |
100 | 1 | int i, j; |
101 | 1 | gs_memory_t *mem = dict_mem(fdict->value.pdict); |
102 | | |
103 | 1 | code = dict_find_string(fdict, "$Blend", &p1); |
104 | 1 | if (code < 0 || !r_is_proc(p1)) |
105 | 0 | goto bad; |
106 | | |
107 | 1 | code = dict_find_string(fdict, "FontInfo", &FInfo); |
108 | 1 | if (code < 0 || !r_has_type(FInfo, t_dictionary)) |
109 | 0 | goto bad; |
110 | | |
111 | 1 | code = dict_find_string(FInfo, "BlendAxisTypes", &p1); |
112 | 1 | if (code < 0 || !r_is_array(p1)) |
113 | 0 | goto bad; |
114 | 2 | for (i = 0; i < r_size(p1); i ++) { |
115 | 1 | code = array_get(mem, p1, i, &p2); |
116 | 1 | if (code < 0 || !r_has_type(&p2, t_name)) |
117 | 0 | goto bad; |
118 | 1 | } |
119 | 1 | code = dict_find_string(FInfo, "BlendDesignPositions", &p1); |
120 | 1 | if (code < 0 || !r_is_array(p1)) |
121 | 0 | goto bad; |
122 | 3 | for (i = 0; i < r_size(p1); i++) { |
123 | 2 | code = array_get(mem, p1, i, &p2); |
124 | 2 | if (code < 0 || !r_is_array(&p2)) { |
125 | 0 | goto bad; |
126 | 0 | } |
127 | 2 | else { |
128 | 4 | for (j = 0; j < r_size(&p2); j++) { |
129 | 2 | code = array_get(mem, &p2, j, &p3); |
130 | 2 | if (code < 0 || !r_has_type(&p3, t_integer)) |
131 | 0 | goto bad; |
132 | 2 | } |
133 | 2 | } |
134 | 2 | } |
135 | 1 | code = dict_find_string(FInfo, "BlendDesignMap", &p1); |
136 | 1 | if (code < 0 || !r_is_array(p1)) |
137 | 0 | goto bad; |
138 | 2 | for (i = 0; i < r_size(p1); i++) { |
139 | 1 | code = array_get(mem, p1, i , &p2); |
140 | 1 | if (code < 0 || !r_is_array(&p2)) { |
141 | 0 | goto bad; |
142 | 0 | } |
143 | 1 | else { |
144 | 3 | for (j = 0; j < r_size(&p2); j++) { |
145 | 2 | code = array_get(mem, &p2, j, &p3); |
146 | 2 | if (code < 0 || !r_is_array(&p3)) |
147 | 0 | goto bad; |
148 | 2 | else { |
149 | 2 | ref p5; |
150 | 2 | int k; |
151 | 6 | for (k = 0; k < r_size(&p3); k++) { |
152 | 4 | code = array_get(mem, &p3, k, &p5); |
153 | 4 | if (code < 0 || !r_is_number(&p5)) |
154 | 0 | goto bad; |
155 | 4 | } |
156 | 2 | } |
157 | 2 | } |
158 | 1 | } |
159 | 1 | } |
160 | 1 | code = dict_find_string(fdict, "Blend", &Blend); |
161 | 1 | if (code < 0 || !r_has_type(Blend, t_dictionary)) |
162 | 0 | goto bad; |
163 | 1 | code = dict_find_string(Blend, "FontBBox", &p1); |
164 | 1 | if (code < 0 || !r_is_array(p1)) |
165 | 0 | goto bad; |
166 | 5 | for (i = 0; i < r_size(p1); i++) { |
167 | 4 | code = array_get(mem, p1, i, &p2); |
168 | 4 | if (code < 0 || !r_is_array(&p2)) { |
169 | 0 | goto bad; |
170 | 0 | } |
171 | 4 | else { |
172 | 12 | for (j = 0; j < r_size(&p2); j++) { |
173 | 8 | code = array_get(mem, &p2, j, &p3); |
174 | 8 | if (code < 0 || !r_is_number(&p3)) |
175 | 0 | goto bad; |
176 | 8 | } |
177 | 4 | } |
178 | 4 | } |
179 | 1 | code = dict_find_string(Blend, "Private", &BPriv); |
180 | 1 | if (code < 0 || !r_has_type(BPriv, t_dictionary)) |
181 | 0 | goto bad; |
182 | 1 | code = dict_find_string(BPriv, "BlueValues", &p1); |
183 | 1 | if (code > 0) { |
184 | 0 | if (!r_is_array(p1) || r_size(p1) < 2) { |
185 | 0 | goto bad; |
186 | 0 | } |
187 | 0 | else { |
188 | 0 | for (i = 0; i < r_size(p1); i++) { |
189 | 0 | code = array_get(mem, p1, i, &p2); |
190 | 0 | if (code < 0 || !r_is_array(&p2)) { |
191 | 0 | goto bad; |
192 | 0 | } |
193 | 0 | else { |
194 | 0 | for (j = 0; j < r_size(&p2); j++) { |
195 | 0 | code = array_get(mem, &p2, j, &p3); |
196 | 0 | if (code < 0 || !r_has_type(&p3, t_integer)) |
197 | 0 | goto bad; |
198 | 0 | } |
199 | 0 | } |
200 | 0 | } |
201 | 0 | } |
202 | 0 | } |
203 | 1 | code = dict_find_string(BPriv, "OtherBlues", &p1); |
204 | 1 | if (code > 0) { |
205 | 0 | if (!r_is_array(p1) || r_size(p1) < 2) { |
206 | 0 | goto bad; |
207 | 0 | } |
208 | 0 | else { |
209 | 0 | for (i = 0; i < r_size(p1); i++) { |
210 | 0 | code = array_get(mem, p1, i, &p2); |
211 | 0 | if (code < 0 || !r_is_array(&p2)) |
212 | 0 | goto bad; |
213 | 0 | else { |
214 | 0 | for (j = 0; j < r_size(&p2); j++) { |
215 | 0 | code = array_get(mem, &p2, j, &p3); |
216 | 0 | if (code < 0 || !r_has_type(&p3, t_integer)) |
217 | 0 | goto bad; |
218 | 0 | } |
219 | 0 | } |
220 | 0 | } |
221 | 0 | } |
222 | 0 | } |
223 | 1 | code = dict_find_string(BPriv, "StdHW", &p1); |
224 | 1 | if (code > 0) { |
225 | 0 | if (!r_is_array(p1)) { |
226 | 0 | goto bad; |
227 | 0 | } |
228 | 0 | else { |
229 | 0 | for (i = 0; i < r_size(p1); i++){ |
230 | 0 | code = array_get(mem, p1, i, &p2); |
231 | 0 | if (code < 0 || !r_is_array(&p2)) |
232 | 0 | goto bad; |
233 | 0 | else { |
234 | 0 | for (j = 0; j < r_size(&p2); j++) { |
235 | 0 | code = array_get(mem, &p2, j, &p3); |
236 | 0 | if (code < 0 || !r_is_number(&p3)) |
237 | 0 | goto bad; |
238 | 0 | } |
239 | 0 | } |
240 | 0 | } |
241 | 0 | } |
242 | 0 | } |
243 | 1 | code = dict_find_string(BPriv, "StdVW", &p1); |
244 | 1 | if (code > 0) { |
245 | 0 | if (!r_is_array(p1)) { |
246 | 0 | goto bad; |
247 | 0 | } |
248 | 0 | else { |
249 | 0 | for (i = 0; i < r_size(p1); i++){ |
250 | 0 | code = array_get(mem, p1, i, &p2); |
251 | 0 | if (code < 0 || !r_is_array(&p2)) |
252 | 0 | goto bad; |
253 | 0 | else { |
254 | 0 | for (j = 0; j < r_size(&p2); j++) { |
255 | 0 | code = array_get(mem, &p2, j, &p3); |
256 | 0 | if (code < 0 || !r_is_number(&p3)) |
257 | 0 | goto bad; |
258 | 0 | } |
259 | 0 | } |
260 | 0 | } |
261 | 0 | } |
262 | 0 | } |
263 | 1 | code = dict_find_string(BPriv, "StemSnapH,", &p1); |
264 | 1 | if (code > 0) { |
265 | 0 | if (!r_is_array(p1)) { |
266 | 0 | goto bad; |
267 | 0 | } |
268 | 0 | else { |
269 | 0 | for (i = 0; i < r_size(p1); i++){ |
270 | 0 | code = array_get(mem, p1, i, &p2); |
271 | 0 | if (code < 0 || !r_is_array(&p2)) |
272 | 0 | goto bad; |
273 | 0 | else { |
274 | 0 | for (j = 0; j < r_size(&p2); j++) { |
275 | 0 | code = array_get(mem, &p2, j, &p3); |
276 | 0 | if (code < 0 || !r_is_number(&p3)) |
277 | 0 | goto bad; |
278 | 0 | } |
279 | 0 | } |
280 | 0 | } |
281 | 0 | } |
282 | 0 | } |
283 | 1 | code = dict_find_string(BPriv, "StemSnapV", &p1); |
284 | 1 | if (code > 0) { |
285 | 0 | if (!r_is_array(p1)) { |
286 | 0 | goto bad; |
287 | 0 | } |
288 | 0 | else { |
289 | 0 | for (i = 0; i < r_size(p1); i++){ |
290 | 0 | code = array_get(mem, p1, i, &p2); |
291 | 0 | if (code < 0 || !r_is_array(&p2)) |
292 | 0 | goto bad; |
293 | 0 | else { |
294 | 0 | for (j = 0; j < r_size(&p2); j++) { |
295 | 0 | code = array_get(mem, &p2, j, &p3); |
296 | 0 | if (code < 0 || !r_is_number(&p3)) |
297 | 0 | goto bad; |
298 | 0 | } |
299 | 0 | } |
300 | 0 | } |
301 | 0 | } |
302 | 0 | } |
303 | 1 | code = dict_find_string(BPriv, "BlueScale", &p1); |
304 | 1 | if (code > 0) { |
305 | 0 | if (!r_is_array(p1)) { |
306 | 0 | goto bad; |
307 | 0 | } |
308 | 0 | else { |
309 | 0 | for (i = 0; i < r_size(p1); i++) { |
310 | 0 | code = array_get(mem, p1, i, &p3); |
311 | 0 | if (code < 0 || !r_is_number(&p3)) |
312 | 0 | goto bad; |
313 | 0 | } |
314 | 0 | } |
315 | 0 | } |
316 | 1 | code = dict_find_string(BPriv, "BlueShift", &p1); |
317 | 1 | if (code > 0) { |
318 | 0 | if (!r_is_array(p1)) { |
319 | 0 | goto bad; |
320 | 0 | } |
321 | 0 | else { |
322 | 0 | for (i = 0; i < r_size(p1); i++) { |
323 | 0 | code = array_get(mem, p1, i, &p3); |
324 | 0 | if (code < 0 || !r_has_type(&p3, t_integer)) |
325 | 0 | goto bad; |
326 | 0 | } |
327 | 0 | } |
328 | 0 | } |
329 | 1 | code = dict_find_string(BPriv, "FamilyBlues", &p1); |
330 | 1 | if (code > 0) { |
331 | 0 | if (!r_is_array(p1) || r_size(p1) < 2) { |
332 | 0 | goto bad; |
333 | 0 | } |
334 | 0 | else { |
335 | 0 | for (i = 0; i < r_size(p1); i++){ |
336 | 0 | code = array_get(mem, p1, i, &p2); |
337 | 0 | if (code < 0 || !r_is_array(&p2)) |
338 | 0 | goto bad; |
339 | 0 | else { |
340 | 0 | for (j = 0; j < r_size(&p2); j++) { |
341 | 0 | code = array_get(mem, &p2, j, &p3); |
342 | 0 | if (code < 0 || !r_has_type(&p3, t_integer)) |
343 | 0 | goto bad; |
344 | 0 | } |
345 | 0 | } |
346 | 0 | } |
347 | 0 | } |
348 | 0 | } |
349 | 1 | code = dict_find_string(BPriv, "FamilyOtherBlues", &p1); |
350 | 1 | if (code > 0) { |
351 | 0 | if (!r_is_array(p1) || r_size(p1) < 2) { |
352 | 0 | goto bad; |
353 | 0 | } |
354 | 0 | else { |
355 | 0 | for (i = 0; i < r_size(p1); i++){ |
356 | 0 | code = array_get(mem, p1, i, &p2); |
357 | 0 | if (code < 0 || !r_is_array(&p2)) |
358 | 0 | goto bad; |
359 | 0 | else { |
360 | 0 | for (j = 0; j < r_size(&p2); j++) { |
361 | 0 | code = array_get(mem, &p2, j, &p3); |
362 | 0 | if (code < 0 || !r_has_type(&p3, t_integer)) |
363 | 0 | goto bad; |
364 | 0 | } |
365 | 0 | } |
366 | 0 | } |
367 | 0 | } |
368 | 0 | } |
369 | 1 | code = dict_find_string(BPriv, "ForceBold", &p1); |
370 | 1 | if (code > 0) { |
371 | 0 | if (!r_is_array(p1)) { |
372 | 0 | goto bad; |
373 | 0 | } |
374 | 0 | else { |
375 | 0 | for (i = 0; i < r_size(p1); i++) { |
376 | 0 | code = array_get(mem, p1, i, &p3); |
377 | 0 | if (code < 0 || !r_has_type(&p3, t_boolean)) |
378 | 0 | goto bad; |
379 | 0 | } |
380 | 0 | } |
381 | 0 | } |
382 | 1 | code = dict_find_string(Blend, "FontInfo", &BFInfo); |
383 | 1 | if (code > 0 && r_has_type(BFInfo, t_dictionary)) { |
384 | 0 | code = dict_find_string(BFInfo, "UnderlinePosition", &p1); |
385 | 0 | if (code > 0) { |
386 | 0 | if (!r_is_array(p1)) { |
387 | 0 | goto bad; |
388 | 0 | } |
389 | 0 | else { |
390 | 0 | for (i = 0; i < r_size(p1); i++) { |
391 | 0 | code = array_get(mem, p1, i, &p3); |
392 | 0 | if (code < 0 || !r_is_number(&p3)) |
393 | 0 | goto bad; |
394 | 0 | } |
395 | 0 | } |
396 | 0 | } |
397 | 0 | code = dict_find_string(BFInfo, "UnderlineThickness", &p1); |
398 | 0 | if (code > 0) { |
399 | 0 | if (!r_is_array(p1)) { |
400 | 0 | goto bad; |
401 | 0 | } |
402 | 0 | else { |
403 | 0 | for (i = 0; i < r_size(p1); i++) { |
404 | 0 | code = array_get(mem, p1, i, &p3); |
405 | 0 | if (code < 0 || !r_is_number(&p3)) |
406 | 0 | goto bad; |
407 | 0 | } |
408 | 0 | } |
409 | 0 | } |
410 | 0 | code = dict_find_string(BFInfo, "ItalicAngle", &p1); |
411 | 0 | if (code > 0) { |
412 | 0 | if (!r_is_array(p1)) { |
413 | 0 | goto bad; |
414 | 0 | } |
415 | 0 | else { |
416 | 0 | for (i = 0; i < r_size(p1); i++) { |
417 | 0 | code = array_get(mem, p1, i, &p3); |
418 | 0 | if (code < 0 || !r_is_number(&p3)) |
419 | 0 | goto bad; |
420 | 0 | } |
421 | 0 | } |
422 | 0 | } |
423 | 0 | } |
424 | 1 | return 0; |
425 | 0 | bad: |
426 | 0 | return_error(gs_error_invalidfont); |
427 | 1 | } |
428 | | |
429 | | /* Get the parameters of a CharString-based font or a FDArray entry. */ |
430 | | int |
431 | | charstring_font_params(const gs_memory_t *mem, |
432 | | const_os_ptr op, charstring_font_refs_t *pfr, |
433 | | gs_type1_data *pdata1) |
434 | 123k | { |
435 | 123k | const ref *pprivate = pfr->Private; |
436 | 123k | int code; |
437 | | |
438 | | /* Get the rest of the information from the Private dictionary. */ |
439 | 123k | if ((code = dict_int_param(pprivate, "lenIV", -1, 255, pdata1->lenIV, &pdata1->lenIV)) < 0) |
440 | 0 | return code; |
441 | 123k | if ((code = dict_uint_param(pprivate, "subroutineNumberBias", |
442 | 123k | 0, max_uint, pdata1->subroutineNumberBias, &pdata1->subroutineNumberBias)) < 0) |
443 | 0 | return code; |
444 | 123k | if ((code = dict_int_param(pprivate, "BlueFuzz", 0, 1999, 1, &pdata1->BlueFuzz)) < 0) |
445 | 0 | return code; |
446 | 123k | if ((code = dict_float_param(pprivate, "BlueScale", 0.039625, &pdata1->BlueScale)) < 0) |
447 | 0 | return code; |
448 | 123k | if ((code = dict_float_param(pprivate, "BlueShift", 7.0, &pdata1->BlueShift)) < 0) |
449 | 0 | return code; |
450 | 123k | if ((code = pdata1->BlueValues.count = dict_float_array_param(mem, pprivate, "BlueValues", |
451 | 123k | max_BlueValues * 2, &pdata1->BlueValues.values[0], NULL)) < 0) |
452 | 0 | return code; |
453 | 123k | if (pdata1->BlueValues.count % 2 != 0) |
454 | 0 | return_error(gs_error_rangecheck); |
455 | | |
456 | 123k | if ((code = dict_float_param(pprivate, "ExpansionFactor", 0.06, &pdata1->ExpansionFactor)) < 0) |
457 | 0 | return code; |
458 | 123k | if ((code = pdata1->FamilyBlues.count = dict_float_array_param(mem, pprivate, "FamilyBlues", |
459 | 123k | max_FamilyBlues * 2, &pdata1->FamilyBlues.values[0], NULL)) < 0) |
460 | 0 | return code; |
461 | 123k | if (pdata1->FamilyBlues.count % 2 != 0) |
462 | 0 | return_error(gs_error_rangecheck); |
463 | | |
464 | 123k | if ((code = pdata1->FamilyOtherBlues.count = dict_float_array_param(mem, pprivate, "FamilyOtherBlues", |
465 | 123k | max_FamilyOtherBlues * 2, &pdata1->FamilyOtherBlues.values[0], NULL)) < 0) |
466 | 0 | return code; |
467 | 123k | if (pdata1->FamilyOtherBlues.count % 2 != 0) |
468 | 0 | return_error(gs_error_rangecheck); |
469 | | |
470 | 123k | if ((code = dict_bool_param(pprivate, "ForceBold", false, &pdata1->ForceBold)) < 0) |
471 | 0 | return code; |
472 | | /* |
473 | | * We've seen a few fonts with out-of-range LanguageGroup values; |
474 | | * if it weren't for this, the only legal values should be 0 or 1. |
475 | | */ |
476 | 123k | if ((code = dict_int_param(pprivate, "LanguageGroup", min_int, max_int, 0, &pdata1->LanguageGroup)) < 0) |
477 | 0 | return code; |
478 | 123k | if ((code = pdata1->OtherBlues.count = dict_float_array_param(mem, pprivate, "OtherBlues", |
479 | 123k | max_OtherBlues * 2, &pdata1->OtherBlues.values[0], NULL)) < 0) |
480 | 0 | return code; |
481 | 123k | if (pdata1->OtherBlues.count % 2 != 0) |
482 | 0 | return_error(gs_error_rangecheck); |
483 | | |
484 | 123k | if ((code = dict_bool_param(pprivate, "RndStemUp", true, &pdata1->RndStemUp)) < 0) |
485 | 0 | return code; |
486 | 123k | if ((code = pdata1->StdHW.count = dict_float_array_check_param(mem, pprivate, "StdHW", |
487 | 123k | 1, &pdata1->StdHW.values[0], NULL, 0, gs_error_rangecheck)) < 0) |
488 | 0 | return code; |
489 | 123k | if ((code = pdata1->StdVW.count = dict_float_array_check_param(mem, pprivate, "StdVW", |
490 | 123k | 1, &pdata1->StdVW.values[0], NULL, 0, gs_error_rangecheck)) < 0) |
491 | 0 | return code; |
492 | 123k | if ((code = pdata1->StemSnapH.count = dict_float_array_param(mem, pprivate, "StemSnapH", |
493 | 123k | max_StemSnap, &pdata1->StemSnapH.values[0], NULL)) < 0) |
494 | 0 | return code; |
495 | 123k | if ((code = pdata1->StemSnapV.count = dict_float_array_param(mem, pprivate, "StemSnapV", |
496 | 123k | max_StemSnap, &pdata1->StemSnapV.values[0], NULL)) < 0) |
497 | 0 | return code; |
498 | | /* The WeightVector is in the font dictionary, not Private. */ |
499 | 123k | if ((code = pdata1->WeightVector.count = dict_float_array_param(mem, op, "WeightVector", |
500 | 123k | max_WeightVector, pdata1->WeightVector.values, NULL)) < 0) |
501 | 0 | return code; |
502 | | |
503 | 123k | if (pdata1->WeightVector.count > 0) { |
504 | 1 | code = charstring_check_mm_params((ref *)op, pdata1->WeightVector.count); |
505 | 1 | if (code < 0) |
506 | 0 | return code; |
507 | 1 | } |
508 | | /* |
509 | | * According to section 5.6 of the "Adobe Type 1 Font Format", |
510 | | * there is a requirement that BlueScale times the maximum |
511 | | * alignment zone height must be less than 1. Some fonts |
512 | | * produced by Fontographer have ridiculously large BlueScale |
513 | | * values, so we force BlueScale back into range here. |
514 | | */ |
515 | 123k | { |
516 | 123k | float max_zone_height = 1.0; |
517 | | |
518 | 123k | find_zone_height(&max_zone_height, pdata1->BlueValues.count, pdata1->BlueValues.values); |
519 | 123k | find_zone_height(&max_zone_height, pdata1->OtherBlues.count, pdata1->OtherBlues.values); |
520 | 123k | find_zone_height(&max_zone_height, pdata1->FamilyBlues.count, pdata1->FamilyBlues.values); |
521 | 123k | find_zone_height(&max_zone_height, pdata1->FamilyOtherBlues.count, pdata1->FamilyOtherBlues.values); |
522 | 123k | if (pdata1->BlueScale * max_zone_height > 1.0) |
523 | 0 | pdata1->BlueScale = 1.0 / max_zone_height; |
524 | 123k | } |
525 | | /* |
526 | | * According to the same Adobe book, section 5.11, only values |
527 | | * 0 and 1 are allowed for LanguageGroup and we have encountered |
528 | | * fonts with other values. If the value is anything else, map it to 0 |
529 | | * so that the remainder of the graphics library won't see an |
530 | | * unexpected value. |
531 | | */ |
532 | 123k | if (pdata1->LanguageGroup > 1 || pdata1->LanguageGroup < 0) |
533 | 0 | pdata1->LanguageGroup = 0; |
534 | | |
535 | | /* This is used only when determining if its possible to copy glyphs |
536 | | * between fonts. Currenly only by pdfwrite and friends. Rather than |
537 | | * check all the subrs (which we used to do) we hash tehm, store it |
538 | | * and check the hashes. Zero except when in use by pdfwrite.. |
539 | | */ |
540 | 123k | memset(&pdata1->hash_subrs, 0x00, 16); |
541 | 123k | return 0; |
542 | 123k | } |
543 | | |
544 | | /* Fill in a newly built CharString-based font or FDArray entry. */ |
545 | | int |
546 | | charstring_font_init(gs_font_type1 *pfont, const charstring_font_refs_t *pfr, |
547 | | const gs_type1_data *pdata1) |
548 | 123k | { |
549 | 123k | font_data *pdata; |
550 | | |
551 | 123k | pdata = pfont_data(pfont); |
552 | 123k | pfont->data = *pdata1; |
553 | 123k | pfont->data.parent = NULL; |
554 | 123k | ref_assign(&pdata->u.type1.OtherSubrs, pfr->OtherSubrs); |
555 | 123k | ref_assign(&pdata->u.type1.Subrs, pfr->Subrs); |
556 | 123k | ref_assign(&pdata->u.type1.GlobalSubrs, pfr->GlobalSubrs); |
557 | 123k | pfont->data.procs = z1_data_procs; |
558 | 123k | pfont->data.proc_data = (char *)pdata; |
559 | 123k | pfont->procs.same_font = z1_same_font; |
560 | 123k | pfont->procs.glyph_info = z1_glyph_info; |
561 | 123k | pfont->procs.enumerate_glyph = z1_enumerate_glyph; |
562 | 123k | pfont->procs.glyph_outline = zchar1_glyph_outline; |
563 | 123k | return 0; |
564 | 123k | } |
565 | | |
566 | | /* Build a Type 1, Type 2, or Type 4 font. */ |
567 | | int |
568 | | build_charstring_font(i_ctx_t *i_ctx_p, os_ptr op, build_proc_refs *pbuild, |
569 | | font_type ftype, charstring_font_refs_t *pfr, |
570 | | gs_type1_data *pdata1, build_font_options_t options) |
571 | 123k | { |
572 | 123k | int code = charstring_font_params(imemory, op, pfr, pdata1); |
573 | 123k | gs_font_type1 *pfont; |
574 | | |
575 | 123k | if (code < 0) |
576 | 0 | return code; |
577 | 123k | code = build_gs_primitive_font(i_ctx_p, op, (gs_font_base **)&pfont, ftype, |
578 | 123k | &st_gs_font_type1, pbuild, options); |
579 | 123k | if (code != 0) |
580 | 44 | return code; |
581 | | /* This is a new font, fill it in. */ |
582 | 123k | charstring_font_init(pfont, pfr, pdata1); |
583 | 123k | return define_gs_font(i_ctx_p, (gs_font *)pfont); |
584 | 123k | } |
585 | | |
586 | | /* ------ Operators ------ */ |
587 | | |
588 | | /* Build a Type 1 or Type 4 font. */ |
589 | | static int |
590 | | buildfont1or4(i_ctx_t *i_ctx_p, os_ptr op, build_proc_refs * pbuild, |
591 | | font_type ftype, build_font_options_t options) |
592 | 123k | { |
593 | 123k | charstring_font_refs_t refs; |
594 | 123k | int code; |
595 | 123k | gs_type1_data data1; |
596 | | |
597 | 123k | check_op(2); |
598 | 123k | code = charstring_font_get_refs(op, &refs); |
599 | 123k | if (code < 0) |
600 | 6 | return code; |
601 | 123k | data1.interpret = gs_type1_interpret; |
602 | 123k | data1.subroutineNumberBias = 0; |
603 | 123k | data1.gsubrNumberBias = 0; |
604 | | |
605 | 123k | data1.lenIV = DEFAULT_LENIV_1; |
606 | 123k | return build_charstring_font(i_ctx_p, op, pbuild, ftype, &refs, &data1, |
607 | 123k | options); |
608 | 123k | } |
609 | | |
610 | | /* <string|name> <font_dict> .buildfont1 <string|name> <font> */ |
611 | | /* Build a type 1 (Adobe encrypted) font. */ |
612 | | static int |
613 | | zbuildfont1(i_ctx_t *i_ctx_p) |
614 | 123k | { |
615 | 123k | os_ptr op = osp; |
616 | 123k | build_proc_refs build; |
617 | 123k | int code = build_proc_name_refs(imemory, &build, |
618 | 123k | "%Type1BuildChar", "%Type1BuildGlyph"); |
619 | | |
620 | 123k | if (code < 0) |
621 | 0 | return code; |
622 | 123k | return buildfont1or4(i_ctx_p, op, &build, ft_encrypted, |
623 | 123k | bf_notdef_required); |
624 | 123k | } |
625 | | |
626 | | /* <string|name> <font_dict> .buildfont4 <string|name> <font> */ |
627 | | /* Build a type 4 (disk-based Adobe encrypted) font. */ |
628 | | static int |
629 | | zbuildfont4(i_ctx_t *i_ctx_p) |
630 | 4 | { |
631 | 4 | os_ptr op = osp; |
632 | 4 | build_proc_refs build; |
633 | 4 | int code = build_gs_font_procs(op, &build); |
634 | | |
635 | 4 | if (code < 0) |
636 | 4 | return code; |
637 | 0 | return buildfont1or4(i_ctx_p, op, &build, ft_disk_based, bf_options_none); |
638 | 4 | } |
639 | | |
640 | | /* ------ Initialization procedure ------ */ |
641 | | |
642 | | const op_def zfont1_op_defs[] = |
643 | | { |
644 | | {"2.buildfont1", zbuildfont1}, |
645 | | {"2.buildfont4", zbuildfont4}, |
646 | | op_def_end(0) |
647 | | }; |
648 | | |
649 | | /* ------ Font procedures for Type 1 fonts ------ */ |
650 | | |
651 | | /* same_font procedure */ |
652 | | static bool |
653 | | same_font_dict(const font_data *pdata, const font_data *podata, |
654 | | const char *key) |
655 | 0 | { |
656 | 0 | ref *pvalue; |
657 | 0 | bool present = dict_find_string(&pdata->dict, key, &pvalue) > 0; |
658 | 0 | ref *povalue; |
659 | 0 | bool opresent = dict_find_string(&podata->dict, key, &povalue) > 0; |
660 | 0 | dict *pdict = (&(podata->dict))->value.pdict; |
661 | |
|
662 | 0 | return (present == opresent && |
663 | 0 | (present <= 0 || obj_eq(dict_mem(pdict), pvalue, povalue))); |
664 | 0 | } |
665 | | static bool z1_check_data_procs_equal(const gs_type1_data_procs_t *p1, const gs_type1_data_procs_t *p2) |
666 | 0 | { |
667 | 0 | if (p1->glyph_data != p2->glyph_data) |
668 | 0 | return false; |
669 | 0 | if (p1->subr_data != p2->subr_data) |
670 | 0 | return false; |
671 | 0 | if (p1->seac_data != p2->seac_data) |
672 | 0 | return false; |
673 | 0 | if (p1->push_values != p2->push_values) |
674 | 0 | return false; |
675 | 0 | if (p1->pop_value != p2->pop_value) |
676 | 0 | return false; |
677 | 0 | return true; |
678 | 0 | } |
679 | | |
680 | | static int |
681 | | z1_same_font(const gs_font *font, const gs_font *ofont, int mask) |
682 | 2.65k | { |
683 | 2.65k | if (ofont->FontType != font->FontType) |
684 | 0 | return 0; |
685 | 3.97k | while (font->base != font) |
686 | 1.32k | font = font->base; |
687 | 3.97k | while (ofont->base != ofont) |
688 | 1.32k | ofont = ofont->base; |
689 | 2.65k | if (ofont == font) |
690 | 2.65k | return mask; |
691 | 0 | { |
692 | 0 | int same = gs_base_same_font(font, ofont, mask); |
693 | 0 | int check = mask & ~same; |
694 | 0 | const gs_font_type1 *const pfont1 = (const gs_font_type1 *)font; |
695 | 0 | const font_data *const pdata = pfont_data(pfont1); |
696 | 0 | const gs_font_type1 *pofont1 = (const gs_font_type1 *)ofont; |
697 | 0 | const font_data *const podata = pfont_data(pofont1); |
698 | 0 | bool same_data_procs = z1_check_data_procs_equal(&pofont1->data.procs, &z1_data_procs); |
699 | | |
700 | |
|
701 | 0 | if ((check & (FONT_SAME_OUTLINES | FONT_SAME_METRICS)) && same_data_procs && |
702 | 0 | obj_eq(font->memory, &pdata->CharStrings, &podata->CharStrings) && |
703 | | /* |
704 | | * We use same_font_dict for convenience: we know that |
705 | | * both fonts do have Private dictionaries. |
706 | | */ |
707 | 0 | same_font_dict(pdata, podata, "Private") |
708 | 0 | ) |
709 | 0 | same |= FONT_SAME_OUTLINES; |
710 | |
|
711 | 0 | if ((check & FONT_SAME_METRICS) && (same & FONT_SAME_OUTLINES) && same_data_procs && |
712 | | /* Metrics may be affected by CDevProc, Metrics, Metrics2. */ |
713 | 0 | same_font_dict(pdata, podata, "Metrics") && |
714 | 0 | same_font_dict(pdata, podata, "Metrics2") && |
715 | 0 | same_font_dict(pdata, podata, "CDevProc") |
716 | 0 | ) |
717 | 0 | same |= FONT_SAME_METRICS; |
718 | |
|
719 | 0 | if ((check & FONT_SAME_ENCODING) && |
720 | 0 | pofont1->procs.same_font == z1_same_font && |
721 | 0 | obj_eq(font->memory, &pdata->Encoding, &podata->Encoding) |
722 | 0 | ) |
723 | 0 | same |= FONT_SAME_ENCODING; |
724 | |
|
725 | 0 | return same & mask; |
726 | 2.65k | } |
727 | 2.65k | } |