/src/ghostpdl/psi/zfapi.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2022 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 | | /* Font API client */ |
18 | | |
19 | | #include "stdlib.h" /* abs() */ |
20 | | |
21 | | #include "memory_.h" |
22 | | #include "math_.h" |
23 | | #include "stat_.h" /* include before definition of esp macro, bug 691123 */ |
24 | | #include "string_.h" |
25 | | #include "ghost.h" |
26 | | #include "gp.h" |
27 | | #include "oper.h" |
28 | | #include "gxdevice.h" |
29 | | #include "gxfont.h" |
30 | | #include "gxfont1.h" |
31 | | #include "gxchar.h" |
32 | | #include "gzpath.h" |
33 | | #include "gxpath.h" |
34 | | #include "gxfcache.h" |
35 | | #include "gxchrout.h" |
36 | | #include "gximask.h" |
37 | | #include "gscoord.h" |
38 | | #include "gspaint.h" |
39 | | #include "gsfont.h" |
40 | | #include "gspath.h" |
41 | | #include "bfont.h" |
42 | | #include "dstack.h" |
43 | | #include "estack.h" |
44 | | #include "ichar.h" |
45 | | #include "idict.h" |
46 | | #include "iname.h" |
47 | | #include "ifont.h" |
48 | | #include "icid.h" |
49 | | #include "igstate.h" |
50 | | #include "icharout.h" |
51 | | |
52 | | #include "ifapi.h" |
53 | | #include "iplugin.h" |
54 | | #include "store.h" |
55 | | #include "gzstate.h" |
56 | | /* #include "gdevpsf.h" */ |
57 | | #include "stream.h" /* for files.h */ |
58 | | #include "gscrypt1.h" |
59 | | #include "gxfcid.h" |
60 | | #include "gsstype.h" |
61 | | #include "gxchar.h" /* for st_gs_show_enum */ |
62 | | #include "ipacked.h" /* for packed_next */ |
63 | | #include "iddict.h" |
64 | | #include "ifont42.h" /* for string_array_access_proc */ |
65 | | #include "gdebug.h" |
66 | | #include "gsimage.h" |
67 | | #include "gxcldev.h" |
68 | | #include "gxdevmem.h" |
69 | | |
70 | | #include "gxfapi.h" |
71 | | |
72 | | /* -------------------------------------------------------- */ |
73 | | |
74 | | typedef struct sfnts_reader_s sfnts_reader; |
75 | | struct sfnts_reader_s |
76 | | { |
77 | | ref *sfnts; |
78 | | const gs_memory_t *memory; |
79 | | const byte *p; |
80 | | long index; |
81 | | uint offset; |
82 | | uint length; |
83 | | int error; |
84 | | byte(*rbyte) (sfnts_reader *r); |
85 | | ushort(*rword) (sfnts_reader *r); |
86 | | ulong(*rlong) (sfnts_reader *r); |
87 | | int (*rstring) (sfnts_reader *r, byte *v, int length); |
88 | | void (*seek) (sfnts_reader *r, ulong pos); |
89 | | }; |
90 | | |
91 | | static void |
92 | | sfnts_next_elem(sfnts_reader *r) |
93 | 134 | { |
94 | 134 | ref s; |
95 | 134 | int code; |
96 | | |
97 | 134 | if (r->error < 0) |
98 | 0 | return; |
99 | 134 | do { |
100 | 134 | r->index++; |
101 | 134 | code = array_get(r->memory, r->sfnts, r->index, &s); |
102 | 134 | if (code < 0) { |
103 | 6 | r->error = code; |
104 | 6 | return; |
105 | 6 | } |
106 | 128 | if (!r_has_type(&s, t_string)) { |
107 | 4 | r->error = gs_note_error(gs_error_typecheck); |
108 | 4 | return; |
109 | 4 | } |
110 | 124 | r->p = s.value.const_bytes; |
111 | 124 | r->length = r_size(&s) & ~(uint) 1; /* See Adobe Technical Note # 5012, section 4.2. */ |
112 | 124 | } while (r->length == 0); |
113 | 124 | r->offset = 0; |
114 | 124 | } |
115 | | |
116 | | static inline byte |
117 | | sfnts_reader_rbyte_inline(sfnts_reader *r) |
118 | 2.37k | { |
119 | 2.37k | if (r->offset >= r->length) |
120 | 2 | sfnts_next_elem(r); |
121 | 2.37k | return ((r->error < 0) ? 0 : r->p[r->offset++]); |
122 | 2.37k | } |
123 | | |
124 | | static byte |
125 | | sfnts_reader_rbyte(sfnts_reader *r) |
126 | 0 | { /* old compiler compatibility */ |
127 | 0 | return (sfnts_reader_rbyte_inline(r)); |
128 | 0 | } |
129 | | |
130 | 176 | #define SFNTS_READER_RBYTE_TO_USHORT(r) ((ulong)sfnts_reader_rbyte_inline(r)) |
131 | | |
132 | | static ushort |
133 | | sfnts_reader_rword(sfnts_reader *r) |
134 | 88 | { |
135 | 88 | ushort retval; |
136 | | |
137 | 88 | retval = SFNTS_READER_RBYTE_TO_USHORT(r) << 8; |
138 | 88 | retval += SFNTS_READER_RBYTE_TO_USHORT(r); |
139 | | |
140 | 88 | return retval; |
141 | 88 | } |
142 | | |
143 | | #undef SFNTS_READER_RBYTE_TO_USHORT |
144 | | |
145 | 2.20k | #define SFNTS_READER_RBYTE_TO_ULONG(r) ((ulong)sfnts_reader_rbyte_inline(r)) |
146 | | |
147 | | static ulong |
148 | | sfnts_reader_rlong(sfnts_reader *r) |
149 | 550 | { |
150 | 550 | ulong retval; |
151 | 550 | retval = SFNTS_READER_RBYTE_TO_ULONG(r) << 24; |
152 | 550 | retval += SFNTS_READER_RBYTE_TO_ULONG(r) << 16; |
153 | 550 | retval += SFNTS_READER_RBYTE_TO_ULONG(r) << 8; |
154 | 550 | retval += SFNTS_READER_RBYTE_TO_ULONG(r); |
155 | 550 | return retval; |
156 | 550 | } |
157 | | |
158 | | #undef SFNTS_READER_RWORD_TO_LONG |
159 | | |
160 | | static int |
161 | | sfnts_reader_rstring(sfnts_reader *r, byte *v, int length) |
162 | 176 | { |
163 | 176 | int rlength = length; |
164 | | |
165 | 176 | if (length <= 0) |
166 | 0 | return (0); |
167 | 178 | while (r->error >= 0) { |
168 | 178 | int l = min(length, r->length - r->offset); |
169 | | |
170 | 178 | memcpy(v, r->p + r->offset, l); |
171 | 178 | length -= l; |
172 | 178 | r->offset += l; |
173 | 178 | if (length <= 0) |
174 | 176 | return (rlength); |
175 | 2 | v += l; |
176 | 2 | sfnts_next_elem(r); |
177 | 2 | } |
178 | 0 | return (rlength - length); |
179 | 176 | } |
180 | | |
181 | | static void |
182 | | sfnts_reader_seek(sfnts_reader *r, ulong pos) |
183 | 10 | { /* fixme : optimize */ |
184 | 10 | ulong skipped = 0; |
185 | | |
186 | 10 | r->index = -1; |
187 | 10 | sfnts_next_elem(r); |
188 | 108 | while (skipped + r->length < pos && r->error >= 0) { |
189 | 98 | skipped += r->length; |
190 | 98 | sfnts_next_elem(r); |
191 | 98 | } |
192 | 10 | r->offset = pos - skipped; |
193 | 10 | } |
194 | | |
195 | | static void |
196 | | sfnts_reader_init(const gs_memory_t *mem, sfnts_reader *r, ref *pdr) |
197 | 22 | { |
198 | 22 | r->memory = mem; |
199 | 22 | r->rbyte = sfnts_reader_rbyte; |
200 | 22 | r->rword = sfnts_reader_rword; |
201 | 22 | r->rlong = sfnts_reader_rlong; |
202 | 22 | r->rstring = sfnts_reader_rstring; |
203 | 22 | r->seek = sfnts_reader_seek; |
204 | 22 | r->index = -1; |
205 | 22 | r->error = 0; |
206 | 22 | if (r_type(pdr) != t_dictionary || |
207 | 22 | dict_find_string(pdr, "sfnts", &r->sfnts) <= 0) |
208 | 0 | r->error = gs_error_undefined; |
209 | 22 | sfnts_next_elem(r); |
210 | 22 | } |
211 | | |
212 | | /* -------------------------------------------------------- */ |
213 | | |
214 | | typedef struct sfnts_writer_s sfnts_writer; |
215 | | struct sfnts_writer_s |
216 | | { |
217 | | byte *buf, *p; |
218 | | int buf_size; |
219 | | void (*wbyte) (sfnts_writer *w, byte v); |
220 | | void (*wword) (sfnts_writer *w, ushort v); |
221 | | void (*wlong) (sfnts_writer *w, ulong v); |
222 | | void (*wstring) (sfnts_writer *w, byte *v, int length); |
223 | | }; |
224 | | |
225 | | static void |
226 | | sfnts_writer_wbyte(sfnts_writer *w, byte v) |
227 | 0 | { |
228 | 0 | if (w->buf + w->buf_size < w->p + 1) |
229 | 0 | return; /* safety */ |
230 | 0 | w->p[0] = v; |
231 | 0 | w->p++; |
232 | 0 | } |
233 | | |
234 | | static void |
235 | | sfnts_writer_wword(sfnts_writer *w, ushort v) |
236 | 40 | { |
237 | 40 | if (w->buf + w->buf_size < w->p + 2) |
238 | 0 | return; /* safety */ |
239 | 40 | w->p[0] = v / 256; |
240 | 40 | w->p[1] = v % 256; |
241 | 40 | w->p += 2; |
242 | 40 | } |
243 | | |
244 | | static void |
245 | | sfnts_writer_wlong(sfnts_writer *w, ulong v) |
246 | 190 | { |
247 | 190 | if (w->buf + w->buf_size < w->p + 4) |
248 | 0 | return; /* safety */ |
249 | 190 | w->p[0] = v >> 24; |
250 | 190 | w->p[1] = (v >> 16) & 0xFF; |
251 | 190 | w->p[2] = (v >> 8) & 0xFF; |
252 | 190 | w->p[3] = v & 0xFF; |
253 | 190 | w->p += 4; |
254 | 190 | } |
255 | | |
256 | | static void |
257 | | sfnts_writer_wstring(sfnts_writer *w, byte *v, int length) |
258 | 60 | { |
259 | 60 | if (w->buf + w->buf_size < w->p + length) |
260 | 0 | return; /* safety */ |
261 | 60 | memcpy(w->p, v, length); |
262 | 60 | w->p += length; |
263 | 60 | } |
264 | | |
265 | | static const sfnts_writer sfnts_writer_stub = { |
266 | | 0, 0, 0, |
267 | | sfnts_writer_wbyte, |
268 | | sfnts_writer_wword, |
269 | | sfnts_writer_wlong, |
270 | | sfnts_writer_wstring |
271 | | }; |
272 | | |
273 | | /* -------------------------------------------------------- */ |
274 | | |
275 | | static inline bool |
276 | | sfnts_need_copy_table(byte *tag) |
277 | 266 | { |
278 | 266 | return (memcmp(tag, "glyf", 4) && memcmp(tag, "glyx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */ |
279 | 266 | memcmp(tag, "loca", 4) && memcmp(tag, "locx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */ |
280 | 266 | memcmp(tag, "cmap", 4)); |
281 | 266 | } |
282 | | |
283 | | static void |
284 | | sfnt_copy_table(sfnts_reader *r, sfnts_writer *w, int length) |
285 | 10 | { |
286 | 10 | byte buf[1024]; |
287 | | |
288 | 10 | while (length > 0 && r->error >= 0) { |
289 | 0 | int l = min(length, sizeof(buf)); |
290 | |
|
291 | 0 | (void)r->rstring(r, buf, l); |
292 | 0 | w->wstring(w, buf, l); |
293 | 0 | length -= l; |
294 | 0 | } |
295 | 10 | } |
296 | | |
297 | | static int |
298 | | sfnts_copy_except_glyf(sfnts_reader *r, sfnts_writer *w) |
299 | 22 | { /* Note : TTC is not supported and probably is unuseful for Type 42. */ |
300 | | /* This skips glyf, loca and cmap from copying. */ |
301 | 22 | struct |
302 | 22 | { |
303 | 22 | byte tag[4]; |
304 | 22 | ulong checkSum, offset, offset_new, length; |
305 | 22 | } tables[30]; |
306 | 22 | const ushort alignment = 4; /* Not sure, maybe 2 */ |
307 | 22 | ulong version = r->rlong(r); |
308 | 22 | ushort num_tables = r->rword(r); |
309 | 22 | ushort i, num_tables_new = 0; |
310 | 22 | ushort searchRange, entrySelector = 0, rangeShift, v; |
311 | 22 | ulong size_new = 12; |
312 | | |
313 | 22 | r->rword(r); /* searchRange */ |
314 | 22 | if (r->error < 0) |
315 | 0 | return r->error; |
316 | | |
317 | 22 | r->rword(r); /* entrySelector */ |
318 | 22 | if (r->error < 0) |
319 | 0 | return r->error; |
320 | | |
321 | 22 | r->rword(r); /* rangeShift */ |
322 | 22 | if (r->error < 0) |
323 | 0 | return r->error; |
324 | | |
325 | 198 | for (i = 0; i < num_tables && r->error >= 0; i++) { |
326 | 176 | (void)r->rstring(r, tables[i].tag, 4); |
327 | 176 | if (r->error < 0) |
328 | 0 | continue; |
329 | 176 | tables[i].checkSum = r->rlong(r); |
330 | 176 | tables[i].offset = r->rlong(r); |
331 | 176 | tables[i].length = r->rlong(r); |
332 | 176 | tables[i].offset_new = size_new; |
333 | 176 | if (sfnts_need_copy_table(tables[i].tag)) { |
334 | 136 | num_tables_new++; |
335 | 136 | size_new += |
336 | 136 | (tables[i].length + alignment - 1) / alignment * alignment; |
337 | 136 | } |
338 | 176 | } |
339 | 22 | if (r->error < 0) |
340 | 0 | return r->error; |
341 | 22 | size_new += num_tables_new * 16; |
342 | 22 | if (w == 0) { |
343 | 12 | return size_new; |
344 | 12 | } |
345 | 10 | searchRange = v = num_tables_new * 16; |
346 | 80 | for (i = 0; v; i++) { |
347 | 70 | v >>= 1; |
348 | 70 | searchRange |= v; |
349 | 70 | entrySelector++; |
350 | 70 | } |
351 | 10 | searchRange -= searchRange >> 1; |
352 | 10 | rangeShift = num_tables_new * 16 - searchRange; |
353 | | |
354 | 10 | w->wlong(w, version); |
355 | 10 | w->wword(w, num_tables_new); |
356 | 10 | w->wword(w, searchRange); |
357 | 10 | w->wword(w, entrySelector); |
358 | 10 | w->wword(w, rangeShift); |
359 | 90 | for (i = 0; i < num_tables; i++) { |
360 | 80 | if (sfnts_need_copy_table(tables[i].tag)) { |
361 | 60 | w->wstring(w, tables[i].tag, 4); |
362 | 60 | w->wlong(w, tables[i].checkSum); |
363 | 60 | w->wlong(w, tables[i].offset_new + num_tables_new * 16); |
364 | 60 | w->wlong(w, tables[i].length); |
365 | 60 | } |
366 | 80 | } |
367 | 20 | for (i = 0; i < num_tables && r->error >= 0; i++) { |
368 | 10 | if (sfnts_need_copy_table(tables[i].tag)) { |
369 | 10 | int k = tables[i].length; |
370 | | |
371 | 10 | r->seek(r, tables[i].offset); |
372 | | |
373 | 10 | if (w->p - w->buf != tables[i].offset_new + num_tables_new * 16) { |
374 | 0 | r->error = gs_error_invalidfont; /* the algorithm consistency check */ |
375 | 0 | continue; |
376 | 0 | } |
377 | 10 | sfnt_copy_table(r, w, tables[i].length); |
378 | 10 | for (; k & (alignment - 1); k++) |
379 | 0 | w->wbyte(w, 0); |
380 | 10 | } |
381 | 10 | } |
382 | 10 | if (r->error < 0) |
383 | 10 | return r->error; |
384 | | |
385 | 0 | return (size_new); |
386 | 10 | } |
387 | | |
388 | | static int |
389 | | true_type_size(const gs_memory_t *mem, ref *pdr, unsigned long int *length) |
390 | 12 | { |
391 | 12 | sfnts_reader r; |
392 | | |
393 | 12 | sfnts_reader_init(mem, &r, pdr); |
394 | 12 | *length = sfnts_copy_except_glyf(&r, 0); |
395 | | |
396 | 12 | return r.error; |
397 | 12 | } |
398 | | |
399 | | static int |
400 | | FAPI_FF_serialize_tt_font(gs_fapi_font *ff, void *buf, int buf_size) |
401 | 10 | { |
402 | 10 | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
403 | 10 | sfnts_reader r; |
404 | 10 | sfnts_writer w = sfnts_writer_stub; |
405 | | |
406 | 10 | w.buf_size = buf_size; |
407 | 10 | w.buf = w.p = buf; |
408 | 10 | sfnts_reader_init(ff->memory, &r, pdr); |
409 | 10 | return sfnts_copy_except_glyf(&r, &w); |
410 | 10 | } |
411 | | |
412 | | static inline ushort |
413 | | float_to_ushort(float v) |
414 | 1.37M | { |
415 | 1.37M | return ((ushort) (v * 16)); /* fixme : the scale may depend on renderer */ |
416 | 1.37M | } |
417 | | |
418 | | /* In general, we assumed that the entries we use below have been validated (at least for type) |
419 | | * at definefont time. This means validating each entry only once, rather than on every read |
420 | | * here. Better, for example, for BlendDesignMap which is an array, of arrays, of arrays of |
421 | | * numbers. |
422 | | */ |
423 | | static int |
424 | | FAPI_FF_get_word(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, unsigned short *ret) |
425 | 2.65M | { |
426 | 2.65M | gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data; |
427 | 2.65M | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
428 | 2.65M | int code = 0; |
429 | | |
430 | 2.65M | switch ((int)var_id) { |
431 | 0 | case gs_fapi_font_feature_Weight: |
432 | 0 | *ret = 0; /* wrong */ |
433 | 0 | break; |
434 | 0 | case gs_fapi_font_feature_ItalicAngle: |
435 | 0 | *ret = 0; /* wrong */ |
436 | 0 | break; |
437 | 0 | case gs_fapi_font_feature_IsFixedPitch: |
438 | 0 | *ret = 0; /* wrong */ |
439 | 0 | break; |
440 | 0 | case gs_fapi_font_feature_UnderLinePosition: |
441 | 0 | *ret = 0; /* wrong */ |
442 | 0 | break; |
443 | 0 | case gs_fapi_font_feature_UnderlineThickness: |
444 | 0 | *ret = 0; /* wrong */ |
445 | 0 | break; |
446 | 43.9k | case gs_fapi_font_feature_FontType: |
447 | 43.9k | *ret = (pfont->FontType == 2 ? 2 : 1); |
448 | 43.9k | break; |
449 | 351k | case gs_fapi_font_feature_FontBBox: |
450 | 351k | switch (index) { |
451 | 87.9k | case 0: |
452 | 87.9k | *ret = ((ushort) pfont->FontBBox.p.x); |
453 | 87.9k | break; |
454 | 87.9k | case 1: |
455 | 87.9k | *ret = ((ushort) pfont->FontBBox.p.y); |
456 | 87.9k | break; |
457 | 87.9k | case 2: |
458 | 87.9k | *ret = ((ushort) pfont->FontBBox.q.x); |
459 | 87.9k | break; |
460 | 87.9k | case 3: |
461 | 87.9k | *ret = ((ushort) pfont->FontBBox.q.y); |
462 | 87.9k | break; |
463 | 0 | default: |
464 | 0 | code = gs_note_error(gs_error_rangecheck); |
465 | 351k | } |
466 | 351k | break; |
467 | 351k | case gs_fapi_font_feature_BlueValues_count: |
468 | 87.9k | *ret = pfont->data.BlueValues.count; |
469 | 87.9k | break; |
470 | 677k | case gs_fapi_font_feature_BlueValues: |
471 | 677k | *ret = (float_to_ushort(pfont->data.BlueValues.values[index])); |
472 | 677k | break; |
473 | 87.9k | case gs_fapi_font_feature_OtherBlues_count: |
474 | 87.9k | *ret = pfont->data.OtherBlues.count; |
475 | 87.9k | break; |
476 | 0 | case gs_fapi_font_feature_OtherBlues: |
477 | 0 | *ret = (float_to_ushort(pfont->data.OtherBlues.values[index])); |
478 | 0 | break; |
479 | 87.9k | case gs_fapi_font_feature_FamilyBlues_count: |
480 | 87.9k | *ret = pfont->data.FamilyBlues.count; |
481 | 87.9k | break; |
482 | 0 | case gs_fapi_font_feature_FamilyBlues: |
483 | 0 | *ret = (float_to_ushort(pfont->data.FamilyBlues.values[index])); |
484 | 0 | break; |
485 | 87.9k | case gs_fapi_font_feature_FamilyOtherBlues_count: |
486 | 87.9k | *ret = pfont->data.FamilyOtherBlues.count; |
487 | 87.9k | break; |
488 | 0 | case gs_fapi_font_feature_FamilyOtherBlues: |
489 | 0 | *ret = (float_to_ushort(pfont->data.FamilyOtherBlues.values[index])); |
490 | 0 | break; |
491 | 87.9k | case gs_fapi_font_feature_BlueShift: |
492 | 87.9k | *ret = float_to_ushort(pfont->data.BlueShift); |
493 | 87.9k | break; |
494 | 87.9k | case gs_fapi_font_feature_BlueFuzz: |
495 | 87.9k | *ret = float_to_ushort(pfont->data.BlueShift); |
496 | 87.9k | break; |
497 | 87.9k | case gs_fapi_font_feature_StdHW: |
498 | 87.9k | *ret = (pfont->data.StdHW.count == 0 ? 0 : float_to_ushort(pfont->data.StdHW.values[0])); /* UFST bug ? */ |
499 | 87.9k | break; |
500 | 87.9k | case gs_fapi_font_feature_StdVW: |
501 | 87.9k | *ret = (pfont->data.StdVW.count == 0 ? 0 : float_to_ushort(pfont->data.StdVW.values[0])); /* UFST bug ? */ |
502 | 87.9k | break; |
503 | 87.9k | case gs_fapi_font_feature_StemSnapH_count: |
504 | 87.9k | *ret = pfont->data.StemSnapH.count; |
505 | 87.9k | break; |
506 | 175k | case gs_fapi_font_feature_StemSnapH: |
507 | 175k | *ret = float_to_ushort(pfont->data.StemSnapH.values[index]); |
508 | 175k | break; |
509 | 87.9k | case gs_fapi_font_feature_StemSnapV_count: |
510 | 87.9k | *ret = pfont->data.StemSnapV.count; |
511 | 87.9k | break; |
512 | 173k | case gs_fapi_font_feature_StemSnapV: |
513 | 173k | *ret = float_to_ushort(pfont->data.StemSnapV.values[index]); |
514 | 173k | break; |
515 | 87.9k | case gs_fapi_font_feature_ForceBold: |
516 | 87.9k | *ret = pfont->data.ForceBold; |
517 | 87.9k | break; |
518 | 0 | case gs_fapi_font_feature_LanguageGroup: |
519 | 0 | *ret = pfont->data.LanguageGroup; |
520 | 0 | break; |
521 | 0 | case gs_fapi_font_feature_lenIV: |
522 | 0 | *ret = ff->need_decrypt ? 0 : pfont->data.lenIV; |
523 | 0 | break; |
524 | 0 | case gs_fapi_font_feature_GlobalSubrs_count: |
525 | 0 | { |
526 | 0 | ref *Private, *GlobalSubrs; |
527 | |
|
528 | 0 | if (pfont->FontType == ft_encrypted2) { |
529 | 0 | if (dict_find_string(pdr, "Private", &Private) <= 0) { |
530 | 0 | *ret = 0; |
531 | 0 | break; |
532 | 0 | } |
533 | 0 | if (dict_find_string(Private, "GlobalSubrs", &GlobalSubrs) <= 0) { |
534 | 0 | *ret = 0; |
535 | 0 | break; |
536 | 0 | } |
537 | 0 | *ret = r_size(GlobalSubrs); |
538 | 0 | break; |
539 | 0 | } |
540 | 0 | *ret = 0; |
541 | 0 | break; |
542 | 0 | } |
543 | 87.9k | case gs_fapi_font_feature_Subrs_count: |
544 | 87.9k | { |
545 | 87.9k | ref *Private, *Subrs; |
546 | | |
547 | 87.9k | if (dict_find_string(pdr, "Private", &Private) <= 0) { |
548 | 0 | *ret = 0; |
549 | 0 | break; |
550 | 0 | } |
551 | 87.9k | if (dict_find_string(Private, "Subrs", &Subrs) <= 0) { |
552 | 0 | *ret = 0; |
553 | 0 | break; |
554 | 0 | } |
555 | 87.9k | *ret = r_size(Subrs); |
556 | 87.9k | break; |
557 | 87.9k | } |
558 | 0 | case gs_fapi_font_feature_CharStrings_count: |
559 | 0 | { |
560 | 0 | ref *CharStrings; |
561 | |
|
562 | 0 | if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0) |
563 | 0 | *ret = 0; |
564 | 0 | else |
565 | 0 | *ret = dict_maxlength(CharStrings); |
566 | 0 | break; |
567 | 87.9k | } |
568 | | /* Multiple Master specific */ |
569 | 175k | case gs_fapi_font_feature_DollarBlend: |
570 | 175k | { |
571 | 175k | ref *DBlend; |
572 | | |
573 | 175k | if (dict_find_string(pdr, "$Blend", &DBlend) <= 0) |
574 | 175k | *ret = 0; |
575 | 0 | else |
576 | 0 | *ret = 1; |
577 | 175k | break; |
578 | 87.9k | } |
579 | 0 | case gs_fapi_font_feature_BlendAxisTypes_count: |
580 | 0 | { |
581 | 0 | ref *Info, *Axes; |
582 | |
|
583 | 0 | if (dict_find_string(pdr, "FontInfo", &Info) <= 0) { |
584 | 0 | *ret = 0; |
585 | 0 | break; |
586 | 0 | } |
587 | 0 | if (dict_find_string(Info, "BlendAxisTypes", &Axes) <= 0) { |
588 | 0 | *ret = 0; |
589 | 0 | break; |
590 | 0 | } |
591 | 0 | *ret = r_size(Axes); |
592 | 0 | break; |
593 | 0 | } |
594 | 0 | case gs_fapi_font_feature_BlendFontInfo_count: |
595 | 0 | { |
596 | 0 | ref *Info, *FontInfo; |
597 | |
|
598 | 0 | if (dict_find_string(pdr, "Blend", &Info) <= 0) { |
599 | 0 | *ret = 0; |
600 | 0 | break; |
601 | 0 | } |
602 | 0 | if (dict_find_string(Info, "FontInfo", &FontInfo) <= 0) { |
603 | 0 | *ret = 0; |
604 | 0 | break; |
605 | 0 | } |
606 | 0 | *ret = dict_length(FontInfo); |
607 | 0 | break; |
608 | 0 | } |
609 | 0 | case gs_fapi_font_feature_BlendPrivate_count: |
610 | 0 | { |
611 | 0 | ref *Info, *Private; |
612 | |
|
613 | 0 | if (dict_find_string(pdr, "Blend", &Info) <= 0) { |
614 | 0 | *ret = 0; |
615 | 0 | break; |
616 | 0 | } |
617 | 0 | if (dict_find_string(Info, "Private", &Private) <= 0) { |
618 | 0 | *ret = 0; |
619 | 0 | break; |
620 | 0 | } |
621 | 0 | *ret = dict_length(Private); |
622 | 0 | break; |
623 | 0 | } |
624 | 0 | case gs_fapi_font_feature_WeightVector_count: |
625 | 0 | { |
626 | 0 | *ret = pfont->data.WeightVector.count; |
627 | 0 | break; |
628 | 0 | } |
629 | 0 | case gs_fapi_font_feature_BlendDesignPositionsArrays_count: |
630 | 0 | { |
631 | 0 | ref *Info, *Array; |
632 | |
|
633 | 0 | if (dict_find_string(pdr, "FontInfo", &Info) <= 0) { |
634 | 0 | *ret = 0; |
635 | 0 | break; |
636 | 0 | } |
637 | 0 | if (dict_find_string(Info, "BlendDesignPositions", &Array) <= 0) { |
638 | 0 | *ret = 0; |
639 | 0 | break; |
640 | 0 | } |
641 | 0 | *ret = r_size(Array); |
642 | 0 | break; |
643 | 0 | } |
644 | 0 | case gs_fapi_font_feature_BlendDesignMapArrays_count: |
645 | 0 | { |
646 | 0 | ref *Info, *Array; |
647 | |
|
648 | 0 | if (dict_find_string(pdr, "FontInfo", &Info) <= 0) { |
649 | 0 | *ret = 0; |
650 | 0 | break; |
651 | 0 | } |
652 | 0 | if (dict_find_string(Info, "BlendDesignMap", &Array) <= 0) { |
653 | 0 | *ret = 0; |
654 | 0 | break; |
655 | 0 | } |
656 | 0 | *ret = r_size(Array); |
657 | 0 | break; |
658 | 0 | } |
659 | 0 | case gs_fapi_font_feature_BlendDesignMapSubArrays_count: |
660 | 0 | { |
661 | 0 | ref *Info, *Array, SubArray; |
662 | |
|
663 | 0 | if (dict_find_string(pdr, "FontInfo", &Info) <= 0) { |
664 | 0 | *ret = 0; |
665 | 0 | break; |
666 | 0 | } |
667 | 0 | if (dict_find_string(Info, "BlendDesignMap", &Array) <= 0) { |
668 | 0 | *ret = 0; |
669 | 0 | break; |
670 | 0 | } |
671 | 0 | if (array_get(ff->memory, Array, index, &SubArray) < 0) { |
672 | 0 | *ret = 0; |
673 | 0 | break; |
674 | 0 | } |
675 | 0 | *ret = r_size(&SubArray); |
676 | 0 | break; |
677 | 0 | } |
678 | 0 | case gs_fapi_font_feature_DollarBlend_length: |
679 | 0 | { |
680 | 0 | ref *DBlend, Element, string; |
681 | 0 | int i, length = 0; |
682 | 0 | char Buffer[32]; |
683 | |
|
684 | 0 | if (dict_find_string(pdr, "$Blend", &DBlend) <= 0) { |
685 | 0 | *ret = 0; |
686 | 0 | break; |
687 | 0 | } |
688 | 0 | for (i = 0; i < r_size(DBlend); i++) { |
689 | 0 | if (array_get(ff->memory, DBlend, i, &Element) < 0) { |
690 | 0 | *ret = 0; |
691 | 0 | break; |
692 | 0 | } |
693 | 0 | switch (r_btype(&Element)) { |
694 | 0 | case t_name: |
695 | 0 | name_string_ref(ff->memory, &Element, &string); |
696 | 0 | length += r_size(&string) + 1; |
697 | 0 | break; |
698 | 0 | case t_real: |
699 | 0 | gs_snprintf(Buffer, sizeof(Buffer), "%f", Element.value.realval); |
700 | 0 | length += strlen(Buffer) + 1; |
701 | 0 | break; |
702 | 0 | case t_integer: |
703 | 0 | gs_snprintf(Buffer, sizeof(Buffer), "%"PRIpsint, Element.value.intval); |
704 | 0 | length += strlen(Buffer) + 1; |
705 | 0 | break; |
706 | 0 | case t_operator: |
707 | 0 | { |
708 | 0 | op_def const *op; |
709 | |
|
710 | 0 | op = op_index_def(r_size(&Element)); |
711 | 0 | length += strlen(op->oname + 1) + 1; |
712 | 0 | } |
713 | 0 | break; |
714 | 0 | default: |
715 | 0 | break; |
716 | 0 | } |
717 | 0 | } |
718 | 0 | *ret = length; |
719 | 0 | break; |
720 | 0 | } |
721 | 0 | case gs_fapi_font_feature_BlendFontBBox_length: |
722 | 0 | { |
723 | 0 | ref *Blend, *bfbbox; |
724 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
725 | 0 | *ret = 0; |
726 | 0 | break; |
727 | 0 | } |
728 | | |
729 | 0 | if (dict_find_string(Blend, "FontBBox", &bfbbox) <= 0) { |
730 | 0 | *ret = 0; |
731 | 0 | break; |
732 | 0 | } |
733 | 0 | *ret = (ushort)r_size(bfbbox); |
734 | 0 | break; |
735 | 0 | } |
736 | 0 | case gs_fapi_font_feature_BlendFontBBox: |
737 | 0 | { |
738 | 0 | ref *Blend, *bfbbox, subbfbbox, val; |
739 | 0 | int aind, ind; |
740 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
741 | 0 | *ret = 0; |
742 | 0 | break; |
743 | 0 | } |
744 | 0 | if (dict_find_string(Blend, "FontBBox", &bfbbox) <= 0) { |
745 | 0 | *ret = 0; |
746 | 0 | break; |
747 | 0 | } |
748 | 0 | ind = index % 4; |
749 | 0 | aind = (index - ind) /4; |
750 | 0 | if (array_get(ff->memory, bfbbox, aind, &subbfbbox) < 0) { |
751 | 0 | *ret = 0; |
752 | 0 | break; |
753 | 0 | } |
754 | 0 | if (array_get(ff->memory, &subbfbbox, ind, &val) < 0) { |
755 | 0 | *ret = 0; |
756 | 0 | break; |
757 | 0 | } |
758 | | |
759 | 0 | *ret = (ushort)val.value.intval; |
760 | 0 | break; |
761 | 0 | } |
762 | 0 | case gs_fapi_font_feature_BlendBlueValues_length: |
763 | 0 | { |
764 | 0 | ref *Priv, *Blend, *bbv; |
765 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
766 | 0 | *ret = 0; |
767 | 0 | break; |
768 | 0 | } |
769 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
770 | 0 | *ret = 0; |
771 | 0 | break; |
772 | 0 | } |
773 | 0 | if (dict_find_string(Priv, "BlueValues", &bbv) <= 0) { |
774 | 0 | *ret = 0; |
775 | 0 | break; |
776 | 0 | } |
777 | 0 | *ret = (ushort)r_size(bbv); |
778 | 0 | break; |
779 | 0 | } |
780 | 0 | case gs_fapi_font_feature_BlendBlueValues_count: |
781 | 0 | { |
782 | 0 | ref *Priv, *Blend, *bbv, sub; |
783 | |
|
784 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
785 | 0 | *ret = 0; |
786 | 0 | break; |
787 | 0 | } |
788 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
789 | 0 | *ret = 0; |
790 | 0 | break; |
791 | 0 | } |
792 | 0 | if (dict_find_string(Priv, "BlueValues", &bbv) <= 0) { |
793 | 0 | *ret = 0; |
794 | 0 | break; |
795 | 0 | } |
796 | 0 | if (array_get(ff->memory, bbv, index, &sub) < 0) { |
797 | 0 | *ret = 0; |
798 | 0 | break; |
799 | 0 | } |
800 | 0 | *ret = (ushort)r_size(&sub); |
801 | 0 | break; |
802 | 0 | } |
803 | 0 | case gs_fapi_font_feature_BlendBlueValues: |
804 | 0 | { |
805 | 0 | ref *Priv, *Blend, *bbv, sub, r; |
806 | 0 | int aind = 0; |
807 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
808 | 0 | *ret = 0; |
809 | 0 | break; |
810 | 0 | } |
811 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
812 | 0 | *ret = 0; |
813 | 0 | break; |
814 | 0 | } |
815 | 0 | if (dict_find_string(Priv, "BlueValues", &bbv) <= 0) { |
816 | 0 | *ret = 0; |
817 | 0 | break; |
818 | 0 | } |
819 | | |
820 | 0 | while (1) { |
821 | 0 | if ((code = array_get(ff->memory, bbv, aind++, &sub)) < 0) { |
822 | 0 | *ret = 0; |
823 | 0 | break; |
824 | 0 | } |
825 | 0 | if (index - (int)r_size(&sub) < 0) { |
826 | 0 | break; |
827 | 0 | } |
828 | 0 | index -= r_size(&sub); |
829 | 0 | } |
830 | 0 | if (code < 0) |
831 | 0 | break; |
832 | | |
833 | 0 | if (array_get(ff->memory, &sub, index, &r) < 0) { |
834 | 0 | *ret = 0; |
835 | 0 | break; |
836 | 0 | } |
837 | | |
838 | 0 | *ret = (ushort)r.value.intval; |
839 | 0 | break; |
840 | 0 | } |
841 | 0 | case gs_fapi_font_feature_BlendOtherBlues_length: |
842 | 0 | { |
843 | 0 | ref *Priv, *Blend, *bob; |
844 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
845 | 0 | *ret = 0; |
846 | 0 | break; |
847 | 0 | } |
848 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
849 | 0 | *ret = 0; |
850 | 0 | break; |
851 | 0 | } |
852 | 0 | if (dict_find_string(Priv, "OtherBlues", &bob) <= 0) { |
853 | 0 | *ret = 0; |
854 | 0 | break; |
855 | 0 | } |
856 | 0 | *ret = (ushort)r_size(bob); |
857 | 0 | break; |
858 | 0 | } |
859 | 0 | case gs_fapi_font_feature_BlendOtherBlues_count: |
860 | 0 | { |
861 | 0 | ref *Priv, *Blend, *bob, sub; |
862 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
863 | 0 | *ret = 0; |
864 | 0 | break; |
865 | 0 | } |
866 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
867 | 0 | *ret = 0; |
868 | 0 | break; |
869 | 0 | } |
870 | 0 | if (dict_find_string(Priv, "OtherBlues", &bob) <= 0) { |
871 | 0 | *ret = 0; |
872 | 0 | break; |
873 | 0 | } |
874 | | |
875 | 0 | if (array_get(ff->memory, bob, index, &sub) < 0) { |
876 | 0 | *ret = 0; |
877 | 0 | break; |
878 | 0 | } |
879 | 0 | *ret = (ushort)r_size(&sub); |
880 | 0 | break; |
881 | 0 | } |
882 | 0 | case gs_fapi_font_feature_BlendOtherBlues: |
883 | 0 | { |
884 | 0 | ref *Priv, *Blend, *bob, sub, r; |
885 | 0 | int aind = 0; |
886 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
887 | 0 | *ret = 0; |
888 | 0 | break; |
889 | 0 | } |
890 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
891 | 0 | *ret = 0; |
892 | 0 | break; |
893 | 0 | } |
894 | 0 | if (dict_find_string(Priv, "OtherBlues", &bob) <= 0) { |
895 | 0 | *ret = 0; |
896 | 0 | break; |
897 | 0 | } |
898 | | |
899 | 0 | while (1) { |
900 | 0 | if ((code = array_get(ff->memory, bob, aind++, &sub)) < 0) |
901 | 0 | break; |
902 | 0 | if (index - (int)r_size(&sub) < 0) { |
903 | 0 | break; |
904 | 0 | } |
905 | 0 | index -= r_size(&sub); |
906 | 0 | } |
907 | 0 | if (code < 0) { |
908 | 0 | *ret = 0; |
909 | 0 | break; |
910 | 0 | } |
911 | 0 | if (array_get(ff->memory, &sub, index, &r) < 0) { |
912 | 0 | *ret = 0; |
913 | 0 | break; |
914 | 0 | } |
915 | | |
916 | 0 | *ret = (ushort)r.value.intval; |
917 | 0 | break; |
918 | 0 | } |
919 | 0 | case gs_fapi_font_feature_BlendBlueScale_count: |
920 | 0 | { |
921 | 0 | ref *Priv, *Blend, *bbs; |
922 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
923 | 0 | *ret = 0; |
924 | 0 | break; |
925 | 0 | } |
926 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
927 | 0 | *ret = 0; |
928 | 0 | break; |
929 | 0 | } |
930 | 0 | if (dict_find_string(Priv, "BlueScale", &bbs) <= 0) { |
931 | 0 | *ret = 0; |
932 | 0 | break; |
933 | 0 | } |
934 | 0 | *ret = (ushort)r_size(bbs); |
935 | 0 | break; |
936 | 0 | } |
937 | 0 | case gs_fapi_font_feature_BlendBlueShift_count: |
938 | 0 | { |
939 | 0 | ref *Priv, *Blend, *bbs; |
940 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
941 | 0 | *ret = 0; |
942 | 0 | break; |
943 | 0 | } |
944 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
945 | 0 | *ret = 0; |
946 | 0 | break; |
947 | 0 | } |
948 | 0 | if (dict_find_string(Priv, "BlueShift", &bbs) <= 0) { |
949 | 0 | *ret = 0; |
950 | 0 | break; |
951 | 0 | } |
952 | 0 | *ret = (ushort)r_size(bbs); |
953 | 0 | break; |
954 | 0 | } |
955 | 0 | case gs_fapi_font_feature_BlendBlueShift: |
956 | 0 | { |
957 | 0 | ref *Priv, *Blend, *bbs, r; |
958 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
959 | 0 | *ret = 0; |
960 | 0 | break; |
961 | 0 | } |
962 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
963 | 0 | *ret = 0; |
964 | 0 | break; |
965 | 0 | } |
966 | 0 | if (dict_find_string(Priv, "BlueShift", &bbs) <= 0) { |
967 | 0 | *ret = 0; |
968 | 0 | break; |
969 | 0 | } |
970 | 0 | if (array_get(ff->memory, bbs, index, &r) < 0) { |
971 | 0 | *ret = 0; |
972 | 0 | break; |
973 | 0 | } |
974 | | |
975 | 0 | *ret = (ushort)r.value.intval; |
976 | 0 | break; |
977 | 0 | } |
978 | 0 | case gs_fapi_font_feature_BlendBlueFuzz_count: |
979 | 0 | { |
980 | 0 | ref *Priv, *Blend, *bbf; |
981 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
982 | 0 | *ret = 0; |
983 | 0 | break; |
984 | 0 | } |
985 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
986 | 0 | *ret = 0; |
987 | 0 | break; |
988 | 0 | } |
989 | 0 | if (dict_find_string(Priv, "BlueFuzz", &bbf) <= 0) { |
990 | 0 | *ret = 0; |
991 | 0 | break; |
992 | 0 | } |
993 | 0 | *ret = (ushort)r_size(bbf); |
994 | 0 | break; |
995 | 0 | } |
996 | 0 | case gs_fapi_font_feature_BlendBlueFuzz: |
997 | 0 | { |
998 | 0 | ref *Priv, *Blend, *bbf, r; |
999 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1000 | 0 | *ret = 0; |
1001 | 0 | break; |
1002 | 0 | } |
1003 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1004 | 0 | *ret = 0; |
1005 | 0 | break; |
1006 | 0 | } |
1007 | 0 | if (dict_find_string(Priv, "BlueFuzz", &bbf) <= 0) { |
1008 | 0 | *ret = 0; |
1009 | 0 | break; |
1010 | 0 | } |
1011 | 0 | if (array_get(ff->memory, bbf, index, &r) < 0) { |
1012 | 0 | *ret = 0; |
1013 | 0 | break; |
1014 | 0 | } |
1015 | | |
1016 | 0 | *ret = (ushort)r.value.intval; |
1017 | 0 | break; |
1018 | 0 | } |
1019 | 0 | case gs_fapi_font_feature_BlendForceBold_count: |
1020 | 0 | { |
1021 | 0 | ref *Priv, *Blend, *bfb; |
1022 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1023 | 0 | *ret = 0; |
1024 | 0 | break; |
1025 | 0 | } |
1026 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1027 | 0 | *ret = 0; |
1028 | 0 | break; |
1029 | 0 | } |
1030 | 0 | if (dict_find_string(Priv, "ForceBold", &bfb) <= 0) { |
1031 | 0 | *ret = 0; |
1032 | 0 | break; |
1033 | 0 | } |
1034 | 0 | *ret = (ushort)r_size(bfb); |
1035 | 0 | break; |
1036 | 0 | } |
1037 | 0 | case gs_fapi_font_feature_BlendForceBold: |
1038 | 0 | { |
1039 | 0 | ref *Priv, *Blend, *bfb, r; |
1040 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1041 | 0 | *ret = 0; |
1042 | 0 | break; |
1043 | 0 | } |
1044 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1045 | 0 | *ret = 0; |
1046 | 0 | break; |
1047 | 0 | } |
1048 | 0 | if (dict_find_string(Priv, "BlueFuzz", &bfb) <= 0) { |
1049 | 0 | *ret = 0; |
1050 | 0 | break; |
1051 | 0 | } |
1052 | 0 | if (array_get(ff->memory, bfb, index, &r) < 0) { |
1053 | 0 | *ret = 0; |
1054 | 0 | break; |
1055 | 0 | } |
1056 | | |
1057 | 0 | *ret = (ushort)r.value.boolval; |
1058 | 0 | } |
1059 | 0 | case gs_fapi_font_feature_BlendStdHW_length: |
1060 | 0 | { |
1061 | 0 | ref *Priv, *Blend, *stdhw; |
1062 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1063 | 0 | *ret = 0; |
1064 | 0 | break; |
1065 | 0 | } |
1066 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1067 | 0 | *ret = 0; |
1068 | 0 | break; |
1069 | 0 | } |
1070 | 0 | if (dict_find_string(Priv, "StdHW", &stdhw) <= 0) { |
1071 | 0 | *ret = 0; |
1072 | 0 | break; |
1073 | 0 | } |
1074 | 0 | *ret = (ushort)r_size(stdhw); |
1075 | 0 | break; |
1076 | 0 | } |
1077 | 0 | case gs_fapi_font_feature_BlendStdHW_count: |
1078 | 0 | { |
1079 | 0 | ref *Priv, *Blend, *stdhw, sub; |
1080 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1081 | 0 | *ret = 0; |
1082 | 0 | break; |
1083 | 0 | } |
1084 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1085 | 0 | *ret = 0; |
1086 | 0 | break; |
1087 | 0 | } |
1088 | 0 | if (dict_find_string(Priv, "StdHW", &stdhw) <= 0) { |
1089 | 0 | *ret = 0; |
1090 | 0 | break; |
1091 | 0 | } |
1092 | | |
1093 | 0 | if (array_get(ff->memory, stdhw, index, &sub) < 0) { |
1094 | 0 | *ret = 0; |
1095 | 0 | break; |
1096 | 0 | } |
1097 | 0 | *ret = (ushort)r_size(&sub); |
1098 | 0 | break; |
1099 | 0 | } |
1100 | 0 | case gs_fapi_font_feature_BlendStdHW: |
1101 | 0 | { |
1102 | 0 | ref *Priv, *Blend, *stdhw, sub, r; |
1103 | 0 | int aind = 0; |
1104 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1105 | 0 | *ret = 0; |
1106 | 0 | break; |
1107 | 0 | } |
1108 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1109 | 0 | *ret = 0; |
1110 | 0 | break; |
1111 | 0 | } |
1112 | 0 | if (dict_find_string(Priv, "StdHW", &stdhw) <= 0) { |
1113 | 0 | *ret = 0; |
1114 | 0 | break; |
1115 | 0 | } |
1116 | | |
1117 | 0 | while (1) { |
1118 | 0 | if ((code = array_get(ff->memory, stdhw, aind++, &sub)) < 0) |
1119 | 0 | break; |
1120 | 0 | if (index - (int)r_size(&sub) < 0) { |
1121 | 0 | break; |
1122 | 0 | } |
1123 | 0 | index -= r_size(&sub); |
1124 | 0 | } |
1125 | 0 | if (code < 0) { |
1126 | 0 | *ret = 0; |
1127 | 0 | break; |
1128 | 0 | } |
1129 | 0 | if (array_get(ff->memory, &sub, index, &r) < 0) { |
1130 | 0 | *ret = 0; |
1131 | 0 | break; |
1132 | 0 | } |
1133 | | |
1134 | 0 | *ret = (ushort)r.value.intval; |
1135 | 0 | break; |
1136 | 0 | } |
1137 | 0 | case gs_fapi_font_feature_BlendStdVW_length: |
1138 | 0 | { |
1139 | 0 | ref *Priv, *Blend, *stdvw; |
1140 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1141 | 0 | *ret = 0; |
1142 | 0 | break; |
1143 | 0 | } |
1144 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1145 | 0 | *ret = 0; |
1146 | 0 | break; |
1147 | 0 | } |
1148 | 0 | if (dict_find_string(Priv, "StdVW", &stdvw) <= 0) { |
1149 | 0 | *ret = 0; |
1150 | 0 | break; |
1151 | 0 | } |
1152 | 0 | *ret = (ushort)r_size(stdvw); |
1153 | 0 | break; |
1154 | 0 | } |
1155 | 0 | case gs_fapi_font_feature_BlendStdVW_count: |
1156 | 0 | { |
1157 | 0 | ref *Priv, *Blend, *stdvw, sub; |
1158 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1159 | 0 | *ret = 0; |
1160 | 0 | break; |
1161 | 0 | } |
1162 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1163 | 0 | *ret = 0; |
1164 | 0 | break; |
1165 | 0 | } |
1166 | | |
1167 | 0 | if (dict_find_string(Priv, "StdVW", &stdvw) <= 0) { |
1168 | 0 | *ret = 0; |
1169 | 0 | break; |
1170 | 0 | } |
1171 | | |
1172 | 0 | if (array_get(ff->memory, stdvw, index, &sub) < 0) { |
1173 | 0 | *ret = 0; |
1174 | 0 | break; |
1175 | 0 | } |
1176 | 0 | *ret = (ushort)r_size(&sub); |
1177 | 0 | break; |
1178 | 0 | } |
1179 | 0 | case gs_fapi_font_feature_BlendStdVW: |
1180 | 0 | { |
1181 | 0 | ref *Priv, *Blend, *stdvw, sub, r; |
1182 | 0 | int aind = 0; |
1183 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1184 | 0 | *ret = 0; |
1185 | 0 | break; |
1186 | 0 | } |
1187 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1188 | 0 | *ret = 0; |
1189 | 0 | break; |
1190 | 0 | } |
1191 | 0 | if (dict_find_string(Priv, "StdVW", &stdvw) <= 0) { |
1192 | 0 | *ret = 0; |
1193 | 0 | break; |
1194 | 0 | } |
1195 | | |
1196 | 0 | while (1) { |
1197 | 0 | if ((code = array_get(ff->memory, stdvw, aind++, &sub)) < 0) |
1198 | 0 | break; |
1199 | 0 | if (index - (int)r_size(&sub) < 0) { |
1200 | 0 | break; |
1201 | 0 | } |
1202 | 0 | index -= r_size(&sub); |
1203 | 0 | } |
1204 | 0 | if (code < 0) { |
1205 | 0 | *ret = 0; |
1206 | 0 | break; |
1207 | 0 | } |
1208 | 0 | if (array_get(ff->memory, &sub, index, &r) < 0) { |
1209 | 0 | *ret = 0; |
1210 | 0 | break; |
1211 | 0 | } |
1212 | | |
1213 | 0 | *ret = (ushort)r.value.intval; |
1214 | 0 | break; |
1215 | 0 | } |
1216 | 0 | case gs_fapi_font_feature_BlendStemSnapH_length: |
1217 | 0 | { |
1218 | 0 | ref *Priv, *Blend, *ssh; |
1219 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1220 | 0 | *ret = 0; |
1221 | 0 | break; |
1222 | 0 | } |
1223 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1224 | 0 | *ret = 0; |
1225 | 0 | break; |
1226 | 0 | } |
1227 | 0 | if (dict_find_string(Priv, "StemSnapH", &ssh) <= 0) { |
1228 | 0 | *ret = 0; |
1229 | 0 | break; |
1230 | 0 | } |
1231 | 0 | *ret = (ushort)r_size(ssh); |
1232 | 0 | break; |
1233 | 0 | } |
1234 | 0 | case gs_fapi_font_feature_BlendStemSnapH_count: |
1235 | 0 | { |
1236 | 0 | ref *Priv, *Blend, *bssh, sub; |
1237 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1238 | 0 | *ret = 0; |
1239 | 0 | break; |
1240 | 0 | } |
1241 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1242 | 0 | *ret = 0; |
1243 | 0 | break; |
1244 | 0 | } |
1245 | 0 | if (dict_find_string(Priv, "StemSnapH", &bssh) <= 0) { |
1246 | 0 | *ret = 0; |
1247 | 0 | break; |
1248 | 0 | } |
1249 | | |
1250 | 0 | if (array_get(ff->memory, bssh, index, &sub) < 0) { |
1251 | 0 | *ret = 0; |
1252 | 0 | break; |
1253 | 0 | } |
1254 | 0 | *ret = (ushort)r_size(&sub); |
1255 | 0 | break; |
1256 | 0 | } |
1257 | 0 | case gs_fapi_font_feature_BlendStemSnapH: |
1258 | 0 | { |
1259 | 0 | ref *Priv, *Blend, *bssh, sub, r; |
1260 | 0 | int aind = 0; |
1261 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1262 | 0 | *ret = 0; |
1263 | 0 | break; |
1264 | 0 | } |
1265 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1266 | 0 | *ret = 0; |
1267 | 0 | break; |
1268 | 0 | } |
1269 | 0 | if (dict_find_string(Priv, "StemSnapH", &bssh) <= 0) { |
1270 | 0 | *ret = 0; |
1271 | 0 | break; |
1272 | 0 | } |
1273 | | |
1274 | 0 | while (1) { |
1275 | 0 | if ((code = array_get(ff->memory, bssh, aind++, &sub)) < 0) |
1276 | 0 | break; |
1277 | 0 | if (index - (int)r_size(&sub) < 0) { |
1278 | 0 | break; |
1279 | 0 | } |
1280 | 0 | index -= r_size(&sub); |
1281 | 0 | } |
1282 | 0 | if (code < 0) { |
1283 | 0 | *ret = 0; |
1284 | 0 | break; |
1285 | 0 | } |
1286 | 0 | if (array_get(ff->memory, &sub, index, &r) < 0) { |
1287 | 0 | *ret = 0; |
1288 | 0 | break; |
1289 | 0 | } |
1290 | | |
1291 | 0 | *ret = (ushort)r.value.intval; |
1292 | 0 | break; |
1293 | 0 | } |
1294 | 0 | case gs_fapi_font_feature_BlendStemSnapV_length: |
1295 | 0 | { |
1296 | 0 | ref *Priv, *Blend, *ssv; |
1297 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1298 | 0 | *ret = 0; |
1299 | 0 | break; |
1300 | 0 | } |
1301 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1302 | 0 | *ret = 0; |
1303 | 0 | break; |
1304 | 0 | } |
1305 | 0 | if (dict_find_string(Priv, "StdHW", &ssv) <= 0) { |
1306 | 0 | *ret = 0; |
1307 | 0 | break; |
1308 | 0 | } |
1309 | 0 | *ret = (ushort)r_size(ssv); |
1310 | 0 | break; |
1311 | 0 | } |
1312 | 0 | case gs_fapi_font_feature_BlendStemSnapV_count: |
1313 | 0 | { |
1314 | 0 | ref *Priv, *Blend, *bssv, sub; |
1315 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1316 | 0 | *ret = 0; |
1317 | 0 | break; |
1318 | 0 | } |
1319 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1320 | 0 | *ret = 0; |
1321 | 0 | break; |
1322 | 0 | } |
1323 | 0 | if (dict_find_string(Priv, "StemSnapV", &bssv) <= 0) { |
1324 | 0 | *ret = 0; |
1325 | 0 | break; |
1326 | 0 | } |
1327 | | |
1328 | 0 | if (array_get(ff->memory, bssv, index, &sub) < 0) { |
1329 | 0 | *ret = 0; |
1330 | 0 | break; |
1331 | 0 | } |
1332 | 0 | *ret = (ushort)r_size(&sub); |
1333 | 0 | break; |
1334 | 0 | } |
1335 | 0 | case gs_fapi_font_feature_BlendStemSnapV: |
1336 | 0 | { |
1337 | 0 | ref *Priv, *Blend, *bssv, sub, r; |
1338 | 0 | int aind = 0; |
1339 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1340 | 0 | *ret = 0; |
1341 | 0 | break; |
1342 | 0 | } |
1343 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1344 | 0 | *ret = 0; |
1345 | 0 | break; |
1346 | 0 | } |
1347 | 0 | if (dict_find_string(Priv, "StemSnapV", &bssv) <= 0) { |
1348 | 0 | *ret = 0; |
1349 | 0 | break; |
1350 | 0 | } |
1351 | | |
1352 | 0 | while (1) { |
1353 | 0 | if ((code = array_get(ff->memory, bssv, aind++, &sub)) < 0) |
1354 | 0 | break; |
1355 | 0 | if (index - (int)r_size(&sub) < 0) { |
1356 | 0 | break; |
1357 | 0 | } |
1358 | 0 | index -= r_size(&sub); |
1359 | 0 | } |
1360 | 0 | if (code < 0) { |
1361 | 0 | *ret = 0; |
1362 | 0 | break; |
1363 | 0 | } |
1364 | 0 | if (array_get(ff->memory, &sub, index, &r) < 0) { |
1365 | 0 | *ret = 0; |
1366 | 0 | break; |
1367 | 0 | } |
1368 | | |
1369 | 0 | *ret = (ushort)r.value.intval; |
1370 | 0 | break; |
1371 | 0 | } |
1372 | | |
1373 | | /* End MM specifics */ |
1374 | 2.65M | } |
1375 | 2.65M | return code; |
1376 | 2.65M | } |
1377 | | |
1378 | | static int |
1379 | | FAPI_FF_get_long(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, unsigned long *ret) |
1380 | 88.0k | { |
1381 | 88.0k | gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data; |
1382 | 88.0k | int code = 0; |
1383 | | |
1384 | 88.0k | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
1385 | | |
1386 | 88.0k | switch ((int)var_id) { |
1387 | 0 | case gs_fapi_font_feature_UniqueID: |
1388 | 0 | *ret = pfont->UID.id; |
1389 | 0 | break; |
1390 | 87.9k | case gs_fapi_font_feature_BlueScale: |
1391 | 87.9k | *ret = (ulong) (pfont->data.BlueScale * 65536); |
1392 | 87.9k | break; |
1393 | 0 | case gs_fapi_font_feature_Subrs_total_size: |
1394 | 0 | { |
1395 | 0 | ref *Private, *Subrs, v; |
1396 | 0 | int lenIV = max(pfont->data.lenIV, 0), k; |
1397 | 0 | ulong size = 0; |
1398 | 0 | long i; |
1399 | 0 | const char *name[2] = { "Subrs", "GlobalSubrs" }; |
1400 | 0 | if (dict_find_string(pdr, "Private", &Private) <= 0) { |
1401 | 0 | *ret = 0; |
1402 | 0 | break; |
1403 | 0 | } |
1404 | 0 | for (k = 0; k < 2; k++) { |
1405 | 0 | if (dict_find_string(Private, name[k], &Subrs) > 0) |
1406 | 0 | for (i = r_size(Subrs) - 1; i >= 0; i--) { |
1407 | 0 | array_get(pfont->memory, Subrs, i, &v); |
1408 | 0 | if (r_type(&v) == t_string) { |
1409 | 0 | size += r_size(&v) - (ff->need_decrypt ? 0 : lenIV); |
1410 | 0 | } |
1411 | 0 | } |
1412 | 0 | } |
1413 | 0 | *ret = size; |
1414 | 0 | } |
1415 | 0 | break; |
1416 | 12 | case gs_fapi_font_feature_TT_size: |
1417 | 12 | code = true_type_size(ff->memory, pdr, ret); |
1418 | 12 | break; |
1419 | 88.0k | } |
1420 | 88.0k | return code; |
1421 | 88.0k | } |
1422 | | |
1423 | | static int |
1424 | | FAPI_FF_get_float(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, float *ret) |
1425 | 527k | { |
1426 | 527k | gs_font_type1 *pfont1 = (gs_font_type1 *) ff->client_font_data; |
1427 | 527k | gs_font_base *pbfont = (gs_font_base *) ff->client_font_data2; |
1428 | 527k | ref *pdr = pfont_dict(pbfont); |
1429 | 527k | int code = 0; |
1430 | 527k | gs_fapi_server *I = pbfont->FAPI; |
1431 | | |
1432 | 527k | switch ((int)var_id) { |
1433 | 527k | case gs_fapi_font_feature_FontMatrix: |
1434 | 527k | { |
1435 | 527k | double FontMatrix_div; |
1436 | 527k | gs_matrix m, *mptr; |
1437 | | |
1438 | 527k | if (I && I->get_fontmatrix) { |
1439 | 527k | FontMatrix_div = 1; |
1440 | 527k | mptr = &m; |
1441 | 527k | I->get_fontmatrix(I, mptr); |
1442 | 527k | } |
1443 | 0 | else { |
1444 | 0 | FontMatrix_div = |
1445 | 0 | ((ff->is_cid |
1446 | 0 | && (!FAPI_ISCIDFONT(pbfont))) ? 1000 : 1); |
1447 | 0 | mptr = &(pbfont->base->FontMatrix); |
1448 | 0 | } |
1449 | 527k | switch (index) { |
1450 | 87.9k | case 0: |
1451 | 87.9k | default: |
1452 | 87.9k | *ret = (mptr->xx / FontMatrix_div); |
1453 | 87.9k | break; |
1454 | 87.9k | case 1: |
1455 | 87.9k | *ret = (mptr->xy / FontMatrix_div); |
1456 | 87.9k | break; |
1457 | 87.9k | case 2: |
1458 | 87.9k | *ret = (mptr->yx / FontMatrix_div); |
1459 | 87.9k | break; |
1460 | 87.9k | case 3: |
1461 | 87.9k | *ret = (mptr->yy / FontMatrix_div); |
1462 | 87.9k | break; |
1463 | 87.9k | case 4: |
1464 | 87.9k | *ret = (mptr->tx / FontMatrix_div); |
1465 | 87.9k | break; |
1466 | 87.9k | case 5: |
1467 | 87.9k | *ret = (mptr->ty / FontMatrix_div); |
1468 | 87.9k | break; |
1469 | 527k | } |
1470 | 527k | break; |
1471 | 527k | } |
1472 | | |
1473 | 527k | case gs_fapi_font_feature_WeightVector: |
1474 | 0 | { |
1475 | 0 | if (index < pfont1->data.WeightVector.count) { |
1476 | 0 | *ret = pfont1->data.WeightVector.values[index]; |
1477 | 0 | } |
1478 | 0 | else { |
1479 | 0 | *ret = 0; |
1480 | 0 | } |
1481 | 0 | } |
1482 | 0 | break; |
1483 | 0 | case gs_fapi_font_feature_BlendDesignPositionsArrayValue: |
1484 | 0 | { |
1485 | 0 | ref *Info, *Array, SubArray, value; |
1486 | 0 | int array_index = index / 8; |
1487 | |
|
1488 | 0 | index %= 8; |
1489 | 0 | if (dict_find_string(pdr, "FontInfo", &Info) <= 0) { |
1490 | 0 | *ret = 0; |
1491 | 0 | break; |
1492 | 0 | } |
1493 | 0 | if (dict_find_string(Info, "BlendDesignPositions", &Array) <= 0) { |
1494 | 0 | *ret = 0; |
1495 | 0 | break; |
1496 | 0 | } |
1497 | 0 | if (array_get(ff->memory, Array, array_index, &SubArray) < 0) { |
1498 | 0 | *ret = 0; |
1499 | 0 | break; |
1500 | 0 | } |
1501 | 0 | if (array_get(ff->memory, &SubArray, index, &value) < 0) |
1502 | 0 | return 0; |
1503 | 0 | if (!r_has_type(&value, t_integer)) { |
1504 | 0 | if (r_has_type(&value, t_real)) { |
1505 | 0 | *ret = value.value.realval; |
1506 | 0 | } |
1507 | 0 | else |
1508 | 0 | *ret = 0; |
1509 | 0 | } |
1510 | 0 | else |
1511 | 0 | *ret = ((float)value.value.intval); |
1512 | 0 | } |
1513 | 0 | break; |
1514 | 0 | case gs_fapi_font_feature_BlendDesignMapArrayValue: |
1515 | 0 | { |
1516 | 0 | ref *Info, *Array, SubArray, SubSubArray, value; |
1517 | 0 | int array_index = index / 64; |
1518 | |
|
1519 | 0 | index %= 8; |
1520 | 0 | if (dict_find_string(pdr, "FontInfo", &Info) <= 0) { |
1521 | 0 | *ret = 0; |
1522 | 0 | break; |
1523 | 0 | } |
1524 | 0 | if (dict_find_string(Info, "BlendDesignMap", &Array) <= 0) { |
1525 | 0 | *ret = 0; |
1526 | 0 | break; |
1527 | 0 | } |
1528 | 0 | if (array_get(ff->memory, Array, array_index, &SubArray) < 0) { |
1529 | 0 | *ret = 0; |
1530 | 0 | break; |
1531 | 0 | } |
1532 | 0 | if (array_get(ff->memory, &SubArray, index, &SubSubArray) < 0) { |
1533 | 0 | *ret = 0; |
1534 | 0 | break; |
1535 | 0 | } |
1536 | 0 | if (array_get(ff->memory, &SubSubArray, index, &value) < 0) { |
1537 | 0 | *ret = 0; |
1538 | 0 | break; |
1539 | 0 | } |
1540 | 0 | if (!r_has_type(&value, t_integer)) { |
1541 | 0 | if (r_has_type(&value, t_real)) { |
1542 | 0 | *ret = (value.value.realval); |
1543 | 0 | } |
1544 | 0 | else |
1545 | 0 | *ret = 0; |
1546 | 0 | } |
1547 | 0 | else |
1548 | 0 | *ret = ((float)value.value.intval); |
1549 | 0 | } |
1550 | 0 | break; |
1551 | 0 | case gs_fapi_font_feature_BlendBlueScale: |
1552 | 0 | { |
1553 | 0 | ref *Priv, *Blend, *bbs, r; |
1554 | |
|
1555 | 0 | if (dict_find_string(pdr, "Blend", &Blend) <= 0) { |
1556 | 0 | *ret = 0; |
1557 | 0 | break; |
1558 | 0 | } |
1559 | 0 | if (dict_find_string(Blend, "Private", &Priv) <= 0) { |
1560 | 0 | *ret = 0; |
1561 | 0 | break; |
1562 | 0 | } |
1563 | 0 | if (dict_find_string(Priv, "BlueScale", &bbs) <= 0) { |
1564 | 0 | *ret = 0; |
1565 | 0 | break; |
1566 | 0 | } |
1567 | 0 | if (array_get(ff->memory, bbs, index, &r) < 0) { |
1568 | 0 | *ret = 0; |
1569 | 0 | break; |
1570 | 0 | } |
1571 | 0 | if (r_has_type(&r, t_real)) |
1572 | 0 | *ret = r.value.realval; |
1573 | 0 | else if (r_has_type(&r, t_integer)) |
1574 | 0 | *ret = (float)r.value.intval; |
1575 | 0 | } |
1576 | 0 | break; |
1577 | 527k | } |
1578 | 527k | return code; |
1579 | 527k | } |
1580 | | |
1581 | | static int |
1582 | | FAPI_FF_get_name(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, |
1583 | | char *Buffer, int len) |
1584 | 0 | { |
1585 | 0 | ref name, string; |
1586 | 0 | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
1587 | 0 | int code = 0; |
1588 | |
|
1589 | 0 | switch ((int)var_id) { |
1590 | 0 | case gs_fapi_font_feature_BlendAxisTypes: |
1591 | 0 | { |
1592 | 0 | ref *Info, *Axes; |
1593 | |
|
1594 | 0 | if (dict_find_string(pdr, "FontInfo", &Info) <= 0) { |
1595 | 0 | code = gs_note_error(gs_error_undefined); |
1596 | 0 | break; |
1597 | 0 | } |
1598 | 0 | if (dict_find_string(Info, "BlendAxisTypes", &Axes) <= 0) { |
1599 | 0 | code = gs_note_error(gs_error_undefined); |
1600 | 0 | break; |
1601 | 0 | } |
1602 | 0 | if (!r_has_type(Axes, t_array)) { |
1603 | 0 | code = gs_note_error(gs_error_undefined); |
1604 | 0 | break; |
1605 | 0 | } |
1606 | 0 | if (array_get(ff->memory, Axes, index, &name) < 0) { |
1607 | 0 | code = gs_note_error(gs_error_undefined); |
1608 | 0 | break; |
1609 | 0 | } |
1610 | 0 | } |
1611 | 0 | } |
1612 | 0 | if (code >= 0) { |
1613 | 0 | name_string_ref(ff->memory, &name, &string); |
1614 | 0 | if (r_size(&string) < len) { |
1615 | 0 | memcpy(Buffer, string.value.const_bytes, r_size(&string)); |
1616 | 0 | Buffer[r_size(&string)] = 0x00; |
1617 | 0 | } |
1618 | 0 | else { |
1619 | 0 | code = gs_note_error(gs_error_unknownerror); |
1620 | 0 | } |
1621 | 0 | } |
1622 | 0 | return code; |
1623 | 0 | } |
1624 | | |
1625 | | /* NOTE: we checked the type of $Blend at definefont time, so we know it is a |
1626 | | * procedure and don't need to check it again here |
1627 | | */ |
1628 | | static int |
1629 | | FAPI_FF_get_proc(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, |
1630 | | char *Buffer) |
1631 | 0 | { |
1632 | 0 | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
1633 | 0 | char *ptr = Buffer; |
1634 | 0 | int code = 0; |
1635 | |
|
1636 | 0 | if (!Buffer) |
1637 | 0 | return_error(gs_error_unknownerror); |
1638 | | |
1639 | 0 | switch ((int)var_id) { |
1640 | 0 | case gs_fapi_font_feature_DollarBlend: |
1641 | 0 | { |
1642 | 0 | ref *DBlend, Element, string; |
1643 | 0 | int i; |
1644 | 0 | char Buf[32]; |
1645 | |
|
1646 | 0 | if (dict_find_string(pdr, "$Blend", &DBlend) <= 0) { |
1647 | 0 | code = gs_note_error(gs_error_undefined); |
1648 | 0 | break; |
1649 | 0 | } |
1650 | 0 | for (i = 0; i < r_size(DBlend); i++) { |
1651 | 0 | *ptr++ = 0x20; |
1652 | 0 | if (array_get(ff->memory, DBlend, i, &Element) < 0) { |
1653 | 0 | code = gs_note_error(gs_error_undefined); |
1654 | 0 | break; |
1655 | 0 | } |
1656 | 0 | switch (r_btype(&Element)) { |
1657 | 0 | case t_name: |
1658 | 0 | name_string_ref(ff->memory, &Element, &string); |
1659 | |
|
1660 | 0 | strncpy(ptr, (char *)string.value.const_bytes, |
1661 | 0 | r_size(&string)); |
1662 | 0 | ptr += r_size(&string); |
1663 | 0 | break; |
1664 | 0 | case t_real: |
1665 | 0 | gs_snprintf(Buf, sizeof(Buf), "%f", Element.value.realval); |
1666 | 0 | strcpy(ptr, Buf); |
1667 | 0 | ptr += strlen(Buf); |
1668 | 0 | break; |
1669 | 0 | case t_integer: |
1670 | 0 | gs_snprintf(Buf, sizeof(Buf), "%"PRIpsint, Element.value.intval); |
1671 | 0 | strcpy(ptr, Buf); |
1672 | 0 | ptr += strlen(Buf); |
1673 | 0 | break; |
1674 | 0 | case t_operator: |
1675 | 0 | { |
1676 | 0 | op_def const *op; |
1677 | |
|
1678 | 0 | op = op_index_def(r_size(&Element)); |
1679 | 0 | strcpy(ptr, op->oname + 1); |
1680 | 0 | ptr += strlen(op->oname + 1); |
1681 | 0 | } |
1682 | 0 | break; |
1683 | 0 | default: |
1684 | 0 | break; |
1685 | 0 | } |
1686 | 0 | } |
1687 | 0 | } |
1688 | 0 | } |
1689 | 0 | return code < 0 ? code : (ptr - Buffer); |
1690 | 0 | } |
1691 | | |
1692 | | static inline void |
1693 | | decode_bytes(byte *p, const byte *s, int l, int lenIV) |
1694 | 1.20M | { |
1695 | 1.20M | ushort state = 4330; |
1696 | | |
1697 | 119M | for (; l; s++, l--) { |
1698 | 118M | uchar c = (*s ^ (state >> 8)); |
1699 | | |
1700 | 118M | state = (*s + state) * crypt_c1 + crypt_c2; |
1701 | 118M | if (lenIV > 0) |
1702 | 4.83M | lenIV--; |
1703 | 113M | else { |
1704 | 113M | *p = c; |
1705 | 113M | p++; |
1706 | 113M | } |
1707 | 118M | } |
1708 | 1.20M | } |
1709 | | |
1710 | | static int |
1711 | | get_type1_data(gs_fapi_font *ff, const ref *type1string, |
1712 | | byte *buf, int buf_length) |
1713 | 1.65M | { |
1714 | 1.65M | gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data; |
1715 | 1.65M | int lenIV = max(pfont->data.lenIV, 0); |
1716 | 1.65M | int length = r_size(type1string) - (ff->need_decrypt ? lenIV : 0); |
1717 | | |
1718 | 1.65M | if (buf != 0) { |
1719 | 1.20M | int l = min(length, buf_length); /*safety */ |
1720 | | |
1721 | 1.20M | if (ff->need_decrypt && pfont->data.lenIV >= 0) |
1722 | 1.20M | decode_bytes(buf, type1string->value.const_bytes, l + lenIV, |
1723 | 1.20M | lenIV); |
1724 | 0 | else |
1725 | 0 | memcpy(buf, type1string->value.const_bytes, l); |
1726 | 1.20M | } |
1727 | 1.65M | return length; |
1728 | 1.65M | } |
1729 | | |
1730 | | static int |
1731 | | FAPI_FF_get_gsubr(gs_fapi_font *ff, int index, byte *buf, int buf_length) |
1732 | 0 | { |
1733 | 0 | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
1734 | 0 | ref *Private, *GlobalSubrs, subr; |
1735 | |
|
1736 | 0 | if (dict_find_string(pdr, "Private", &Private) <= 0) |
1737 | 0 | return 0; |
1738 | 0 | if (dict_find_string(Private, "GlobalSubrs", &GlobalSubrs) <= 0) |
1739 | 0 | return 0; |
1740 | 0 | if (array_get(ff->memory, |
1741 | 0 | GlobalSubrs, index, &subr) < 0 || r_type(&subr) != t_string) |
1742 | 0 | return 0; |
1743 | 0 | return (get_type1_data(ff, &subr, buf, buf_length)); |
1744 | 0 | } |
1745 | | |
1746 | | static int |
1747 | | FAPI_FF_get_subr(gs_fapi_font *ff, int index, byte *buf, int buf_length) |
1748 | 659k | { |
1749 | 659k | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
1750 | 659k | ref *Private, *Subrs, subr; |
1751 | | |
1752 | 659k | if (dict_find_string(pdr, "Private", &Private) <= 0) |
1753 | 0 | return 0; |
1754 | 659k | if (dict_find_string(Private, "Subrs", &Subrs) <= 0) |
1755 | 0 | return 0; |
1756 | 659k | if (array_get(ff->memory, Subrs, index, &subr) < 0 |
1757 | 659k | || r_type(&subr) != t_string) |
1758 | 0 | return 0; |
1759 | 659k | return (get_type1_data(ff, &subr, buf, buf_length)); |
1760 | 659k | } |
1761 | | |
1762 | | static int |
1763 | | FAPI_FF_get_raw_subr(gs_fapi_font *ff, int index, byte *buf, |
1764 | | int buf_length) |
1765 | 0 | { |
1766 | 0 | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
1767 | 0 | ref *Private, *Subrs, subr; |
1768 | 0 | int code = 0; |
1769 | |
|
1770 | 0 | do { |
1771 | 0 | if (dict_find_string(pdr, "Private", &Private) <= 0) { |
1772 | 0 | code = gs_note_error(gs_error_undefined); |
1773 | 0 | break; |
1774 | 0 | } |
1775 | 0 | if (dict_find_string(Private, "Subrs", &Subrs) <= 0) { |
1776 | 0 | code = gs_note_error(gs_error_undefined); |
1777 | 0 | break; |
1778 | 0 | } |
1779 | 0 | if (array_get(ff->memory, Subrs, index, &subr) < 0) { |
1780 | 0 | code = gs_note_error(gs_error_undefined); |
1781 | 0 | break; |
1782 | 0 | } |
1783 | 0 | if (r_type(&subr) != t_string) { |
1784 | 0 | code = gs_note_error(gs_error_undefined); |
1785 | 0 | break; |
1786 | 0 | } |
1787 | 0 | if (buf && buf_length && buf_length >= r_size(&subr)) { |
1788 | 0 | memcpy(buf, subr.value.const_bytes, r_size(&subr)); |
1789 | 0 | } |
1790 | 0 | } while(0); |
1791 | | |
1792 | 0 | return code < 0 ? code : r_size(&subr); |
1793 | 0 | } |
1794 | | |
1795 | | /* FAPI_FF_get_charstring_name() and FAPI_FF_get_charstring() |
1796 | | * |
1797 | | * Generally we'd want to use the dictionary content |
1798 | | * enumeration API rather than dict_index_entry(), but |
1799 | | * the FAPI interface doesn't enforce sequential accessing |
1800 | | * of the indices. |
1801 | | * Setting up enumeration and enumerating through the entries |
1802 | | * until we reach the requested valid index is a performance |
1803 | | * hit we don't want to pay. |
1804 | | * |
1805 | | * Luckily, the checks we need for invalid CharString contents |
1806 | | * also handle empty "slots" in the dictionary. |
1807 | | */ |
1808 | | |
1809 | | static int |
1810 | | FAPI_FF_get_charstring_name(gs_fapi_font *ff, int index, byte *buf, |
1811 | | ushort buf_length) |
1812 | 0 | { |
1813 | 0 | int code = 0; |
1814 | 0 | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
1815 | 0 | ref *CharStrings, eltp[2], string; |
1816 | |
|
1817 | 0 | do { |
1818 | 0 | if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0) { |
1819 | 0 | code = gs_note_error(gs_error_undefined); |
1820 | 0 | break; |
1821 | 0 | } |
1822 | 0 | if (dict_index_entry(CharStrings, index, eltp) < 0) { |
1823 | 0 | code = gs_note_error(gs_error_undefined); |
1824 | 0 | break; |
1825 | 0 | } |
1826 | 0 | if (r_type(&eltp[0]) != t_name) { |
1827 | 0 | code = gs_note_error(gs_error_undefined); |
1828 | 0 | break; |
1829 | 0 | } |
1830 | 0 | name_string_ref(ff->memory, &eltp[0], &string); |
1831 | 0 | if (r_size(&string) <= buf_length) { |
1832 | 0 | memcpy(buf, string.value.const_bytes, r_size(&string)); |
1833 | 0 | buf[r_size(&string)] = 0x00; |
1834 | 0 | } |
1835 | 0 | } while(0); |
1836 | 0 | return code < 0 ? code : r_size(&string); |
1837 | 0 | } |
1838 | | |
1839 | | static int |
1840 | | FAPI_FF_get_charstring(gs_fapi_font *ff, int index, byte *buf, |
1841 | | ushort buf_length) |
1842 | 0 | { |
1843 | 0 | int code = 0; |
1844 | 0 | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
1845 | 0 | ref *CharStrings, eltp[2]; |
1846 | |
|
1847 | 0 | do { |
1848 | 0 | if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0) { |
1849 | 0 | code = gs_note_error(gs_error_undefined); |
1850 | 0 | break; |
1851 | 0 | } |
1852 | 0 | if (dict_index_entry(CharStrings, index, eltp) < 0) { |
1853 | 0 | code = gs_note_error(gs_error_undefined); |
1854 | 0 | break; |
1855 | 0 | } |
1856 | 0 | if (r_type(&eltp[1]) != t_string) { |
1857 | 0 | code = gs_note_error(gs_error_typecheck); |
1858 | 0 | break; |
1859 | 0 | } |
1860 | 0 | if (buf && buf_length && buf_length >= r_size(&eltp[1])) { |
1861 | 0 | memcpy(buf, eltp[1].value.const_bytes, r_size(&eltp[1])); |
1862 | 0 | } |
1863 | 0 | } while(0); |
1864 | | |
1865 | 0 | return code < 0 ? code : r_size(&eltp[1]); |
1866 | 0 | } |
1867 | | |
1868 | | static int |
1869 | | sfnt_get_sfnt_length(ref *pdr, ulong *len) |
1870 | 0 | { |
1871 | 0 | int code = 0; |
1872 | 0 | ref *sfnts, sfnt_elem; |
1873 | 0 | const gs_memory_t *mem = dict_mem(pdr->value.pdict); |
1874 | |
|
1875 | 0 | *len = 0; |
1876 | 0 | if (r_type(pdr) != t_dictionary || |
1877 | 0 | dict_find_string(pdr, "sfnts", &sfnts) <= 0) { |
1878 | 0 | code = gs_error_invalidfont; |
1879 | 0 | } |
1880 | 0 | else { |
1881 | 0 | if (r_type(sfnts) != t_array && r_type(sfnts) != t_string) { |
1882 | 0 | code = gs_error_invalidfont; |
1883 | 0 | } |
1884 | 0 | else { |
1885 | 0 | if (r_type(sfnts) == t_string) { |
1886 | 0 | *len = r_size(sfnts); |
1887 | 0 | } |
1888 | 0 | else { |
1889 | 0 | int i; |
1890 | 0 | for (i = 0; i < r_size(sfnts); i++) { |
1891 | 0 | code = array_get(mem, sfnts, i, &sfnt_elem); |
1892 | 0 | if (code < 0) break; |
1893 | 0 | *len += r_size(&sfnt_elem); |
1894 | 0 | } |
1895 | 0 | } |
1896 | 0 | } |
1897 | 0 | } |
1898 | 0 | return code; |
1899 | 0 | } |
1900 | | |
1901 | | static int |
1902 | | sfnt_get_glyph_offset(ref *pdr, gs_font_type42 *pfont42, int index, |
1903 | | ulong *offset0) |
1904 | 0 | { /* Note : TTC is not supported and probably is unuseful for Type 42. */ |
1905 | 0 | sfnts_reader r; |
1906 | 0 | int glyf_elem_size = (pfont42->data.indexToLocFormat) ? 4 : 2; |
1907 | 0 | ulong fullsize; |
1908 | |
|
1909 | 0 | if (index < pfont42->data.trueNumGlyphs) { |
1910 | 0 | sfnts_reader_init(pfont42->memory, &r, pdr); |
1911 | 0 | r.seek(&r, pfont42->data.loca + index * (ulong)glyf_elem_size); |
1912 | 0 | *offset0 = |
1913 | 0 | pfont42->data.glyf + (glyf_elem_size == |
1914 | 0 | 2 ? r.rword(&r) * 2 : r.rlong(&r)); |
1915 | 0 | r.error = sfnt_get_sfnt_length(pdr, &fullsize); |
1916 | 0 | if (r.error < 0 || *offset0 > fullsize) { |
1917 | 0 | r.error = gs_note_error(gs_error_invalidaccess); |
1918 | 0 | } |
1919 | 0 | } |
1920 | 0 | else { |
1921 | 0 | r.error = gs_note_error(gs_error_rangecheck); |
1922 | 0 | } |
1923 | 0 | return (r.error); |
1924 | 0 | } |
1925 | | |
1926 | | static int |
1927 | | ps_get_GlyphDirectory_data_ptr(gs_fapi_font *ff, int char_code, |
1928 | | const byte **ptr) |
1929 | 0 | { |
1930 | 0 | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
1931 | 0 | ref *GlyphDirectory, glyph0, *glyph = &glyph0, glyph_index; |
1932 | |
|
1933 | 0 | if (dict_find_string(pdr, "GlyphDirectory", &GlyphDirectory) > 0) { |
1934 | 0 | if (((r_type(GlyphDirectory) == t_dictionary && |
1935 | 0 | (make_int(&glyph_index, char_code), |
1936 | 0 | dict_find(GlyphDirectory, &glyph_index, &glyph) > 0)) || |
1937 | 0 | (r_type(GlyphDirectory) == t_array && |
1938 | 0 | array_get(ff->memory, GlyphDirectory, char_code, &glyph0) >= 0) |
1939 | 0 | ) |
1940 | 0 | && r_type(glyph) == t_string) { |
1941 | 0 | *ptr = glyph->value.const_bytes; |
1942 | 0 | return (r_size(glyph)); |
1943 | 0 | } |
1944 | 0 | else |
1945 | | /* We have a GlyphDirectory, but couldn't find the glyph. If we |
1946 | | * return -1 then we will attempt to use glyf and loca which |
1947 | | * will fail. Instead return 0, so we execute an 'empty' glyph. |
1948 | | */ |
1949 | 0 | return 0; |
1950 | 0 | } |
1951 | 0 | return -1; |
1952 | 0 | } |
1953 | | |
1954 | | static int |
1955 | | get_charstring(gs_fapi_font *ff, int char_code, ref **proc, ref *char_name) |
1956 | 0 | { |
1957 | 0 | ref *CharStrings; |
1958 | 0 | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
1959 | |
|
1960 | 0 | if (ff->is_type1) { |
1961 | 0 | if (ff->is_cid) |
1962 | 0 | return -1; |
1963 | 0 | if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0) |
1964 | 0 | return -1; |
1965 | | |
1966 | 0 | if (ff->char_data != NULL) { |
1967 | | /* |
1968 | | * Can't use char_code in this case because hooked Type 1 fonts |
1969 | | * with 'glyphshow' may render a character which has no |
1970 | | * Encoding entry. |
1971 | | */ |
1972 | 0 | if (name_ref |
1973 | 0 | (ff->memory, ff->char_data, ff->char_data_len, char_name, |
1974 | 0 | -1) < 0) |
1975 | 0 | return -1; |
1976 | 0 | } |
1977 | 0 | else { /* seac */ |
1978 | 0 | i_ctx_t *i_ctx_p = (i_ctx_t *) ff->client_ctx_p; |
1979 | 0 | ref *StandardEncoding; |
1980 | |
|
1981 | 0 | if (dict_find_string |
1982 | 0 | (systemdict, "StandardEncoding", &StandardEncoding) <= 0 |
1983 | 0 | || array_get(ff->memory, StandardEncoding, char_code, |
1984 | 0 | char_name) < 0) { |
1985 | 0 | if (name_ref |
1986 | 0 | (ff->memory, (const byte *)".notdef", 7, char_name, |
1987 | 0 | -1) < 0) |
1988 | 0 | return -1; |
1989 | 0 | } |
1990 | 0 | } |
1991 | 0 | if (dict_find(CharStrings, char_name, (ref **) proc) <= 0) |
1992 | 0 | return -1; |
1993 | 0 | } |
1994 | 0 | return 0; |
1995 | 0 | } |
1996 | | |
1997 | | static int |
1998 | | FAPI_FF_get_glyph(gs_fapi_font *ff, gs_glyph char_code, byte *buf, int buf_length) |
1999 | 991k | { |
2000 | | /* |
2001 | | * We assume that renderer requests glyph data with multiple |
2002 | | * consecutive calls to this function. |
2003 | | * |
2004 | | * For a simple glyph it calls this function exactly twice: first |
2005 | | * with buf == NULL for requesting the necessary buffer length, and |
2006 | | * second with buf != NULL for requesting the data (the second call |
2007 | | * may be skipped if the renderer discontinues the rendering). |
2008 | | * |
2009 | | * For a composite glyph it calls this function 2 * (N + 1) |
2010 | | * times: 2 calls for the main glyph (same as above) followed with |
2011 | | * 2 * N calls for subglyphs, where N is less or equal to the number |
2012 | | * of subglyphs (N may be less if the renderer caches glyph data, |
2013 | | * or discontinues rendering on an exception). |
2014 | | */ |
2015 | 991k | ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2)); |
2016 | | |
2017 | 991k | int glyph_length; |
2018 | 991k | i_ctx_t *i_ctx_p = (i_ctx_t *) ff->client_ctx_p; |
2019 | | |
2020 | 991k | if (ff->is_type1) { |
2021 | 991k | if (ff->is_cid) { |
2022 | 0 | const gs_string *char_str = (const gs_string *)ff->char_data; |
2023 | 0 | ref glyph; |
2024 | |
|
2025 | 0 | make_string(&glyph, avm_foreign | a_readonly, char_str->size, |
2026 | 0 | char_str->data); |
2027 | |
|
2028 | 0 | glyph_length = get_type1_data(ff, &glyph, buf, buf_length); |
2029 | 0 | } |
2030 | 991k | else { |
2031 | 991k | ref *CharStrings, *CFFCharStrings, char_name, *glyph; |
2032 | | |
2033 | 991k | if (ff->char_data != NULL) { |
2034 | | /* |
2035 | | * Can't use char_code in this case because hooked Type 1 fonts |
2036 | | * with 'glyphshow' may render a character which has no |
2037 | | * Encoding entry. |
2038 | | */ |
2039 | 991k | if (name_ref(ff->memory, ff->char_data, |
2040 | 991k | ff->char_data_len, &char_name, -1) < 0) |
2041 | 0 | return gs_fapi_glyph_invalid_format; |
2042 | 991k | if (buf != NULL) { |
2043 | | /* |
2044 | | * Trigger the next call to the 'seac' case below. |
2045 | | * Here we use the assumption about call sequence |
2046 | | * being documented above. |
2047 | | */ |
2048 | 988k | ff->char_data = NULL; |
2049 | 988k | } |
2050 | 991k | } |
2051 | 0 | else { /* seac */ |
2052 | 0 | ref *StandardEncoding; |
2053 | |
|
2054 | 0 | if (dict_find_string |
2055 | 0 | (systemdict, "StandardEncoding", &StandardEncoding) <= 0 |
2056 | 0 | || array_get(ff->memory, StandardEncoding, char_code, |
2057 | 0 | &char_name) < 0) |
2058 | 0 | if (name_ref |
2059 | 0 | (ff->memory, (const byte *)".notdef", 7, &char_name, -1) < 0) |
2060 | 0 | return gs_fapi_glyph_invalid_format; |
2061 | 0 | } |
2062 | 991k | if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0) |
2063 | 0 | return gs_fapi_glyph_invalid_format; |
2064 | | |
2065 | 991k | if (dict_find(CharStrings, &char_name, &glyph) <= 0) { |
2066 | 0 | if (name_ref |
2067 | 0 | (ff->memory, (const byte *)".notdef", 7, &char_name, -1) < 0) { |
2068 | 0 | return gs_fapi_glyph_invalid_format; |
2069 | 0 | } |
2070 | 0 | if (dict_find(CharStrings, &char_name, &glyph) <= 0) { |
2071 | 0 | return gs_fapi_glyph_invalid_format; |
2072 | 0 | } |
2073 | 0 | } |
2074 | 991k | if (r_has_type(glyph, t_array) || r_has_type(glyph, t_mixedarray)) |
2075 | 0 | return gs_fapi_glyph_invalid_format; |
2076 | | |
2077 | 991k | if (r_has_type(glyph, t_integer) |
2078 | 991k | && dict_find_string(pdr, "CFFCharStrings", &CFFCharStrings) > 0) { |
2079 | 0 | ref *g2; |
2080 | 0 | if (dict_find(CFFCharStrings, glyph, &g2) <= 0) { |
2081 | 0 | ref nd; |
2082 | 0 | make_int(&nd, 0); |
2083 | 0 | if (dict_find(CFFCharStrings, &nd, &g2) <= 0) { |
2084 | 0 | return gs_fapi_glyph_invalid_format; |
2085 | 0 | } |
2086 | 0 | } |
2087 | 0 | glyph = g2; |
2088 | 0 | } |
2089 | | |
2090 | 991k | if (!r_has_type(glyph, t_string)) |
2091 | 0 | return 0; |
2092 | 991k | glyph_length = get_type1_data(ff, glyph, buf, buf_length); |
2093 | 991k | } |
2094 | 991k | } |
2095 | 0 | else { /* type 42 */ |
2096 | 0 | const byte *data_ptr; |
2097 | 0 | int l = ff->get_glyphdirectory_data(ff, char_code, &data_ptr); |
2098 | 0 | ref *render_notdef_ref; |
2099 | 0 | bool render_notdef = true; |
2100 | |
|
2101 | 0 | if (dict_find_string(pdr, ".render_notdef", &render_notdef_ref) > 0 |
2102 | 0 | && r_has_type(render_notdef_ref, t_boolean)) { |
2103 | 0 | render_notdef = render_notdef_ref->value.boolval; |
2104 | 0 | } |
2105 | 0 | else { |
2106 | 0 | render_notdef = i_ctx_p->RenderTTNotdef; |
2107 | 0 | } |
2108 | | |
2109 | | /* We should only render the TT notdef if we've been told to - logic lifted from zchar42.c */ |
2110 | 0 | if (!render_notdef |
2111 | 0 | && |
2112 | 0 | ((ff->char_data_len == 7 |
2113 | 0 | && strncmp((const char *)ff->char_data, ".notdef", 7) == 0) |
2114 | 0 | || (ff->char_data_len > 9 |
2115 | 0 | && strncmp((const char *)ff->char_data, ".notdef~GS", |
2116 | 0 | 10) == 0))) { |
2117 | 0 | glyph_length = 0; |
2118 | 0 | } |
2119 | 0 | else { |
2120 | 0 | if (l >= 0) { |
2121 | 0 | int MetricsCount = gs_fapi_get_metrics_count(ff), mc = |
2122 | 0 | MetricsCount << 1; |
2123 | |
|
2124 | 0 | glyph_length = max((ushort) (l - mc), 0); /* safety */ |
2125 | 0 | if (buf != 0 && glyph_length > 0) |
2126 | 0 | memcpy(buf, data_ptr + mc, |
2127 | 0 | min(glyph_length, buf_length) /* safety */ ); |
2128 | 0 | } |
2129 | 0 | else { |
2130 | 0 | gs_font_type42 *pfont42 = (gs_font_type42 *) ff->client_font_data; |
2131 | 0 | ulong offset0, length_read; |
2132 | 0 | int error = sfnt_get_glyph_offset(pdr, pfont42, char_code, &offset0); |
2133 | |
|
2134 | 0 | if (error < 0) { |
2135 | 0 | glyph_length = gs_fapi_glyph_invalid_index; |
2136 | 0 | } |
2137 | 0 | else if (pfont42->data.len_glyphs) { |
2138 | 0 | if (char_code <= pfont42->data.numGlyphs) |
2139 | 0 | glyph_length = pfont42->data.len_glyphs[char_code]; |
2140 | 0 | else |
2141 | 0 | glyph_length = gs_fapi_glyph_invalid_index; |
2142 | 0 | } |
2143 | 0 | else { |
2144 | 0 | ulong noffs, endoffs; |
2145 | | /* If we haven't got a len_glyphs array, try using the offset of the next glyph offset |
2146 | | * to work out the length |
2147 | | */ |
2148 | 0 | error = sfnt_get_glyph_offset(pdr, pfont42, char_code + 1, &noffs); |
2149 | 0 | if (error == 0) { |
2150 | 0 | glyph_length = noffs - offset0; |
2151 | 0 | error = sfnt_get_sfnt_length(pdr, &endoffs); |
2152 | 0 | if (error < 0) { |
2153 | 0 | glyph_length = gs_fapi_glyph_invalid_index; |
2154 | 0 | } |
2155 | 0 | else { |
2156 | 0 | if (glyph_length + offset0 > endoffs) { |
2157 | 0 | glyph_length = gs_fapi_glyph_invalid_index; |
2158 | 0 | } |
2159 | 0 | } |
2160 | 0 | } |
2161 | 0 | else { |
2162 | | /* And if we can't get the next glyph offset, use the end of the sfnt data |
2163 | | * to work out the length. |
2164 | | */ |
2165 | 0 | error = sfnt_get_sfnt_length(pdr, &noffs); |
2166 | 0 | if (error < 0) { |
2167 | 0 | glyph_length = gs_fapi_glyph_invalid_index; |
2168 | 0 | } |
2169 | 0 | else { |
2170 | 0 | glyph_length = noffs - offset0; |
2171 | 0 | } |
2172 | 0 | } |
2173 | 0 | } |
2174 | |
|
2175 | 0 | if (buf != 0 && !error) { |
2176 | 0 | sfnts_reader r; |
2177 | |
|
2178 | 0 | sfnts_reader_init(pfont42->memory, &r, pdr); |
2179 | |
|
2180 | 0 | r.seek(&r, offset0); |
2181 | 0 | length_read = |
2182 | 0 | r.rstring(&r, buf, |
2183 | 0 | min(glyph_length, |
2184 | 0 | buf_length) /* safety */ ); |
2185 | 0 | if (r.error == 1) { |
2186 | 0 | glyph_length = gs_fapi_glyph_invalid_index; |
2187 | 0 | } |
2188 | | /* r.error == 2 means a rangecheck, and probably means that the |
2189 | | * font is broken, and the final glyph length is longer than the data available for it. |
2190 | | * In which case we need to return the number of bytes read. |
2191 | | */ |
2192 | 0 | if (r.error == 2) { |
2193 | 0 | glyph_length = length_read; |
2194 | 0 | } |
2195 | 0 | } |
2196 | 0 | } |
2197 | 0 | } |
2198 | 0 | } |
2199 | 991k | return glyph_length; |
2200 | 991k | } |
2201 | | |
2202 | | static int |
2203 | | ps_fapi_get_metrics(gs_fapi_font *ff, gs_string *char_name, gs_glyph cid, double *m, bool vertical) |
2204 | 984k | { |
2205 | 984k | ref glyph; |
2206 | 984k | int code; |
2207 | 984k | gs_font_base *pbfont = ((gs_font_base *) ff->client_font_data2); |
2208 | | |
2209 | 984k | if (char_name->data != NULL) { |
2210 | 984k | make_string(&glyph, avm_foreign | a_readonly, char_name->size, char_name->data); |
2211 | 984k | } |
2212 | 0 | else { |
2213 | 0 | make_int(&glyph, cid); |
2214 | 0 | } |
2215 | | |
2216 | 984k | if (vertical) { |
2217 | 0 | code = zchar_get_metrics2(pbfont, &glyph, m); |
2218 | 0 | } |
2219 | 984k | else { |
2220 | 984k | code = zchar_get_metrics(pbfont, &glyph, m); |
2221 | 984k | } |
2222 | | |
2223 | 984k | make_null(&glyph); |
2224 | | |
2225 | 984k | return (code); |
2226 | 984k | } |
2227 | | |
2228 | | |
2229 | | /* forward declaration for the ps_ff_stub assignment */ |
2230 | | static int ps_get_glyphname_or_cid(gs_text_enum_t *penum, |
2231 | | gs_font_base *pbfont, |
2232 | | gs_string *charstring, gs_string *name, |
2233 | | gs_glyph ccode, gs_string *enc_char_name, |
2234 | | char *font_file_path, |
2235 | | gs_fapi_char_ref *cr, bool bCID); |
2236 | | |
2237 | | static int ps_fapi_set_cache(gs_text_enum_t *penum, |
2238 | | const gs_font_base *pbfont, |
2239 | | const gs_string *char_name, gs_glyph cid, |
2240 | | const double pwidth[2], const gs_rect *pbbox, |
2241 | | const double Metrics2_sbw_default[4], |
2242 | | bool *imagenow); |
2243 | | |
2244 | | static const gs_fapi_font ps_ff_stub = { |
2245 | | 0, /* server_font_data */ |
2246 | | 0, /* need_decrypt */ |
2247 | | NULL, /* const gs_memory_t */ |
2248 | | 0, /* font_file_path */ |
2249 | | 0, /* full_font_buf */ |
2250 | | 0, /* full_font_buf_len */ |
2251 | | 0, /* subfont */ |
2252 | | false, /* is_type1 */ |
2253 | | false, /* is_cid */ |
2254 | | false, /* is_outline_font */ |
2255 | | false, /* is_mtx_skipped */ |
2256 | | false, /* is_vertical */ |
2257 | | false, /* metrics_only */ |
2258 | | {{-1, -1}}, /* ttf_cmap_req */ |
2259 | | {-1, -1}, /* ttf_cmap_selected */ |
2260 | | 0, /* client_ctx_p */ |
2261 | | 0, /* client_font_data */ |
2262 | | 0, /* client_font_data2 */ |
2263 | | 0, /* char_data */ |
2264 | | 0, /* char_data_len */ |
2265 | | 0, /* embolden */ |
2266 | | FAPI_FF_get_word, |
2267 | | FAPI_FF_get_long, |
2268 | | FAPI_FF_get_float, |
2269 | | FAPI_FF_get_name, |
2270 | | FAPI_FF_get_proc, |
2271 | | FAPI_FF_get_gsubr, |
2272 | | FAPI_FF_get_subr, |
2273 | | FAPI_FF_get_raw_subr, |
2274 | | FAPI_FF_get_glyph, |
2275 | | FAPI_FF_serialize_tt_font, |
2276 | | NULL, /* retrieve_tt_font */ |
2277 | | FAPI_FF_get_charstring, |
2278 | | FAPI_FF_get_charstring_name, |
2279 | | ps_get_GlyphDirectory_data_ptr, |
2280 | | ps_get_glyphname_or_cid, |
2281 | | ps_fapi_get_metrics, |
2282 | | ps_fapi_set_cache |
2283 | | }; |
2284 | | |
2285 | | static int |
2286 | | FAPI_get_xlatmap(i_ctx_t *i_ctx_p, char **xlatmap) |
2287 | 7.52k | { |
2288 | 7.52k | ref *pref; |
2289 | 7.52k | int code; |
2290 | | |
2291 | 7.52k | if ((code = dict_find_string(systemdict, ".xlatmap", &pref)) < 0) |
2292 | 0 | return code; |
2293 | 7.52k | if (code == 0) |
2294 | 0 | return_error(gs_error_undefined); |
2295 | | |
2296 | 7.52k | if (r_type(pref) != t_string) |
2297 | 0 | return_error(gs_error_typecheck); |
2298 | 7.52k | *xlatmap = (char *)pref->value.bytes; |
2299 | | /* Note : this supposes that xlatmap doesn't move in virtual memory. |
2300 | | Garbager must not be called while plugin executes get_scaled_font, get_decodingID. |
2301 | | Fix some day with making copy of xlatmap in system memory. |
2302 | | */ |
2303 | 7.52k | return 0; |
2304 | 7.52k | } |
2305 | | |
2306 | | static int |
2307 | | renderer_retcode(gs_memory_t *mem, gs_fapi_server *I, gs_fapi_retcode rc) |
2308 | 0 | { |
2309 | 0 | if (rc == 0) |
2310 | 0 | return 0; |
2311 | 0 | emprintf2(mem, |
2312 | 0 | "Error: Font Renderer Plugin ( %s ) return code = %d\n", |
2313 | 0 | I->ig.d->subtype, rc); |
2314 | 0 | return rc < 0 ? rc : gs_error_invalidfont; |
2315 | 0 | } |
2316 | | |
2317 | | /* <server name>/<null> object .FAPIavailable bool */ |
2318 | | static int |
2319 | | zFAPIavailable(i_ctx_t *i_ctx_p) |
2320 | 178k | { |
2321 | 178k | os_ptr op = osp; |
2322 | 178k | char *serv_name = NULL; |
2323 | 178k | ref name_ref; |
2324 | | |
2325 | 178k | check_op(1); |
2326 | 178k | if (r_has_type(op, t_name)) { |
2327 | 89.2k | name_string_ref(imemory, op, &name_ref); |
2328 | | |
2329 | 89.2k | serv_name = |
2330 | 89.2k | (char *) ref_to_string(&name_ref, imemory, "zFAPIavailable"); |
2331 | 89.2k | if (!serv_name) { |
2332 | 0 | return_error(gs_error_VMerror); |
2333 | 0 | } |
2334 | 89.2k | } |
2335 | | |
2336 | 178k | make_bool(op, gs_fapi_available(imemory, serv_name)); |
2337 | | |
2338 | 178k | if (serv_name) { |
2339 | 89.2k | gs_free_string(imemory, (byte *) serv_name, |
2340 | 89.2k | strlen((char *)serv_name) + 1, "zFAPIavailable"); |
2341 | 89.2k | } |
2342 | 178k | return (0); |
2343 | 178k | } |
2344 | | |
2345 | | static void |
2346 | | ps_get_server_param(gs_fapi_server *I, const byte *subtype, |
2347 | | byte **server_param, int *server_param_size) |
2348 | 44.0k | { |
2349 | 44.0k | ref *FAPIconfig, *options, *server_options; |
2350 | 44.0k | i_ctx_t *i_ctx_p = (i_ctx_t *) I->client_ctx_p; |
2351 | | |
2352 | 44.0k | if (dict_find_string(systemdict, ".FAPIconfig", &FAPIconfig) > 0 |
2353 | 44.0k | && r_has_type(FAPIconfig, t_dictionary)) { |
2354 | 44.0k | if (dict_find_string(FAPIconfig, "ServerOptions", &options) > 0 |
2355 | 44.0k | && r_has_type(options, t_dictionary)) { |
2356 | 44.0k | if (dict_find_string(options, (char *)subtype, &server_options) > |
2357 | 44.0k | 0 && r_has_type(server_options, t_string)) { |
2358 | 0 | *server_param = (byte *) server_options->value.const_bytes; |
2359 | 0 | *server_param_size = r_size(server_options); |
2360 | 0 | } |
2361 | 44.0k | } |
2362 | 44.0k | } |
2363 | 44.0k | } |
2364 | | |
2365 | | static int |
2366 | | FAPI_refine_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font *pfont, |
2367 | | int subfont, const char *font_file_path) |
2368 | 43.9k | { |
2369 | 43.9k | ref *pdr = op; /* font dict */ |
2370 | 43.9k | const char *decodingID = NULL; |
2371 | 43.9k | char *xlatmap = NULL; |
2372 | 43.9k | gs_font_base *pbfont = (gs_font_base *)pfont; |
2373 | 43.9k | gs_fapi_server *I = pbfont->FAPI; |
2374 | 43.9k | ref *Decoding_old; |
2375 | 43.9k | int code; |
2376 | | |
2377 | 43.9k | if (font_file_path != NULL && pbfont->FAPI_font_data == NULL) |
2378 | 0 | if ((code = FAPI_get_xlatmap(i_ctx_p, &xlatmap)) < 0) |
2379 | 0 | return code; |
2380 | | |
2381 | 43.9k | gs_fapi_set_servers_client_data(imemory, NULL, i_ctx_p); |
2382 | | |
2383 | 43.9k | code = |
2384 | 43.9k | gs_fapi_prepare_font(pfont, I, subfont, font_file_path, |
2385 | 43.9k | NULL, xlatmap, &decodingID); |
2386 | 43.9k | if (code < 0) |
2387 | 0 | return code; |
2388 | | |
2389 | 43.9k | if (code > 0) { |
2390 | | /* save refined FontBBox back to PS world */ |
2391 | 0 | ref *v, mat[4], arr; |
2392 | 0 | int attrs; |
2393 | |
|
2394 | 0 | if (dict_find_string(op, "FontBBox", &v) > 0) { |
2395 | 0 | if (!r_has_type(v, t_array) && !r_has_type(v, t_shortarray) |
2396 | 0 | && !r_has_type(v, t_mixedarray)) |
2397 | 0 | return_error(gs_error_invalidfont); |
2398 | 0 | make_real(&mat[0], pbfont->FontBBox.p.x); |
2399 | 0 | make_real(&mat[1], pbfont->FontBBox.p.y); |
2400 | 0 | make_real(&mat[2], pbfont->FontBBox.q.x); |
2401 | 0 | make_real(&mat[3], pbfont->FontBBox.q.y); |
2402 | 0 | if (r_has_type(v, t_shortarray) || r_has_type(v, t_mixedarray) |
2403 | 0 | || r_size(v) < 4) { |
2404 | | /* Create a new full blown array in case the values are reals */ |
2405 | 0 | code = ialloc_ref_array(&arr, a_all, 4, "array"); |
2406 | 0 | if (code < 0) |
2407 | 0 | return code; |
2408 | 0 | v = &arr; |
2409 | 0 | code = idict_put_string(op, "FontBBox", &arr); |
2410 | 0 | if (code < 0) |
2411 | 0 | return code; |
2412 | 0 | ref_assign_new(v->value.refs + 0, &mat[0]); |
2413 | 0 | ref_assign_new(v->value.refs + 1, &mat[1]); |
2414 | 0 | ref_assign_new(v->value.refs + 2, &mat[2]); |
2415 | 0 | ref_assign_new(v->value.refs + 3, &mat[3]); |
2416 | 0 | } |
2417 | 0 | else { |
2418 | 0 | ref_assign_old(v, v->value.refs + 0, &mat[0], |
2419 | 0 | "FAPI_refine_font_BBox"); |
2420 | 0 | ref_assign_old(v, v->value.refs + 1, &mat[1], |
2421 | 0 | "FAPI_refine_font_BBox"); |
2422 | 0 | ref_assign_old(v, v->value.refs + 2, &mat[2], |
2423 | 0 | "FAPI_refine_font_BBox"); |
2424 | 0 | ref_assign_old(v, v->value.refs + 3, &mat[3], |
2425 | 0 | "FAPI_refine_font_BBox"); |
2426 | 0 | } |
2427 | 0 | attrs = v->tas.type_attrs; |
2428 | 0 | r_clear_attrs(v, a_all); |
2429 | 0 | r_set_attrs(v, attrs | a_execute); |
2430 | 0 | } |
2431 | 0 | } |
2432 | | |
2433 | | /* Assign a Decoding : */ |
2434 | 43.9k | if (decodingID != 0 && *decodingID |
2435 | 43.9k | && dict_find_string(pdr, "Decoding", &Decoding_old) <= 0) { |
2436 | 0 | ref Decoding; |
2437 | |
|
2438 | 0 | if (FAPI_ISCIDFONT(pbfont)) { |
2439 | 0 | ref *CIDSystemInfo, *Ordering, SubstNWP; |
2440 | 0 | byte buf[30]; |
2441 | 0 | int ordering_length, decodingID_length = |
2442 | 0 | min(strlen(decodingID), sizeof(buf) - 2); |
2443 | |
|
2444 | 0 | if (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) <= 0 |
2445 | 0 | || !r_has_type(CIDSystemInfo, t_dictionary)) |
2446 | 0 | return_error(gs_error_invalidfont); |
2447 | | |
2448 | 0 | if (dict_find_string(CIDSystemInfo, "Ordering", &Ordering) <= 0 |
2449 | 0 | || !r_has_type(Ordering, t_string)) { |
2450 | 0 | return_error(gs_error_invalidfont); |
2451 | 0 | } |
2452 | | |
2453 | 0 | ordering_length = |
2454 | 0 | min(r_size(Ordering), sizeof(buf) - 2 - decodingID_length); |
2455 | 0 | memcpy(buf, Ordering->value.const_bytes, ordering_length); |
2456 | 0 | if ((code = |
2457 | 0 | name_ref(imemory, buf, ordering_length, &SubstNWP, 0)) < 0) |
2458 | 0 | return code; |
2459 | 0 | if ((code = |
2460 | 0 | dict_put_string(pdr, "SubstNWP", &SubstNWP, NULL)) < 0) |
2461 | 0 | return code; |
2462 | 0 | buf[ordering_length] = '.'; |
2463 | 0 | memcpy(buf + ordering_length + 1, decodingID, decodingID_length); |
2464 | 0 | buf[decodingID_length + 1 + ordering_length] = 0; /* Debug purpose only */ |
2465 | 0 | if ((code = name_ref(imemory, buf, |
2466 | 0 | decodingID_length + 1 + ordering_length, |
2467 | 0 | &Decoding, 0)) < 0) |
2468 | 0 | return code; |
2469 | 0 | } |
2470 | 0 | else if ((code = name_ref(imemory, (const byte *)decodingID, |
2471 | 0 | strlen(decodingID), &Decoding, 0)) < 0) |
2472 | 0 | return code; |
2473 | 0 | if ((code = dict_put_string(pdr, "Decoding", &Decoding, NULL)) < 0) |
2474 | 0 | return code; |
2475 | 0 | } |
2476 | 43.9k | return 0; |
2477 | 43.9k | } |
2478 | | |
2479 | | /* <string|name> <font> <is_disk_font> .rebuildfontFAPI <string|name> <font> */ |
2480 | | /* Rebuild a font for handling it with an external renderer. |
2481 | | |
2482 | | The font was built as a native GS font to allow easy access |
2483 | | to font features. Then zFAPIrebuildfont sets FAPI entry |
2484 | | into gx_font_base and replaces BuildGlyph and BuildChar |
2485 | | to enforce the FAPI handling. |
2486 | | |
2487 | | This operator must not be called with devices which embed fonts. |
2488 | | |
2489 | | */ |
2490 | | static int |
2491 | | zFAPIrebuildfont(i_ctx_t *i_ctx_p) |
2492 | 44.0k | { |
2493 | 44.0k | os_ptr op = osp; |
2494 | 44.0k | build_proc_refs build; |
2495 | 44.0k | gs_font *pfont; |
2496 | 44.0k | int code = font_param(op - 1, &pfont); |
2497 | 44.0k | gs_font_base *pbfont = (gs_font_base *) pfont; |
2498 | 44.0k | ref *v; |
2499 | 44.0k | char *font_file_path = NULL; |
2500 | 44.0k | char FAPI_ID[20]; |
2501 | 44.0k | const byte *pchars; |
2502 | 44.0k | uint len; |
2503 | 44.0k | font_data *pdata; |
2504 | 44.0k | gs_fapi_server *I; |
2505 | 44.0k | bool has_buildglyph; |
2506 | 44.0k | bool has_buildchar; |
2507 | 44.0k | int subfont; |
2508 | | |
2509 | 44.0k | if (code < 0) |
2510 | 0 | return code; |
2511 | | |
2512 | 44.0k | check_type(*op, t_boolean); |
2513 | | /* If someone has copied the font dictionary, we may still |
2514 | | * have the FAPI entry in the dict, but not have the FAPI |
2515 | | * server assigned in the font object. |
2516 | | */ |
2517 | 44.0k | if (pbfont->FAPI == NULL) { |
2518 | 36.4k | if (dict_find_string(op - 1, "FAPI", &v) <= 0 |
2519 | 36.4k | || !r_has_type(v, t_name)) |
2520 | 0 | return_error(gs_error_invalidfont); |
2521 | 36.4k | obj_string_data(imemory, v, &pchars, &len); |
2522 | 36.4k | len = min(len, sizeof(FAPI_ID) - 1); |
2523 | 36.4k | strncpy((char *)FAPI_ID, (const char *)pchars, len); |
2524 | 36.4k | FAPI_ID[len] = 0; |
2525 | | |
2526 | 36.4k | gs_fapi_set_servers_client_data(imemory, &ps_ff_stub, i_ctx_p); |
2527 | | |
2528 | 36.4k | code = |
2529 | 36.4k | gs_fapi_find_server(imemory, FAPI_ID, |
2530 | 36.4k | (gs_fapi_server **) & (pbfont->FAPI), |
2531 | 36.4k | (gs_fapi_get_server_param_callback) |
2532 | 36.4k | ps_get_server_param); |
2533 | 36.4k | if (!pbfont->FAPI || code < 0) { |
2534 | 0 | return_error(gs_error_invalidfont); |
2535 | 0 | } |
2536 | 36.4k | } |
2537 | | |
2538 | 44.0k | pdata = (font_data *) pfont->client_data; |
2539 | 44.0k | I = pbfont->FAPI; |
2540 | | |
2541 | 44.0k | if (dict_find_string((op - 1), "SubfontId", &v) > 0 |
2542 | 44.0k | && r_has_type(v, t_integer)) |
2543 | 0 | subfont = v->value.intval; |
2544 | 44.0k | else |
2545 | 44.0k | subfont = 0; |
2546 | | |
2547 | | |
2548 | 44.0k | if (r_type(&(pdata->BuildGlyph)) != t_null) { |
2549 | 44.0k | has_buildglyph = true; |
2550 | 44.0k | } |
2551 | 0 | else { |
2552 | 0 | has_buildglyph = false; |
2553 | 0 | } |
2554 | | |
2555 | 44.0k | if (r_type(&(pdata->BuildChar)) != t_null) { |
2556 | 44.0k | has_buildchar = true; |
2557 | 44.0k | } |
2558 | 0 | else { |
2559 | 0 | has_buildchar = false; |
2560 | 0 | } |
2561 | | |
2562 | | /* This shouldn't happen, but just in case */ |
2563 | 44.0k | if (has_buildglyph == false && has_buildchar == false) { |
2564 | 0 | has_buildglyph = true; |
2565 | 0 | } |
2566 | | |
2567 | 44.0k | if (dict_find_string(op - 1, "Path", &v) <= 0 || !r_has_type(v, t_string)) { |
2568 | 44.0k | v = NULL; |
2569 | 44.0k | } |
2570 | | |
2571 | 44.0k | if (pfont->FontType == ft_CID_encrypted && v == NULL) { |
2572 | 0 | if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildGlyph9", |
2573 | 0 | ".FAPIBuildGlyph9")) < 0) { |
2574 | 0 | return code; |
2575 | 0 | } |
2576 | 0 | } |
2577 | 44.0k | else { |
2578 | 44.0k | if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildChar", |
2579 | 44.0k | ".FAPIBuildGlyph")) < 0) { |
2580 | 0 | return code; |
2581 | 0 | } |
2582 | 44.0k | } |
2583 | | |
2584 | 44.0k | if (! |
2585 | 44.0k | ((r_type(&(pdata->BuildChar)) != t_null |
2586 | 44.0k | && pdata->BuildChar.value.pname && build.BuildChar.value.pname |
2587 | 44.0k | && name_index(imemory, &pdata->BuildChar) == name_index(imemory, |
2588 | 44.0k | &build. |
2589 | 44.0k | BuildChar)) |
2590 | 44.0k | || (r_type(&(pdata->BuildGlyph)) != t_null |
2591 | 43.9k | && pdata->BuildGlyph.value.pname && build.BuildGlyph.value.pname |
2592 | 43.9k | && name_index(imemory, &pdata->BuildGlyph) == name_index(imemory, |
2593 | 43.9k | &build. |
2594 | 43.9k | BuildGlyph)))) |
2595 | 43.9k | { |
2596 | | |
2597 | 43.9k | if (has_buildchar == true) { |
2598 | 43.9k | ref_assign_new(&pdata->BuildChar, &build.BuildChar); |
2599 | 43.9k | } |
2600 | 0 | else { |
2601 | 0 | make_null(&pdata->BuildChar); |
2602 | 0 | } |
2603 | | |
2604 | 43.9k | if (has_buildglyph == true) { |
2605 | 43.9k | ref_assign_new(&pdata->BuildGlyph, &build.BuildGlyph); |
2606 | 43.9k | } |
2607 | 0 | else { |
2608 | 0 | make_null(&pdata->BuildGlyph); |
2609 | 0 | } |
2610 | 43.9k | if (v != NULL) { |
2611 | 0 | font_file_path = |
2612 | 0 | ref_to_string(v, imemory_global, "font file path"); |
2613 | 0 | } |
2614 | | |
2615 | 43.9k | code = |
2616 | 43.9k | FAPI_refine_font(i_ctx_p, op - 1, pfont, subfont, |
2617 | 43.9k | font_file_path); |
2618 | | |
2619 | 43.9k | memcpy(&I->initial_FontMatrix, &pbfont->FontMatrix, |
2620 | 43.9k | sizeof(gs_matrix)); |
2621 | | |
2622 | 43.9k | if (font_file_path != NULL) { |
2623 | 0 | gs_free_string(imemory_global, (byte *) font_file_path, |
2624 | 0 | r_size(v) + 1, "font file path"); |
2625 | 0 | } |
2626 | 43.9k | } |
2627 | 44.0k | pop(1); |
2628 | 44.0k | return code; |
2629 | 44.0k | } |
2630 | | |
2631 | | static ulong |
2632 | | array_find(const gs_memory_t *mem, ref *Encoding, ref *char_name) |
2633 | 0 | { |
2634 | 0 | ulong n = r_size(Encoding), i; |
2635 | 0 | ref v; |
2636 | |
|
2637 | 0 | for (i = 0; i < n; i++) |
2638 | 0 | if (array_get(mem, Encoding, i, &v) < 0) |
2639 | 0 | break; |
2640 | 0 | else if (r_type(char_name) == r_type(&v) |
2641 | 0 | && char_name->value.const_pname == v.value.const_pname) |
2642 | 0 | return i; |
2643 | 0 | return 0; |
2644 | 0 | } |
2645 | | |
2646 | | static int |
2647 | | zfapi_finish_render(i_ctx_t *i_ctx_p) |
2648 | 0 | { |
2649 | 0 | os_ptr op = osp; |
2650 | 0 | gs_font *pfont; |
2651 | 0 | int code = font_param(op - 1, &pfont); |
2652 | |
|
2653 | 0 | if (code == 0) { |
2654 | 0 | gs_font_base *pbfont = (gs_font_base *) pfont; |
2655 | 0 | gs_fapi_server *I = pbfont->FAPI; |
2656 | 0 | gs_text_enum_t *penum = op_show_find(i_ctx_p); |
2657 | |
|
2658 | 0 | gs_fapi_set_servers_client_data(imemory, NULL, i_ctx_p); |
2659 | |
|
2660 | 0 | code = gs_fapi_finish_render(pfont, igs, penum, I); |
2661 | 0 | pop(2); |
2662 | 0 | I->release_char_data(I); |
2663 | 0 | } |
2664 | 0 | return code; |
2665 | 0 | } |
2666 | | |
2667 | | static int |
2668 | | ps_fapi_set_cache(gs_text_enum_t *penum, const gs_font_base *pbfont, |
2669 | | const gs_string *char_name, gs_glyph cid, |
2670 | | const double pwidth[2], const gs_rect *pbbox, |
2671 | | const double Metrics2_sbw_default[4], bool *imagenow) |
2672 | 964k | { |
2673 | 964k | i_ctx_t *i_ctx_p = (i_ctx_t *) pbfont->FAPI->client_ctx_p; |
2674 | 964k | op_proc_t exec_cont = 0; /* dummy - see below */ |
2675 | 964k | int code = 0; |
2676 | | |
2677 | 964k | if (cid < GS_MIN_CID_GLYPH) { |
2678 | 964k | ref cname; |
2679 | | |
2680 | 964k | make_string(&cname, avm_foreign | a_readonly, char_name->size, |
2681 | 964k | char_name->data); |
2682 | 964k | code = |
2683 | 964k | zchar_set_cache(i_ctx_p, pbfont, &cname, NULL, pwidth, pbbox, |
2684 | 964k | zfapi_finish_render, &exec_cont, |
2685 | 964k | Metrics2_sbw_default); |
2686 | 964k | } |
2687 | 0 | else { |
2688 | 0 | ref cidref; |
2689 | |
|
2690 | 0 | make_int(&cidref, (cid - GS_MIN_CID_GLYPH)); |
2691 | 0 | code = zchar_set_cache(i_ctx_p, pbfont, &cidref, NULL, pwidth, pbbox, |
2692 | 0 | zfapi_finish_render, &exec_cont, |
2693 | 0 | Metrics2_sbw_default); |
2694 | 0 | } |
2695 | | |
2696 | 964k | if (code >= 0 && exec_cont != NULL) { |
2697 | 963k | *imagenow = true; |
2698 | 963k | } |
2699 | 1.02k | else { |
2700 | 1.02k | *imagenow = false; |
2701 | 1.02k | } |
2702 | | /* We ignore the value of exec_cont here, and leave it up to |
2703 | | * gs_fapi_do_char() to do the "right" thing based on the |
2704 | | * return value |
2705 | | */ |
2706 | 964k | return (code); |
2707 | 964k | } |
2708 | | |
2709 | | |
2710 | | static const byte * |
2711 | | find_substring(const byte *where, int length, const char *what) |
2712 | 0 | { |
2713 | 0 | int l = strlen(what); |
2714 | 0 | int n = length - l; |
2715 | 0 | const byte *p = where; |
2716 | |
|
2717 | 0 | for (; n >= 0; n--, p++) |
2718 | 0 | if (!memcmp(p, what, l)) |
2719 | 0 | return p; |
2720 | 0 | return NULL; |
2721 | 0 | } |
2722 | | |
2723 | | static int |
2724 | | ps_get_glyphname_or_cid(gs_text_enum_t *penum, |
2725 | | gs_font_base *pbfont, gs_string *charstring, |
2726 | | gs_string *name, gs_glyph ccode, |
2727 | | gs_string *enc_char_name, char *font_file_path, |
2728 | | gs_fapi_char_ref *cr, bool bCID) |
2729 | 984k | { |
2730 | 984k | ref *pdr = pfont_dict(pbfont); |
2731 | 984k | int client_char_code = ccode; |
2732 | 984k | ref char_name, cname_str; |
2733 | 984k | int code = 0; |
2734 | 984k | gs_fapi_server *I = pbfont->FAPI; |
2735 | 984k | bool is_TT_from_type42 = (pbfont->FontType == ft_TrueType && font_file_path == NULL); |
2736 | 984k | bool is_glyph_index = false; |
2737 | 984k | bool is_embedded_type1 = |
2738 | 984k | ((pbfont->FontType == ft_encrypted |
2739 | 984k | || pbfont->FontType == ft_encrypted2) && font_file_path == NULL); |
2740 | 984k | i_ctx_t *i_ctx_p = (i_ctx_t *) I->client_ctx_p; |
2741 | 984k | bool unicode_cp = false; |
2742 | | |
2743 | | /* Obtain the character name : */ |
2744 | 984k | if (bCID) { |
2745 | 0 | if (pbfont->FontType == ft_CID_TrueType && font_file_path) { |
2746 | 0 | ref *pdr2, *fidr, *dummy; |
2747 | 0 | pdr2 = pfont_dict(gs_rootfont(igs)); |
2748 | 0 | if (dict_find_string(pdr2, "FontInfo", &fidr) > 0 && |
2749 | 0 | dict_find_string(fidr, "GlyphNames2Unicode", &dummy) > 0) |
2750 | 0 | { |
2751 | 0 | unsigned char uc[4] = {0}; |
2752 | 0 | unsigned int cc = 0; |
2753 | 0 | int i, l; |
2754 | 0 | if (penum->text.operation & TEXT_FROM_SINGLE_CHAR) { |
2755 | 0 | cc = penum->text.data.d_char; |
2756 | 0 | } else if (penum->text.operation & TEXT_FROM_SINGLE_GLYPH) { |
2757 | 0 | cc = penum->text.data.d_glyph - GS_MIN_CID_GLYPH; |
2758 | 0 | } |
2759 | 0 | else { |
2760 | 0 | byte *c = (byte *)&penum->text.data.bytes[penum->index - penum->bytes_decoded]; |
2761 | 0 | for (i = 0; i < penum->bytes_decoded ; i++) { |
2762 | 0 | cc |= c[i] << ((penum->bytes_decoded - 1) - i) * 8; |
2763 | 0 | } |
2764 | 0 | } |
2765 | 0 | l = ((gs_font_base *)gs_rootfont(igs))->procs.decode_glyph(gs_rootfont(igs), cc + GS_MIN_CID_GLYPH, ccode, (unsigned short *)uc, sizeof(uc)); |
2766 | 0 | if (l > 0 && l < sizeof(uc)) { |
2767 | 0 | cc = 0; |
2768 | 0 | for (i = 0; i < l; i++) { |
2769 | 0 | cc |= uc[l - 1 - i] << (i * 8); |
2770 | 0 | } |
2771 | 0 | ccode = cc; |
2772 | 0 | unicode_cp = true; |
2773 | 0 | } |
2774 | 0 | } |
2775 | 0 | } |
2776 | 0 | client_char_code = ccode; |
2777 | 0 | make_null(&char_name); |
2778 | 0 | enc_char_name->data = NULL; |
2779 | 0 | enc_char_name->size = 0; |
2780 | 0 | } |
2781 | 984k | else { |
2782 | 984k | if (ccode != GS_NO_CHAR) { |
2783 | | /* Translate from PS encoding to char name : */ |
2784 | 984k | ref *Encoding; |
2785 | | |
2786 | 984k | client_char_code = ccode; |
2787 | 984k | if (dict_find_string(pdr, "Encoding", &Encoding) > 0 && |
2788 | 984k | (r_has_type(Encoding, t_array) || |
2789 | 984k | r_has_type(Encoding, t_shortarray) |
2790 | 984k | || r_has_type(Encoding, t_mixedarray))) { |
2791 | 984k | if (array_get(imemory, Encoding, client_char_code, &char_name) |
2792 | 984k | < 0) |
2793 | 0 | if ((code = |
2794 | 0 | name_ref(imemory, (const byte *)".notdef", 7, |
2795 | 0 | &char_name, -1)) < 0) |
2796 | 0 | return code; |
2797 | 984k | } |
2798 | 0 | else { |
2799 | 0 | return_error(gs_error_invalidfont); |
2800 | 0 | } |
2801 | 984k | } |
2802 | 0 | else { |
2803 | 0 | code = |
2804 | 0 | names_ref(imemory->gs_lib_ctx->gs_name_table, |
2805 | 0 | (const byte *)name->data, name->size, &char_name, |
2806 | 0 | 0); |
2807 | |
|
2808 | 0 | } |
2809 | | /* We need to store the name as we get it (from the Encoding array), in case it's |
2810 | | * had the name extended (with "~GS~xx"), we'll remove the extension before passing |
2811 | | * it to the renderer for a disk based font. But the metrics dictionary may have |
2812 | | * been constructed using the extended name.... |
2813 | | */ |
2814 | 984k | if (!r_has_type(&char_name, t_name)) |
2815 | 0 | return_error(gs_error_invalidfont); |
2816 | 984k | name_string_ref(imemory, &char_name, &cname_str); |
2817 | 984k | enc_char_name->data = cname_str.value.bytes; |
2818 | 984k | enc_char_name->size = r_size(&cname_str); |
2819 | 984k | } |
2820 | | |
2821 | | /* Obtain the character code or glyph index : */ |
2822 | 984k | cr->char_codes_count = 1; |
2823 | 984k | if (bCID) { |
2824 | 0 | if (font_file_path != NULL) { |
2825 | 0 | ref *Decoding, *TT_cmap = NULL, *SubstNWP; |
2826 | 0 | ref src_type, dst_type; |
2827 | 0 | uint c = 0; |
2828 | |
|
2829 | 0 | is_glyph_index = true; |
2830 | |
|
2831 | 0 | if (dict_find_string(pdr, "Decoding", &Decoding) <= 0 |
2832 | 0 | || !r_has_type(Decoding, t_dictionary)) |
2833 | 0 | return_error(gs_error_invalidfont); |
2834 | 0 | if (dict_find_string(pdr, "SubstNWP", &SubstNWP) <= 0 |
2835 | 0 | || !r_has_type(SubstNWP, t_array)) |
2836 | 0 | return_error(gs_error_invalidfont); |
2837 | 0 | if (dict_find_string(pdr, "TT_cmap", &TT_cmap) <= 0 |
2838 | 0 | || !r_has_type(TT_cmap, t_dictionary)) { |
2839 | 0 | ref *DecodingArray, char_code, char_code1, ih; |
2840 | 0 | int i = client_char_code % 256, n; |
2841 | |
|
2842 | 0 | make_int(&ih, client_char_code / 256); |
2843 | | /* Check the Decoding array for this block of CIDs */ |
2844 | 0 | if (dict_find(Decoding, &ih, &DecodingArray) <= 0 |
2845 | 0 | || !r_has_type(DecodingArray, t_array) |
2846 | 0 | || array_get(imemory, DecodingArray, i, &char_code) < 0) { |
2847 | 0 | return_error(gs_error_invalidfont); |
2848 | 0 | } |
2849 | | |
2850 | | /* Check the Decoding entry */ |
2851 | 0 | if (r_has_type(&char_code, t_integer)) { |
2852 | 0 | n = 1; |
2853 | 0 | } |
2854 | 0 | else if (r_has_type(&char_code, t_array)) { |
2855 | 0 | DecodingArray = &char_code; |
2856 | 0 | i = 0; |
2857 | 0 | n = r_size(DecodingArray); |
2858 | 0 | } |
2859 | 0 | else { |
2860 | 0 | return_error(gs_error_invalidfont); |
2861 | 0 | } |
2862 | | |
2863 | 0 | for (; n--; i++) { |
2864 | 0 | if (array_get(imemory, DecodingArray, i, &char_code1) < 0 |
2865 | 0 | || !r_has_type(&char_code1, t_integer)) { |
2866 | 0 | return_error(gs_error_invalidfont); |
2867 | 0 | } |
2868 | | |
2869 | 0 | c = char_code1.value.intval; |
2870 | 0 | I->check_cmap_for_GID(I, &c); |
2871 | 0 | if (c != 0) |
2872 | 0 | break; |
2873 | 0 | } |
2874 | 0 | } |
2875 | 0 | else { |
2876 | 0 | ref *CIDSystemInfo; |
2877 | 0 | ref *Ordering; |
2878 | 0 | ref *fdict, *CMapDict, *CMapName, *WMode, CMapNameStr; |
2879 | 0 | char *cmapnm = NULL; |
2880 | 0 | int cmapnmlen = 0; |
2881 | 0 | int wmode = 0; |
2882 | | /* leave off the -H or -V */ |
2883 | 0 | const char * const utfcmap = "Identity-UTF16"; |
2884 | 0 | int utfcmaplen = strlen(utfcmap); |
2885 | |
|
2886 | 0 | fdict = pfont_dict(gs_rootfont(igs)); |
2887 | 0 | code = dict_find_string(fdict, "CMap", &CMapDict); |
2888 | 0 | if (code > 0 && r_has_type(CMapDict, t_dictionary)) { |
2889 | 0 | code = dict_find_string(CMapDict, "WMode", &WMode); |
2890 | 0 | if (code > 0 && r_has_type(WMode, t_integer)) { |
2891 | 0 | wmode = WMode->value.intval; |
2892 | 0 | } |
2893 | 0 | code = dict_find_string(CMapDict, "CMapName", &CMapName); |
2894 | 0 | if (code > 0 && r_has_type(CMapName, t_name)) { |
2895 | 0 | name_string_ref(imemory, CMapName, &CMapNameStr); |
2896 | 0 | cmapnm = (char *)CMapNameStr.value.bytes; |
2897 | 0 | cmapnmlen = r_size(&CMapNameStr); |
2898 | 0 | } |
2899 | 0 | } |
2900 | | /* We only have to lookup the char code if we're *not* using an identity ordering |
2901 | | with the exception of Identity-UTF16 which is a different beast altogether */ |
2902 | 0 | if (unicode_cp || (cmapnmlen > 0 && !strncmp(cmapnm, utfcmap, cmapnmlen > utfcmaplen ? utfcmaplen : cmapnmlen)) |
2903 | 0 | || (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) > 0 |
2904 | 0 | && r_has_type(CIDSystemInfo, t_dictionary) |
2905 | 0 | && dict_find_string(CIDSystemInfo, "Ordering", |
2906 | 0 | &Ordering) > 0 |
2907 | 0 | && r_has_type(Ordering, t_string) |
2908 | 0 | && strncmp((const char *)Ordering->value.bytes, |
2909 | 0 | "Identity", 8) != 0)) { |
2910 | |
|
2911 | 0 | if ((code = |
2912 | 0 | cid_to_TT_charcode(imemory, Decoding, TT_cmap, |
2913 | 0 | SubstNWP, client_char_code, &c, |
2914 | 0 | &src_type, &dst_type)) < 0) { |
2915 | 0 | return code; |
2916 | 0 | } |
2917 | 0 | } |
2918 | 0 | else { |
2919 | 0 | if (pbfont->FontType == ft_CID_TrueType) { |
2920 | 0 | c = ((gs_font_cid2 *)pbfont)->cidata.CIDMap_proc(((gs_font_cid2 *)pbfont), |
2921 | 0 | client_char_code + GS_MIN_CID_GLYPH); |
2922 | 0 | } |
2923 | 0 | else { |
2924 | 0 | c = client_char_code; |
2925 | 0 | } |
2926 | 0 | } |
2927 | 0 | if (pbfont->FontType == ft_CID_TrueType) |
2928 | 0 | c = ((gs_font_cid2 *)pbfont)->data.substitute_glyph_index_vertical((gs_font_type42 *)pbfont, c, wmode, ccode); |
2929 | 0 | } |
2930 | 0 | if (pbfont->FontType == ft_CID_TrueType && c == 0 && TT_cmap) { |
2931 | 0 | ref cc32; |
2932 | 0 | ref *gid; |
2933 | 0 | make_int(&cc32, 32); |
2934 | 0 | if (dict_find(TT_cmap, &cc32, &gid) > 0) |
2935 | 0 | c = gid->value.intval; |
2936 | 0 | } |
2937 | 0 | cr->char_codes[0] = c; |
2938 | | /* fixme : process the narrow/wide/proportional mapping type, |
2939 | | using src_type, dst_type. Should adjust the 'matrix' above. |
2940 | | Call get_font_proportional_feature for proper choice. |
2941 | | */ |
2942 | 0 | } |
2943 | 0 | else { |
2944 | 0 | ref *CIDMap; |
2945 | 0 | byte *Map; |
2946 | 0 | int c_code = client_char_code; |
2947 | 0 | int gdb = 2; |
2948 | 0 | int i; |
2949 | 0 | ref *GDBytes = NULL; |
2950 | |
|
2951 | 0 | if ((dict_find_string(pdr, "GDBytes", &GDBytes) > 0) |
2952 | 0 | && r_has_type(GDBytes, t_integer)) { |
2953 | 0 | gdb = GDBytes->value.intval; |
2954 | 0 | } |
2955 | | |
2956 | | /* The PDF Reference says that we should use a CIDToGIDMap, but the PDF |
2957 | | * interpreter converts this into a CIDMap (see pdf_font.ps, processCIDToGIDMap) |
2958 | | */ |
2959 | 0 | if (dict_find_string(pdr, "CIDMap", &CIDMap) > 0 |
2960 | 0 | && !r_has_type(CIDMap, t_name) && (r_has_type(CIDMap, t_array) |
2961 | 0 | || r_has_type(CIDMap, |
2962 | 0 | t_string))) { |
2963 | |
|
2964 | 0 | if (r_has_type(CIDMap, t_array)) { |
2965 | | |
2966 | | /* Too big for single string, so its an array of 2 strings */ |
2967 | 0 | code = string_array_access_proc(pbfont->memory, CIDMap, 1, |
2968 | 0 | client_char_code * (ulong)gdb, |
2969 | 0 | gdb, NULL, NULL, |
2970 | 0 | (const byte **)&Map); |
2971 | 0 | } |
2972 | 0 | else { |
2973 | 0 | if (CIDMap->tas.rsize <= c_code * gdb) { |
2974 | 0 | c_code = 0; |
2975 | 0 | } |
2976 | 0 | Map = &CIDMap->value.bytes[c_code * gdb]; |
2977 | 0 | } |
2978 | 0 | cr->char_codes[0] = 0; |
2979 | 0 | is_glyph_index = true; |
2980 | 0 | if (code >= 0) { |
2981 | 0 | for (i = 0; i < gdb; i++) { |
2982 | 0 | cr->char_codes[0] = (cr->char_codes[0] << 8) + Map[i]; |
2983 | 0 | } |
2984 | 0 | } |
2985 | 0 | else { |
2986 | 0 | ref *cstr, *refcode; |
2987 | 0 | code = dict_find_string(pdr, "CharStrings", &cstr); |
2988 | 0 | if (code > 0) { |
2989 | 0 | code = dict_find_string(cstr, ".notdef", &refcode); |
2990 | 0 | if (code > 0) { |
2991 | 0 | cr->char_codes[0] = refcode->value.intval; |
2992 | 0 | } |
2993 | 0 | } |
2994 | 0 | } |
2995 | 0 | } |
2996 | 0 | else |
2997 | 0 | cr->char_codes[0] = client_char_code; |
2998 | 0 | } |
2999 | 0 | } |
3000 | 984k | else if (is_TT_from_type42) { |
3001 | | /* This font must not use 'cmap', so compute glyph index from CharStrings : */ |
3002 | 0 | ref *CharStrings, *glyph_index, *cmaptab; |
3003 | |
|
3004 | 0 | if (dict_find_string(pdr, "TT_cmap", &cmaptab) > 0 && |
3005 | 0 | r_has_type(cmaptab, t_dictionary)) { |
3006 | 0 | const char *nd = ".notdef"; |
3007 | |
|
3008 | 0 | if (enc_char_name->size >= strlen(nd) && |
3009 | 0 | enc_char_name->data[0] == nd[0] && |
3010 | 0 | !memcmp(enc_char_name->data, nd, strlen(nd))) { |
3011 | 0 | ref ccref, *gidref, boolref; |
3012 | 0 | make_int(&ccref, ccode); |
3013 | 0 | if (dict_find(cmaptab, &ccref, &gidref) > 0 && |
3014 | 0 | r_has_type(gidref, t_integer) && |
3015 | 0 | gidref->value.intval == 0) { |
3016 | 0 | make_bool(&boolref, true); |
3017 | 0 | } |
3018 | 0 | else { |
3019 | 0 | make_bool(&boolref, false); |
3020 | 0 | } |
3021 | 0 | dict_put_string(pdr, ".render_notdef", &boolref, NULL); |
3022 | 0 | } |
3023 | 0 | } |
3024 | |
|
3025 | 0 | if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0 |
3026 | 0 | || !r_has_type(CharStrings, t_dictionary)) |
3027 | 0 | return_error(gs_error_invalidfont); |
3028 | 0 | if ((dict_find(CharStrings, &char_name, &glyph_index) <= 0) |
3029 | 0 | || r_has_type(glyph_index, t_null)) { |
3030 | | #ifdef DEBUG |
3031 | | ref *pvalue; |
3032 | | |
3033 | | if (gs_debug_c('1') |
3034 | | && (dict_find_string(systemdict, "QUIET", &pvalue)) > 0 |
3035 | | && (r_has_type(pvalue, t_boolean) |
3036 | | && pvalue->value.boolval == false)) { |
3037 | | char *glyphn; |
3038 | | |
3039 | | name_string_ref(imemory, &char_name, &char_name); |
3040 | | |
3041 | | glyphn = |
3042 | | ref_to_string(&char_name, imemory, |
3043 | | "ps_get_glyphname_or_cid"); |
3044 | | if (glyphn) { |
3045 | | dmprintf2(imemory, " Substituting .notdef for %s in the font %s \n", |
3046 | | glyphn, pbfont->font_name.chars); |
3047 | | gs_free_string(imemory, (byte *) glyphn, |
3048 | | strlen(glyphn) + 1, |
3049 | | "ps_get_glyphname_or_cid"); |
3050 | | } |
3051 | | } |
3052 | | #endif |
3053 | |
|
3054 | 0 | cr->char_codes[0] = 0; /* .notdef */ |
3055 | 0 | if ((code = |
3056 | 0 | name_ref(imemory, (const byte *)".notdef", 7, &char_name, |
3057 | 0 | -1)) < 0) |
3058 | 0 | return code; |
3059 | 0 | } |
3060 | 0 | else if (r_has_type(glyph_index, t_integer)) { |
3061 | 0 | cr->char_codes[0] = glyph_index->value.intval; |
3062 | 0 | } |
3063 | 0 | else { |
3064 | 0 | #if 1 /* I can't find this ever being used, no idea what it's for..... */ |
3065 | 0 | os_ptr op = osp; |
3066 | | |
3067 | | /* Check execution stack has space for BuldChar proc and finish_render */ |
3068 | 0 | check_estack(2); |
3069 | | /* check space and duplicate the glyph index for BuildChar */ |
3070 | 0 | check_op(1); |
3071 | 0 | push(1); |
3072 | 0 | ref_assign_inline(op, op - 1); |
3073 | | /* Come back to fapi_finish_render after running the BuildChar */ |
3074 | 0 | push_op_estack(zfapi_finish_render); |
3075 | 0 | ++esp; |
3076 | 0 | ref_assign(esp, glyph_index); |
3077 | 0 | return o_push_estack; |
3078 | | #else |
3079 | | return (gs_error_invalidfont); |
3080 | | #endif |
3081 | 0 | } |
3082 | 0 | is_glyph_index = true; |
3083 | 0 | } |
3084 | 984k | else if (is_embedded_type1) { |
3085 | | /* Since the client passes charstring by callback using I->ff.char_data, |
3086 | | the client doesn't need to provide a good cr here. |
3087 | | Perhaps since UFST uses char codes as glyph cache keys (UFST 4.2 cannot use names), |
3088 | | we provide font char codes equal to document's char codes. |
3089 | | This trick assumes that Encoding can't point different glyphs |
3090 | | for same char code. The last should be true due to |
3091 | | PLRM3, "5.9.4 Subsetting and Incremental Definition of Glyphs". |
3092 | | */ |
3093 | 984k | if (ccode != GS_NO_CHAR) { |
3094 | 984k | cr->char_codes[0] = client_char_code; |
3095 | 984k | } |
3096 | 0 | else { |
3097 | | /* |
3098 | | * Reverse Encoding here, because it can be an incremental one. |
3099 | | * Note that this can cause problems with UFST (see the comment above), |
3100 | | * if the encoding doesn't contain the glyph name rendered with glyphshow. |
3101 | | */ |
3102 | 0 | ref *Encoding; |
3103 | 0 | ref glyph; |
3104 | |
|
3105 | 0 | if ((code = name_ref(pbfont->memory, name->data, name->size, &glyph, false)) < 0) |
3106 | 0 | return code; |
3107 | | |
3108 | 0 | if (dict_find_string(osp - 1, "Encoding", &Encoding) > 0) { |
3109 | 0 | cr->char_codes[0] = |
3110 | 0 | (uint) array_find(imemory, Encoding, &glyph); |
3111 | 0 | } |
3112 | 0 | else |
3113 | 0 | return_error(gs_error_invalidfont); |
3114 | 0 | } |
3115 | 984k | } |
3116 | 0 | else { /* a non-embedded font, i.e. a disk font */ |
3117 | 0 | bool can_retrieve_char_by_name = false; |
3118 | 0 | const byte *p; |
3119 | |
|
3120 | 0 | obj_string_data(imemory, &char_name, &cr->char_name, |
3121 | 0 | &cr->char_name_length); |
3122 | 0 | p = find_substring(cr->char_name, cr->char_name_length, |
3123 | 0 | gx_extendeg_glyph_name_separator); |
3124 | 0 | if (p != NULL) { |
3125 | 0 | cr->char_name_length = p - cr->char_name; |
3126 | 0 | if ((code = name_ref(pbfont->memory, cr->char_name, |
3127 | 0 | cr->char_name_length, &char_name, true)) < 0) |
3128 | 0 | return code; |
3129 | 0 | } |
3130 | 0 | if ((code = |
3131 | 0 | renderer_retcode(imemory, I, |
3132 | 0 | I->can_retrieve_char_by_name(I, &I->ff, cr, |
3133 | 0 | &can_retrieve_char_by_name))) |
3134 | 0 | < 0) |
3135 | 0 | return code; |
3136 | | |
3137 | 0 | if (!can_retrieve_char_by_name) { |
3138 | | /* Translate from char name to encoding used with 3d party font technology : */ |
3139 | 0 | ref *Decoding, *char_code; |
3140 | |
|
3141 | 0 | if (dict_find_string(osp - 1, "Decoding", &Decoding) > 0 |
3142 | 0 | && r_has_type(Decoding, t_dictionary)) { |
3143 | 0 | if (dict_find(Decoding, &char_name, &char_code) > 0) { |
3144 | 0 | code = 0; |
3145 | 0 | if (r_has_type(char_code, t_integer)) { |
3146 | 0 | int c_code; |
3147 | 0 | int_param(char_code, 0xFFFF, &c_code); |
3148 | 0 | cr->char_codes[0] = (gs_glyph)c_code; |
3149 | 0 | } |
3150 | 0 | else if (r_has_type(char_code, t_array) |
3151 | 0 | || r_has_type(char_code, t_shortarray)) { |
3152 | 0 | int i; |
3153 | 0 | ref v; |
3154 | |
|
3155 | 0 | cr->char_codes_count = r_size(char_code); |
3156 | 0 | if (cr->char_codes_count > count_of(cr->char_codes)) |
3157 | 0 | code = gs_note_error(gs_error_rangecheck); |
3158 | 0 | if (code >= 0) { |
3159 | 0 | for (i = 0; i < cr->char_codes_count; i++) { |
3160 | 0 | code = array_get(imemory, char_code, i, &v); |
3161 | 0 | if (code < 0) |
3162 | 0 | break; |
3163 | 0 | if (!r_has_type(char_code, t_integer)) { |
3164 | 0 | code = gs_note_error(gs_error_rangecheck); |
3165 | 0 | break; |
3166 | 0 | } |
3167 | 0 | cr->char_codes[i] = v.value.intval; |
3168 | 0 | } |
3169 | 0 | } |
3170 | 0 | } |
3171 | 0 | else { |
3172 | 0 | code = gs_note_error(gs_error_rangecheck); |
3173 | 0 | } |
3174 | 0 | if (code < 0) { |
3175 | 0 | char buf[16]; |
3176 | 0 | int l = cr->char_name_length; |
3177 | |
|
3178 | 0 | if (l > sizeof(buf) - 1) { |
3179 | 0 | l = sizeof(buf) - 1; |
3180 | 0 | } |
3181 | 0 | memcpy(buf, cr->char_name, l); |
3182 | 0 | buf[l] = 0; |
3183 | 0 | emprintf1(imemory, |
3184 | 0 | "Wrong decoding entry for the character '%s'.\n", |
3185 | 0 | buf); |
3186 | 0 | return_error(gs_error_rangecheck); |
3187 | 0 | } |
3188 | 0 | } |
3189 | 0 | } |
3190 | 0 | } |
3191 | 0 | } |
3192 | | |
3193 | | /* Provide glyph data for renderer : */ |
3194 | | /* Occasionally, char_name is already a glyph index to pass to the rendering engine |
3195 | | * so don't treat it as a name object. |
3196 | | * I believe this will only happen with a TTF/Type42, but checking the object type |
3197 | | * is cheap, and covers all font type eventualities. |
3198 | | */ |
3199 | 984k | if (!I->ff.is_cid && r_has_type(&char_name, t_name)) { |
3200 | 984k | ref sname; |
3201 | | |
3202 | 984k | name_string_ref(imemory, &char_name, &sname); |
3203 | 984k | I->ff.char_data = sname.value.const_bytes; |
3204 | 984k | I->ff.char_data_len = r_size(&sname); |
3205 | 984k | } |
3206 | 0 | else if (I->ff.is_type1) { |
3207 | 0 | I->ff.char_data = charstring; |
3208 | 0 | } |
3209 | | |
3210 | 984k | cr->is_glyph_index = is_glyph_index; |
3211 | 984k | cr->client_char_code = client_char_code; |
3212 | | |
3213 | 984k | return (code); |
3214 | 984k | } |
3215 | | |
3216 | | |
3217 | | static int |
3218 | | FAPI_char(i_ctx_t *i_ctx_p, bool bBuildGlyph, ref *charstring) |
3219 | 964k | { /* Stack : <font> <code|name> --> - */ |
3220 | 964k | os_ptr op = osp; |
3221 | 964k | ref *pdr = op - 1; |
3222 | 964k | ref *v; |
3223 | 964k | char *font_file_path = NULL; |
3224 | 964k | gs_font *pfont; |
3225 | 964k | int code = font_param(osp - 1, &pfont); |
3226 | | |
3227 | 964k | if (code == 0) { |
3228 | 964k | gs_font_base *pbfont = (gs_font_base *) pfont; |
3229 | 964k | bool bCID = (FAPI_ISCIDFONT(pbfont) || charstring != NULL); |
3230 | 964k | int subfont; |
3231 | 964k | gs_fapi_server *I = pbfont->FAPI; |
3232 | 964k | gs_text_enum_t *penum = op_show_find(i_ctx_p); |
3233 | 964k | gs_string char_string, *c_string_p = NULL; |
3234 | 964k | gs_string char_name, *c_name_p = NULL; |
3235 | 964k | gs_glyph cindex = GS_NO_CHAR; |
3236 | 964k | ref gname; |
3237 | | |
3238 | 964k | if (I == NULL) |
3239 | 0 | return_error(gs_error_invalidfont); |
3240 | | |
3241 | | /* initialise the FAPI font, this includes language specific stuff */ |
3242 | 964k | I->ff = ps_ff_stub; |
3243 | | |
3244 | 964k | I->client_ctx_p = i_ctx_p; |
3245 | | |
3246 | 964k | if (bBuildGlyph && !bCID) { |
3247 | 0 | if (r_type(op) != t_name) { |
3248 | 0 | name_enter_string(imemory, ".notdef", op); |
3249 | 0 | } |
3250 | 0 | check_type(*op, t_name); |
3251 | | |
3252 | 0 | name_string_ref(imemory, op, &gname); |
3253 | 0 | c_name_p = &char_name; |
3254 | 0 | c_name_p->data = gname.value.bytes; |
3255 | 0 | c_name_p->size = r_size(&gname); |
3256 | |
|
3257 | 0 | } |
3258 | 964k | else { |
3259 | 964k | int chint; |
3260 | 964k | if (bBuildGlyph && pbfont->FontType == ft_CID_TrueType |
3261 | 964k | && r_has_type(op, t_name)) { |
3262 | 0 | ref *chstrs, *chs; |
3263 | | |
3264 | | /* This logic is lifted from %Type11BuildGlyph in gs_cidfn.ps |
3265 | | * Note we only have to deal with mistakenly being given a name object |
3266 | | * here, the out of range CID is handled later |
3267 | | */ |
3268 | 0 | if ((dict_find_string(op - 1, "CharStrings", &chstrs)) <= 0) { |
3269 | 0 | return_error(gs_error_undefined); |
3270 | 0 | } |
3271 | | |
3272 | 0 | if ((dict_find_string(chstrs, ".notdef", &chs)) <= 0) { |
3273 | 0 | return_error(gs_error_undefined); |
3274 | 0 | } |
3275 | 0 | ref_assign_inline(op, chs); |
3276 | 0 | } |
3277 | | |
3278 | 964k | make_null(&gname); |
3279 | 964k | check_type(*op, t_integer); |
3280 | 964k | int_param(op, 0xFFFF, (int *)&chint); |
3281 | 964k | cindex = chint; |
3282 | 964k | } |
3283 | | |
3284 | 964k | if (dict_find_string(pdr, "SubfontId", &v) > 0 |
3285 | 964k | && r_has_type(v, t_integer)) |
3286 | 0 | subfont = v->value.intval; |
3287 | 964k | else |
3288 | 964k | subfont = 0; |
3289 | | |
3290 | 964k | if (dict_find_string(osp - 1, "Path", &v) > 0 |
3291 | 964k | && r_has_type(v, t_string)) { |
3292 | 0 | font_file_path = ref_to_string(v, imemory, "font file path"); |
3293 | 0 | } |
3294 | | |
3295 | 964k | if (charstring) { |
3296 | 0 | c_string_p = &char_string; |
3297 | 0 | c_string_p->data = charstring->value.bytes; |
3298 | 0 | c_string_p->size = r_size(charstring); |
3299 | 0 | } |
3300 | | |
3301 | 964k | code = |
3302 | 964k | gs_fapi_do_char(pfont, igs, penum, font_file_path, |
3303 | 964k | bBuildGlyph, c_string_p, c_name_p, (gs_char)cindex, cindex, |
3304 | 964k | subfont); |
3305 | 964k | if (font_file_path != NULL) { |
3306 | 0 | gs_free_string(imemory, (byte *) font_file_path, r_size(v) + 1, |
3307 | 0 | "font file path"); |
3308 | 0 | } |
3309 | | /* This handles the situation where a charstring has been replaced with a PS procedure. |
3310 | | * against the rules, but not *that* rare. |
3311 | | * It's also something that GS does internally to simulate font styles. |
3312 | | */ |
3313 | 964k | if (code == gs_error_unregistered) { |
3314 | 0 | os_ptr op = osp; |
3315 | 0 | ref *proc = NULL, gname; |
3316 | |
|
3317 | 0 | if (I->ff.is_type1 |
3318 | 0 | && (get_charstring(&I->ff, cindex, &proc, &gname) >= 0) |
3319 | 0 | && proc != NULL && (r_has_type(proc, t_array) |
3320 | 0 | || r_has_type(proc, t_mixedarray))) { |
3321 | 0 | push(2); |
3322 | 0 | ref_assign(op - 1, &gname); |
3323 | 0 | ref_assign(op, proc); |
3324 | 0 | return (zchar_exec_char_proc(i_ctx_p)); |
3325 | 0 | } |
3326 | 0 | else { |
3327 | 0 | return_error(gs_error_invalidfont); |
3328 | 0 | } |
3329 | 0 | } |
3330 | 964k | } |
3331 | | /* We've already imaged teh glyph, pop the operands */ |
3332 | 964k | if (code == 0) |
3333 | 963k | pop(2); |
3334 | 964k | return code; |
3335 | 964k | } |
3336 | | |
3337 | | static int |
3338 | | zFAPIBuildGlyph9(i_ctx_t *i_ctx_p) |
3339 | 0 | { |
3340 | | /* The alghorithm is taken from %Type9BuildGlyph - see gs_cidfn.ps . */ |
3341 | 0 | os_ptr lop, op = osp; |
3342 | 0 | int cid, code; |
3343 | 0 | avm_space s = ialloc_space(idmemory); |
3344 | 0 | ref font9 = *pfont_dict(gs_currentfont(igs)); |
3345 | 0 | ref *rFDArray, f; |
3346 | 0 | int font_index; |
3347 | |
|
3348 | 0 | check_type(op[0], t_integer); |
3349 | 0 | check_type(op[-1], t_dictionary); |
3350 | 0 | cid = op[0].value.intval; |
3351 | 0 | push(2); |
3352 | 0 | op[-1] = *pfont_dict(gs_currentfont(igs)); |
3353 | 0 | op[0] = op[-2]; /* <font0> <cid> <font9> <cid> */ |
3354 | 0 | ialloc_set_space(idmemory, (r_is_local(op - 3) ? avm_global : avm_local)); /* for ztype9mapcid */ |
3355 | | |
3356 | | /* stack: <font0> <cid> <font9> <cid> */ |
3357 | 0 | if ((code = ztype9mapcid(i_ctx_p)) < 0) |
3358 | 0 | return code; /* <font0> <cid> <charstring> <font_index> */ |
3359 | | /* fixme: what happens if the charstring is absent ? |
3360 | | Can FDArray contain 'null' (see %Type9BuildGlyph in gs_cidfn.ps)? */ |
3361 | 0 | font_index = op[0].value.intval; |
3362 | 0 | if (dict_find_string(&font9, "FDArray", &rFDArray) <= 0 |
3363 | 0 | || r_type(rFDArray) != t_array) |
3364 | 0 | return_error(gs_error_invalidfont); |
3365 | 0 | if (array_get(imemory, rFDArray, font_index, &f) < 0 |
3366 | 0 | || r_type(&f) != t_dictionary) |
3367 | 0 | return_error(gs_error_invalidfont); |
3368 | | |
3369 | 0 | op[0] = op[-2]; |
3370 | 0 | op[-2] = op[-1]; /* Keep the charstring on ostack for the garbager. */ |
3371 | 0 | op[-1] = f; /* <font0> <charstring> <subfont> <cid> */ |
3372 | 0 | if ((code = FAPI_char(i_ctx_p, true, op - 2)) < 0) |
3373 | 0 | return code; |
3374 | | /* stack: <font0> <charstring> */ |
3375 | | |
3376 | 0 | lop = osp; |
3377 | 0 | if (code == 5) { |
3378 | 0 | int i, ind = (lop - op); |
3379 | |
|
3380 | 0 | op = osp; |
3381 | |
|
3382 | 0 | for (i = ind; i >= 0; i--) { |
3383 | 0 | op[-i - 2] = op[-i]; |
3384 | 0 | } |
3385 | 0 | pop(2); |
3386 | 0 | } |
3387 | 0 | else if (code < 0) { /* <font0> <dirty> <dirty> <dirty> */ |
3388 | | /* Adjust ostack for the correct error handling : */ |
3389 | 0 | make_int(op - 2, cid); |
3390 | 0 | pop(2); /* <font0> <cid> */ |
3391 | 0 | } |
3392 | 0 | else if (code != 5) { /* <font0> <dirty> */ |
3393 | | |
3394 | |
|
3395 | 0 | pop(2); /* */ |
3396 | | /* Note that this releases the charstring, and it may be garbage-collected |
3397 | | before the interpreter calls fapi_finish_render. This requires the server |
3398 | | to keep glyph raster internally between calls to get_char_raster_metrics |
3399 | | and get_char_raster. Perhaps UFST cannot provide metrics without |
3400 | | building a raster, so this constraint actually goes from UFST. |
3401 | | */ |
3402 | 0 | } |
3403 | 0 | ialloc_set_space(idmemory, s); |
3404 | 0 | return code; |
3405 | 0 | } |
3406 | | |
3407 | | /* <font> <code> .FAPIBuildChar - */ |
3408 | | static int |
3409 | | zFAPIBuildChar(i_ctx_t *i_ctx_p) |
3410 | 964k | { |
3411 | 964k | return FAPI_char(i_ctx_p, false, NULL); |
3412 | 964k | } |
3413 | | |
3414 | | /* non-CID : <font> <code> .FAPIBuildGlyph - */ |
3415 | | /* CID : <font> <name> .FAPIBuildGlyph - */ |
3416 | | static int |
3417 | | zFAPIBuildGlyph(i_ctx_t *i_ctx_p) |
3418 | 2 | { |
3419 | 2 | return FAPI_char(i_ctx_p, true, NULL); |
3420 | 2 | } |
3421 | | |
3422 | | |
3423 | | /* <font_dict> .FAPIpassfont bool <font_dict> */ |
3424 | | /* must insert /FAPI to font dictionary */ |
3425 | | static int |
3426 | | zFAPIpassfont(i_ctx_t *i_ctx_p) |
3427 | 7.52k | { |
3428 | 7.52k | os_ptr op = osp; |
3429 | 7.52k | gs_font *pfont; |
3430 | 7.52k | int code; |
3431 | 7.52k | char *font_file_path = NULL; |
3432 | 7.52k | ref *v; |
3433 | 7.52k | char *xlatmap = NULL; |
3434 | 7.52k | char *fapi_request = NULL; |
3435 | 7.52k | char *fapi_id = NULL; |
3436 | 7.52k | ref reqstr; |
3437 | 7.52k | int subfont; |
3438 | | |
3439 | | /* Normally embedded fonts have no Path, but if a CID font is |
3440 | | * emulated with a TT font, and it is hooked with FAPI, |
3441 | | * the path presents and is neccessary to access the full font data. |
3442 | | */ |
3443 | 7.52k | check_type(*op, t_dictionary); |
3444 | | |
3445 | 7.52k | code = font_param(osp, &pfont); |
3446 | 7.52k | if (code < 0) |
3447 | 0 | return code; |
3448 | | |
3449 | 7.52k | if (dict_find_string(op, "SubfontId", &v) > 0 |
3450 | 7.52k | && r_has_type(v, t_integer)) |
3451 | 0 | subfont = v->value.intval; |
3452 | 7.52k | else |
3453 | 7.52k | subfont = 0; |
3454 | | |
3455 | 7.52k | code = FAPI_get_xlatmap(i_ctx_p, &xlatmap); /* Useful for emulated fonts hooked with FAPI. */ |
3456 | 7.52k | if (code < 0) |
3457 | 0 | return code; |
3458 | | |
3459 | | /* If the font dictionary contains a FAPIPlugInReq key, the the PS world wants us |
3460 | | * to try to use a specific FAPI plugin, so find it, and try it.... |
3461 | | */ |
3462 | 7.52k | if (dict_find_string(op, "FAPIPlugInReq", &v) > 0 && r_type(v) == t_name) { |
3463 | |
|
3464 | 0 | name_string_ref(imemory, v, &reqstr); |
3465 | |
|
3466 | 0 | fapi_request = ref_to_string(&reqstr, imemory, "zFAPIpassfont"); |
3467 | 0 | } |
3468 | | |
3469 | 7.52k | if (dict_find_string(op, "Path", &v) > 0 && r_has_type(v, t_string)) |
3470 | 0 | font_file_path = ref_to_string(v, imemory_global, "font file path"); |
3471 | | |
3472 | 7.52k | gs_fapi_set_servers_client_data(imemory, &ps_ff_stub, i_ctx_p); |
3473 | | |
3474 | 7.52k | code = |
3475 | 7.52k | gs_fapi_passfont(pfont, subfont, font_file_path, NULL, fapi_request, xlatmap, |
3476 | 7.52k | &fapi_id, (gs_fapi_get_server_param_callback)ps_get_server_param); |
3477 | | |
3478 | 7.52k | if (font_file_path != NULL) |
3479 | 0 | gs_free_string(imemory_global, (byte *) font_file_path, r_size(v) + 1, |
3480 | 7.52k | "font file path"); |
3481 | | |
3482 | 7.52k | if (fapi_request != NULL) |
3483 | 0 | gs_free_string(imemory, (byte *) fapi_request, |
3484 | 7.52k | strlen(fapi_request) + 1, "do_FAPIpassfont"); |
3485 | 7.52k | if (code < 0 && code != gs_error_invalidaccess) |
3486 | 6 | return code; |
3487 | | |
3488 | 7.52k | if (code >= 0 && fapi_id != NULL) { |
3489 | 7.52k | ref FAPI_ID; |
3490 | | |
3491 | 7.52k | if ((code = |
3492 | 7.52k | name_ref(imemory, (const byte *)fapi_id, |
3493 | 7.52k | strlen(fapi_id), &FAPI_ID, false)) < 0) |
3494 | 0 | return code; |
3495 | 7.52k | if ((code = dict_put_string(op, "FAPI", &FAPI_ID, NULL)) < 0) |
3496 | 0 | return code; /* Insert FAPI entry to font dictionary. */ |
3497 | 7.52k | } |
3498 | 7.52k | push(1); |
3499 | 7.52k | make_bool(op, (fapi_id != NULL)); |
3500 | 7.52k | return 0; |
3501 | 7.52k | } |
3502 | | |
3503 | | const op_def zfapi_op_defs[] = { |
3504 | | {"1.FAPIavailable", zFAPIavailable}, |
3505 | | {"2.FAPIpassfont", zFAPIpassfont}, |
3506 | | {"2.FAPIrebuildfont", zFAPIrebuildfont}, |
3507 | | {"2.FAPIBuildChar", zFAPIBuildChar}, |
3508 | | {"2.FAPIBuildGlyph", zFAPIBuildGlyph}, |
3509 | | {"2.FAPIBuildGlyph9", zFAPIBuildGlyph9}, |
3510 | | op_def_end(0) |
3511 | | }; |