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