1 /* Copyright (C) 2001-2012 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., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, 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 #include "ifapi.h"
52 #include "iplugin.h"
53 #include "store.h"
54 #include "gzstate.h"
55 #include "gdevpsf.h"
56 #include "stream.h" /* for files.h */
57 #include "gscrypt1.h"
58 #include "gxfcid.h"
59 #include "gsstype.h"
60 #include "gxchar.h" /* for st_gs_show_enum */
61 #include "ipacked.h" /* for packed_next */
62 #include "iddict.h"
63 #include "ifont42.h" /* for string_array_access_proc */
64 #include "gdebug.h"
65 #include "gsimage.h"
66 #include "gxcldev.h"
67 #include "gxdevmem.h"
68
69 /* lifted from gxchar.c */
70 static const uint MAX_TEMP_BITMAP_BITS = 80000;
71 /* -------------------------------------------------------- */
72
73 typedef struct FAPI_outline_handler_s {
74 struct gx_path_s *path;
75 fixed x0, y0;
76 bool close_path, need_close; /* This stuff fixes unclosed paths being rendered with UFST */
77 } FAPI_outline_handler;
78
import_shift(int64_t x,int64_t n)79 static inline int64_t import_shift(int64_t x, int64_t n)
80 { return n > 0 ? x << n : x >> -n;
81 }
82
export_shift(int x,int n)83 static inline int export_shift(int x, int n)
84 { return n > 0 ? x >> n : x << -n;
85 }
86
fapi_round(double x)87 static inline int fapi_round(double x)
88 { return (int)(x + 0.5);
89 }
90
add_closepath(FAPI_path * I)91 static int add_closepath(FAPI_path *I)
92 { FAPI_outline_handler *olh = (FAPI_outline_handler *)I->olh;
93
94 if (olh->need_close == true) {
95 olh->need_close = false;
96 I->gs_error = gx_path_close_subpath_notes(olh->path, 0);
97 }
98 return I->gs_error;
99 }
100
add_move(FAPI_path * I,int64_t x,int64_t y)101 static int add_move(FAPI_path *I, int64_t x, int64_t y)
102 { FAPI_outline_handler *olh = (FAPI_outline_handler *)I->olh;
103
104 x = import_shift(x, I->shift) + olh->x0;
105 y = -import_shift(y, I->shift) + olh->y0;
106
107 if (x > (int64_t)max_fixed) {
108 x = (int64_t)max_fixed;
109 }
110 else if (x < (int64_t)min_fixed) {
111 x = (int64_t)min_fixed;
112 }
113
114 if (y > (int64_t)max_fixed) {
115 y = (int64_t)max_fixed;
116 }
117 else if (y < (int64_t)min_fixed) {
118 y = (int64_t)min_fixed;
119 }
120
121 if (olh->need_close && olh->close_path)
122 if ((I->gs_error = add_closepath(I)) < 0)
123 return I->gs_error;
124 olh->need_close = false;
125 I->gs_error = gx_path_add_point(olh->path, (fixed)x, (fixed)y);
126
127 return I->gs_error;
128 }
129
add_line(FAPI_path * I,int64_t x,int64_t y)130 static int add_line(FAPI_path *I, int64_t x, int64_t y)
131 { FAPI_outline_handler *olh = (FAPI_outline_handler *)I->olh;
132
133 x = import_shift(x, I->shift) + olh->x0;
134 y = -import_shift(y, I->shift) + olh->y0;
135 if (x > (int64_t)max_fixed) {
136 x = (int64_t)max_fixed;
137 }
138 else if (x < (int64_t)min_fixed) {
139 x = (int64_t)min_fixed;
140 }
141
142 if (y > (int64_t)max_fixed) {
143 y = (int64_t)max_fixed;
144 }
145 else if (y < (int64_t)min_fixed) {
146 y = (int64_t)min_fixed;
147 }
148
149 olh->need_close = true;
150 I->gs_error = gx_path_add_line_notes(olh->path, (fixed)x, (fixed)y, 0);
151 return I->gs_error;
152 }
153
add_curve(FAPI_path * I,int64_t x0,int64_t y0,int64_t x1,int64_t y1,int64_t x2,int64_t y2)154 static int add_curve(FAPI_path *I, int64_t x0, int64_t y0, int64_t x1, int64_t y1, int64_t x2, int64_t y2)
155 { FAPI_outline_handler *olh = (FAPI_outline_handler *)I->olh;
156
157 x0 = import_shift(x0, I->shift) + olh->x0;
158 y0 = -import_shift(y0, I->shift) + olh->y0;
159 x1 = import_shift(x1, I->shift) + olh->x0;
160 y1 = -import_shift(y1, I->shift) + olh->y0;
161 x2 = import_shift(x2, I->shift) + olh->x0;
162 y2 = -import_shift(y2, I->shift) + olh->y0;
163
164 if (x0 > (int64_t)max_fixed) {
165 x0 = (int64_t)max_fixed;
166 }
167 else if (x0 < (int64_t)min_fixed) {
168 x0 = (int64_t)min_fixed;
169 }
170
171 if (y0 > (int64_t)max_fixed) {
172 y0 = (int64_t)max_fixed;
173 }
174 else if (y0 < (int64_t)min_fixed) {
175 y0 = (int64_t)min_fixed;
176 }
177 if (x1 > (int64_t)max_fixed) {
178 x1 = (int64_t)max_fixed;
179 }
180 else if (x1 < (int64_t)min_fixed) {
181 x1 = (int64_t)min_fixed;
182 }
183
184 if (y1 > (int64_t)max_fixed) {
185 y1 = (int64_t)max_fixed;
186 }
187 else if (y1 < (int64_t)min_fixed) {
188 y1 = (int64_t)min_fixed;
189 }
190 if (x2 > (int64_t)max_fixed) {
191 x2 = (int64_t)max_fixed;
192 }
193 else if (x2 < (int64_t)min_fixed) {
194 x2 = (int64_t)min_fixed;
195 }
196
197 if (y2 > (int64_t)max_fixed) {
198 y2 = (int64_t)max_fixed;
199 }
200 else if (y2 < (int64_t)min_fixed) {
201 y2 = (int64_t)min_fixed;
202 }
203
204 olh->need_close = true;
205 I->gs_error = gx_path_add_curve_notes(olh->path, (fixed)x0, (fixed)y0, (fixed)x1, (fixed)y1, (fixed)x2, (fixed)y2, 0);
206 return I->gs_error;
207 }
208
209 static FAPI_path path_interface_stub = { NULL, 0, 0, add_move, add_line, add_curve, add_closepath };
210
IsCIDFont(const gs_font_base * pbfont)211 static inline bool IsCIDFont(const gs_font_base *pbfont)
212 { return (pbfont->FontType == ft_CID_encrypted ||
213 pbfont->FontType == ft_CID_user_defined ||
214 pbfont->FontType == ft_CID_TrueType);
215 /* The font type 10 (ft_CID_user_defined) must not pass to FAPI. */
216 }
217
IsType1GlyphData(const gs_font_base * pbfont)218 static inline bool IsType1GlyphData(const gs_font_base *pbfont)
219 { return pbfont->FontType == ft_encrypted ||
220 pbfont->FontType == ft_encrypted2 ||
221 pbfont->FontType == ft_CID_encrypted;
222 }
223
224 /* -------------------------------------------------------- */
225
226 typedef struct sfnts_reader_s sfnts_reader;
227 struct sfnts_reader_s {
228 ref *sfnts;
229 const gs_memory_t *memory;
230 const byte *p;
231 long index;
232 uint offset;
233 uint length;
234 bool error;
235 byte (*rbyte)(sfnts_reader *r);
236 ushort (*rword)(sfnts_reader *r);
237 ulong (*rlong)(sfnts_reader *r);
238 int (*rstring)(sfnts_reader *r, byte *v, int length);
239 void (*seek)(sfnts_reader *r, ulong pos);
240 };
241
sfnts_next_elem(sfnts_reader * r)242 static void sfnts_next_elem(sfnts_reader *r)
243 {
244 ref s;
245 int code;
246
247 if (r->error)
248 return;
249 r->index++;
250 code = array_get(r->memory, r->sfnts, r->index, &s);
251 if (code == e_rangecheck) {
252 r->error |= 2;
253 }
254 else if (code < 0) {
255 r->error |= 1;
256 }
257 if (r->error)
258 return;
259 r->p = s.value.const_bytes;
260 r->length = r_size(&s) & ~(uint)1; /* See Adobe Technical Note # 5012, section 4.2. */
261 r->offset = 0;
262 }
263
sfnts_reader_rbyte_inline(sfnts_reader * r)264 static inline byte sfnts_reader_rbyte_inline(sfnts_reader *r)
265 { if (r->offset >= r->length)
266 sfnts_next_elem(r);
267 return (r->error ? 0 : r->p[r->offset++]);
268 }
269
sfnts_reader_rbyte(sfnts_reader * r)270 static byte sfnts_reader_rbyte(sfnts_reader *r) /* old compiler compatibility */
271 { return sfnts_reader_rbyte_inline(r);
272 }
273
sfnts_reader_rword(sfnts_reader * r)274 static ushort sfnts_reader_rword(sfnts_reader *r)
275 { return (sfnts_reader_rbyte_inline(r) << 8) + sfnts_reader_rbyte_inline(r);
276 }
277
sfnts_reader_rlong(sfnts_reader * r)278 static ulong sfnts_reader_rlong(sfnts_reader *r)
279 { return (sfnts_reader_rbyte_inline(r) << 24) + (sfnts_reader_rbyte_inline(r) << 16) +
280 (sfnts_reader_rbyte_inline(r) << 8) + sfnts_reader_rbyte_inline(r);
281 }
282
sfnts_reader_rstring(sfnts_reader * r,byte * v,int length)283 static int sfnts_reader_rstring(sfnts_reader *r, byte *v, int length)
284 {
285 int rlength = length;
286
287 if (length <= 0)
288 return(0);
289 while (!r->error) {
290 int l = min(length, r->length - r->offset);
291 memcpy(v, r->p + r->offset, l);
292 length -= l;
293 r->offset += l;
294 if (length <= 0)
295 return(rlength);
296 v += l;
297 sfnts_next_elem(r);
298 }
299 return(rlength - length);
300 }
301
sfnts_reader_seek(sfnts_reader * r,ulong pos)302 static void sfnts_reader_seek(sfnts_reader *r, ulong pos)
303 { /* fixme : optimize */
304 ulong skipped = 0;
305
306 r->index = -1;
307 sfnts_next_elem(r);
308 while (skipped + r->length < pos && !r->error) {
309 skipped += r->length;
310 sfnts_next_elem(r);
311 }
312 r->offset = pos - skipped;
313 }
314
sfnts_reader_init(sfnts_reader * r,ref * pdr)315 static void sfnts_reader_init(sfnts_reader *r, ref *pdr)
316 { r->rbyte = sfnts_reader_rbyte;
317 r->rword = sfnts_reader_rword;
318 r->rlong = sfnts_reader_rlong;
319 r->rstring = sfnts_reader_rstring;
320 r->seek = sfnts_reader_seek;
321 r->index = -1;
322 r->error = false;
323 if (r_type(pdr) != t_dictionary ||
324 dict_find_string(pdr, "sfnts", &r->sfnts) <= 0)
325 r->error = true;
326 sfnts_next_elem(r);
327 }
328
329 /* -------------------------------------------------------- */
330
331 typedef struct sfnts_writer_s sfnts_writer;
332 struct sfnts_writer_s {
333 byte *buf, *p;
334 int buf_size;
335 void (*wbyte)(sfnts_writer *w, byte v);
336 void (*wword)(sfnts_writer *w, ushort v);
337 void (*wlong)(sfnts_writer *w, ulong v);
338 void (*wstring)(sfnts_writer *w, byte *v, int length);
339 };
340
sfnts_writer_wbyte(sfnts_writer * w,byte v)341 static void sfnts_writer_wbyte(sfnts_writer *w, byte v)
342 { if (w->buf + w->buf_size < w->p + 1)
343 return; /* safety */
344 w->p[0] = v;
345 w->p++;
346 }
347
sfnts_writer_wword(sfnts_writer * w,ushort v)348 static void sfnts_writer_wword(sfnts_writer *w, ushort v)
349 { if (w->buf + w->buf_size < w->p + 2)
350 return; /* safety */
351 w->p[0] = v / 256;
352 w->p[1] = v % 256;
353 w->p += 2;
354 }
355
sfnts_writer_wlong(sfnts_writer * w,ulong v)356 static void sfnts_writer_wlong(sfnts_writer *w, ulong v)
357 { if (w->buf + w->buf_size < w->p + 4)
358 return; /* safety */
359 w->p[0] = v >> 24;
360 w->p[1] = (v >> 16) & 0xFF;
361 w->p[2] = (v >> 8) & 0xFF;
362 w->p[3] = v & 0xFF;
363 w->p += 4;
364 }
365
sfnts_writer_wstring(sfnts_writer * w,byte * v,int length)366 static void sfnts_writer_wstring(sfnts_writer *w, byte *v, int length)
367 { if (w->buf + w->buf_size < w->p + length)
368 return; /* safety */
369 memcpy(w->p, v, length);
370 w->p += length;
371 }
372
373 static const sfnts_writer sfnts_writer_stub = {
374 0, 0, 0,
375 sfnts_writer_wbyte,
376 sfnts_writer_wword,
377 sfnts_writer_wlong,
378 sfnts_writer_wstring
379 };
380
381 /* -------------------------------------------------------- */
382
sfnts_need_copy_table(byte * tag)383 static inline bool sfnts_need_copy_table(byte *tag)
384 { return memcmp(tag, "glyf", 4) &&
385 memcmp(tag, "glyx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */
386 memcmp(tag, "loca", 4) &&
387 memcmp(tag, "locx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */
388 memcmp(tag, "cmap", 4);
389 }
390
sfnt_copy_table(sfnts_reader * r,sfnts_writer * w,int length)391 static void sfnt_copy_table(sfnts_reader *r, sfnts_writer *w, int length)
392 { byte buf[1024];
393
394 while (length > 0 && !r->error) {
395 int l = min(length, sizeof(buf));
396 (void)r->rstring(r, buf, l);
397 w->wstring(w, buf, l);
398 length -= l;
399 }
400 }
401
sfnts_copy_except_glyf(sfnts_reader * r,sfnts_writer * w)402 static ulong sfnts_copy_except_glyf(sfnts_reader *r, sfnts_writer *w)
403 { /* Note : TTC is not supported and probably is unuseful for Type 42. */
404 /* This skips glyf, loca and cmap from copying. */
405 struct {
406 byte tag[4];
407 ulong checkSum, offset, offset_new, length;
408 } tables[30];
409 const ushort alignment = 4; /* Not sure, maybe 2 */
410 ulong version = r->rlong(r);
411 ushort num_tables = r->rword(r);
412 ushort i, num_tables_new = 0;
413 ushort searchRange, entrySelector = 0, rangeShift, v;
414 ulong size_new = 12;
415
416 r->rword(r); /* searchRange */
417 r->rword(r); /* entrySelector */
418 r->rword(r); /* rangeShift */
419 for (i = 0; i < num_tables; i++) {
420 if (r->error)
421 return 0;
422 (void)r->rstring(r, tables[i].tag, 4);
423 tables[i].checkSum = r->rlong(r);
424 tables[i].offset = r->rlong(r);
425 tables[i].length = r->rlong(r);
426 tables[i].offset_new = size_new;
427 if (sfnts_need_copy_table(tables[i].tag)) {
428 num_tables_new ++;
429 size_new += (tables[i].length + alignment - 1) / alignment * alignment;
430 }
431 }
432 size_new += num_tables_new * 16;
433 if (w == 0)
434 return size_new;
435
436 searchRange = v = num_tables_new * 16;
437 for (i = 0; v; i++) {
438 v >>= 1;
439 searchRange |= v;
440 entrySelector++;
441 }
442 searchRange -= searchRange >> 1;
443 rangeShift = num_tables_new * 16 - searchRange;
444
445 w->wlong(w, version);
446 w->wword(w, num_tables_new);
447 w->wword(w, searchRange);
448 w->wword(w, entrySelector);
449 w->wword(w, rangeShift);
450 for (i = 0; i < num_tables; i++)
451 if (sfnts_need_copy_table(tables[i].tag)) {
452 w->wstring(w, tables[i].tag, 4);
453 w->wlong(w, tables[i].checkSum);
454 w->wlong(w, tables[i].offset_new + num_tables_new * 16);
455 w->wlong(w, tables[i].length);
456 }
457 for (i = 0; i < num_tables; i++)
458 if (sfnts_need_copy_table(tables[i].tag)) {
459 int k = tables[i].length;
460 r->seek(r, tables[i].offset);
461 if (r->error)
462 return 0;
463 if (w->p - w->buf != tables[i].offset_new + num_tables_new * 16)
464 return 0; /* the algorithm consistency check */
465 sfnt_copy_table(r, w, tables[i].length);
466 for (; k & (alignment - 1); k++)
467 w->wbyte(w, 0);
468 }
469 return size_new;
470 }
471
true_type_size(ref * pdr)472 static ulong true_type_size(ref *pdr)
473 { sfnts_reader r;
474
475 sfnts_reader_init(&r, pdr);
476 return sfnts_copy_except_glyf(&r, 0);
477 }
478
FAPI_FF_serialize_tt_font(FAPI_font * ff,void * buf,int buf_size)479 static ushort FAPI_FF_serialize_tt_font(FAPI_font *ff, void *buf, int buf_size)
480 { ref *pdr = (ref *)ff->client_font_data2;
481 sfnts_reader r;
482 sfnts_writer w = sfnts_writer_stub;
483
484 w.buf_size = buf_size;
485 w.buf = w.p = buf;
486 sfnts_reader_init(&r, pdr);
487 if(!sfnts_copy_except_glyf(&r, &w))
488 return 1;
489 return r.error;
490 }
491
float_to_ushort(float v)492 static inline ushort float_to_ushort(float v)
493 { return (ushort)(v * 16); /* fixme : the scale may depend on renderer */
494 }
495
FAPI_FF_get_word(FAPI_font * ff,fapi_font_feature var_id,int index)496 static ushort FAPI_FF_get_word(FAPI_font *ff, fapi_font_feature var_id, int index)
497 { gs_font_type1 *pfont = (gs_font_type1 *)ff->client_font_data;
498 ref *pdr = (ref *)ff->client_font_data2;
499
500 switch((int)var_id) {
501 case FAPI_FONT_FEATURE_Weight: return 0; /* wrong */
502 case FAPI_FONT_FEATURE_ItalicAngle: return 0; /* wrong */
503 case FAPI_FONT_FEATURE_IsFixedPitch: return 0; /* wrong */
504 case FAPI_FONT_FEATURE_UnderLinePosition: return 0; /* wrong */
505 case FAPI_FONT_FEATURE_UnderlineThickness: return 0; /* wrong */
506 case FAPI_FONT_FEATURE_FontType: return (pfont->FontType == 2 ? 2 : 1);
507 case FAPI_FONT_FEATURE_FontBBox:
508 switch (index) {
509 case 0 : return (ushort)pfont->FontBBox.p.x;
510 case 1 : return (ushort)pfont->FontBBox.p.y;
511 case 2 : return (ushort)pfont->FontBBox.q.x;
512 case 3 : return (ushort)pfont->FontBBox.q.y;
513 }
514 return 0;
515 case FAPI_FONT_FEATURE_BlueValues_count: return pfont->data.BlueValues.count;
516 case FAPI_FONT_FEATURE_BlueValues: return float_to_ushort(pfont->data.BlueValues.values[index]);
517 case FAPI_FONT_FEATURE_OtherBlues_count: return pfont->data.OtherBlues.count;
518 case FAPI_FONT_FEATURE_OtherBlues: return float_to_ushort(pfont->data.OtherBlues.values[index]);
519 case FAPI_FONT_FEATURE_FamilyBlues_count: return pfont->data.FamilyBlues.count;
520 case FAPI_FONT_FEATURE_FamilyBlues: return float_to_ushort(pfont->data.FamilyBlues.values[index]);
521 case FAPI_FONT_FEATURE_FamilyOtherBlues_count: return pfont->data.FamilyOtherBlues.count;
522 case FAPI_FONT_FEATURE_FamilyOtherBlues: return float_to_ushort(pfont->data.FamilyOtherBlues.values[index]);
523 case FAPI_FONT_FEATURE_BlueShift: return float_to_ushort(pfont->data.BlueShift);
524 case FAPI_FONT_FEATURE_BlueFuzz: return float_to_ushort(pfont->data.BlueShift);
525 case FAPI_FONT_FEATURE_StdHW: return (pfont->data.StdHW.count == 0 ? 0 : float_to_ushort(pfont->data.StdHW.values[0])); /* UFST bug ? */
526 case FAPI_FONT_FEATURE_StdVW: return (pfont->data.StdVW.count == 0 ? 0 : float_to_ushort(pfont->data.StdVW.values[0])); /* UFST bug ? */
527 case FAPI_FONT_FEATURE_StemSnapH_count: return pfont->data.StemSnapH.count;
528 case FAPI_FONT_FEATURE_StemSnapH: return float_to_ushort(pfont->data.StemSnapH.values[index]);
529 case FAPI_FONT_FEATURE_StemSnapV_count: return pfont->data.StemSnapV.count;
530 case FAPI_FONT_FEATURE_StemSnapV: return float_to_ushort(pfont->data.StemSnapV.values[index]);
531 case FAPI_FONT_FEATURE_ForceBold: return pfont->data.ForceBold;
532 case FAPI_FONT_FEATURE_LanguageGroup: return pfont->data.LanguageGroup;
533 case FAPI_FONT_FEATURE_lenIV: return (ff->need_decrypt ? 0 : pfont->data.lenIV);
534 case FAPI_FONT_FEATURE_GlobalSubrs_count:
535 { ref *Private, *GlobalSubrs;
536 if (pfont->FontType == ft_encrypted2) {
537 if (dict_find_string(pdr, "Private", &Private) <= 0)
538 return 0;
539 if (dict_find_string(Private, "GlobalSubrs", &GlobalSubrs) <= 0)
540 return 0;;
541 return r_size(GlobalSubrs);
542 }
543 /* Since we don't have an error return capability, use as unlikely a value as possible */
544 return(65535);
545 }
546 case FAPI_FONT_FEATURE_Subrs_count:
547 { ref *Private, *Subrs;
548 if (dict_find_string(pdr, "Private", &Private) <= 0)
549 return 0;
550 if (dict_find_string(Private, "Subrs", &Subrs) <= 0)
551 return 0;
552 return r_size(Subrs);
553 }
554 case FAPI_FONT_FEATURE_CharStrings_count:
555 { ref *CharStrings;
556 if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0)
557 return 0;
558 return dict_length(CharStrings);
559 }
560 /* Multiple Master specific */
561 case FAPI_FONT_FEATURE_DollarBlend:
562 { ref *DBlend;
563 if (dict_find_string(pdr, "$Blend", &DBlend) <= 0)
564 return 0;
565 return 1;
566 }
567 case FAPI_FONT_FEATURE_BlendAxisTypes_count:
568 { ref *Info, *Axes;
569 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
570 return 0;
571 if (dict_find_string(Info, "BlendAxisTypes", &Axes) <= 0)
572 return 0;
573 return r_size(Axes);
574 }
575 case FAPI_FONT_FEATURE_BlendFontInfo_count:
576 { ref *Info, *FontInfo;
577 if (dict_find_string(pdr, "Blend", &Info) <= 0)
578 return 0;
579 if (dict_find_string(Info, "FontInfo", &FontInfo) <= 0)
580 return 0;
581 return dict_length(FontInfo);
582 }
583 case FAPI_FONT_FEATURE_BlendPrivate_count:
584 { ref *Info, *Private;
585 if (dict_find_string(pdr, "Blend", &Info) <= 0)
586 return 0;
587 if (dict_find_string(Info, "Private", &Private) <= 0)
588 return 0;
589 return dict_length(Private);
590 }
591 case FAPI_FONT_FEATURE_WeightVector_count:
592 { ref *Array;
593 if (dict_find_string(pdr, "WeightVector", &Array) <= 0)
594 return 0;
595 return r_size(Array);
596 }
597 case FAPI_FONT_FEATURE_BlendDesignPositionsArrays_count:
598 { ref *Info, *Array;
599 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
600 return 0;
601 if (dict_find_string(Info, "BlendDesignPositions", &Array) <= 0)
602 return 0;
603 return r_size(Array);
604 }
605 case FAPI_FONT_FEATURE_BlendDesignMapArrays_count:
606 { ref *Info, *Array;
607 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
608 return 0;
609 if (dict_find_string(Info, "BlendDesignMap", &Array) <= 0)
610 return 0;
611 return r_size(Array);
612 }
613 case FAPI_FONT_FEATURE_BlendDesignMapSubArrays_count:
614 { ref *Info, *Array, SubArray;
615 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
616 return 0;
617 if (dict_find_string(Info, "BlendDesignMap", &Array) <= 0)
618 return 0;
619 if (array_get(ff->memory, Array, index, &SubArray) < 0)
620 return 0;
621 return r_size(&SubArray);
622 }
623 case FAPI_FONT_FEATURE_DollarBlend_length:
624 { ref *DBlend, Element, string;
625 int i, length = 0;
626 char Buffer[32];
627 if (dict_find_string(pdr, "$Blend", &DBlend) <= 0)
628 return 0;
629 for (i = 0;i < r_size(DBlend);i++) {
630 if (array_get(ff->memory, DBlend, i, &Element) < 0)
631 return 0;
632 switch (r_btype(&Element)) {
633 case t_name:
634 name_string_ref(ff->memory, &Element, &string);
635 length += r_size(&string) + 1;
636 break;
637 case t_real:
638 sprintf(Buffer, "%f", Element.value.realval);
639 length += strlen(Buffer) + 1;
640 break;
641 case t_integer:
642 sprintf(Buffer, "%d", Element.value.intval);
643 length += strlen(Buffer) + 1;
644 break;
645 case t_operator:
646 { op_def const *op;
647
648 op = op_index_def(r_size(&Element));
649 length += strlen(op->oname + 1) + 1;
650 }
651 break;
652 default:
653 break;
654 }
655 }
656 return length;
657 }
658 /* End MM specifics */
659 }
660 return 0;
661 }
662
FAPI_FF_get_long(FAPI_font * ff,fapi_font_feature var_id,int index)663 static ulong FAPI_FF_get_long(FAPI_font *ff, fapi_font_feature var_id, int index)
664 { gs_font_type1 *pfont = (gs_font_type1 *)ff->client_font_data;
665 ref *pdr = (ref *)ff->client_font_data2;
666
667 switch((int)var_id) {
668 case FAPI_FONT_FEATURE_UniqueID: return pfont->UID.id;
669 case FAPI_FONT_FEATURE_BlueScale: return (ulong)(pfont->data.BlueScale * 65536);
670 case FAPI_FONT_FEATURE_Subrs_total_size :
671 { ref *Private, *Subrs, v;
672 int lenIV = max(pfont->data.lenIV, 0), k;
673 ulong size = 0;
674 long i;
675 const char *name[2] = {"Subrs", "GlobalSubrs"};
676 if (dict_find_string(pdr, "Private", &Private) <= 0)
677 return 0;
678 for (k = 0; k < 2; k++) {
679 if (dict_find_string(Private, name[k], &Subrs) > 0)
680 for (i = r_size(Subrs) - 1; i >= 0; i--) {
681 array_get(pfont->memory, Subrs, i, &v);
682 size += r_size(&v) - (ff->need_decrypt ? 0 : lenIV);
683 }
684 }
685 return size;
686 }
687 case FAPI_FONT_FEATURE_TT_size:
688 return true_type_size(pdr);
689 }
690 return 0;
691 }
692
FAPI_FF_get_float(FAPI_font * ff,fapi_font_feature var_id,int index)693 static float FAPI_FF_get_float(FAPI_font *ff, fapi_font_feature var_id, int index)
694 { gs_font_base *pbfont = (gs_font_base *)ff->client_font_data;
695 ref *pdr = (ref *)ff->client_font_data2;
696 FAPI_server *I = pbfont->FAPI;
697
698 switch((int)var_id) {
699 case FAPI_FONT_FEATURE_FontMatrix:
700 {
701 double FontMatrix_div;
702 gs_matrix m, *mptr;
703
704 if (I && I->get_fontmatrix) {
705 FontMatrix_div = 1;
706 mptr = &m;
707 I->get_fontmatrix (I, mptr);
708 }
709 else {
710 FontMatrix_div = (ff->is_cid && !IsCIDFont(pbfont) ? 1000 : 1);
711 mptr = &(pbfont->base->FontMatrix);
712 }
713 switch(index) {
714 case 0 : return mptr->xx / FontMatrix_div;
715 case 1 : return mptr->xy / FontMatrix_div;
716 case 2 : return mptr->yx / FontMatrix_div;
717 case 3 : return mptr->yy / FontMatrix_div;
718 case 4 : return mptr->tx / FontMatrix_div;
719 case 5 : return mptr->ty / FontMatrix_div;
720 }
721 }
722
723 case FAPI_FONT_FEATURE_WeightVector:
724 { ref *Array, value;
725
726 if (dict_find_string(pdr, "WeightVector", &Array) <= 0)
727 return 0;
728 if (array_get(ff->memory, Array, index, &value) < 0)
729 return 0;
730 if (!r_has_type(&value, t_integer)) {
731 if (r_has_type(&value, t_real)) {
732 return value.value.realval;
733 } else
734 return 0;
735 }
736 else
737 return (float)value.value.intval;
738 }
739 case FAPI_FONT_FEATURE_BlendDesignPositionsArrayValue:
740 { ref *Info, *Array, SubArray, value;
741 int array_index = index / 8;
742 index %= 8;
743 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
744 return 0;
745 if (dict_find_string(Info, "BlendDesignPositions", &Array) <= 0)
746 return 0;
747 if (array_get(ff->memory, Array, array_index, &SubArray) < 0)
748 return 0;
749 if (array_get(ff->memory, &SubArray, index, &value) < 0)
750 return 0;
751 if (!r_has_type(&value, t_integer)) {
752 if (r_has_type(&value, t_real)) {
753 return value.value.realval;
754 } else
755 return 0;
756 }
757 else
758 return (float)value.value.intval;
759 }
760 case FAPI_FONT_FEATURE_BlendDesignMapArrayValue:
761 { ref *Info, *Array, SubArray, SubSubArray, value;
762 int array_index = index / 64;
763 index %= 8;
764 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
765 return 0;
766 if (dict_find_string(Info, "BlendDesignMap", &Array) <= 0)
767 return 0;
768 if (array_get(ff->memory, Array, array_index, &SubArray) < 0)
769 return 0;
770 if (array_get(ff->memory, &SubArray, index, &SubSubArray) < 0)
771 return 0;
772 if (array_get(ff->memory, &SubSubArray, index, &value) < 0)
773 return 0;
774 if (!r_has_type(&value, t_integer)) {
775 if (r_has_type(&value, t_real)) {
776 return value.value.realval;
777 } else
778 return 0;
779 }
780 else
781 return (float)value.value.intval;
782 }
783 }
784 return 0;
785 }
786
FAPI_FF_get_name(FAPI_font * ff,fapi_font_feature var_id,int index,char * Buffer,int len)787 static int FAPI_FF_get_name(FAPI_font *ff, fapi_font_feature var_id, int index, char *Buffer, int len)
788 {
789 ref name, string, *pdr = (ref *)ff->client_font_data2;
790
791 switch((int)var_id) {
792 case FAPI_FONT_FEATURE_BlendAxisTypes:
793 { ref *Info, *Axes;
794 if (dict_find_string(pdr, "FontInfo", &Info) <= 0)
795 return 0;
796 if (dict_find_string(Info, "BlendAxisTypes", &Axes) <= 0)
797 return 0;
798 if(!r_has_type(Axes, t_array))
799 return 0;
800 if (array_get(ff->memory, Axes, index, &name) < 0)
801 return 0;
802 }
803 }
804 name_string_ref(ff->memory, &name, &string);
805 if(r_size(&string) >= len)
806 return 0;
807 memcpy(Buffer, string.value.const_bytes, r_size(&string));
808 Buffer[r_size(&string)] = 0x00;
809 return 1;
810 }
811
FAPI_FF_get_proc(FAPI_font * ff,fapi_font_feature var_id,int index,char * Buffer)812 static int FAPI_FF_get_proc(FAPI_font *ff, fapi_font_feature var_id, int index, char *Buffer)
813 {
814 ref *pdr = (ref *)ff->client_font_data2;
815 char *ptr = Buffer;
816
817 if (!Buffer)
818 return 0;
819
820 switch((int)var_id) {
821 case FAPI_FONT_FEATURE_DollarBlend:
822 { ref *DBlend, Element, string;
823 int i;
824 char Buf[32];
825 if (dict_find_string(pdr, "$Blend", &DBlend) <= 0)
826 return 0;
827 for (i = 0;i < r_size(DBlend);i++) {
828 *ptr++ = 0x20;
829 if (array_get(ff->memory, DBlend, i, &Element) < 0)
830 return 0;
831 switch (r_btype(&Element)) {
832 case t_name:
833 name_string_ref(ff->memory, &Element, &string);
834
835 strncpy(ptr, (char *)string.value.const_bytes, r_size(&string));
836 ptr += r_size(&string);
837 break;
838 case t_real:
839 sprintf(Buf, "%f", Element.value.realval);
840 strcpy(ptr, Buf);
841 ptr += strlen(Buf);
842 break;
843 case t_integer:
844 sprintf(Buf, "%d", Element.value.intval);
845 strcpy(ptr, Buf);
846 ptr += strlen(Buf);
847 break;
848 case t_operator:
849 { op_def const *op;
850
851 op = op_index_def(r_size(&Element));
852 strcpy(ptr, op->oname + 1);
853 ptr += strlen(op->oname + 1);
854 }
855 break;
856 default:
857 break;
858 }
859 }
860 }
861 }
862 return ptr - Buffer;
863 }
decode_bytes(byte * p,const byte * s,int l,int lenIV)864 static inline void decode_bytes(byte *p, const byte *s, int l, int lenIV)
865 { ushort state = 4330;
866
867 for (; l; s++, l--) {
868 uchar c = (*s ^ (state >> 8));
869 state = (*s + state) * crypt_c1 + crypt_c2;
870 if (lenIV > 0)
871 lenIV--;
872 else {
873 *p = c;
874 p++;
875 }
876 }
877 }
878
get_type1_data(FAPI_font * ff,const ref * type1string,byte * buf,ushort buf_length)879 static ushort get_type1_data(FAPI_font *ff, const ref *type1string,
880 byte *buf, ushort buf_length)
881 { gs_font_type1 *pfont = (gs_font_type1 *)ff->client_font_data;
882 int lenIV = max(pfont->data.lenIV, 0);
883 int length = r_size(type1string) - (ff->need_decrypt ? lenIV : 0);
884
885 if (buf != 0) {
886 int l = min(length, buf_length); /*safety */
887 if (ff->need_decrypt && pfont->data.lenIV >= 0)
888 decode_bytes(buf, type1string->value.const_bytes, l + lenIV, lenIV);
889 else
890 memcpy(buf, type1string->value.const_bytes, l);
891 }
892 return length;
893 }
894
FAPI_FF_get_gsubr(FAPI_font * ff,int index,byte * buf,ushort buf_length)895 static ushort FAPI_FF_get_gsubr(FAPI_font *ff, int index, byte *buf, ushort buf_length)
896 { ref *pdr = (ref *)ff->client_font_data2;
897 ref *Private, *GlobalSubrs, subr;
898
899 if (dict_find_string(pdr, "Private", &Private) <= 0)
900 return 0;
901 if (dict_find_string(Private, "GlobalSubrs", &GlobalSubrs) <= 0)
902 return 0;
903 if (array_get(ff->memory,
904 GlobalSubrs, index, &subr) < 0 || r_type(&subr) != t_string)
905 return 0;
906 return get_type1_data(ff, &subr, buf, buf_length);
907 }
908
FAPI_FF_get_subr(FAPI_font * ff,int index,byte * buf,ushort buf_length)909 static ushort FAPI_FF_get_subr(FAPI_font *ff, int index, byte *buf, ushort buf_length)
910 { ref *pdr = (ref *)ff->client_font_data2;
911 ref *Private, *Subrs, subr;
912
913 if (dict_find_string(pdr, "Private", &Private) <= 0)
914 return 0;
915 if (dict_find_string(Private, "Subrs", &Subrs) <= 0)
916 return 0;
917 if (array_get(ff->memory, Subrs, index, &subr) < 0 || r_type(&subr) != t_string)
918 return 0;
919 return get_type1_data(ff, &subr, buf, buf_length);
920 }
921
FAPI_FF_get_raw_subr(FAPI_font * ff,int index,byte * buf,ushort buf_length)922 static ushort FAPI_FF_get_raw_subr(FAPI_font *ff, int index, byte *buf, ushort buf_length)
923 { ref *pdr = (ref *)ff->client_font_data2;
924 ref *Private, *Subrs, subr;
925
926 if (dict_find_string(pdr, "Private", &Private) <= 0)
927 return 0;
928 if (dict_find_string(Private, "Subrs", &Subrs) <= 0)
929 return 0;
930 if (array_get(ff->memory, Subrs, index, &subr) < 0 || r_type(&subr) != t_string)
931 return 0;
932 if (buf && buf_length && buf_length >= r_size(&subr)) {
933 memcpy(buf, subr.value.const_bytes, r_size(&subr));
934 }
935 return r_size(&subr);
936 }
937
FAPI_FF_get_charstring_name(FAPI_font * ff,int index,byte * buf,ushort buf_length)938 static ushort FAPI_FF_get_charstring_name(FAPI_font *ff, int index, byte *buf, ushort buf_length)
939 {
940 ref *pdr = (ref *)ff->client_font_data2;
941 ref *CharStrings, eltp[2], string;
942
943 if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0)
944 return 0;
945 if (dict_index_entry(CharStrings, index, eltp) < 0)
946 return 0;
947 name_string_ref(ff->memory, &eltp[0], &string);
948 if(r_size(&string) > buf_length)
949 return r_size(&string);
950 memcpy(buf, string.value.const_bytes, r_size(&string));
951 buf[r_size(&string)] = 0x00;
952 return r_size(&string);
953 }
954
FAPI_FF_get_charstring(FAPI_font * ff,int index,byte * buf,ushort buf_length)955 static ushort FAPI_FF_get_charstring(FAPI_font *ff, int index, byte *buf, ushort buf_length)
956 {
957 ref *pdr = (ref *)ff->client_font_data2;
958 ref *CharStrings, eltp[2];
959
960 if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0)
961 return 0;
962 if (dict_index_entry(CharStrings, index, eltp) < 0)
963 return 0;
964 if (buf && buf_length && buf_length >= r_size(&eltp[1])) {
965 memcpy(buf, eltp[1].value.const_bytes, r_size(&eltp[1]));
966 }
967 return r_size(&eltp[1]);
968 }
969
sfnt_get_glyph_offset(ref * pdr,gs_font_type42 * pfont42,int index,ulong * offset0)970 static bool sfnt_get_glyph_offset(ref *pdr, gs_font_type42 *pfont42, int index, ulong *offset0)
971 { /* Note : TTC is not supported and probably is unuseful for Type 42. */
972 sfnts_reader r;
973 int glyf_elem_size = (pfont42->data.indexToLocFormat) ? 4 : 2;
974
975 sfnts_reader_init(&r, pdr);
976 r.seek(&r, pfont42->data.loca + index * glyf_elem_size);
977 *offset0 = pfont42->data.glyf + (glyf_elem_size == 2 ? r.rword(&r) * 2 : r.rlong(&r));
978 return r.error;
979 }
980
get_GlyphDirectory_data_ptr(const gs_memory_t * mem,ref * pdr,int char_code,const byte ** ptr)981 static int get_GlyphDirectory_data_ptr(const gs_memory_t *mem,
982 ref *pdr, int char_code, const byte **ptr)
983 {
984 ref *GlyphDirectory, glyph0, *glyph = &glyph0, glyph_index;
985 if (dict_find_string(pdr, "GlyphDirectory", &GlyphDirectory) > 0) {
986 if (((r_type(GlyphDirectory) == t_dictionary &&
987 (make_int(&glyph_index, char_code),
988 dict_find(GlyphDirectory, &glyph_index, &glyph) > 0)) ||
989 (r_type(GlyphDirectory) == t_array &&
990 array_get(mem, GlyphDirectory, char_code, &glyph0) >= 0)
991 )
992 && r_type(glyph) == t_string) {
993 *ptr = glyph->value.const_bytes;
994 return r_size(glyph);
995 } else
996 /* We have a GlyphDirectory, but couldn't find the glyph. If we
997 * return -1 then we will attempt to use glyf and loca which
998 * will fail. Instead return 0, so we execute an 'empty' glyph.
999 */
1000 return 0;
1001 }
1002 return -1;
1003 }
1004
get_MetricsCount(FAPI_font * ff)1005 static bool get_MetricsCount(FAPI_font *ff)
1006 { if (!ff->is_type1 && ff->is_cid) {
1007 gs_font_cid2 *pfcid = (gs_font_cid2 *)ff->client_font_data;
1008
1009 return pfcid->cidata.MetricsCount;
1010 }
1011 return 0;
1012 }
1013
get_charstring(FAPI_font * ff,int char_code,ref ** proc)1014 static int get_charstring(FAPI_font *ff, int char_code, ref **proc)
1015 {
1016 ref *CharStrings, char_name;
1017 ref *pdr = (ref *)ff->client_font_data2;
1018
1019 if (ff->is_type1) {
1020 if (ff->is_cid)
1021 return -1;
1022 if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0)
1023 return -1;
1024
1025 if (ff->char_data != NULL) {
1026 /*
1027 * Can't use char_code in this case because hooked Type 1 fonts
1028 * with 'glyphshow' may render a character which has no
1029 * Encoding entry.
1030 */
1031 if (name_ref(ff->memory, ff->char_data,
1032 ff->char_data_len, &char_name, -1) < 0)
1033 return -1;
1034 } else { /* seac */
1035 i_ctx_t *i_ctx_p = (i_ctx_t *)ff->client_ctx_p;
1036 ref *StandardEncoding;
1037
1038 if (dict_find_string(systemdict, "StandardEncoding", &StandardEncoding) <= 0 ||
1039 array_get(ff->memory, StandardEncoding, char_code, &char_name) < 0)
1040 if (name_ref(ff->memory, (const byte *)".notdef", 7, &char_name, -1) < 0)
1041 return -1;
1042 }
1043 if (dict_find(CharStrings, &char_name, (ref **)proc) <= 0)
1044 return -1;
1045 }
1046 return 0;
1047 }
1048
FAPI_FF_get_glyph(FAPI_font * ff,int char_code,byte * buf,ushort buf_length)1049 static int FAPI_FF_get_glyph(FAPI_font *ff, int char_code, byte *buf, ushort buf_length)
1050 { /*
1051 * We assume that renderer requests glyph data with multiple
1052 * consecutive calls to this function.
1053 *
1054 * For a simple glyph it calls this function exactly twice: first
1055 * with buf == NULL for requesting the necessary buffer length, and
1056 * second with buf != NULL for requesting the data (the second call
1057 * may be skipped if the renderer discontinues the rendering).
1058 *
1059 * For a composite glyph it calls this function 2 * (N + 1)
1060 * times: 2 calls for the main glyph (same as above) followed with
1061 * 2 * N calls for subglyphs, where N is less or equal to the number
1062 * of subglyphs (N may be less if the renderer caches glyph data,
1063 * or discontinues rendering on an exception).
1064 */
1065 ref *pdr = (ref *)ff->client_font_data2;
1066 ushort glyph_length;
1067 i_ctx_t *i_ctx_p = (i_ctx_t *)ff->client_ctx_p;
1068
1069 if (ff->is_type1) {
1070 if (ff->is_cid) {
1071 const ref *glyph = ff->char_data;
1072
1073 glyph_length = get_type1_data(ff, glyph, buf, buf_length);
1074 } else {
1075 ref *CharStrings, char_name, *glyph;
1076 if (ff->char_data != NULL) {
1077 /*
1078 * Can't use char_code in this case because hooked Type 1 fonts
1079 * with 'glyphshow' may render a character which has no
1080 * Encoding entry.
1081 */
1082 if (name_ref(ff->memory, ff->char_data,
1083 ff->char_data_len, &char_name, -1) < 0)
1084 return -1;
1085 if (buf != NULL) {
1086 /*
1087 * Trigger the next call to the 'seac' case below.
1088 * Here we use the assumption about call sequence
1089 * being documented above.
1090 */
1091 ff->char_data = NULL;
1092 }
1093 } else { /* seac */
1094 ref *StandardEncoding;
1095
1096 if (dict_find_string(systemdict, "StandardEncoding", &StandardEncoding) <= 0 ||
1097 array_get(ff->memory, StandardEncoding, char_code, &char_name) < 0)
1098 if (name_ref(ff->memory, (const byte *)".notdef", 7, &char_name, -1) < 0)
1099 return -1;
1100 }
1101 if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0)
1102 return -1;
1103
1104 if (dict_find(CharStrings, &char_name, &glyph) <= 0) {
1105 if (name_ref(ff->memory, (const byte *)".notdef", 7, &char_name, -1) < 0) {
1106 return -1;
1107 }
1108 if (dict_find(CharStrings, &char_name, &glyph) <= 0) {
1109 return -1;
1110 }
1111 }
1112 if (r_has_type(glyph, t_array) || r_has_type(glyph, t_mixedarray))
1113 return -1;
1114 glyph_length = get_type1_data(ff, glyph, buf, buf_length);
1115 }
1116 } else { /* type 42 */
1117 const byte *data_ptr;
1118 int l = get_GlyphDirectory_data_ptr(ff->memory, pdr, char_code, &data_ptr);
1119
1120 /* We should only render the TT notdef if we've been told to - logic lifted from zchar42.c */
1121 if (!i_ctx_p->RenderTTNotdef && ((ff->char_data_len == 7 && strncmp((const char *)ff->char_data, ".notdef", 7) == 0)
1122 || (ff->char_data_len > 9 && strncmp((const char *)ff->char_data, ".notdef~GS", 10) == 0))) {
1123 glyph_length = 0;
1124 }
1125 else {
1126 if (l >= 0) {
1127 int MetricsCount = get_MetricsCount(ff), mc = MetricsCount << 1;
1128
1129 glyph_length = max((ushort)(l - mc), 0); /* safety */
1130 if (buf != 0 && glyph_length > 0)
1131 memcpy(buf, data_ptr + mc, min(glyph_length, buf_length)/* safety */);
1132 } else {
1133 gs_font_type42 *pfont42 = (gs_font_type42 *)ff->client_font_data;
1134 ulong offset0, length_read;
1135 bool error = sfnt_get_glyph_offset(pdr, pfont42, char_code, &offset0);
1136
1137 glyph_length = (error ? -1 : pfont42->data.len_glyphs[char_code]);
1138
1139 if (buf != 0 && !error) {
1140 sfnts_reader r;
1141 sfnts_reader_init(&r, pdr);
1142
1143 r.seek(&r, offset0);
1144 length_read = r.rstring(&r, buf, min(glyph_length, buf_length)/* safety */);
1145 if (r.error == 1) {
1146 glyph_length = -1;
1147 }
1148 /* r.error == 2 means a rangecheck, and probably means that the
1149 * font is broken, and the final glyph length is longer than the data available for it.
1150 * In which case we need to return the number of bytes read.
1151 */
1152 if (r.error == 2) {
1153 glyph_length = length_read;
1154 }
1155 }
1156 }
1157 }
1158 }
1159 return glyph_length;
1160 }
1161
1162 /* If we're rendering an uncached glyph, we need to know
1163 * whether we're filling it with a pattern, and whether
1164 * transparency is involved - if so, we have to produce
1165 * a path outline, and not a bitmap.
1166 */
using_transparency_pattern(gs_state * pgs)1167 static bool using_transparency_pattern (gs_state *pgs)
1168 {
1169 gx_device *dev = gs_currentdevice_inline(pgs);
1170
1171 return((!gs_color_writes_pure(pgs)) && dev->procs.begin_transparency_group != NULL && dev->procs.end_transparency_group != NULL);
1172 }
1173
produce_outline_char(i_ctx_t * i_ctx_p,gs_show_enum * penum_s,gs_font_base * pbfont,int abits,gs_log2_scale_point * log2_scale)1174 static bool produce_outline_char (i_ctx_t *i_ctx_p, gs_show_enum *penum_s, gs_font_base *pbfont, int abits, gs_log2_scale_point *log2_scale)
1175 {
1176 gs_state *pgs = (gs_state *)penum_s->pis;
1177
1178 log2_scale->x = 0;
1179 log2_scale->y = 0;
1180
1181 /* Checking both gx_compute_text_oversampling() result, and abits (below) may seem redundant,
1182 * and hopefully it will be soon, but for now, gx_compute_text_oversampling() could opt to
1183 * "oversample" sufficiently small glyphs (fwiw, I don't think gx_compute_text_oversampling is
1184 * working as intended in that respect), regardless of the device's anti-alias setting.
1185 * This was an old, partial solution for dropouts in small glyphs.
1186 */
1187 gx_compute_text_oversampling(penum_s, (gs_font *)pbfont, abits, log2_scale);
1188
1189 return (pgs->in_charpath || pbfont->PaintType != 0 ||
1190 (pgs->in_cachedevice != CACHE_DEVICE_CACHING && using_transparency_pattern ((gs_state *)penum_s->pis)) ||
1191 (pgs->in_cachedevice != CACHE_DEVICE_CACHING && (log2_scale->x > 0 || log2_scale->y > 0)) ||
1192 (pgs->in_cachedevice != CACHE_DEVICE_CACHING && abits > 1));
1193 }
1194
1195 static const FAPI_font ff_stub = {
1196 0, /* server_font_data */
1197 0, /* need_decrypt */
1198 NULL, /* const gs_memory_t */
1199 0, /* font_file_path */
1200 0, /* subfont */
1201 false, /* is_type1 */
1202 false, /* is_cid */
1203 false, /* is_outline_font */
1204 false, /* is_mtx_skipped */
1205 false, /* is_vertical */
1206 0, /* client_ctx_p */
1207 0, /* client_font_data */
1208 0, /* client_font_data2 */
1209 0, /* char_data */
1210 0, /* char_data_len */
1211 FAPI_FF_get_word,
1212 FAPI_FF_get_long,
1213 FAPI_FF_get_float,
1214 FAPI_FF_get_name,
1215 FAPI_FF_get_proc,
1216 FAPI_FF_get_gsubr,
1217 FAPI_FF_get_subr,
1218 FAPI_FF_get_raw_subr,
1219 FAPI_FF_get_glyph,
1220 FAPI_FF_serialize_tt_font,
1221 FAPI_FF_get_charstring,
1222 FAPI_FF_get_charstring_name
1223 };
1224
FAPI_get_xlatmap(i_ctx_t * i_ctx_p,char ** xlatmap)1225 static int FAPI_get_xlatmap(i_ctx_t *i_ctx_p, char **xlatmap)
1226 { ref *pref;
1227 int code;
1228
1229 if ((code = dict_find_string(systemdict, ".xlatmap", &pref)) < 0)
1230 return code;
1231 if (r_type(pref) != t_string)
1232 return_error(e_typecheck);
1233 *xlatmap = (char *)pref->value.bytes;
1234 /* Note : this supposes that xlatmap doesn't move in virtual memory.
1235 Garbager must not be called while plugin executes get_scaled_font, get_decodingID.
1236 Fix some day with making copy of xlatmap in system memory.
1237 */
1238 return 0;
1239 }
1240
renderer_retcode(i_ctx_t * i_ctx_p,FAPI_server * I,FAPI_retcode rc)1241 static int renderer_retcode(i_ctx_t *i_ctx_p, FAPI_server *I, FAPI_retcode rc)
1242 { if (rc == 0)
1243 return 0;
1244 emprintf2(imemory,
1245 "Error: Font Renderer Plugin ( %s ) return code = %d\n",
1246 I->ig.d->subtype,
1247 rc);
1248 return rc < 0 ? rc : e_invalidfont;
1249 }
1250
zFAPIavailable(i_ctx_t * i_ctx_p)1251 static int zFAPIavailable(i_ctx_t *i_ctx_p)
1252 { i_plugin_holder *h = i_plugin_get_list(i_ctx_p);
1253 bool available = true;
1254 os_ptr op = osp;
1255
1256 for (; h != 0; h = h->next)
1257 if (!strcmp(h->I->d->type,"FAPI"))
1258 goto found;
1259 available = false;
1260 found :
1261 push(1);
1262 make_bool(op, available);
1263 return 0;
1264 }
1265
get_server_param(i_ctx_t * i_ctx_p,const char * subtype,const byte ** server_param,int * server_param_size)1266 static void get_server_param(i_ctx_t *i_ctx_p, const char *subtype, const byte **server_param, int *server_param_size)
1267 { ref *FAPIconfig, *options, *server_options;
1268
1269 if (dict_find_string(systemdict, ".FAPIconfig", &FAPIconfig) >= 0 && r_has_type(FAPIconfig, t_dictionary)) {
1270 if (dict_find_string(FAPIconfig, "ServerOptions", &options) >= 0 && r_has_type(options, t_dictionary)) {
1271 if (dict_find_string(options, subtype, &server_options) >= 0 && r_has_type(server_options, t_string)) {
1272 *server_param = server_options->value.const_bytes;
1273 *server_param_size = r_size(server_options);
1274 }
1275 }
1276 }
1277 }
1278
FAPI_find_plugin(i_ctx_t * i_ctx_p,const char * subtype,FAPI_server ** pI)1279 static int FAPI_find_plugin(i_ctx_t *i_ctx_p, const char *subtype, FAPI_server **pI)
1280 { i_plugin_holder *h = i_plugin_get_list(i_ctx_p);
1281 int code;
1282
1283 for (; h != 0; h = h->next)
1284 if (!strcmp(h->I->d->type,"FAPI"))
1285 if (!strcmp(h->I->d->subtype, subtype)) {
1286 FAPI_server *I = *pI = (FAPI_server *)h->I;
1287 const byte *server_param = NULL;
1288 int server_param_size = 0;
1289
1290 get_server_param(i_ctx_p, subtype, &server_param, &server_param_size);
1291 if ((code = renderer_retcode(i_ctx_p, I, I->ensure_open(I, server_param, server_param_size))) < 0)
1292 return code;
1293 return 0;
1294 }
1295 return_error(e_invalidfont);
1296 }
1297
release_typeface(FAPI_server * I,void ** server_font_data)1298 static inline void release_typeface(FAPI_server *I, void **server_font_data)
1299 {
1300 I->release_typeface(I, *server_font_data);
1301 I->face.font_id = gs_no_id;
1302 if (I->ff.server_font_data == *server_font_data)
1303 I->ff.server_font_data = 0;
1304 *server_font_data = 0;
1305 }
1306
FAPI_prepare_font(i_ctx_t * i_ctx_p,FAPI_server * I,ref * pdr,gs_font_base * pbfont,const char * font_file_path,const FAPI_font_scale * font_scale,const char * xlatmap,int BBox[4],const char ** decodingID)1307 static int FAPI_prepare_font(i_ctx_t *i_ctx_p, FAPI_server *I, ref *pdr, gs_font_base *pbfont,
1308 const char *font_file_path, const FAPI_font_scale *font_scale,
1309 const char *xlatmap, int BBox[4], const char **decodingID)
1310 { /* Returns 1 iff BBox is set. */
1311 /* Cleans up server's font data if failed. */
1312
1313 /* A renderer may need to access the top level font's data of
1314 * a CIDFontType 0 (FontType 9) font while preparing its subfonts,
1315 * and/or perform a completion action with the top level font after
1316 * its descendants are prepared. Therefore with such fonts
1317 * we first call get_scaled_font(..., FAPI_TOPLEVEL_BEGIN), then
1318 * get_scaled_font(..., i) with eash descendant font index i,
1319 * and then get_scaled_font(..., FAPI_TOPLEVEL_COMPLETE).
1320 * For other fonts we don't call with 'i'.
1321 *
1322 * Actually server's data for top level CIDFontTYpe 0 non-disk fonts should not be important,
1323 * because with non-disk fonts FAPI_do_char never deals with the top-level font,
1324 * but does with its descendants individually.
1325 * Therefore a recommendation for the renderer is don't build any special
1326 * data for the top-level non-disk font of CIDFontType 0, but return immediately
1327 * with success code and NULL data pointer.
1328 *
1329 * get_scaled_font may be called for same font at second time,
1330 * so the renderen must check whether the data is already built.
1331 */
1332 int code, bbox_set = 0;
1333 ref *SubfontId;
1334 int subfont;
1335
1336 I->ff = ff_stub;
1337 if (dict_find_string(pdr, "SubfontId", &SubfontId) >= 0 && r_has_type(SubfontId, t_integer))
1338 subfont = SubfontId->value.intval;
1339 else
1340 subfont = 0;
1341 I->ff.subfont = subfont;
1342 I->ff.font_file_path = font_file_path;
1343 I->ff.is_type1 = IsType1GlyphData(pbfont);
1344 I->ff.is_vertical = (pbfont->WMode != 0);
1345 I->ff.memory = imemory;
1346 I->ff.client_ctx_p = i_ctx_p;
1347 I->ff.client_font_data = pbfont;
1348 I->ff.client_font_data2 = pdr;
1349 I->ff.server_font_data = pbfont->FAPI_font_data; /* Possibly pass it from zFAPIpassfont. */
1350 I->ff.is_cid = IsCIDFont(pbfont);
1351 I->ff.is_outline_font = pbfont->PaintType != 0;
1352 I->ff.is_mtx_skipped = (get_MetricsCount(&I->ff) != 0);
1353 if ((code = renderer_retcode(i_ctx_p, I, I->get_scaled_font(I, &I->ff,
1354 font_scale, xlatmap, FAPI_TOPLEVEL_BEGIN))) < 0)
1355 return code;
1356 pbfont->FAPI_font_data = I->ff.server_font_data; /* Save it back to GS font. */
1357 if (I->ff.server_font_data != 0) {
1358 if ((code = renderer_retcode(i_ctx_p, I, I->get_font_bbox(I, &I->ff, BBox))) < 0) {
1359 release_typeface(I, &pbfont->FAPI_font_data);
1360 return code;
1361 }
1362 bbox_set = 1;
1363 }
1364 if (xlatmap != NULL && pbfont->FAPI_font_data != NULL)
1365 if ((code = renderer_retcode(i_ctx_p, I, I->get_decodingID(I, &I->ff, decodingID))) < 0) {
1366 release_typeface(I, &pbfont->FAPI_font_data);
1367 return code;
1368 }
1369 /* Prepare descendant fonts : */
1370 if (font_file_path == NULL && I->ff.is_type1 && I->ff.is_cid) { /* Renderers should expect same condition. */
1371 gs_font_cid0 *pfcid = (gs_font_cid0 *)pbfont;
1372 gs_font_type1 **FDArray = pfcid->cidata.FDArray;
1373 int i, n = pfcid->cidata.FDArray_size;
1374 ref *rFDArray, f;
1375
1376 if (dict_find_string(pdr, "FDArray", &rFDArray) <= 0 || r_type(rFDArray) != t_array)
1377 return_error(e_invalidfont);
1378 I->ff = ff_stub;
1379 I->ff.is_type1 = true;
1380 I->ff.is_vertical = false; /* A subfont may be shared with another fonts. */
1381 I->ff.memory = imemory;
1382 I->ff.client_ctx_p = i_ctx_p;
1383 for (i = 0; i < n; i++) {
1384 gs_font_type1 *pbfont1 = FDArray[i];
1385 int BBox_temp[4];
1386
1387 pbfont1->FontBBox = pbfont->FontBBox; /* Inherit FontBBox from the type 9 font. */
1388 if(array_get(imemory, rFDArray, i, &f) < 0 || r_type(&f) != t_dictionary)
1389 return_error(e_invalidfont);
1390
1391 I->ff.client_font_data = pbfont1;
1392 pbfont1->FAPI = pbfont->FAPI;
1393 I->ff.client_font_data2 = &f;
1394 I->ff.server_font_data = pbfont1->FAPI_font_data;
1395 I->ff.is_cid = true;
1396 I->ff.is_outline_font = pbfont1->PaintType != 0;
1397 I->ff.is_mtx_skipped = (get_MetricsCount(&I->ff) != 0);
1398 I->ff.subfont = 0;
1399 if ((code = renderer_retcode(i_ctx_p, I, I->get_scaled_font(I, &I->ff,
1400 font_scale, NULL, i))) < 0)
1401 break;
1402 pbfont1->FAPI_font_data = I->ff.server_font_data; /* Save it back to GS font. */
1403 /* Try to do something with the descendant font to ensure that it's working : */
1404 if ((code = renderer_retcode(i_ctx_p, I, I->get_font_bbox(I, &I->ff, BBox_temp))) < 0)
1405 break;
1406 }
1407 if (i == n) {
1408 code = renderer_retcode(i_ctx_p, I, I->get_scaled_font(I, &I->ff,
1409 font_scale, NULL, FAPI_TOPLEVEL_COMPLETE));
1410 if (code >= 0)
1411 return bbox_set; /* Full success. */
1412 }
1413 /* Fail, release server's font data : */
1414 for (i = 0; i < n; i++) {
1415 gs_font_type1 *pbfont1 = FDArray[i];
1416
1417 if (pbfont1->FAPI_font_data != NULL)
1418 release_typeface(I, &pbfont1->FAPI_font_data);
1419 }
1420 if (pbfont->FAPI_font_data != NULL)
1421 release_typeface(I, &pbfont->FAPI_font_data);
1422 return_error(e_invalidfont);
1423 } else {
1424 code = renderer_retcode(i_ctx_p, I, I->get_scaled_font(I, &I->ff,
1425 font_scale, xlatmap, FAPI_TOPLEVEL_COMPLETE));
1426 if (code < 0) {
1427 release_typeface(I, &pbfont->FAPI_font_data);
1428 return code;
1429 }
1430 return bbox_set;
1431 }
1432 }
1433
FAPI_refine_font(i_ctx_t * i_ctx_p,os_ptr op,gs_font_base * pbfont,const char * font_file_path)1434 static int FAPI_refine_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base *pbfont, const char *font_file_path)
1435 { ref *pdr = op; /* font dict */
1436 double size, size1;
1437 int BBox[4], scale;
1438 const char *decodingID = NULL;
1439 char *xlatmap = NULL;
1440 FAPI_server *I = pbfont->FAPI;
1441 FAPI_font_scale font_scale = {{1, 0, 0, 1, 0, 0}, {0, 0}, {1, 1}, true};
1442 ref *Decoding_old;
1443 int code;
1444
1445 if (font_file_path != NULL && pbfont->FAPI_font_data == NULL)
1446 if ((code = FAPI_get_xlatmap(i_ctx_p, &xlatmap)) < 0)
1447 return code;
1448 scale = 1 << I->frac_shift;
1449 size1 = size = 1 / hypot(pbfont->FontMatrix.xx, pbfont->FontMatrix.xy);
1450 if (size < 1000)
1451 size = 1000;
1452 if (size1 > 100)
1453 size1 = (int)(size1 + 0.5);
1454 font_scale.matrix[0] = font_scale.matrix[3] = (int)(size * scale + 0.5);
1455 font_scale.HWResolution[0] = (FracInt)(72 * scale);
1456 font_scale.HWResolution[1] = (FracInt)(72 * scale);
1457
1458 code = FAPI_prepare_font(i_ctx_p, I, pdr, pbfont, font_file_path, &font_scale, xlatmap, BBox, &decodingID);
1459 if (code < 0)
1460 return code;
1461
1462 if (code > 0) {
1463 /* Refine FontBBox : */
1464 ref *v, mat[4], arr;
1465 int attrs;
1466
1467 pbfont->FontBBox.p.x = (double)BBox[0] * size1 / size;
1468 pbfont->FontBBox.p.y = (double)BBox[1] * size1 / size;
1469 pbfont->FontBBox.q.x = (double)BBox[2] * size1 / size;
1470 pbfont->FontBBox.q.y = (double)BBox[3] * size1 / size;
1471 if (dict_find_string(op, "FontBBox", &v) > 0) {
1472 if(!r_has_type(v, t_array) && !r_has_type(v, t_shortarray) && !r_has_type(v, t_mixedarray))
1473 return_error(e_invalidfont);
1474 make_real(&mat[0], pbfont->FontBBox.p.x);
1475 make_real(&mat[1], pbfont->FontBBox.p.y);
1476 make_real(&mat[2], pbfont->FontBBox.q.x);
1477 make_real(&mat[3], pbfont->FontBBox.q.y);
1478 if(r_has_type(v, t_shortarray) || r_has_type(v, t_mixedarray) || r_size(v) < 4) {
1479 /* Create a new full blown array in case the values are reals */
1480 code = ialloc_ref_array(&arr, a_all, 4, "array");
1481 if (code < 0)
1482 return code;
1483 v = &arr;
1484 code = idict_put_string(op, "FontBBox", &arr);
1485 if (code < 0)
1486 return code;
1487 ref_assign_new(v->value.refs + 0, &mat[0]);
1488 ref_assign_new(v->value.refs + 1, &mat[1]);
1489 ref_assign_new(v->value.refs + 2, &mat[2]);
1490 ref_assign_new(v->value.refs + 3, &mat[3]);
1491 } else {
1492 ref_assign_old(v, v->value.refs + 0, &mat[0], "FAPI_refine_font_BBox");
1493 ref_assign_old(v, v->value.refs + 1, &mat[1], "FAPI_refine_font_BBox");
1494 ref_assign_old(v, v->value.refs + 2, &mat[2], "FAPI_refine_font_BBox");
1495 ref_assign_old(v, v->value.refs + 3, &mat[3], "FAPI_refine_font_BBox");
1496 }
1497 attrs = v->tas.type_attrs;
1498 r_clear_attrs(v, a_all);
1499 r_set_attrs(v, attrs | a_execute);
1500 }
1501 }
1502
1503 /* Assign a Decoding : */
1504 if (decodingID != 0 && *decodingID && dict_find_string(pdr, "Decoding", &Decoding_old) <= 0) {
1505 ref Decoding;
1506
1507 if (IsCIDFont(pbfont)) {
1508 ref *CIDSystemInfo, *Ordering, SubstNWP;
1509 byte buf[30];
1510 int ordering_length, decodingID_length = min(strlen(decodingID), sizeof(buf) - 2);
1511
1512 if (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) <= 0 || !r_has_type(CIDSystemInfo, t_dictionary))
1513 return_error(e_invalidfont);
1514 if (dict_find_string(CIDSystemInfo, "Ordering", &Ordering) <= 0 || !r_has_type(Ordering, t_string))
1515 return_error(e_invalidfont);
1516 ordering_length = min(r_size(Ordering), sizeof(buf) - 2 - decodingID_length);
1517 memcpy(buf, Ordering->value.const_bytes, ordering_length);
1518 if ((code = name_ref(imemory, buf, ordering_length, &SubstNWP, 0)) < 0)
1519 return code;
1520 if ((code = dict_put_string(pdr, "SubstNWP", &SubstNWP, NULL)) < 0)
1521 return code;
1522 buf[ordering_length] = '.';
1523 memcpy(buf + ordering_length + 1, decodingID, decodingID_length);
1524 buf[decodingID_length + 1 + ordering_length] = 0; /* Debug purpose only */
1525 if ((code = name_ref(imemory, buf,
1526 decodingID_length + 1 + ordering_length, &Decoding, 0)) < 0)
1527 return code;
1528 } else
1529 if ((code = name_ref(imemory, (const byte *)decodingID,
1530 strlen(decodingID), &Decoding, 0)) < 0)
1531 return code;
1532 if ((code = dict_put_string(pdr, "Decoding", &Decoding, NULL)) < 0)
1533 return code;
1534 }
1535 return 0;
1536 }
1537
notify_remove_font(void * proc_data,void * event_data)1538 static int notify_remove_font(void *proc_data, void *event_data)
1539 { /* gs_font_finalize passes event_data == NULL, so check it here. */
1540 if (event_data == NULL) {
1541 gs_font_base *pbfont = proc_data;
1542 FAPI_server *I = pbfont->FAPI;
1543
1544 if (pbfont->FAPI_font_data != 0) {
1545 release_typeface(I, &pbfont->FAPI_font_data);
1546 }
1547 }
1548 return 0;
1549 }
1550
1551 /* <string|name> <font> <is_disk_font> .rebuildfontFAPI <string|name> <font> */
1552 /* Rebuild a font for handling it with an external renderer.
1553
1554 The font was built as a native GS font to allow easy access
1555 to font features. Then zFAPIrebuildfont sets FAPI entry
1556 into gx_font_base and replaces BuildGlyph and BuildChar
1557 to enforce the FAPI handling.
1558
1559 This operator must not be called with devices which embed fonts.
1560
1561 */
zFAPIrebuildfont(i_ctx_t * i_ctx_p)1562 static int zFAPIrebuildfont(i_ctx_t *i_ctx_p)
1563 { os_ptr op = osp;
1564 build_proc_refs build;
1565 gs_font *pfont;
1566 int code = font_param(op - 1, &pfont), code1;
1567 gs_font_base *pbfont = (gs_font_base *)pfont;
1568 ref *v;
1569 char *font_file_path = NULL, FAPI_ID[20];
1570 const byte *pchars;
1571 uint len;
1572 font_data *pdata;
1573 FAPI_server *I;
1574 bool has_buildglyph;
1575 bool has_buildchar;
1576
1577 if (code < 0)
1578 return code;
1579
1580 check_type(*op, t_boolean);
1581 if (pbfont->FAPI != 0) {
1582 /* If the font was processed with zFAPIpassfont,
1583 it already has an attached FAPI and server_font_data.
1584 Don't change them here.
1585 */
1586 } else {
1587 if (dict_find_string(op - 1, "FAPI", &v) <= 0 || !r_has_type(v, t_name))
1588 return_error(e_invalidfont);
1589 obj_string_data(imemory, v, &pchars, &len);
1590 len = min(len, sizeof(FAPI_ID) - 1);
1591 strncpy(FAPI_ID, (const char *)pchars, len);
1592 FAPI_ID[len] = 0;
1593 if ((code = FAPI_find_plugin(i_ctx_p, FAPI_ID, &pbfont->FAPI)) < 0)
1594 return code;
1595 }
1596 pdata = (font_data *)pfont->client_data;
1597 I = pbfont->FAPI;
1598
1599 if (r_type(&(pdata->BuildGlyph)) != t_null) {
1600 has_buildglyph = true;
1601 } else {
1602 has_buildglyph = false;
1603 }
1604
1605 if (r_type(&(pdata->BuildChar)) != t_null) {
1606 has_buildchar = true;
1607 } else {
1608 has_buildchar = false;
1609 }
1610
1611 /* This shouldn't happen, but just in case */
1612 if (has_buildglyph == false && has_buildchar == false) {
1613 has_buildglyph = true;
1614 }
1615
1616 if (dict_find_string(op - 1, "Path", &v) <= 0 || !r_has_type(v, t_string))
1617 v = NULL;
1618 if (pfont->FontType == ft_CID_encrypted && v == NULL) {
1619 if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildGlyph9", ".FAPIBuildGlyph9")) < 0)
1620 return code;
1621 } else
1622 if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildChar", ".FAPIBuildGlyph")) < 0)
1623 return code;
1624 if ((r_type(&(pdata->BuildChar)) != t_null && pdata->BuildChar.value.pname && build.BuildChar.value.pname &&
1625 name_index(imemory, &pdata->BuildChar) == name_index(imemory, &build.BuildChar))
1626 || (r_type(&(pdata->BuildGlyph)) != t_null && pdata->BuildGlyph.value.pname && build.BuildGlyph.value.pname &&
1627 name_index(imemory, &pdata->BuildGlyph) == name_index(imemory, &build.BuildGlyph))) {
1628 /* Already rebuilt - maybe a substituted font. */
1629 } else {
1630
1631 if (has_buildchar == true) {
1632 ref_assign_new(&pdata->BuildChar, &build.BuildChar);
1633 } else {
1634 make_null(&pdata->BuildChar);
1635 }
1636
1637 if (has_buildglyph == true) {
1638 ref_assign_new(&pdata->BuildGlyph, &build.BuildGlyph);
1639 } else {
1640 make_null(&pdata->BuildGlyph);
1641 }
1642 if (v != NULL)
1643 font_file_path = ref_to_string(v, imemory_global, "font file path");
1644 code = FAPI_refine_font(i_ctx_p, op - 1, pbfont, font_file_path);
1645 memcpy(&I->initial_FontMatrix, &pbfont->FontMatrix, sizeof(gs_matrix));
1646 if (font_file_path != NULL)
1647 gs_free_string(imemory_global, (byte *)font_file_path, r_size(v) + 1, "font file path");
1648 code1 = gs_notify_register(&pfont->notify_list, notify_remove_font, pbfont);
1649 (void)code1; /* Recover possible error just ignoring it. */
1650 }
1651 pop(1);
1652 return code;
1653 }
1654
array_find(const gs_memory_t * mem,ref * Encoding,ref * char_name)1655 static ulong array_find(const gs_memory_t *mem, ref *Encoding, ref *char_name) {
1656 ulong n = r_size(Encoding), i;
1657 ref v;
1658 for (i = 0; i < n; i++)
1659 if (array_get(mem, Encoding, i, &v) < 0)
1660 break;
1661 else if(r_type(char_name) == r_type(&v) && char_name->value.const_pname == v.value.const_pname)
1662 return i;
1663 return 0;
1664 }
1665
outline_char(i_ctx_t * i_ctx_p,FAPI_server * I,int import_shift_v,gs_show_enum * penum_s,struct gx_path_s * path,bool close_path)1666 static int outline_char(i_ctx_t *i_ctx_p, FAPI_server *I, int import_shift_v, gs_show_enum *penum_s, struct gx_path_s *path, bool close_path)
1667 { FAPI_path path_interface = path_interface_stub;
1668 FAPI_outline_handler olh;
1669 int code;
1670 gs_state *pgs;
1671 extern_st(st_gs_show_enum);
1672 extern_st(st_gs_state);
1673
1674 if (gs_object_type(penum_s->memory, penum_s) == &st_gs_show_enum) {
1675 pgs = penum_s->pgs;
1676 } else {
1677 if (gs_object_type(penum_s->memory, penum_s->pis) == &st_gs_state) {
1678 pgs = (gs_state *)penum_s->pis;
1679 } else
1680 /* No graphics state, give up... */
1681 return_error(e_undefined);
1682 }
1683 olh.path = path;
1684 olh.x0 = pgs->ctm.tx_fixed;
1685 olh.y0 = pgs->ctm.ty_fixed;
1686 olh.close_path = close_path;
1687 olh.need_close = false;
1688 path_interface.olh = &olh;
1689 path_interface.shift = import_shift_v;
1690 if ((code = renderer_retcode(i_ctx_p, I, I->get_char_outline(I, &path_interface))) < 0 || path_interface.gs_error != 0) {
1691 if (path_interface.gs_error != 0)
1692 return path_interface.gs_error;
1693 else
1694 return code;
1695 }
1696 if (olh.need_close && olh.close_path)
1697 if ((code = add_closepath(&path_interface)) < 0)
1698 return code;
1699 return 0;
1700 }
1701
compute_em_scale(const gs_font_base * pbfont,FAPI_metrics * metrics,double FontMatrix_div,double * em_scale_x,double * em_scale_y)1702 static void compute_em_scale(const gs_font_base *pbfont, FAPI_metrics *metrics, double FontMatrix_div, double *em_scale_x, double *em_scale_y)
1703 { /* optimize : move this stuff to FAPI_refine_font */
1704 gs_matrix mat;
1705 gs_matrix *m = &pbfont->base->orig_FontMatrix;
1706 int rounding_x, rounding_y; /* Striking out the 'float' representation error in FontMatrix. */
1707 double sx, sy;
1708 FAPI_server *I = pbfont->FAPI;
1709
1710 m = &mat;
1711 #if 1
1712 I->get_fontmatrix(I, m);
1713 #else
1714 /* Temporary: replace with a FAPI call to check *if* the library needs a replacement matrix */
1715 memset(m, 0x00, sizeof(gs_matrix));
1716 m->xx = m->yy = 1.0;
1717 #endif
1718
1719 if (m->xx == 0 && m->xy == 0 && m->yx == 0 && m->yy == 0)
1720 m = &pbfont->base->FontMatrix;
1721 sx = hypot(m->xx, m->xy) * metrics->em_x / FontMatrix_div;
1722 sy = hypot(m->yx, m->yy) * metrics->em_y / FontMatrix_div;
1723 rounding_x = (int)(0x00800000 / sx);
1724 rounding_y = (int)(0x00800000 / sy);
1725 *em_scale_x = (int)(sx * rounding_x + 0.5) / (double)rounding_x;
1726 *em_scale_y = (int)(sy * rounding_y + 0.5) / (double)rounding_y;
1727 }
1728
fapi_copy_mono(gx_device * dev1,FAPI_raster * rast,int dx,int dy)1729 static int fapi_copy_mono(gx_device *dev1, FAPI_raster *rast, int dx, int dy)
1730 { if ((rast->line_step & (align_bitmap_mod - 1)) == 0)
1731 return dev_proc(dev1, copy_mono)(dev1, rast->p, 0, rast->line_step, 0, dx, dy, rast->width, rast->height, 0, 1);
1732 else { /* bitmap data needs to be aligned, make the aligned copy : */
1733 int line_step = bitmap_raster(rast->width), code;
1734 byte *p = gs_alloc_byte_array(dev1->memory, rast->height, line_step, "fapi_copy_mono");
1735 byte *q = p, *r = rast->p, *pe;
1736 if (p == NULL)
1737 return_error(e_VMerror);
1738 pe = p + rast->height * line_step;
1739 for (; q < pe; q+=line_step, r += rast->line_step)
1740 memcpy(q, r, rast->line_step);
1741 code = dev_proc(dev1, copy_mono)(dev1, p, 0, line_step, 0, dx, dy, rast->width, rast->height, 0, 1);
1742 gs_free_object(dev1->memory, p, "fapi_copy_mono");
1743 return code;
1744 }
1745 }
1746
1747 static const int frac_pixel_shift = 4;
1748
1749 /* NOTE: fapi_image_uncached_glyph() doesn't check various paramters: it assumes fapi_finish_render_aux()
1750 * has done so: if it gets called from another function, the function must either do all the parameter
1751 * validation, or fapi_image_uncached_glyph() must be changed to include the validation.
1752 */
fapi_image_uncached_glyph(i_ctx_t * i_ctx_p,gs_show_enum * penum,FAPI_raster * rast,const int import_shift_v)1753 static int fapi_image_uncached_glyph (i_ctx_t *i_ctx_p, gs_show_enum *penum, FAPI_raster *rast, const int import_shift_v)
1754 {
1755 gx_device *dev = penum->dev;
1756 gs_state *pgs = (gs_state *)penum->pis;
1757 int code;
1758 const gx_clip_path * pcpath = i_ctx_p->pgs->clip_path;
1759 const gx_drawing_color * pdcolor = penum->pdcolor;
1760 int rast_orig_x = rast->orig_x;
1761 int rast_orig_y = - rast->orig_y;
1762 extern_st(st_gs_show_enum);
1763
1764 byte *r = rast->p;
1765 byte *src, *dst;
1766 int h, padbytes, cpbytes, dstr = bitmap_raster(rast->width);
1767 int sstr = rast->line_step;
1768
1769 /* we can only safely use the gx_image_fill_masked() "shortcut" if we're drawing
1770 * a "simple" colour, rather than a pattern.
1771 */
1772 if (gs_color_writes_pure(pgs)) {
1773 if (dstr != sstr) {
1774
1775 /* If the stride of the bitmap we've got doesn't match what the rest
1776 * of the Ghostscript world expects, make one that does.
1777 * Ghostscript aligns bitmap raster memory in a platform specific
1778 * manner, so see gxbitmap.h for details.
1779 *
1780 * Ideally the padding bytes wouldn't matter, but currently the
1781 * clist code ends up compressing it using bitmap compression. To
1782 * ensure consistency across runs (and to get the best possible
1783 * compression ratios) we therefore set such bytes to zero. It would
1784 * be nicer if this was fixed in future.
1785 */
1786 r = gs_alloc_bytes(penum->memory, dstr * rast->height, "fapi_finish_render_aux");
1787 if (!r) {
1788 return_error(e_VMerror);
1789 }
1790
1791 cpbytes = sstr < dstr ? sstr: dstr;
1792 padbytes = dstr-cpbytes;
1793 h = rast->height;
1794 src = rast->p;
1795 dst = r;
1796 if (padbytes > 0)
1797 {
1798 while (h-- > 0) {
1799 memcpy(dst, src, cpbytes);
1800 memset(dst+cpbytes, 0, padbytes);
1801 src += sstr;
1802 dst += dstr;
1803 }
1804 }
1805 else
1806 {
1807 while (h-- > 0) {
1808 memcpy(dst, src, cpbytes);
1809 src += sstr;
1810 dst += dstr;
1811 }
1812 }
1813 }
1814
1815 if (gs_object_type(penum->memory, penum) == &st_gs_show_enum) {
1816 code = gx_image_fill_masked(dev, r, 0, dstr, 0,
1817 (int)(pgs->ctm.tx + (double)rast_orig_x / (1 << frac_pixel_shift) + penum->fapi_glyph_shift.x + 0.5),
1818 (int)(pgs->ctm.ty + (double)rast_orig_y / (1 << frac_pixel_shift) + penum->fapi_glyph_shift.y + 0.5),
1819 rast->width, rast->height,
1820 pdcolor, 1, rop3_default, pcpath);
1821 } else {
1822 code = gx_image_fill_masked(dev, r, 0, dstr, 0,
1823 (int)(pgs->ctm.tx + (double)rast_orig_x / (1 << frac_pixel_shift) + 0.5),
1824 (int)(pgs->ctm.ty + (double)rast_orig_y / (1 << frac_pixel_shift) + 0.5),
1825 rast->width, rast->height,
1826 pdcolor, 1, rop3_default, pcpath);
1827 }
1828 if (rast->p != r) {
1829 gs_free_object(penum->memory, r, "fapi_finish_render_aux");
1830 }
1831 }
1832 else {
1833 gs_memory_t *mem = penum->memory->non_gc_memory;
1834 gs_image_enum *pie = gs_image_enum_alloc(mem, "image_char(image_enum)");
1835 gs_image_t image;
1836 int iy, nbytes;
1837 uint used;
1838 int code1;
1839 int x, y, w, h;
1840
1841 if (!pie) {
1842 return_error(e_VMerror);
1843 }
1844
1845 x = (int) (pgs->ctm.tx + (double)rast_orig_x / (1 << frac_pixel_shift) + 0.5);
1846 y = (int) (pgs->ctm.ty + (double)rast_orig_y / (1 << frac_pixel_shift) + 0.5);
1847 w = rast->width;
1848 h = rast->height;
1849
1850 /* Make a matrix that will place the image */
1851 /* at (x,y) with no transformation. */
1852 gs_image_t_init_mask(&image, true);
1853 gs_make_translation((floatp) -x, (floatp) -y, &image.ImageMatrix);
1854 gs_matrix_multiply(&ctm_only(pgs), &image.ImageMatrix, &image.ImageMatrix);
1855 image.Width = w;
1856 image.Height = h;
1857 image.adjust = false;
1858 code = gs_image_init(pie, &image, false, pgs);
1859 nbytes = (rast->width + 7) >> 3;
1860
1861 switch (code) {
1862 case 1: /* empty image */
1863 code = 0;
1864 default:
1865 break;
1866 case 0:
1867 for (iy = 0; iy < h && code >= 0; iy++, r += sstr)
1868 code = gs_image_next(pie, r, nbytes, &used);
1869 }
1870 code1 = gs_image_cleanup_and_free_enum(pie, pgs);
1871 if (code >= 0 && code1 < 0)
1872 code = code1;
1873 }
1874 return(code);
1875 }
1876
fapi_finish_render_aux(i_ctx_t * i_ctx_p,gs_font_base * pbfont,FAPI_server * I)1877 static int fapi_finish_render_aux(i_ctx_t *i_ctx_p, gs_font_base *pbfont, FAPI_server *I)
1878 { gs_text_enum_t *penum = op_show_find(i_ctx_p);
1879 gs_show_enum *penum_s = (gs_show_enum *)penum;
1880 gs_state *pgs;
1881 gx_device *dev1;
1882 const int import_shift_v = _fixed_shift - 32; /* we always 32.32 values for the outline interface now */
1883 FAPI_raster rast = {0};
1884 int code;
1885 extern_st(st_gs_show_enum);
1886 extern_st(st_gs_state);
1887
1888 if(penum == NULL) {
1889 return_error(e_undefined);
1890 }
1891
1892 /* Ensure that pis points to a st_gs_gstate (graphics state) structure */
1893 if (gs_object_type(penum->memory, penum->pis) != &st_gs_state) {
1894 /* If pis is not a graphics state, see if the text enumerator is a
1895 * show enumerator, in which case we have a pointer to the graphics state there
1896 */
1897 if (gs_object_type(penum->memory, penum) == &st_gs_show_enum) {
1898 pgs = penum_s->pgs;
1899 } else
1900 /* No graphics state, give up... */
1901 return_error(e_undefined);
1902 } else
1903 pgs = (gs_state *)penum->pis;
1904
1905 dev1 = gs_currentdevice_inline(pgs); /* Possibly changed by zchar_set_cache. */
1906
1907 /* Even for "non-marking" text operations (for example, stringwidth) we are expected
1908 * to have a glyph bitmap for the cache, if we're using the cache. For the
1909 * non-cacheing, non-marking cases, we must not draw the glyph.
1910 */
1911 if (igs->in_charpath && !SHOW_IS(penum, TEXT_DO_NONE)) {
1912 if ((code = outline_char(i_ctx_p, I, import_shift_v, penum_s, pgs->path, !pbfont->PaintType)) < 0)
1913 return code;
1914
1915 if ((code = gx_path_add_char_path(pgs->show_gstate->path, pgs->path, pgs->in_charpath)) < 0)
1916 return code;
1917
1918 } else {
1919 int code;
1920
1921 code = I->get_char_raster(I, &rast);
1922 if (!SHOW_IS(penum, TEXT_DO_NONE) && I->use_outline) {
1923 /* The server provides an outline instead the raster. */
1924 gs_imager_state *pis = (gs_imager_state *)pgs->show_gstate;
1925 gs_point pt;
1926
1927 if ((code = gs_currentpoint(pgs, &pt)) < 0)
1928 return code;
1929 if ((code = outline_char(i_ctx_p, I, import_shift_v, penum_s, pgs->path, !pbfont->PaintType)) < 0)
1930 return code;
1931 if ((code = gs_imager_setflat((gs_imager_state *)pgs, gs_char_flatness(pis, 1.0))) < 0)
1932 return code;
1933 if (pbfont->PaintType) {
1934 float lw = gs_currentlinewidth(pgs);
1935
1936 gs_setlinewidth(pgs, pbfont->StrokeWidth);
1937 code = gs_stroke(pgs);
1938 gs_setlinewidth(pgs, lw);
1939 if (code < 0)
1940 return code;
1941 } else {
1942 gs_in_cache_device_t in_cachedevice = pgs->in_cachedevice;
1943 pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;
1944
1945 pgs->fill_adjust.x = pgs->fill_adjust.y = 0;
1946
1947 if ((code = gs_fill(pgs)) < 0)
1948 return code;
1949
1950 pgs->in_cachedevice = in_cachedevice;
1951 }
1952 if ((code = gs_moveto(pgs, pt.x, pt.y)) < 0)
1953 return code;
1954 } else {
1955 int rast_orig_x = rast.orig_x;
1956 int rast_orig_y = - rast.orig_y;
1957
1958 if (pgs->in_cachedevice == CACHE_DEVICE_CACHING) { /* Using GS cache */
1959 /* GS and renderer may transform coordinates few differently.
1960 The best way is to make set_cache_device to take the renderer's bitmap metrics immediately,
1961 but we need to account CDevProc, which may truncate the bitmap.
1962 Perhaps GS overestimates the bitmap size,
1963 so now we only add a compensating shift - the dx and dy.
1964 */
1965 if (rast.width != 0) {
1966 int shift_rd = _fixed_shift - frac_pixel_shift;
1967 int rounding = 1 << (frac_pixel_shift - 1);
1968 int dx = arith_rshift_slow((pgs->ctm.tx_fixed >> shift_rd) + rast_orig_x + rounding, frac_pixel_shift);
1969 int dy = arith_rshift_slow((pgs->ctm.ty_fixed >> shift_rd) + rast_orig_y + rounding, frac_pixel_shift);
1970
1971 if (dx + rast.left_indent < 0 || dx + rast.left_indent + rast.black_width > dev1->width) {
1972 #ifdef DEBUG
1973 if (gs_debug_c('m')) {
1974 emprintf2(dev1->memory,
1975 "Warning : Cropping a FAPI glyph while caching : dx=%d,%d.\n",
1976 dx + rast.left_indent,
1977 dx + rast.left_indent + rast.black_width - dev1->width);
1978 }
1979 #endif
1980 if (dx + rast.left_indent < 0)
1981 dx -= dx + rast.left_indent;
1982 }
1983 if (dy + rast.top_indent < 0 || dy + rast.top_indent + rast.black_height > dev1->height) {
1984 #ifdef DEBUG
1985 if (gs_debug_c('m')) {
1986 emprintf2(dev1->memory,
1987 "Warning : Cropping a FAPI glyph while caching : dx=%d,%d.\n",
1988 dy + rast.top_indent,
1989 dy + rast.top_indent + rast.black_height - dev1->height);
1990 }
1991 #endif
1992 if (dy + rast.top_indent < 0)
1993 dy -= dy + rast.top_indent;
1994 }
1995 if ((code = fapi_copy_mono(dev1, &rast, dx, dy)) < 0)
1996 return code;
1997
1998 if (gs_object_type(penum->memory, penum) == &st_gs_show_enum) {
1999 penum_s->cc->offset.x += float2fixed(penum_s->fapi_glyph_shift.x);
2000 penum_s->cc->offset.y += float2fixed(penum_s->fapi_glyph_shift.y);
2001 }
2002 }
2003 } else if (!SHOW_IS(penum, TEXT_DO_NONE)) { /* Not using GS cache */
2004 if ((code = fapi_image_uncached_glyph(i_ctx_p, penum_s, &rast, import_shift_v)) < 0)
2005 return code;
2006 }
2007 }
2008 }
2009 pop(2);
2010 return 0;
2011 }
2012
fapi_finish_render(i_ctx_t * i_ctx_p)2013 static int fapi_finish_render(i_ctx_t *i_ctx_p)
2014 { os_ptr op = osp;
2015 gs_font *pfont;
2016 int code = font_param(op - 1, &pfont);
2017
2018 if (code == 0) {
2019 gs_font_base *pbfont = (gs_font_base *) pfont;
2020 FAPI_server *I = pbfont->FAPI;
2021 code = fapi_finish_render_aux(i_ctx_p, pbfont, I);
2022 I->release_char_data(I);
2023 }
2024 return code;
2025 }
2026
2027 static const byte *
find_substring(const byte * where,int length,const char * what)2028 find_substring(const byte *where, int length, const char *what)
2029 {
2030 int l = strlen(what);
2031 int n = length - l;
2032 const byte *p = where;
2033
2034 for (; n >= 0; n--, p++)
2035 if (!memcmp(p, what, l))
2036 return p;
2037 return NULL;
2038 }
2039
2040 #define GET_U16_MSB(p) (((uint)((p)[0]) << 8) + (p)[1])
2041 #define GET_S16_MSB(p) (int)((GET_U16_MSB(p) ^ 0x8000) - 0x8000)
2042
2043 #define MTX_EQ(mtx1,mtx2) (mtx1->xx == mtx2->xx && mtx1->xy == mtx2->xy && \
2044 mtx1->yx == mtx2->yx && mtx1->yy == mtx2->yy && \
2045 mtx1->tx == mtx2->tx && mtx1->ty == mtx2->ty)
2046
FAPI_do_char(i_ctx_t * i_ctx_p,gs_font_base * pbfont,gx_device * dev,char * font_file_path,bool bBuildGlyph,ref * charstring)2047 static int FAPI_do_char(i_ctx_t *i_ctx_p, gs_font_base *pbfont, gx_device *dev, char *font_file_path, bool bBuildGlyph, ref *charstring)
2048 { /* Stack : <font> <code|name> --> - */
2049 os_ptr op = osp;
2050 ref *pdr = op - 1;
2051 gs_text_enum_t *penum = op_show_find(i_ctx_p);
2052 gs_show_enum *penum_s = (gs_show_enum *)penum;
2053 /*
2054 fixme: the following code needs to optimize with a maintainence of scaled font objects
2055 in graphics library and in interpreter. Now we suppose that the renderer
2056 uses font cache, so redundant font opening isn't a big expense.
2057 */
2058 FAPI_char_ref cr = {0, 0, {0}, 0, false, NULL, 0, 0, 0, 0, 0, FAPI_METRICS_NOTDEF};
2059 const gs_matrix * ctm = &ctm_only(igs);
2060 int scale;
2061 FAPI_metrics metrics;
2062 FAPI_server *I = pbfont->FAPI;
2063 int client_char_code = 0;
2064 ref char_name, enc_char_name, *SubfontId;
2065 bool is_TT_from_type42 = (pbfont->FontType == ft_TrueType && font_file_path == NULL);
2066 bool is_embedded_type1 = ((pbfont->FontType == ft_encrypted ||
2067 pbfont->FontType == ft_encrypted2) &&
2068 font_file_path == NULL);
2069 bool bCID = (IsCIDFont(pbfont) || charstring != NULL);
2070 bool bIsType1GlyphData = IsType1GlyphData(pbfont);
2071 gs_log2_scale_point log2_scale = {0, 0};
2072 int alpha_bits = (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
2073 double FontMatrix_div = 1;
2074 bool bVertical = (gs_rootfont(igs)->WMode != 0), bVertical0 = bVertical;
2075 double *sbwp, sbw[4] = {0, 0, 0, 0};
2076 double em_scale_x, em_scale_y;
2077 gs_rect char_bbox;
2078 op_proc_t exec_cont = 0;
2079 int code;
2080 bool align_to_pixels = gs_currentaligntopixels(pbfont->dir);
2081 enum {
2082 SBW_DONE,
2083 SBW_SCALE,
2084 SBW_FROM_RENDERER
2085 } sbw_state = SBW_SCALE;
2086
2087 I->use_outline = false;
2088 memset(&char_bbox, 0x00, sizeof(char_bbox));
2089
2090 I->ff = ff_stub;
2091 if(bBuildGlyph && !bCID) {
2092 if (r_type(op) != t_name) {
2093 name_enter_string (imemory, ".notdef", op);
2094 }
2095 check_type(*op, t_name);
2096 } else {
2097
2098 if (bBuildGlyph && pbfont->FontType == ft_CID_TrueType && r_has_type(op, t_name)) {
2099 ref *chstrs, *chs;
2100 /* This logic is lifted from %Type11BuildGlyph in gs_cidfn.ps
2101 * Note we only have to deal with mistakenly being given a name object
2102 * here, the out of range CID is handled later
2103 */
2104 if ((dict_find_string(op - 1, "CharStrings", &chstrs)) <= 0) {
2105 return_error(e_undefined);
2106 }
2107
2108 if ((dict_find_string(chstrs, ".notdef", &chs)) <= 0) {
2109 return_error(e_undefined);
2110 }
2111 ref_assign_inline(op, chs);
2112 }
2113
2114 check_type(*op, t_integer);
2115 }
2116
2117 if (penum == 0)
2118 return_error(e_undefined);
2119
2120 I->use_outline = produce_outline_char(i_ctx_p, penum_s, pbfont, alpha_bits, &log2_scale);
2121 if (I->use_outline) {
2122 I->max_bitmap = 0;
2123 }
2124 else {
2125 /* FIX ME: It can be a very bad thing, right now, for the FAPI code to decide unilaterally to
2126 * produce an outline, when the rest of GS expects a bitmap, so we give ourselves a
2127 * 50% leeway on the maximum cache bitmap, just to be sure. Or the same maximum bitmap size
2128 * used in gxchar.c
2129 */
2130 I->max_bitmap = pbfont->dir->ccache.upper + (pbfont->dir->ccache.upper >> 1) < MAX_TEMP_BITMAP_BITS ?
2131 pbfont->dir->ccache.upper + (pbfont->dir->ccache.upper >> 1) : MAX_TEMP_BITMAP_BITS;
2132 }
2133
2134 /* Compute the scale : */
2135 if (!SHOW_IS(penum, TEXT_DO_NONE) && !I->use_outline) {
2136 gs_currentcharmatrix(igs, NULL, 1); /* make char_tm valid */
2137 penum_s->fapi_log2_scale = log2_scale;
2138 }
2139 else {
2140 log2_scale.x = 0;
2141 log2_scale.y = 0;
2142 }
2143
2144 /* Prepare font data
2145 * This needs done here (earlier than it used to be) because FAPI/UFST has conflicting
2146 * requirements in what I->get_fontmatrix() returns based on font type, so it needs to
2147 * find the font type.
2148 */
2149 if (dict_find_string(pdr, "SubfontId", &SubfontId) > 0 && r_has_type(SubfontId, t_integer))
2150 I->ff.subfont = SubfontId->value.intval;
2151 else
2152 I->ff.subfont = 0;
2153 I->ff.memory = pbfont->memory;
2154 I->ff.font_file_path = font_file_path;
2155 I->ff.client_font_data = pbfont;
2156 I->ff.client_font_data2 = pdr;
2157 I->ff.server_font_data = pbfont->FAPI_font_data;
2158 I->ff.is_type1 = bIsType1GlyphData;
2159 I->ff.is_cid = bCID;
2160 I->ff.is_outline_font = pbfont->PaintType != 0;
2161 I->ff.is_mtx_skipped = (get_MetricsCount(&I->ff) != 0);
2162 I->ff.is_vertical = bVertical;
2163 I->ff.client_ctx_p = i_ctx_p;
2164
2165 scale = 1 << I->frac_shift;
2166 retry_oversampling:
2167 if (I->face.font_id != pbfont->id ||
2168 !MTX_EQ((&I->face.ctm),ctm) ||
2169 I->face.log2_scale.x != log2_scale.x ||
2170 I->face.log2_scale.y != log2_scale.y ||
2171 I->face.align_to_pixels != align_to_pixels ||
2172 I->face.HWResolution[0] != dev->HWResolution[0] ||
2173 I->face.HWResolution[1] != dev->HWResolution[1]
2174 ) {
2175 FAPI_font_scale font_scale = {{1, 0, 0, 1, 0, 0}, {0, 0}, {1, 1}, true};
2176 gs_matrix scale_mat, scale_ctm;
2177
2178 I->face.font_id = pbfont->id;
2179 I->face.ctm = *ctm;
2180 I->face.log2_scale = log2_scale;
2181 I->face.align_to_pixels = align_to_pixels;
2182 I->face.HWResolution[0] = dev->HWResolution[0];
2183 I->face.HWResolution[1] = dev->HWResolution[1];
2184
2185 font_scale.subpixels[0] = 1 << log2_scale.x;
2186 font_scale.subpixels[1] = 1 << log2_scale.y;
2187 font_scale.align_to_pixels = align_to_pixels;
2188
2189 #if 1
2190 /* We apply the entire transform to the glyph (that is ctm x FontMatrix)
2191 * at render time.
2192 */
2193
2194 memset(&scale_ctm, 0x00, sizeof(gs_matrix));
2195 scale_ctm.xx = dev->HWResolution[0]/72;
2196 scale_ctm.yy = dev->HWResolution[1]/72;
2197
2198 code = gs_matrix_invert((const gs_matrix *)&scale_ctm, &scale_ctm);
2199
2200 code = gs_matrix_multiply(ctm, &scale_ctm, &scale_mat); /* scale_mat == CTM - resolution scaling */
2201
2202 code = I->get_fontmatrix(I, &scale_ctm);
2203 code = gs_matrix_invert((const gs_matrix *)&scale_ctm, &scale_ctm);
2204 code = gs_matrix_multiply(&scale_mat, &scale_ctm, &scale_mat); /* scale_mat == CTM - resolution scaling - FontMatrix scaling */
2205
2206 font_scale.matrix[0] = (FracInt)(scale_mat.xx * FontMatrix_div * scale + 0.5);
2207 font_scale.matrix[1] = -(FracInt)(scale_mat.xy * FontMatrix_div * scale + 0.5);
2208 font_scale.matrix[2] = (FracInt)(scale_mat.yx * FontMatrix_div * scale + 0.5);
2209 font_scale.matrix[3] = -(FracInt)(scale_mat.yy * FontMatrix_div * scale + 0.5);
2210 font_scale.matrix[4] = (FracInt)(scale_mat.tx * FontMatrix_div * scale + 0.5);
2211 font_scale.matrix[5] = (FracInt)(scale_mat.ty * FontMatrix_div * scale + 0.5);
2212 #else
2213
2214 # if 1
2215 base_font_matrix = &I->initial_FontMatrix;
2216 # else
2217 base_font_matrix = &pbfont->base->orig_FontMatrix;
2218 # endif
2219 if (base_font_matrix->xx == 0 && base_font_matrix->xy == 0 &&
2220 base_font_matrix->yx == 0 && base_font_matrix->yy == 0)
2221 base_font_matrix = &pbfont->base->FontMatrix;
2222 dx = hypot(base_font_matrix->xx, base_font_matrix->xy);
2223 dy = hypot(base_font_matrix->yx, base_font_matrix->yy);
2224 /* Trick : we need to restore the font scale from ctm, pbfont->FontMatrix,
2225 and base_font_matrix. We assume that base_font_matrix is
2226 a multiple of pbfont->FontMatrix with a constant from scalefont.
2227 But we cannot devide ctm by pbfont->FontMatrix for getting
2228 a proper result: the base_font_matrix may be XY transposition,
2229 but we must not cut out the transposition from ctm.
2230 Therefore we use the norm of base_font_matrix columns as the divisors
2231 for X and Y. It is not clear what to do when base_font_matrix is anisotropic
2232 (i.e. dx != dy), but we did not meet such fonts before now.
2233 */
2234 font_scale.matrix[0] = (FracInt)(ctm->xx * FontMatrix_div / dx * 72 / dev->HWResolution[0] * scale + 0.5);
2235 font_scale.matrix[1] = -(FracInt)(ctm->xy * FontMatrix_div / dy * 72 / dev->HWResolution[0] * scale + 0.5);
2236 font_scale.matrix[2] = (FracInt)(ctm->yx * FontMatrix_div / dx * 72 / dev->HWResolution[1] * scale + 0.5);
2237 font_scale.matrix[3] = -(FracInt)(ctm->yy * FontMatrix_div / dy * 72 / dev->HWResolution[1] * scale + 0.5);
2238 font_scale.matrix[4] = (FracInt)(ctm->tx * FontMatrix_div / dx * 72 / dev->HWResolution[0] * scale + 0.5);
2239 font_scale.matrix[5] = (FracInt)(ctm->ty * FontMatrix_div / dy * 72 / dev->HWResolution[1] * scale + 0.5);
2240 #endif
2241 /* Note: the ctm mapping here is upside down. */
2242 font_scale.HWResolution[0] = (FracInt)((double)dev->HWResolution[0] * font_scale.subpixels[0] * scale);
2243 font_scale.HWResolution[1] = (FracInt)((double)dev->HWResolution[1] * font_scale.subpixels[1] * scale);
2244
2245
2246 if ((hypot ((double)font_scale.matrix[0], (double)font_scale.matrix[2]) == 0.0
2247 || hypot ((double)font_scale.matrix[1], (double)font_scale.matrix[3]) == 0.0)) {
2248 /* If the matrix is degenerate, force a scale to 1 unit. */
2249 if (!font_scale.matrix[0]) font_scale.matrix[0] = 1;
2250 if (!font_scale.matrix[3]) font_scale.matrix[3] = 1;
2251 }
2252
2253 if ((code = renderer_retcode(i_ctx_p, I, I->get_scaled_font(I, &I->ff, &font_scale,
2254 NULL,
2255 (!bCID || (pbfont->FontType != ft_encrypted &&
2256 pbfont->FontType != ft_encrypted2)
2257 ? FAPI_TOPLEVEL_PREPARED : FAPI_DESCENDANT_PREPARED)))) < 0)
2258 return code;
2259 }
2260 else {
2261 }
2262
2263 /* Obtain the character name : */
2264 if (bCID) {
2265 int_param(op, 0xFFFF, &client_char_code);
2266 make_null(&char_name);
2267 } else if (r_has_type(op, t_integer)) {
2268 /* Translate from PS encoding to char name : */
2269 ref *Encoding;
2270 int_param(op, 0xFF, &client_char_code);
2271 if (dict_find_string(pdr, "Encoding", &Encoding) > 0 &&
2272 (r_has_type(Encoding, t_array) ||
2273 r_has_type(Encoding, t_shortarray) || r_has_type(Encoding, t_mixedarray))) {
2274 if (array_get(imemory, Encoding, client_char_code, &char_name) < 0)
2275 if ((code = name_ref(imemory, (const byte *)".notdef", 7, &char_name, -1)) < 0)
2276 return code;
2277 } else
2278 return_error(e_invalidfont);
2279 } else
2280 char_name = *op;
2281
2282 /* We need to store the name as we get it (from the Encoding array), in case it's
2283 * had the name extended (with "~GS~xx"), we'll remove the extension before passing
2284 * it to the renderer for a disk based font. But the metrics dictionary may have
2285 * been constructed using the extended name....
2286 */
2287 ref_assign(&enc_char_name, &char_name);
2288
2289 /* Obtain the character code or glyph index : */
2290 cr.char_codes_count = 1;
2291 if (bCID) {
2292 if (font_file_path != NULL) {
2293 ref *Decoding, *TT_cmap, *SubstNWP;
2294 ref src_type, dst_type;
2295 bool is_glyph_index = true;
2296 uint c;
2297
2298 if (dict_find_string(pdr, "Decoding", &Decoding) <= 0 || !r_has_type(Decoding, t_dictionary))
2299 return_error(e_invalidfont);
2300 if (dict_find_string(pdr, "SubstNWP", &SubstNWP) <= 0 || !r_has_type(SubstNWP, t_array))
2301 return_error(e_invalidfont);
2302 if (dict_find_string(pdr, "TT_cmap", &TT_cmap) <= 0 || !r_has_type(TT_cmap, t_dictionary)) {
2303 ref *DecodingArray, char_code, char_code1, ih;
2304 int i = client_char_code % 256, n;
2305
2306 make_int(&ih, client_char_code / 256);
2307 /* Check the Decoding array for this block of CIDs */
2308 if (dict_find(Decoding, &ih, &DecodingArray) <= 0 ||
2309 !r_has_type(DecodingArray, t_array) ||
2310 array_get(imemory, DecodingArray, i, &char_code) < 0)
2311 return_error(e_invalidfont);
2312
2313 /* Check the Decoding entry */
2314 if (r_has_type(&char_code, t_integer))
2315 n = 1;
2316 else if (r_has_type(&char_code, t_array)) {
2317 DecodingArray = &char_code;
2318 i = 0;
2319 n = r_size(DecodingArray);
2320 } else
2321 return_error(e_invalidfont);
2322
2323 for (;n--; i++) {
2324 if (array_get(imemory, DecodingArray, i, &char_code1) < 0 ||
2325 !r_has_type(&char_code1, t_integer))
2326 return_error(e_invalidfont);
2327
2328 c = char_code1.value.intval;
2329 I->check_cmap_for_GID(I, &c);
2330 if (c != 0)
2331 break;
2332 }
2333 } else {
2334 ref *CIDSystemInfo;
2335 ref *Ordering;
2336
2337 /* We only have to lookup the char code if we're *not* using an identity ordering */
2338 if (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) >= 0 && r_has_type(CIDSystemInfo, t_dictionary) &&
2339 dict_find_string(CIDSystemInfo, "Ordering", &Ordering) >= 0 && r_has_type(Ordering, t_string) &&
2340 strncmp((const char *)Ordering->value.bytes, "Identity", 8) != 0) {
2341
2342 code = cid_to_TT_charcode(imemory, Decoding, TT_cmap, SubstNWP,
2343 client_char_code, &c, &src_type, &dst_type);
2344 if (code < 0)
2345 return code;
2346
2347 /* cid_to_TT_charcode() returns 1 if it found a
2348 * matching character code. Otherwise it returns
2349 * zero after setting c to zero (.notdef glyph id)
2350 * or a negative value on error. */
2351 #if 0
2352 if (code > 0)
2353 is_glyph_index = false;
2354 #endif
2355 }
2356 else {
2357 c = client_char_code;
2358 }
2359 }
2360 cr.char_codes[0] = c;
2361 cr.is_glyph_index = is_glyph_index;
2362 /* fixme : process the narrow/wide/proportional mapping type,
2363 using src_type, dst_type. Should adjust the 'matrix' above.
2364 Call get_font_proportional_feature for proper choice.
2365 */
2366 } else {
2367 ref *CIDMap;
2368 byte *Map;
2369 int ccode = client_char_code;
2370 int gdb = 2;
2371 int i;
2372 ref *GDBytes = NULL;
2373
2374 if ((dict_find_string(pdr, "GDBytes", &GDBytes) > 0) && r_has_type(GDBytes, t_integer)) {
2375 gdb = GDBytes->value.intval;
2376 }
2377
2378 /* The PDF Reference says that we should use a CIDToGIDMap, but the PDF
2379 * interpreter converts this into a CIDMap (see pdf_font.ps, processCIDToGIDMap)
2380 */
2381 if (dict_find_string(pdr, "CIDMap", &CIDMap) > 0 && !r_has_type(CIDMap, t_name) &&
2382 (r_has_type(CIDMap, t_array) || r_has_type(CIDMap, t_string))) {
2383
2384 if (r_has_type(CIDMap, t_array)) {
2385
2386 /* Too big for single string, so its an array of 2 strings */
2387 code = string_array_access_proc(pbfont->memory, CIDMap, 1, client_char_code * gdb, gdb, NULL, NULL, (const byte **)&Map);
2388
2389 } else {
2390 if (CIDMap->tas.rsize < ccode * gdb) {
2391 ccode = 0;
2392 }
2393 Map = &CIDMap->value.bytes[ccode * gdb];
2394 }
2395 cr.char_codes[0] = 0;
2396
2397 for (i = 0; i < gdb; i++) {
2398 cr.char_codes[0] = (cr.char_codes[0] << 8) + Map[i];
2399 }
2400 }
2401 else
2402 cr.char_codes[0] = client_char_code;
2403 }
2404 } else if (is_TT_from_type42) {
2405 /* This font must not use 'cmap', so compute glyph index from CharStrings : */
2406 ref *CharStrings, *glyph_index;
2407 if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0 || !r_has_type(CharStrings, t_dictionary))
2408 return_error(e_invalidfont);
2409 if ((dict_find(CharStrings, &char_name, &glyph_index) < 0) || r_has_type(glyph_index, t_null)) {
2410 #ifdef DEBUG
2411 ref *pvalue;
2412 if (gs_debug_c('1') && (dict_find_string(systemdict,"QUIET", &pvalue)) > 0 &&
2413 (r_has_type(pvalue, t_boolean) && pvalue->value.boolval == false)) {
2414 char *glyphn;
2415
2416 name_string_ref (imemory, &char_name, &char_name);
2417
2418 glyphn = ref_to_string(&char_name, imemory, "FAPI_do_char");
2419 if (glyphn) {
2420 dprintf2(" Substituting .notdef for %s in the font %s \n", glyphn, pbfont->font_name.chars);
2421 gs_free_string(imemory, (byte *)glyphn, strlen(glyphn) + 1, "FAPI_do_char");
2422 }
2423 }
2424 #endif
2425
2426 cr.char_codes[0] = 0; /* .notdef */
2427 if ((code = name_ref(imemory, (const byte *)".notdef", 7, &char_name, -1)) < 0)
2428 return code;
2429 } else if (r_has_type(glyph_index, t_integer))
2430 cr.char_codes[0] = glyph_index->value.intval;
2431 else {
2432 /* Check execution stack has space for BuldChar proc and finish_render */
2433 check_estack(2);
2434 /* check space and duplicate the glyph index for BuildChar */
2435 check_op(1);
2436 push(1);
2437 ref_assign_inline(op, op - 1);
2438 /* Come back to fapi_finish_render after running the BuildChar */
2439 push_op_estack(fapi_finish_render);
2440 ++esp;
2441 ref_assign(esp, glyph_index);
2442 return o_push_estack;
2443 }
2444 cr.is_glyph_index = true;
2445 } else if (is_embedded_type1) {
2446 /* Since the client passes charstring by callback using I->ff.char_data,
2447 the client doesn't need to provide a good cr here.
2448 Perhaps since UFST uses char codes as glyph cache keys (UFST 4.2 cannot use names),
2449 we provide font char codes equal to document's char codes.
2450 This trick assumes that Encoding can't point different glyphs
2451 for same char code. The last should be true due to
2452 PLRM3, "5.9.4 Subsetting and Incremental Definition of Glyphs".
2453 */
2454 if (r_has_type(op, t_integer))
2455 cr.char_codes[0] = client_char_code;
2456 else {
2457 /*
2458 * Reverse Encoding here, because it can be an incremental one.
2459 * Note that this can cause problems with UFST (see the comment above),
2460 * if the encoding doesn't contain the glyph name rendered with glyphshow.
2461 */
2462 ref *Encoding;
2463 if (dict_find_string(osp - 1, "Encoding", &Encoding) > 0)
2464 cr.char_codes[0] = (uint)array_find(imemory, Encoding, op);
2465 else
2466 return_error(e_invalidfont);
2467 }
2468 } else { /* a non-embedded font, i.e. a disk font */
2469 bool can_retrieve_char_by_name = false;
2470 const byte *p;
2471
2472 obj_string_data(imemory, &char_name, &cr.char_name, &cr.char_name_length);
2473 p = find_substring(cr.char_name, cr.char_name_length, gx_extendeg_glyph_name_separator);
2474 if (p != NULL) {
2475 cr.char_name_length = p - cr.char_name;
2476 name_ref(pbfont->memory, cr.char_name, cr.char_name_length, &char_name, true);
2477 }
2478 if ((code = renderer_retcode(i_ctx_p, I, I->can_retrieve_char_by_name(I, &I->ff, &cr, &can_retrieve_char_by_name))) < 0)
2479 return code;
2480 if (!can_retrieve_char_by_name) {
2481 /* Translate from char name to encoding used with 3d party font technology : */
2482 ref *Decoding, *char_code;
2483 if (dict_find_string(osp - 1, "Decoding", &Decoding) > 0 && r_has_type(Decoding, t_dictionary)) {
2484 if (dict_find(Decoding, &char_name, &char_code) > 0) {
2485 code = 0;
2486 if (r_has_type(char_code, t_integer)) {
2487 int_param(char_code, 0xFFFF, &cr.char_codes[0]);
2488 } else if (r_has_type(char_code, t_array) || r_has_type(char_code, t_shortarray)) {
2489 int i;
2490 ref v;
2491
2492 cr.char_codes_count = r_size(char_code);
2493 if (cr.char_codes_count > count_of(cr.char_codes))
2494 code = gs_note_error(e_rangecheck);
2495 if (code >= 0) {
2496 for (i = 0; i < cr.char_codes_count; i++) {
2497 code = array_get(imemory, char_code, i, &v);
2498 if (code < 0)
2499 break;
2500 if (!r_has_type(char_code, t_integer)) {
2501 code = gs_note_error(e_rangecheck);
2502 break;
2503 }
2504 cr.char_codes[i] = v.value.intval;
2505 }
2506 }
2507 } else
2508 code = gs_note_error(e_rangecheck);
2509 if (code < 0) {
2510 char buf[16];
2511 int l = cr.char_name_length;
2512
2513 if (l > sizeof(buf) - 1)
2514 l = sizeof(buf) - 1;
2515 memcpy(buf, cr.char_name, l);
2516 buf[l] = 0;
2517 emprintf1(imemory,
2518 "Wrong decoding entry for the character '%s'.\n",
2519 buf);
2520 return_error(e_rangecheck);
2521 }
2522 }
2523 }
2524 }
2525 }
2526 cr.char_code = cr.char_codes[0];
2527 cr.client_char_code = client_char_code;
2528 #if 0 /* Debug purpose only: search chars in UFST fonts. */
2529 cr.char_code = client_char_code; /* remove for release !!!!!!!!!!!!!!!! */
2530 #endif
2531
2532 /* Provide glyph data for renderer : */
2533 /* Occasionally, char_name is already a glyph index to pass to the rendering engine
2534 * so don't treat it as a name object.
2535 * I believe this will only happen with a TTF/Type42, but checking the object type
2536 * is cheap, and covers all font type eventualities.
2537 */
2538 if (!I->ff.is_cid && r_has_type(&char_name, t_name)) {
2539 ref sname;
2540 name_string_ref(imemory, &char_name, &sname);
2541 I->ff.char_data = sname.value.const_bytes;
2542 I->ff.char_data_len = r_size(&sname);
2543 } else if (I->ff.is_type1)
2544 I->ff.char_data = charstring;
2545
2546 /* Compute the metrics replacement : */
2547
2548 if(bCID && !bIsType1GlyphData) {
2549 gs_font_cid2 *pfcid = (gs_font_cid2 *)pbfont;
2550 int MetricsCount = pfcid->cidata.MetricsCount;
2551
2552 if (MetricsCount > 0) {
2553 const byte *data_ptr;
2554 int l = get_GlyphDirectory_data_ptr(imemory, pdr, cr.char_code, &data_ptr);
2555
2556 if (MetricsCount == 2 && l >= 4) {
2557 if (!bVertical0) {
2558 cr.sb_x = GET_S16_MSB(data_ptr + 2) * scale;
2559 cr.aw_x = GET_U16_MSB(data_ptr + 0) * scale;
2560 cr.metrics_type = FAPI_METRICS_REPLACE;
2561 }
2562 } else if (l >= 8){
2563 cr.sb_y = GET_S16_MSB(data_ptr + 2) * scale;
2564 cr.aw_y = GET_U16_MSB(data_ptr + 0) * scale;
2565 cr.sb_x = GET_S16_MSB(data_ptr + 6) * scale;
2566 cr.aw_x = GET_U16_MSB(data_ptr + 4) * scale;
2567 cr.metrics_type = FAPI_METRICS_REPLACE;
2568 }
2569 }
2570 }
2571 if (cr.metrics_type != FAPI_METRICS_REPLACE && bVertical) {
2572 double pwv[4];
2573 code = zchar_get_metrics2(pbfont, &enc_char_name, pwv);
2574 if (code < 0)
2575 return code;
2576 if (code == metricsNone) {
2577 if (bCID && (!bIsType1GlyphData && font_file_path)) {
2578 cr.sb_x = fapi_round(sbw[2] / 2 * scale);
2579 cr.sb_y = fapi_round(pbfont->FontBBox.q.y * scale);
2580 cr.aw_y = fapi_round(- pbfont->FontBBox.q.x * scale); /* Sic ! */
2581 cr.metrics_scale = (bIsType1GlyphData ? 1000 : 1);
2582 cr.metrics_type = FAPI_METRICS_REPLACE;
2583 sbw[0] = sbw[2] / 2;
2584 sbw[1] = pbfont->FontBBox.q.y;
2585 sbw[2] = 0;
2586 sbw[3] = - pbfont->FontBBox.q.x; /* Sic ! */
2587 sbw_state = SBW_DONE;
2588 } else
2589 bVertical = false;
2590 } else {
2591 cr.sb_x = fapi_round(pwv[2] * scale);
2592 cr.sb_y = fapi_round(pwv[3] * scale);
2593 cr.aw_x = fapi_round(pwv[0] * scale);
2594 cr.aw_y = fapi_round(pwv[1] * scale);
2595 cr.metrics_scale = (bIsType1GlyphData ? 1000 : 1);
2596 cr.metrics_type = (code == metricsSideBearingAndWidth ?
2597 FAPI_METRICS_REPLACE : FAPI_METRICS_REPLACE_WIDTH);
2598 sbw[0] = pwv[2];
2599 sbw[1] = pwv[3];
2600 sbw[2] = pwv[0];
2601 sbw[3] = pwv[1];
2602 sbw_state = SBW_DONE;
2603 }
2604 }
2605 if (cr.metrics_type == FAPI_METRICS_NOTDEF && !bVertical) {
2606 code = zchar_get_metrics(pbfont, &enc_char_name, sbw);
2607 if (code < 0)
2608 return code;
2609 if (code == metricsNone) {
2610 sbw_state = SBW_FROM_RENDERER;
2611 if (pbfont->FontType == 2) {
2612 gs_font_type1 *pfont1 = (gs_font_type1 *)pbfont;
2613
2614 cr.aw_x = export_shift(pfont1->data.defaultWidthX, _fixed_shift - I->frac_shift);
2615 cr.metrics_scale = 1000;
2616 cr.metrics_type = FAPI_METRICS_ADD;
2617 }
2618 } else {
2619 cr.sb_x = fapi_round(sbw[0] * scale);
2620 cr.sb_y = fapi_round(sbw[1] * scale);
2621 cr.aw_x = fapi_round(sbw[2] * scale);
2622 cr.aw_y = fapi_round(sbw[3] * scale);
2623 cr.metrics_scale = (bIsType1GlyphData ? 1000 : 1);
2624 cr.metrics_type = (code == metricsSideBearingAndWidth ?
2625 FAPI_METRICS_REPLACE : FAPI_METRICS_REPLACE_WIDTH);
2626 sbw_state = SBW_DONE;
2627 }
2628 }
2629 memset(&metrics, 0x00, sizeof(metrics));
2630 /* Take metrics from font : */
2631 if (zchar_show_width_only(penum)) {
2632 code = I->get_char_width(I, &I->ff, &cr, &metrics);
2633 /* A VMerror could be a real out of memory, or the glyph being too big for a bitmap
2634 * so it's worth retrying as an outline glyph
2635 */
2636 if (code == e_VMerror && I->use_outline == false) {
2637 I->max_bitmap = 0;
2638 I->use_outline = true;
2639 goto retry_oversampling;
2640 }
2641
2642 } else if (I->use_outline) {
2643
2644 code = I->get_char_outline_metrics(I, &I->ff, &cr, &metrics);
2645 } else {
2646 #if 0 /* Debug purpose only. */
2647 code = e_limitcheck;
2648 #else
2649 code = I->get_char_raster_metrics(I, &I->ff, &cr, &metrics);
2650 #endif
2651 /* A VMerror could be a real out of memory, or the glyph being too big for a bitmap
2652 * so it's worth retrying as an outline glyph
2653 */
2654 if (code == e_VMerror) {
2655 I->use_outline = true;
2656 goto retry_oversampling;
2657 }
2658
2659 if (code == e_limitcheck) {
2660 if(log2_scale.x > 0 || log2_scale.y > 0) {
2661 penum_s->fapi_log2_scale.x = log2_scale.x = penum_s->fapi_log2_scale.y = log2_scale.y = 0;
2662 I->release_char_data(I);
2663 goto retry_oversampling;
2664 }
2665 if ((code = renderer_retcode(i_ctx_p, I, I->get_char_outline_metrics(I, &I->ff, &cr, &metrics))) < 0)
2666 return code;
2667 }
2668 }
2669
2670 /* This handles the situation where a charstring has been replaced with a PS procedure.
2671 * against the rules, but not *that* rare.
2672 * It's also something that GS does internally to simulate font styles.
2673 */
2674 if (code > 0) {
2675 os_ptr op = osp;
2676 ref *proc;
2677 if ((get_charstring(&I->ff, code - 1, &proc) >= 0) && (r_has_type(proc, t_array) || r_has_type(proc, t_mixedarray))) {
2678 push(2);
2679 ref_assign(op - 1, &char_name);
2680 ref_assign(op, proc);
2681 return(zchar_exec_char_proc(i_ctx_p));
2682 }
2683 }
2684
2685 if ((code = renderer_retcode(i_ctx_p, I, code)) < 0)
2686 return code;
2687
2688 compute_em_scale(pbfont, &metrics, FontMatrix_div, &em_scale_x, &em_scale_y);
2689 char_bbox.p.x = metrics.bbox_x0 / em_scale_x;
2690 char_bbox.p.y = metrics.bbox_y0 / em_scale_y;
2691 char_bbox.q.x = metrics.bbox_x1 / em_scale_x;
2692 char_bbox.q.y = metrics.bbox_y1 / em_scale_y;
2693
2694 /* We must use the FontBBox, but it seems some buggy fonts have glyphs which extend outside the
2695 * FontBBox, so we have to do this....
2696 */
2697 if (!bCID && pbfont->FontBBox.q.x > pbfont->FontBBox.p.x
2698 && pbfont->FontBBox.q.y > pbfont->FontBBox.p.y) {
2699 char_bbox.p.x = min(char_bbox.p.x, pbfont->FontBBox.p.x);
2700 char_bbox.p.y = min(char_bbox.p.y, pbfont->FontBBox.p.y);
2701 char_bbox.q.x = max(char_bbox.q.x, pbfont->FontBBox.q.x);
2702 char_bbox.q.y = max(char_bbox.q.y, pbfont->FontBBox.q.y);
2703 }
2704
2705 if (pbfont->PaintType != 0) {
2706 float w = pbfont->StrokeWidth / 2;
2707
2708 char_bbox.p.x -= w;
2709 char_bbox.p.y -= w;
2710 char_bbox.q.x += w;
2711 char_bbox.q.y += w;
2712 }
2713 penum_s->fapi_glyph_shift.x = penum_s->fapi_glyph_shift.y = 0;
2714 if (sbw_state == SBW_FROM_RENDERER) {
2715 int can_replace_metrics;
2716
2717 if ((code = renderer_retcode(i_ctx_p, I, I->can_replace_metrics(I, &I->ff, &cr, &can_replace_metrics))) < 0)
2718 return code;
2719
2720 sbw[2] = metrics.escapement / em_scale_x;
2721 sbw[3] = metrics.v_escapement / em_scale_y;
2722 if (pbfont->FontType == 2 && !can_replace_metrics) {
2723 gs_font_type1 *pfont1 = (gs_font_type1 *)pbfont;
2724
2725 sbw[2] += fixed2float(pfont1->data.nominalWidthX);
2726 }
2727 } else if (sbw_state == SBW_SCALE) {
2728 sbw[0] = (double)cr.sb_x / scale / em_scale_x;
2729 sbw[1] = (double)cr.sb_y / scale / em_scale_y;
2730 sbw[2] = (double)cr.aw_x / scale / em_scale_x;
2731 sbw[3] = (double)cr.aw_y / scale / em_scale_y;
2732 }
2733
2734 /* Setup cache and render : */
2735 if (cr.metrics_type == FAPI_METRICS_REPLACE) {
2736 /*
2737 * Here we don't take care of replaced advance width
2738 * because gs_text_setcachedevice handles it.
2739 */
2740 int can_replace_metrics;
2741
2742 if ((code = renderer_retcode(i_ctx_p, I, I->can_replace_metrics(I, &I->ff, &cr, &can_replace_metrics))) < 0)
2743 return code;
2744 if (!can_replace_metrics) {
2745 /*
2746 * The renderer should replace the lsb, but it can't.
2747 * To work around we compute a displacement in integral pixels
2748 * and later shift the bitmap to it. The raster will be inprecise
2749 * with non-integral pixels shift.
2750 */
2751 char_bbox.q.x -= char_bbox.p.x;
2752 char_bbox.p.x = 0;
2753 gs_distance_transform((metrics.bbox_x0 / em_scale_x - sbw[0]),
2754 0, ctm, &penum_s->fapi_glyph_shift);
2755 penum_s->fapi_glyph_shift.x *= 1 << log2_scale.x;
2756 penum_s->fapi_glyph_shift.y *= 1 << log2_scale.y;
2757 }
2758 }
2759
2760 /*
2761 * We assume that if bMetricsFromGlyphDirectory is true,
2762 * the font does not specify Metrics[2] and/or CDevProc
2763 * If someday we meet a font contradicting this assumption,
2764 * zchar_set_cache to be improved with additional flag,
2765 * to ignore Metrics[2] and CDevProc.
2766 *
2767 * Note that for best quality the result of CDevProc
2768 * to be passed to I->get_char_raster_metrics, because
2769 * both raster and metrics depend on replaced lsb.
2770 * Perhaps in many cases the metrics from font is
2771 * used as an argument for CDevProc. Only way to resolve
2772 * is to call I->get_char_raster_metrics twice (before
2773 * and after CDevProc), or better to split it into
2774 * smaller functions. Unfortunately UFST cannot retrieve metrics
2775 * quickly and separately from raster. Only way to resolve is
2776 * to devide the replaced lsb into 2 parts, which correspond to
2777 * integral and fractinal pixels, then pass the fractional shift
2778 * to renderer and apply the integer shift after it.
2779 *
2780 * Besides that, we are not sure what to do if a font
2781 * contains both Metrics[2] and CDevProc. Should
2782 * CDevProc to be applied to Metrics[2] or to the metrics
2783 * from glyph code ? Currently we keep a compatibility
2784 * to the native GS font renderer without a deep analyzis.
2785 */
2786
2787 if (igs->in_cachedevice == CACHE_DEVICE_CACHING) {
2788 sbwp = sbw;
2789 }
2790 else {
2791 /* Very occasionally, if we don't do this, setcachedevice2
2792 * will decide we are cacheing, when we're not, and this
2793 * causes problems when we get to show_update().
2794 */
2795 sbwp = NULL;
2796
2797 if (I->use_outline) {
2798 /* HACK!!
2799 * The decision about whether to cache has already been
2800 * we need to prevent it being made again....
2801 */
2802 igs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;
2803 }
2804 }
2805
2806 if (bCID)
2807 code = zchar_set_cache(i_ctx_p, pbfont, op,
2808 NULL, sbw + 2, &char_bbox,
2809 fapi_finish_render, &exec_cont, sbwp);
2810 else
2811 code = zchar_set_cache(i_ctx_p, pbfont, &char_name,
2812 NULL, sbw + 2, &char_bbox,
2813 fapi_finish_render, &exec_cont, sbwp);
2814
2815 if (code >= 0 && exec_cont != 0)
2816 code = (*exec_cont)(i_ctx_p);
2817 if (code != 0) {
2818 if (code < 0) {
2819 /* An error */
2820 I->release_char_data(I);
2821 } else {
2822 /* Callout to CDevProc, zsetcachedevice2, fapi_finish_render. */
2823 }
2824 }
2825
2826 return code;
2827 }
2828
FAPI_char(i_ctx_t * i_ctx_p,bool bBuildGlyph,ref * charstring)2829 static int FAPI_char(i_ctx_t *i_ctx_p, bool bBuildGlyph, ref *charstring)
2830 { /* Stack : <font> <code|name> --> - */
2831 ref *v;
2832 char *font_file_path = NULL;
2833 gx_device *dev = gs_currentdevice_inline(igs);
2834 gs_font *pfont;
2835 int code = font_param(osp - 1, &pfont);
2836
2837 if (code == 0) {
2838 gs_font_base *pbfont = (gs_font_base *) pfont;
2839 if (dict_find_string(osp - 1, "Path", &v) > 0 && r_has_type(v, t_string))
2840 font_file_path = ref_to_string(v, imemory, "font file path");
2841 code = FAPI_do_char(i_ctx_p, pbfont, dev, font_file_path, bBuildGlyph, charstring);
2842 if (font_file_path != NULL)
2843 gs_free_string(imemory, (byte *)font_file_path, r_size(v) + 1, "font file path");
2844 }
2845 return code;
2846 }
2847
FAPIBuildGlyph9aux(i_ctx_t * i_ctx_p)2848 static int FAPIBuildGlyph9aux(i_ctx_t *i_ctx_p)
2849 {
2850 os_ptr op = osp; /* <font0> <cid> <font9> <cid> */
2851 ref font9 = *pfont_dict(gs_currentfont(igs));
2852 ref *rFDArray, f;
2853 int font_index;
2854 int code;
2855
2856 if ((code = ztype9mapcid(i_ctx_p)) < 0)
2857 return code; /* <font0> <cid> <charstring> <font_index> */
2858 /* fixme: what happens if the charstring is absent ?
2859 Can FDArray contain 'null' (see %Type9BuildGlyph in gs_cidfn.ps)? */
2860 font_index = op[0].value.intval;
2861 if (dict_find_string(&font9, "FDArray", &rFDArray) <= 0 || r_type(rFDArray) != t_array)
2862 return_error(e_invalidfont);
2863 if(array_get(imemory, rFDArray, font_index, &f) < 0 || r_type(&f) != t_dictionary)
2864 return_error(e_invalidfont);
2865 op[0] = op[-2];
2866 op[-2] = op[-1]; /* Keep the charstring on ostack for the garbager. */
2867 op[-1] = f; /* <font0> <charstring> <subfont> <cid> */
2868 if ((code = FAPI_char(i_ctx_p, true, op - 2)) < 0)
2869 return code;
2870 /* <font0> <charstring> */
2871 return code;
2872 }
2873
2874 /* <font> <code> .FAPIBuildChar - */
zFAPIBuildChar(i_ctx_t * i_ctx_p)2875 static int zFAPIBuildChar(i_ctx_t *i_ctx_p)
2876 {
2877 return FAPI_char(i_ctx_p, false, NULL);
2878 }
2879
2880 /* non-CID : <font> <code> .FAPIBuildGlyph - */
2881 /* CID : <font> <name> .FAPIBuildGlyph - */
zFAPIBuildGlyph(i_ctx_t * i_ctx_p)2882 static int zFAPIBuildGlyph(i_ctx_t *i_ctx_p)
2883 {
2884 return FAPI_char(i_ctx_p, true, NULL);
2885 }
2886
2887 /* <font> <cid> .FAPIBuildGlyph9 - */
zFAPIBuildGlyph9(i_ctx_t * i_ctx_p)2888 static int zFAPIBuildGlyph9(i_ctx_t *i_ctx_p)
2889 {
2890 /* The alghorithm is taken from %Type9BuildGlyph - see gs_cidfn.ps . */
2891 os_ptr lop, op = osp;
2892 int cid, code;
2893 avm_space s = ialloc_space(idmemory);
2894
2895 check_type(op[ 0], t_integer);
2896 check_type(op[-1], t_dictionary);
2897 cid = op[0].value.intval;
2898 push(2);
2899 op[-1] = *pfont_dict(gs_currentfont(igs));
2900 op[0] = op[-2]; /* <font0> <cid> <font9> <cid> */
2901 ialloc_set_space(idmemory, (r_is_local(op - 3) ? avm_global : avm_local)); /* for ztype9mapcid */
2902 code = FAPIBuildGlyph9aux(i_ctx_p);
2903 lop = osp;
2904 if (code == 5) {
2905 int i, ind = (lop - op);
2906 op = osp;
2907
2908 for (i = ind; i >= 0; i--) {
2909 op[-i - 2] = op[-i];
2910 }
2911 pop(2);
2912 }
2913 else if (code < 0) { /* <font0> <dirty> <dirty> <dirty> */
2914 /* Adjust ostack for the correct error handling : */
2915 make_int(op - 2, cid);
2916 pop(2); /* <font0> <cid> */
2917 } else if (code != 5) { /* <font0> <dirty> */
2918
2919
2920 pop(2); /* */
2921 /* Note that this releases the charstring, and it may be garbage-collected
2922 before the interpreter calls fapi_finish_render. This requires the server
2923 to keep glyph raster internally between calls to get_char_raster_metrics
2924 and get_char_raster. Perhaps UFST cannot provide metrics without
2925 building a raster, so this constraint actually goes from UFST.
2926 */
2927 }
2928 ialloc_set_space(idmemory, s);
2929 return code;
2930 }
2931
do_FAPIpassfont(i_ctx_t * i_ctx_p,char * font_file_path,bool * success)2932 static int do_FAPIpassfont(i_ctx_t *i_ctx_p, char *font_file_path, bool *success)
2933 { ref *pdr = osp; /* font dict */
2934 gs_font *pfont;
2935 int code = font_param(osp, &pfont);
2936 gs_font_base *pbfont;
2937 int BBox[4];
2938 i_plugin_holder *h = i_plugin_get_list(i_ctx_p);
2939 char *xlatmap = NULL;
2940 FAPI_font_scale font_scale = {{1, 0, 0, 1, 0, 0}, {0, 0}, {1, 1}, true};
2941 const char *decodingID = NULL;
2942 ref *req, reqstr;
2943 bool do_restart = false;
2944
2945 if (code < 0)
2946 return code;
2947 code = FAPI_get_xlatmap(i_ctx_p, &xlatmap); /* Useful for emulated fonts hooked with FAPI. */
2948 if (code < 0)
2949 return code;
2950 pbfont = (gs_font_base *)pfont;
2951
2952 *success = false;
2953
2954 /* If the font dictionary contains a FAPIPlugInReq key, the the PS world wants us
2955 * to try to use a specific FAPI plugin, so find it, and try it....
2956 */
2957 if (dict_find_string(pdr, "FAPIPlugInReq", &req) >= 0 && r_type(req) == t_name) {
2958 char *fapi_request;
2959 name_string_ref (imemory, req, &reqstr);
2960
2961 fapi_request = ref_to_string(&reqstr, imemory, "FAPI_do_char");
2962 if (fapi_request) {
2963 dprintf1("Requested FAPI plugin: %s ", fapi_request);
2964
2965 while (h && (strncmp(h->I->d->type, "FAPI", 4) != 0 || strncmp(h->I->d->subtype, fapi_request, strlen(fapi_request)) != 0)) {
2966 h = h->next;
2967 }
2968 if (!h) {
2969 dprintf("not found. Falling back to normal plugin search\n");
2970 h = i_plugin_get_list(i_ctx_p);
2971 }
2972 else {
2973 dprintf("found.\n");
2974 do_restart = true;
2975 }
2976 gs_free_string(imemory, (byte *)fapi_request, strlen(fapi_request) + 1, "do_FAPIpassfont");
2977 }
2978 }
2979
2980 while (h) {
2981 ref FAPI_ID;
2982 FAPI_server *I;
2983 const byte *server_param = NULL;
2984 int server_param_size = 0;
2985
2986 if (!strcmp(h->I->d->type, "FAPI")) {
2987 I = (FAPI_server *)h->I;
2988 get_server_param(i_ctx_p, I->ig.d->subtype, &server_param, &server_param_size);
2989 if ((code = renderer_retcode(i_ctx_p, I, I->ensure_open(I, server_param, server_param_size))) < 0)
2990 return code;
2991 font_scale.HWResolution[0] = font_scale.HWResolution[1] = 72 << I->frac_shift;
2992 font_scale.matrix[0] = font_scale.matrix[3] = 1 << I->frac_shift;
2993
2994 pbfont->FAPI = I; /* we need the FAPI server during this stage */
2995 code = FAPI_prepare_font(i_ctx_p, I, pdr, pbfont, font_file_path, &font_scale, xlatmap, BBox, &decodingID);
2996 if (code >= 0) {
2997 if ((code = name_ref(imemory, (const byte *)I->ig.d->subtype, strlen(I->ig.d->subtype), &FAPI_ID, false)) < 0)
2998 return code;
2999 if ((code = dict_put_string(pdr, "FAPI", &FAPI_ID, NULL)) < 0)
3000 return code; /* Insert FAPI entry to font dictionary. */
3001 *success = true;
3002 return 0;
3003 }
3004 }
3005 /* renderer failed, continue search */
3006 pbfont->FAPI = NULL;
3007 if (do_restart == true) {
3008 dprintf1("Requested FAPI plugin %s failed, searching for alternative plugin\n", h->I->d->subtype);
3009 h = i_plugin_get_list(i_ctx_p);
3010 do_restart = false;
3011 }
3012 else {
3013 h = h->next;
3014 }
3015 }
3016 /* Could not find renderer, return with false success. */
3017 return 0;
3018 }
3019
3020 /* <font_dict> .FAPIpassfont bool <font_dict> */
3021 /* must insert /FAPI to font dictionary */
3022 /* This operator must not be called with devices which embed fonts. */
zFAPIpassfont(i_ctx_t * i_ctx_p)3023 static int zFAPIpassfont(i_ctx_t *i_ctx_p)
3024 { os_ptr op = osp;
3025 int code;
3026 bool found = false;
3027 char *font_file_path = NULL;
3028 ref *v;
3029
3030 /* Normally embedded fonts have no Path, but if a CID font is
3031 * emulated with a TT font, and it is hooked with FAPI,
3032 * the path presents and is neccessary to access the full font data.
3033 */
3034 check_type(*op, t_dictionary);
3035 if (dict_find_string(op, "Path", &v) > 0 && r_has_type(v, t_string))
3036 font_file_path = ref_to_string(v, imemory_global, "font file path");
3037 code = do_FAPIpassfont(i_ctx_p, font_file_path, &found);
3038 if (font_file_path != NULL)
3039 gs_free_string(imemory_global, (byte *)font_file_path, r_size(v) + 1, "font file path");
3040 if(code != 0)
3041 return code;
3042 push(1);
3043 make_bool(op, found);
3044 return 0;
3045 }
3046
3047 const op_def zfapi_op_defs[] =
3048 { {"2.FAPIavailable", zFAPIavailable},
3049 {"2.FAPIpassfont", zFAPIpassfont},
3050 {"2.FAPIrebuildfont", zFAPIrebuildfont},
3051 {"2.FAPIBuildChar", zFAPIBuildChar},
3052 {"2.FAPIBuildGlyph", zFAPIBuildGlyph},
3053 {"2.FAPIBuildGlyph9", zFAPIBuildGlyph9},
3054 op_def_end(0)
3055 };
3056