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