xref: /plan9/sys/src/cmd/gs/src/zfapi.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1991, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: zfapi.c,v 1.53 2004/10/05 12:45:29 igor Exp $ */
18 /* Font API client */
19 
20 #include "memory_.h"
21 #include "string_.h"
22 #include "math_.h"
23 #include "ghost.h"
24 #include "gp.h"
25 #include "oper.h"
26 #include "gxdevice.h"
27 #include "gxfont.h"
28 #include "gxfont1.h"
29 #include "gxchar.h"
30 #include "gxpath.h"
31 #include "gxfcache.h"
32 #include "gxchrout.h"
33 #include "gscoord.h"
34 #include "gspaint.h"
35 #include "gsfont.h"
36 #include "gspath.h"
37 #include "bfont.h"
38 #include "dstack.h"
39 #include "ichar.h"
40 #include "idict.h"
41 #include "iddict.h"
42 #include "idparam.h"
43 #include "iname.h"
44 #include "ifont.h"
45 #include "icid.h"
46 #include "igstate.h"
47 #include "icharout.h"
48 #include "ifapi.h"
49 #include "iplugin.h"
50 #include "store.h"
51 #include "gzstate.h"
52 #include "gdevpsf.h"
53 #include "stream.h"		/* for files.h */
54 #include "files.h"
55 #include "gscrypt1.h"
56 #include "gxfcid.h"
57 
58 /* -------------------------------------------------------- */
59 
60 typedef struct FAPI_outline_handler_s {
61     struct gx_path_s *path;
62     fixed x0, y0;
63     bool close_path, need_close; /* This stuff fixes unclosed paths being rendered with UFST */
64 } FAPI_outline_handler;
65 
import_shift(int x,int n)66 private inline int import_shift(int x, int n)
67 {   return n > 0 ? x << n : x >> -n;
68 }
69 
export_shift(int x,int n)70 private inline int export_shift(int x, int n)
71 {   return n > 0 ? x >> n : x << -n;
72 }
73 
fapi_round(double x)74 private inline int fapi_round(double x)
75 {   return (int)(x + 0.5);
76 }
77 
add_closepath(FAPI_path * I)78 private int add_closepath(FAPI_path *I)
79 {   FAPI_outline_handler *olh = (FAPI_outline_handler *)I->olh;
80 
81     olh->need_close = false;
82     return gx_path_close_subpath_notes(olh->path, 0);
83 }
84 
add_move(FAPI_path * I,FracInt x,FracInt y)85 private int add_move(FAPI_path *I, FracInt x, FracInt y)
86 {   FAPI_outline_handler *olh = (FAPI_outline_handler *)I->olh;
87     int code;
88 
89     if (olh->need_close && olh->close_path)
90         if ((code = add_closepath(I)) < 0)
91 	    return code;
92     olh->need_close = false;
93     return gx_path_add_point(olh->path, import_shift(x, I->shift) + olh->x0, -import_shift(y, I->shift) + olh->y0);
94 }
95 
add_line(FAPI_path * I,FracInt x,FracInt y)96 private int add_line(FAPI_path *I, FracInt x, FracInt y)
97 {   FAPI_outline_handler *olh = (FAPI_outline_handler *)I->olh;
98 
99     olh->need_close = true;
100     return gx_path_add_line_notes(olh->path, import_shift(x, I->shift) + olh->x0, -import_shift(y, I->shift) + olh->y0, 0);
101 }
102 
add_curve(FAPI_path * I,FracInt x0,FracInt y0,FracInt x1,FracInt y1,FracInt x2,FracInt y2)103 private int add_curve(FAPI_path *I, FracInt x0, FracInt y0, FracInt x1, FracInt y1, FracInt x2, FracInt y2)
104 {   FAPI_outline_handler *olh = (FAPI_outline_handler *)I->olh;
105 
106     olh->need_close = true;
107     return gx_path_add_curve_notes(olh->path, import_shift(x0, I->shift) + olh->x0, -import_shift(y0, I->shift) + olh->y0,
108 					      import_shift(x1, I->shift) + olh->x0, -import_shift(y1, I->shift) + olh->y0,
109 					      import_shift(x2, I->shift) + olh->x0, -import_shift(y2, I->shift) + olh->y0, 0);
110 }
111 
112 private FAPI_path path_interface_stub = { NULL, 0, add_move, add_line, add_curve, add_closepath };
113 
IsCIDFont(const gs_font_base * pbfont)114 private inline bool IsCIDFont(const gs_font_base *pbfont)
115 {   return (pbfont->FontType == ft_CID_encrypted ||
116             pbfont->FontType == ft_CID_user_defined ||
117             pbfont->FontType == ft_CID_TrueType);
118     /* The font type 10 (ft_CID_user_defined) must not pass to FAPI. */
119 }
120 
IsType1GlyphData(const gs_font_base * pbfont)121 private inline bool IsType1GlyphData(const gs_font_base *pbfont)
122 {   return pbfont->FontType == ft_encrypted ||
123            pbfont->FontType == ft_encrypted2 ||
124            pbfont->FontType == ft_CID_encrypted;
125 }
126 
127 /* -------------------------------------------------------- */
128 
129 typedef struct sfnts_reader_s sfnts_reader;
130 struct sfnts_reader_s {
131     ref *sfnts;
132     const gs_memory_t *memory;
133     const byte *p;
134     long index;
135     uint offset;
136     uint length;
137     bool error;
138     byte (*rbyte)(sfnts_reader *r);
139     ushort (*rword)(sfnts_reader *r);
140     ulong (*rlong)(sfnts_reader *r);
141     void (*rstring)(sfnts_reader *r, byte *v, int length);
142     void (*seek)(sfnts_reader *r, ulong pos);
143 };
144 
sfnts_next_elem(sfnts_reader * r)145 private void sfnts_next_elem(sfnts_reader *r)
146 {   ref s;
147 
148     if (r->error)
149         return;
150     r->index++;
151     r->error |= (array_get(r->memory, r->sfnts, r->index, &s) < 0);
152     if (r->error)
153         return;
154     r->p = s.value.const_bytes;
155     r->length = r_size(&s) & ~(uint)1; /* See Adobe Technical Note # 5012, section 4.2. */
156     r->offset = 0;
157 }
158 
sfnts_reader_rbyte_inline(sfnts_reader * r)159 private inline byte sfnts_reader_rbyte_inline(sfnts_reader *r)
160 {   if (r->offset >= r->length)
161         sfnts_next_elem(r);
162     return (r->error ? 0 : r->p[r->offset++]);
163 }
164 
sfnts_reader_rbyte(sfnts_reader * r)165 private byte sfnts_reader_rbyte(sfnts_reader *r) /* old compiler compatibility */
166 {   return sfnts_reader_rbyte_inline(r);
167 }
168 
sfnts_reader_rword(sfnts_reader * r)169 private ushort sfnts_reader_rword(sfnts_reader *r)
170 {   return (sfnts_reader_rbyte_inline(r) << 8) + sfnts_reader_rbyte_inline(r);
171 }
172 
sfnts_reader_rlong(sfnts_reader * r)173 private ulong sfnts_reader_rlong(sfnts_reader *r)
174 {   return (sfnts_reader_rbyte_inline(r) << 24) + (sfnts_reader_rbyte_inline(r) << 16) +
175            (sfnts_reader_rbyte_inline(r) << 8) + sfnts_reader_rbyte_inline(r);
176 }
177 
sfnts_reader_rstring(sfnts_reader * r,byte * v,int length)178 private void sfnts_reader_rstring(sfnts_reader *r, byte *v, int length)
179 {   if (length < 0)
180         return;
181     while (!r->error) {
182         int l = min(length, r->length - r->offset);
183         memcpy(v, r->p + r->offset, l);
184         r->p += l;
185         length -= l;
186         if (length <= 0)
187             return;
188         sfnts_next_elem(r);
189     }
190 }
191 
sfnts_reader_seek(sfnts_reader * r,ulong pos)192 private void sfnts_reader_seek(sfnts_reader *r, ulong pos)
193 {   /* fixme : optimize */
194     ulong skipped = 0;
195 
196     r->index = -1;
197     sfnts_next_elem(r);
198     while (skipped + r->length < pos && !r->error) {
199         skipped += r->length;
200         sfnts_next_elem(r);
201     }
202     r->offset = pos - skipped;
203 }
204 
sfnts_reader_init(sfnts_reader * r,ref * pdr)205 private void sfnts_reader_init(sfnts_reader *r, ref *pdr)
206 {   r->rbyte = sfnts_reader_rbyte;
207     r->rword = sfnts_reader_rword;
208     r->rlong = sfnts_reader_rlong;
209     r->rstring = sfnts_reader_rstring;
210     r->seek = sfnts_reader_seek;
211     r->index = -1;
212     r->error = false;
213     if (r_type(pdr) != t_dictionary ||
214         dict_find_string(pdr, "sfnts", &r->sfnts) <= 0)
215         r->error = true;
216     sfnts_next_elem(r);
217 }
218 
219 /* -------------------------------------------------------- */
220 
221 typedef struct sfnts_writer_s sfnts_writer;
222 struct sfnts_writer_s {
223     byte *buf, *p;
224     int buf_size;
225     void (*wbyte)(sfnts_writer *w, byte v);
226     void (*wword)(sfnts_writer *w, ushort v);
227     void (*wlong)(sfnts_writer *w, ulong v);
228     void (*wstring)(sfnts_writer *w, byte *v, int length);
229 };
230 
sfnts_writer_wbyte(sfnts_writer * w,byte v)231 private void sfnts_writer_wbyte(sfnts_writer *w, byte v)
232 {   if (w->buf + w->buf_size < w->p + 1)
233         return; /* safety */
234     w->p[0] = v;
235     w->p++;
236 }
237 
sfnts_writer_wword(sfnts_writer * w,ushort v)238 private void sfnts_writer_wword(sfnts_writer *w, ushort v)
239 {   if (w->buf + w->buf_size < w->p + 2)
240         return; /* safety */
241     w->p[0] = v / 256;
242     w->p[1] = v % 256;
243     w->p += 2;
244 }
245 
sfnts_writer_wlong(sfnts_writer * w,ulong v)246 private void sfnts_writer_wlong(sfnts_writer *w, ulong v)
247 {   if (w->buf + w->buf_size < w->p + 4)
248         return; /* safety */
249     w->p[0] = v >> 24;
250     w->p[1] = (v >> 16) & 0xFF;
251     w->p[2] = (v >>  8) & 0xFF;
252     w->p[3] = v & 0xFF;
253     w->p += 4;
254 }
255 
sfnts_writer_wstring(sfnts_writer * w,byte * v,int length)256 private void sfnts_writer_wstring(sfnts_writer *w, byte *v, int length)
257 {   if (w->buf + w->buf_size < w->p + length)
258         return; /* safety */
259     memcpy(w->p, v, length);
260     w->p += length;
261 }
262 
263 private const sfnts_writer sfnts_writer_stub = {
264     0, 0, 0,
265     sfnts_writer_wbyte,
266     sfnts_writer_wword,
267     sfnts_writer_wlong,
268     sfnts_writer_wstring
269 };
270 
271 /* -------------------------------------------------------- */
272 
sfnts_need_copy_table(byte * tag)273 private inline bool sfnts_need_copy_table(byte *tag)
274 { return memcmp(tag, "glyf", 4) &&
275          memcmp(tag, "glyx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */
276          memcmp(tag, "loca", 4) &&
277          memcmp(tag, "locx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */
278          memcmp(tag, "cmap", 4);
279 }
280 
sfnt_copy_table(sfnts_reader * r,sfnts_writer * w,int length)281 private void sfnt_copy_table(sfnts_reader *r, sfnts_writer *w, int length)
282 {   byte buf[1024];
283 
284     while (length > 0 && !r->error) {
285         int l = min(length, sizeof(buf));
286         r->rstring(r, buf, l);
287         w->wstring(w, buf, l);
288         length -= l;
289     }
290 }
291 
sfnts_copy_except_glyf(sfnts_reader * r,sfnts_writer * w)292 private ulong sfnts_copy_except_glyf(sfnts_reader *r, sfnts_writer *w)
293 {   /* Note : TTC is not supported and probably is unuseful for Type 42. */
294     /* This skips glyf, loca and cmap from copying. */
295     struct {
296         byte tag[4];
297         ulong checkSum, offset, offset_new, length;
298     } tables[30];
299     const ushort alignment = 4; /* Not sure, maybe 2 */
300     ulong version = r->rlong(r);
301     ushort num_tables = r->rword(r);
302     ushort i, num_tables_new = 0;
303     ushort searchRange, entrySelector = 0, rangeShift, v;
304     ulong size_new = 12;
305 
306     r->rword(r); /* searchRange */
307     r->rword(r); /* entrySelector */
308     r->rword(r); /* rangeShift */
309     for (i = 0; i < num_tables; i++) {
310         if (r->error)
311             return 0;
312         r->rstring(r, tables[i].tag, 4);
313         tables[i].checkSum = r->rlong(r);
314         tables[i].offset = r->rlong(r);
315         tables[i].length = r->rlong(r);
316         tables[i].offset_new = size_new;
317         if (sfnts_need_copy_table(tables[i].tag)) {
318             num_tables_new ++;
319             size_new += (tables[i].length + alignment - 1) / alignment * alignment;
320         }
321     }
322     size_new += num_tables_new * 16;
323     if (w == 0)
324         return size_new;
325 
326     searchRange = v = num_tables_new * 16;
327     for (i = 0; v; i++) {
328         v >>= 1;
329         searchRange |= v;
330         entrySelector++;
331     }
332     searchRange -= searchRange >> 1;
333     rangeShift = num_tables_new * 16 - searchRange;
334 
335     w->wlong(w, version);
336     w->wword(w, num_tables_new);
337     w->wword(w, searchRange);
338     w->wword(w, entrySelector);
339     w->wword(w, rangeShift);
340     for (i = 0; i < num_tables; i++)
341         if (sfnts_need_copy_table(tables[i].tag)) {
342             w->wstring(w, tables[i].tag, 4);
343             w->wlong(w, tables[i].checkSum);
344             w->wlong(w, tables[i].offset_new + num_tables_new * 16);
345             w->wlong(w, tables[i].length);
346         }
347     for (i = 0; i < num_tables; i++)
348         if (sfnts_need_copy_table(tables[i].tag)) {
349             int k = tables[i].length;
350             r->seek(r, tables[i].offset);
351             if (r->error)
352                 return 0;
353             if (w->p - w->buf != tables[i].offset_new + num_tables_new * 16)
354                 return 0; /* the algorithm consistency check */
355             sfnt_copy_table(r, w, tables[i].length);
356             for (; k & (alignment - 1); k++)
357                 w->wbyte(w, 0);
358         }
359     return size_new;
360 }
361 
true_type_size(ref * pdr)362 private ulong true_type_size(ref *pdr)
363 {   sfnts_reader r;
364 
365     sfnts_reader_init(&r, pdr);
366     return sfnts_copy_except_glyf(&r, 0);
367 }
368 
FAPI_FF_serialize_tt_font(FAPI_font * ff,void * buf,int buf_size)369 private ushort FAPI_FF_serialize_tt_font(FAPI_font *ff, void *buf, int buf_size)
370 {   ref *pdr = (ref *)ff->client_font_data2;
371     sfnts_reader r;
372     sfnts_writer w = sfnts_writer_stub;
373 
374     w.buf_size = buf_size;
375     w.buf = w.p = buf;
376     sfnts_reader_init(&r, pdr);
377     if(!sfnts_copy_except_glyf(&r, &w))
378         return 1;
379     return r.error;
380 }
381 
float_to_ushort(float v)382 private inline ushort float_to_ushort(float v)
383 {   return (ushort)(v * 16); /* fixme : the scale may depend on renderer */
384 }
385 
FAPI_FF_get_word(FAPI_font * ff,fapi_font_feature var_id,int index)386 private ushort FAPI_FF_get_word(FAPI_font *ff, fapi_font_feature var_id, int index)
387 {   gs_font_type1 *pfont = (gs_font_type1 *)ff->client_font_data;
388     ref *pdr = (ref *)ff->client_font_data2;
389 
390     switch((int)var_id) {
391         case FAPI_FONT_FEATURE_Weight: return 0; /* wrong */
392         case FAPI_FONT_FEATURE_ItalicAngle: return 0; /* wrong */
393         case FAPI_FONT_FEATURE_IsFixedPitch: return 0; /* wrong */
394         case FAPI_FONT_FEATURE_UnderLinePosition: return 0; /* wrong */
395         case FAPI_FONT_FEATURE_UnderlineThickness: return 0; /* wrong */
396         case FAPI_FONT_FEATURE_FontType: return (pfont->FontType == 2 ? 2 : 1);
397         case FAPI_FONT_FEATURE_FontBBox:
398             switch (index) {
399                 case 0 : return (ushort)pfont->FontBBox.p.x;
400                 case 1 : return (ushort)pfont->FontBBox.p.y;
401                 case 2 : return (ushort)pfont->FontBBox.q.x;
402                 case 3 : return (ushort)pfont->FontBBox.q.y;
403             }
404             return 0;
405         case FAPI_FONT_FEATURE_BlueValues_count: return pfont->data.BlueValues.count;
406         case FAPI_FONT_FEATURE_BlueValues: return float_to_ushort(pfont->data.BlueValues.values[index]);
407         case FAPI_FONT_FEATURE_OtherBlues_count: return pfont->data.OtherBlues.count;
408         case FAPI_FONT_FEATURE_OtherBlues: return float_to_ushort(pfont->data.OtherBlues.values[index]);
409         case FAPI_FONT_FEATURE_FamilyBlues_count: return pfont->data.FamilyBlues.count;
410         case FAPI_FONT_FEATURE_FamilyBlues: return float_to_ushort(pfont->data.FamilyBlues.values[index]);
411         case FAPI_FONT_FEATURE_FamilyOtherBlues_count: return pfont->data.FamilyOtherBlues.count;
412         case FAPI_FONT_FEATURE_FamilyOtherBlues: return float_to_ushort(pfont->data.FamilyOtherBlues.values[index]);
413         case FAPI_FONT_FEATURE_BlueShift: return float_to_ushort(pfont->data.BlueShift);
414         case FAPI_FONT_FEATURE_BlueFuzz: return float_to_ushort(pfont->data.BlueShift);
415         case FAPI_FONT_FEATURE_StdHW: return (pfont->data.StdHW.count == 0 ? 0 : float_to_ushort(pfont->data.StdHW.values[0])); /* UFST bug ? */
416         case FAPI_FONT_FEATURE_StdVW: return (pfont->data.StdVW.count == 0 ? 0 : float_to_ushort(pfont->data.StdVW.values[0])); /* UFST bug ? */
417         case FAPI_FONT_FEATURE_StemSnapH_count: return pfont->data.StemSnapH.count;
418         case FAPI_FONT_FEATURE_StemSnapH: return float_to_ushort(pfont->data.StemSnapH.values[index]);
419         case FAPI_FONT_FEATURE_StemSnapV_count: return pfont->data.StemSnapV.count;
420         case FAPI_FONT_FEATURE_StemSnapV: return float_to_ushort(pfont->data.StemSnapV.values[index]);
421         case FAPI_FONT_FEATURE_ForceBold: return pfont->data.ForceBold;
422         case FAPI_FONT_FEATURE_LanguageGroup: return pfont->data.LanguageGroup;
423         case FAPI_FONT_FEATURE_lenIV: return (ff->need_decrypt ? 0 : pfont->data.lenIV);
424         case FAPI_FONT_FEATURE_Subrs_count:
425             {   ref *Private, *Subrs, *GlobalSubrs;
426                 int n1, n2;
427                 if (dict_find_string(pdr, "Private", &Private) <= 0)
428                     return 0;
429                 if (dict_find_string(Private, "Subrs", &Subrs) <= 0)
430                     Subrs = NULL;
431                 if (dict_find_string(Private, "GlobalSubrs", &GlobalSubrs) <= 0)
432                     GlobalSubrs = NULL;
433                 n1 = (Subrs != NULL ? r_size(Subrs) : 0);
434                 n2 = (GlobalSubrs != NULL ? r_size(GlobalSubrs) : 0);
435                 /* trick : we return twice maximum of n1, n2 to pass both Subrs and GlobalSubrs in same array.
436                 */
437                 return (n1 < n2 ? n2 : n1) * 2;
438             }
439     }
440     return 0;
441 }
442 
FAPI_FF_get_long(FAPI_font * ff,fapi_font_feature var_id,int index)443 private ulong FAPI_FF_get_long(FAPI_font *ff, fapi_font_feature var_id, int index)
444 {   gs_font_type1 *pfont = (gs_font_type1 *)ff->client_font_data;
445     ref *pdr = (ref *)ff->client_font_data2;
446 
447     switch((int)var_id) {
448         case FAPI_FONT_FEATURE_UniqueID: return pfont->UID.id;
449         case FAPI_FONT_FEATURE_BlueScale: return (ulong)(pfont->data.BlueScale * 65536);
450         case FAPI_FONT_FEATURE_Subrs_total_size :
451             {   ref *Private, *Subrs, v;
452                 int lenIV = max(pfont->data.lenIV, 0), k;
453                 ulong size = 0;
454                 long i;
455                 const char *name[2] = {"Subrs", "GlobalSubrs"};
456                 if (dict_find_string(pdr, "Private", &Private) <= 0)
457                     return 0;
458                 for (k = 0; k < 2; k++) {
459                     if (dict_find_string(Private, name[k], &Subrs) > 0)
460                         for (i = r_size(Subrs) - 1; i >= 0; i--) {
461                             array_get(pfont->memory, Subrs, i, &v);
462                             size += r_size(&v) - (ff->need_decrypt ? 0 : lenIV);
463                         }
464                 }
465                 return size;
466             }
467         case FAPI_FONT_FEATURE_TT_size:
468             return true_type_size(pdr);
469     }
470     return 0;
471 }
472 
FAPI_FF_get_float(FAPI_font * ff,fapi_font_feature var_id,int index)473 private float FAPI_FF_get_float(FAPI_font *ff, fapi_font_feature var_id, int index)
474 {   gs_font_base *pbfont = (gs_font_base *)ff->client_font_data;
475 
476     switch((int)var_id) {
477         case FAPI_FONT_FEATURE_FontMatrix:
478             {   double FontMatrix_div = (ff->is_cid && !IsCIDFont(pbfont) ? 1000 : 1);
479                 switch(index) {
480                     case 0 : return pbfont->base->FontMatrix.xx / FontMatrix_div;
481                     case 1 : return pbfont->base->FontMatrix.xy / FontMatrix_div;
482                     case 2 : return pbfont->base->FontMatrix.yx / FontMatrix_div;
483                     case 3 : return pbfont->base->FontMatrix.yy / FontMatrix_div;
484                     case 4 : return pbfont->base->FontMatrix.tx / FontMatrix_div;
485                     case 5 : return pbfont->base->FontMatrix.ty / FontMatrix_div;
486                 }
487             }
488     }
489     return 0;
490 }
491 
decode_bytes(byte * p,const byte * s,int l,int lenIV)492 private inline void decode_bytes(byte *p, const byte *s, int l, int lenIV)
493 {   ushort state = 4330;
494 
495     for (; l; s++, l--) {
496         uchar c = (*s ^ (state >> 8));
497         state = (*s + state) * crypt_c1 + crypt_c2;
498         if (lenIV > 0)
499             lenIV--;
500         else {
501             *p = c;
502             p++;
503         }
504     }
505 }
506 
get_type1_data(FAPI_font * ff,const ref * type1string,byte * buf,ushort buf_length)507 private ushort get_type1_data(FAPI_font *ff, const ref *type1string,
508 			      byte *buf, ushort buf_length)
509 {   gs_font_type1 *pfont = (gs_font_type1 *)ff->client_font_data;
510     int lenIV = max(pfont->data.lenIV, 0);
511     int length = r_size(type1string) - (ff->need_decrypt ? lenIV : 0);
512 
513     if (buf != 0) {
514         int l = min(length, buf_length); /*safety */
515         if (ff->need_decrypt && pfont->data.lenIV >= 0)
516             decode_bytes(buf, type1string->value.const_bytes, l + lenIV, lenIV);
517         else
518             memcpy(buf, type1string->value.const_bytes, l);
519     }
520     return length;
521 }
522 
FAPI_FF_get_subr(FAPI_font * ff,int index,byte * buf,ushort buf_length)523 private ushort FAPI_FF_get_subr(FAPI_font *ff, int index, byte *buf, ushort buf_length)
524 {   ref *pdr = (ref *)ff->client_font_data2;
525     ref *Private, *Subrs, *GlobalSubrs, subr;
526     int n1, n2, n;
527 
528     if (dict_find_string(pdr, "Private", &Private) <= 0)
529         return 0;
530     if (dict_find_string(Private, "Subrs", &Subrs) <= 0)
531         Subrs = NULL;
532     if (dict_find_string(Private, "GlobalSubrs", &GlobalSubrs) <= 0)
533         GlobalSubrs = NULL;
534     n1 = (Subrs != NULL ? r_size(Subrs) : 0);
535     n2 = (GlobalSubrs != NULL ? r_size(GlobalSubrs) : 0);
536     /* trick : we use the maximum of n1, n2 to pass both Subrs and GlobalSubrs in same array.
537     */
538     n = (n1 < n2 ? n2 : n1);
539     if (index < n && Subrs != NULL) {
540         if (array_get(ff->memory, Subrs, index, &subr) < 0 || r_type(&subr) != t_string)
541             return 0;
542     } else if (index >= n && GlobalSubrs != NULL) {
543         if (array_get(ff->memory,
544 		      GlobalSubrs, index - n, &subr) < 0 || r_type(&subr) != t_string)
545             return 0;
546     } else
547         return 0;
548     return get_type1_data(ff, &subr, buf, buf_length);
549 }
550 
sfnt_get_glyph_offset(ref * pdr,gs_font_type42 * pfont42,int index,ulong * offset0,ulong * offset1)551 private bool sfnt_get_glyph_offset(ref *pdr, gs_font_type42 *pfont42, int index, ulong *offset0, ulong *offset1)
552 {   /* Note : TTC is not supported and probably is unuseful for Type 42. */
553     sfnts_reader r;
554     int glyf_elem_size = (2 << pfont42->data.indexToLocFormat);
555 
556     sfnts_reader_init(&r, pdr);
557     r.seek(&r, pfont42->data.loca + index * glyf_elem_size);
558     *offset0 = pfont42->data.glyf + (glyf_elem_size == 2 ? r.rword(&r) * 2 : r.rlong(&r));
559     *offset1 = pfont42->data.glyf + (glyf_elem_size == 2 ? r.rword(&r) * 2 : r.rlong(&r));
560     return r.error;
561 }
562 
get_GlyphDirectory_data_ptr(const gs_memory_t * mem,ref * pdr,int char_code,const byte ** ptr)563 private int get_GlyphDirectory_data_ptr(const gs_memory_t *mem,
564 					ref *pdr, int char_code, const byte **ptr)
565 {
566     ref *GlyphDirectory, glyph0, *glyph = &glyph0, glyph_index;
567     if ((dict_find_string(pdr, "GlyphDirectory", &GlyphDirectory) > 0 &&
568          (r_type(GlyphDirectory) == t_dictionary &&
569           ( make_int(&glyph_index, char_code),
570             dict_find(GlyphDirectory, &glyph_index, &glyph) > 0))) ||
571         ((r_type(GlyphDirectory) == t_array &&
572           array_get(mem, GlyphDirectory, char_code, &glyph0) >= 0) &&
573          r_type(glyph) == t_string)) {
574         *ptr = glyph->value.const_bytes;
575 	return r_size(glyph);
576     }
577     return -1;
578 }
579 
get_MetricsCount(FAPI_font * ff)580 private bool get_MetricsCount(FAPI_font *ff)
581 {   if (!ff->is_type1 && ff->is_cid) {
582 	gs_font_cid2 *pfcid = (gs_font_cid2 *)ff->client_font_data;
583 
584 	return pfcid->cidata.MetricsCount;
585     }
586     return 0;
587 }
588 
589 
590 
FAPI_FF_get_glyph(FAPI_font * ff,int char_code,byte * buf,ushort buf_length)591 private ushort FAPI_FF_get_glyph(FAPI_font *ff, int char_code, byte *buf, ushort buf_length)
592 {   /*
593      * We assume that renderer requests glyph data with multiple consequtive
594      * calls to this function.
595      *
596      * For a simple glyph it calls this
597      * function exactly twice : first with buf == NULL for requesting
598      * the necessary buffer length, and second with
599      * buf != NULL for requesting the data (the second call may be skept
600      * if the renderer discontinues the rendering on an exception).
601      *
602      * For a composite glyph it calls this function 2 * (N + 1)
603      * times : 2 calls for the main glyph (same as above) followed with
604      * 2 * N calls for subglyphs, where N is less or equal to the number of
605      * subglyphs ( N may be less if the renderer caches glyph data,
606      * or discontinues the rendering on an exception).
607      */
608     ref *pdr = (ref *)ff->client_font_data2;
609     ushort glyph_length;
610 
611     if (ff->is_type1) {
612         if (ff->is_cid) {
613             const ref *glyph = ff->char_data;
614 
615             glyph_length = get_type1_data(ff, glyph, buf, buf_length);
616         } else {
617             ref *CharStrings, char_name, *glyph;
618             if (ff->char_data != NULL) {
619 		/*
620 		 * Can't use char_code in this case because hooked Type 1 fonts
621 		 * with 'glyphshow' may render a character which has no
622 		 * Encoding entry.
623 		 */
624                 if (name_ref(ff->memory, ff->char_data,
625 			     ff->char_data_len, &char_name, -1) < 0)
626 		    return -1;
627 		if (buf != NULL) {
628 		    /*
629 		     * Trigger the next call to the 'seac' case below.
630 		     * Here we use the assumption about call sequence
631 		     * being documented above.
632 		     */
633 		    ff->char_data = NULL;
634 		}
635 	    }  else { /* seac */
636 		i_ctx_t *i_ctx_p = (i_ctx_t *)ff->client_ctx_p;
637 		ref *StandardEncoding;
638 
639 		if (dict_find_string(systemdict, "StandardEncoding", &StandardEncoding) <= 0 ||
640 		    array_get(ff->memory, StandardEncoding, char_code, &char_name) < 0)
641 		    if (name_ref(ff->memory, (const byte *)".notdef", 7, &char_name, -1) < 0)
642 			return -1;
643 	    }
644             if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0)
645                 return -1;
646             if (dict_find(CharStrings, &char_name, &glyph) <= 0)
647                 return -1;
648             glyph_length = get_type1_data(ff, glyph, buf, buf_length);
649         }
650     } else { /* type 42 */
651 	const byte *data_ptr;
652 	int l = get_GlyphDirectory_data_ptr(ff->memory, pdr, char_code, &data_ptr);
653 
654 	if (l >= 0) {
655 	    int MetricsCount = get_MetricsCount(ff), mc = MetricsCount << 1;
656 
657             glyph_length = max((ushort)(l - mc), 0); /* safety */
658             if (buf != 0 && glyph_length > 0)
659                 memcpy(buf, data_ptr + mc, min(glyph_length, buf_length)/* safety */);
660         } else {
661             gs_font_type42 *pfont42 = (gs_font_type42 *)ff->client_font_data;
662             ulong offset0, offset1;
663             bool error = sfnt_get_glyph_offset(pdr, pfont42, char_code, &offset0, &offset1);
664 
665             glyph_length = (error ? -1 : offset1 - offset0);
666             if (buf != 0 && !error) {
667                 sfnts_reader r;
668                 sfnts_reader_init(&r, pdr);
669 
670                 r.seek(&r, offset0);
671                 r.rstring(&r, buf, min(glyph_length, buf_length)/* safety */);
672                 if (r.error)
673                     glyph_length = -1;
674             }
675         }
676     }
677     return glyph_length;
678 }
679 
680 private const FAPI_font ff_stub = {
681     0, /* server_font_data */
682     0, /* need_decrypt */
683     NULL, /* const gs_memory_t */
684     0, /* font_file_path */
685     0, /* subfont */
686     false, /* is_type1 */
687     false, /* is_cid */
688     false, /* is_mtx_skipped */
689     0, /* client_ctx_p */
690     0, /* client_font_data */
691     0, /* client_font_data2 */
692     0, /* char_data */
693     0, /* char_data_len */
694     FAPI_FF_get_word,
695     FAPI_FF_get_long,
696     FAPI_FF_get_float,
697     FAPI_FF_get_subr,
698     FAPI_FF_get_glyph,
699     FAPI_FF_serialize_tt_font
700 };
701 
FAPI_get_xlatmap(i_ctx_t * i_ctx_p,char ** xlatmap)702 private int FAPI_get_xlatmap(i_ctx_t *i_ctx_p, char **xlatmap)
703 {   ref *pref;
704     int code;
705 
706     if ((code = dict_find_string(systemdict, ".xlatmap", &pref)) < 0)
707 	return code;
708     if (r_type(pref) != t_string)
709         return_error(e_typecheck);
710     *xlatmap = (char *)pref->value.bytes;
711     /*  Note : this supposes that xlatmap doesn't move in virtual memory.
712         Garbager must not be called while plugin executes get_scaled_font, get_decodingID.
713         Fix some day with making copy of xlatmap in system memory.
714     */
715     return 0;
716 }
717 
renderer_retcode(i_ctx_t * i_ctx_p,FAPI_server * I,FAPI_retcode rc)718 private int renderer_retcode(i_ctx_t *i_ctx_p, FAPI_server *I, FAPI_retcode rc)
719 {   if (rc == 0)
720 	return 0;
721     eprintf2("Error: Font Renderer Plugin ( %s ) return code = %d\n", I->ig.d->subtype, rc);
722     return rc < 0 ? rc : e_invalidfont;
723 }
724 
zFAPIavailable(i_ctx_t * i_ctx_p)725 private int zFAPIavailable(i_ctx_t *i_ctx_p)
726 {   i_plugin_holder *h = i_plugin_get_list(i_ctx_p);
727     bool available = true;
728     os_ptr op = osp;
729 
730     for (; h != 0; h = h->next)
731        	if (!strcmp(h->I->d->type,"FAPI"))
732             goto found;
733     available = false;
734     found :
735     push(1);
736     make_bool(op, available);
737     return 0;
738 }
739 
740 
FAPI_find_plugin(i_ctx_t * i_ctx_p,const char * subtype,FAPI_server ** pI)741 private int FAPI_find_plugin(i_ctx_t *i_ctx_p, const char *subtype, FAPI_server **pI)
742 {   i_plugin_holder *h = i_plugin_get_list(i_ctx_p);
743     int code;
744 
745     for (; h != 0; h = h->next)
746        	if (!strcmp(h->I->d->type,"FAPI"))
747 	    if (!strcmp(h->I->d->subtype, subtype)) {
748 	        FAPI_server *I = *pI = (FAPI_server *)h->I;
749 
750 	        if ((code = renderer_retcode(i_ctx_p, I, I->ensure_open(I))) < 0)
751 		    return code;
752 	        return 0;
753 	    }
754     return_error(e_invalidfont);
755 }
756 
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)757 private int FAPI_prepare_font(i_ctx_t *i_ctx_p, FAPI_server *I, ref *pdr, gs_font_base *pbfont,
758                               const char *font_file_path, const FAPI_font_scale *font_scale,
759 			      const char *xlatmap, int BBox[4], const char **decodingID)
760 {   /* Returns 1 iff BBox is set. */
761     /* Cleans up server's font data if failed. */
762 
763     /* A renderer may need to access the top level font's data of
764      * a CIDFontType 0 (FontType 9) font while preparing its subfonts,
765      * and/or perform a completion action with the top level font after
766      * its descendants are prepared. Therefore with such fonts
767      * we first call get_scaled_font(..., FAPI_TOPLEVEL_BEGIN), then
768      * get_scaled_font(..., i) with eash descendant font index i,
769      * and then get_scaled_font(..., FAPI_TOPLEVEL_COMPLETE).
770      * For other fonts we don't call with 'i'.
771      *
772      * Actually server's data for top level CIDFontTYpe 0 non-disk fonts should not be important,
773      * because with non-disk fonts FAPI_do_char never deals with the top-level font,
774      * but does with its descendants individually.
775      * Therefore a recommendation for the renderer is don't build any special
776      * data for the top-level non-disk font of CIDFontType 0, but return immediately
777      * with success code and NULL data pointer.
778      *
779      * get_scaled_font may be called for same font at second time,
780      * so the renderen must check whether the data is already built.
781      */
782     int code, bbox_set = 0, subfont = 0;
783     FAPI_font ff = ff_stub;
784     ref *SubfontId;
785 
786     if (dict_find_string(pdr, "SubfontId", &SubfontId) >= 0 && r_has_type(SubfontId, t_integer))
787         subfont = SubfontId->value.intval;
788     ff.font_file_path = font_file_path;
789     ff.is_type1 = IsType1GlyphData(pbfont);
790     ff.memory = imemory;
791     ff.client_ctx_p = i_ctx_p;
792     ff.client_font_data = pbfont;
793     ff.client_font_data2 = pdr;
794     ff.server_font_data = pbfont->FAPI_font_data; /* Possibly pass it from zFAPIpassfont. */
795     ff.is_cid = IsCIDFont(pbfont);
796     ff.is_mtx_skipped = (get_MetricsCount(&ff) != 0);
797     if ((code = renderer_retcode(i_ctx_p, I, I->get_scaled_font(I, &ff, subfont,
798                                          font_scale, xlatmap, false, FAPI_TOPLEVEL_BEGIN))) < 0)
799 	return code;
800     pbfont->FAPI_font_data = ff.server_font_data; /* Save it back to GS font. */
801     if (ff.server_font_data != 0) {
802 	if ((code = renderer_retcode(i_ctx_p, I, I->get_font_bbox(I, &ff, BBox))) < 0) {
803 	    I->release_typeface(I, ff.server_font_data);
804 	    return code;
805 	}
806 	bbox_set = 1;
807     }
808     if (xlatmap != NULL && pbfont->FAPI_font_data != NULL)
809 	if ((code = renderer_retcode(i_ctx_p, I, I->get_decodingID(I, &ff, decodingID))) < 0) {
810 	    I->release_typeface(I, pbfont->FAPI_font_data);
811 	    pbfont->FAPI_font_data = 0;
812 	    return code;
813 	}
814     /* Prepare descendant fonts : */
815     if (font_file_path == NULL && ff.is_type1 && ff.is_cid) { /* Renderers should expect same condition. */
816         gs_font_cid0 *pfcid = (gs_font_cid0 *)pbfont;
817         gs_font_type1 **FDArray = pfcid->cidata.FDArray;
818         int i, n = pfcid->cidata.FDArray_size;
819         ref *rFDArray, f;
820 
821         if (dict_find_string(pdr, "FDArray", &rFDArray) <= 0 || r_type(rFDArray) != t_array)
822             return_error(e_invalidfont);
823         ff = ff_stub;
824         ff.is_type1 = true;
825 	ff.memory = imemory;
826 	ff.client_ctx_p = i_ctx_p;
827         for (i = 0; i < n; i++) {
828             gs_font_type1 *pbfont1 = FDArray[i];
829 	    int BBox_temp[4];
830 
831             pbfont1->FontBBox = pbfont->FontBBox; /* Inherit FontBBox from the type 9 font. */
832             if(array_get(imemory, rFDArray, i, &f) < 0 || r_type(&f) != t_dictionary)
833                 return_error(e_invalidfont);
834             ff.client_font_data = pbfont1;
835             pbfont1->FAPI = pbfont->FAPI;
836             ff.client_font_data2 = &f;
837             ff.server_font_data = pbfont1->FAPI_font_data;
838             ff.is_cid = true;
839 	    ff.is_mtx_skipped = (get_MetricsCount(&ff) != 0);
840             if ((code = renderer_retcode(i_ctx_p, I, I->get_scaled_font(I, &ff, 0,
841 	                                 font_scale, NULL, false, i))) < 0)
842 		break;
843             pbfont1->FAPI_font_data = ff.server_font_data; /* Save it back to GS font. */
844 	    /* Try to do something with the descendant font to ensure that it's working : */
845 	    if ((code = renderer_retcode(i_ctx_p, I, I->get_font_bbox(I, &ff, BBox_temp))) < 0)
846 		break;
847         }
848 	if (i == n) {
849 	    code = renderer_retcode(i_ctx_p, I, I->get_scaled_font(I, &ff, subfont,
850 	                                 font_scale, NULL, false, FAPI_TOPLEVEL_COMPLETE));
851 	    if (code >= 0)
852 		return bbox_set; /* Full success. */
853 	}
854 	/* Fail, release server's font data : */
855         for (i = 0; i < n; i++) {
856             gs_font_type1 *pbfont1 = FDArray[i];
857 
858 	    if (pbfont1->FAPI_font_data != NULL)
859 		I->release_typeface(I, pbfont1->FAPI_font_data);
860 	    pbfont1->FAPI_font_data = 0;
861 	}
862 	if (pbfont->FAPI_font_data != NULL)
863 	    I->release_typeface(I, pbfont->FAPI_font_data);
864 	pbfont->FAPI_font_data = 0;
865 	return_error(e_invalidfont);
866     } else {
867 	code = renderer_retcode(i_ctx_p, I, I->get_scaled_font(I, &ff, subfont,
868 	                                 font_scale, xlatmap, false, FAPI_TOPLEVEL_COMPLETE));
869         if (code < 0) {
870 	    I->release_typeface(I, pbfont->FAPI_font_data);
871 	    pbfont->FAPI_font_data = 0;
872 	    return code;
873         }
874 	return bbox_set;
875     }
876 }
877 
FAPI_refine_font(i_ctx_t * i_ctx_p,os_ptr op,gs_font_base * pbfont,const char * font_file_path)878 private int FAPI_refine_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base *pbfont, const char *font_file_path)
879 {   ref *pdr = op;  /* font dict */
880     double size, size1;
881     int BBox[4], scale;
882     const char *decodingID = NULL;
883     char *xlatmap = NULL;
884     FAPI_server *I = pbfont->FAPI;
885     FAPI_font_scale font_scale = {{1, 0, 0, 1, 0, 0}, {0, 0}, {1, 1}, true};
886     int code;
887 
888     if (font_file_path != NULL && pbfont->FAPI_font_data == NULL)
889         if ((code = FAPI_get_xlatmap(i_ctx_p, &xlatmap)) < 0)
890 	    return code;
891     scale = 1 << I->frac_shift;
892     size1 = size = 1 / hypot(pbfont->FontMatrix.xx, pbfont->FontMatrix.xy);
893     if (size < 1000)
894 	size = 1000;
895     if (size1 > 100)
896         size1 = (int)(size1 + 0.5);
897     font_scale.matrix[0] = font_scale.matrix[3] = (int)(size * scale + 0.5);
898     font_scale.HWResolution[0] = (FracInt)(72 * scale);
899     font_scale.HWResolution[1] = (FracInt)(72 * scale);
900 
901     code = FAPI_prepare_font(i_ctx_p, I, pdr, pbfont, font_file_path, &font_scale, xlatmap, BBox, &decodingID);
902     if (code < 0)
903 	return code;
904 
905     if (code > 0) {
906 	/* Refine FontBBox : */
907 	ref *v, x0, y0, x1, y1;
908 
909 	pbfont->FontBBox.p.x = (double)BBox[0] * size1 / size;
910 	pbfont->FontBBox.p.y = (double)BBox[1] * size1 / size;
911 	pbfont->FontBBox.q.x = (double)BBox[2] * size1 / size;
912 	pbfont->FontBBox.q.y = (double)BBox[3] * size1 / size;
913 	if (dict_find_string(op, "FontBBox", &v) <= 0 || !r_has_type(v, t_array))
914 	    return_error(e_invalidfont);
915 	if (r_size(v) < 4)
916 	    return_error(e_invalidfont);
917 	make_real(&x0, pbfont->FontBBox.p.x);
918 	make_real(&y0, pbfont->FontBBox.p.y);
919 	make_real(&x1, pbfont->FontBBox.q.x);
920 	make_real(&y1, pbfont->FontBBox.q.y);
921 	ref_assign_old(v, v->value.refs + 0, &x0, "FAPI_refine_font_BBox");
922 	ref_assign_old(v, v->value.refs + 1, &y0, "FAPI_refine_font_BBox");
923 	ref_assign_old(v, v->value.refs + 2, &x1, "FAPI_refine_font_BBox");
924 	ref_assign_old(v, v->value.refs + 3, &y1, "FAPI_refine_font_BBox");
925     }
926 
927     /* Assign a Decoding : */
928     if (decodingID != 0 && *decodingID) {
929        ref Decoding;
930 
931        if (IsCIDFont(pbfont)) {
932             ref *CIDSystemInfo, *Ordering, SubstNWP;
933             byte buf[30];
934             int ordering_length, decodingID_length = min(strlen(decodingID), sizeof(buf) - 2);
935 
936             if (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) <= 0 || !r_has_type(CIDSystemInfo, t_dictionary))
937                 return_error(e_invalidfont);
938             if (dict_find_string(CIDSystemInfo, "Ordering", &Ordering) <= 0 || !r_has_type(Ordering, t_string))
939                 return_error(e_invalidfont);
940             ordering_length = min(r_size(Ordering), sizeof(buf) - 2 - decodingID_length);
941             memcpy(buf, Ordering->value.const_bytes, ordering_length);
942             if ((code = name_ref(imemory, buf, ordering_length, &SubstNWP, 0)) < 0)
943 		return code;
944             if ((code = dict_put_string(pdr, "SubstNWP", &SubstNWP, NULL)) < 0)
945 		return code;
946             buf[ordering_length] = '.';
947             memcpy(buf + ordering_length + 1, decodingID, decodingID_length);
948             buf[decodingID_length + 1 + ordering_length] = 0; /* Debug purpose only */
949             if ((code = name_ref(imemory, buf,
950 				 decodingID_length + 1 + ordering_length, &Decoding, 0)) < 0)
951 		return code;
952         } else
953             if ((code = name_ref(imemory, (const byte *)decodingID,
954 				 strlen(decodingID), &Decoding, 0)) < 0)
955 		return code;
956         if ((code = dict_put_string(pdr, "Decoding", &Decoding, NULL)) < 0)
957 	    return code;
958     }
959     return 0;
960 }
961 
notify_remove_font(void * proc_data,void * event_data)962 private int notify_remove_font(void *proc_data, void *event_data)
963 {   /* gs_font_finalize passes event_data == NULL, so check it here. */
964     if (event_data == NULL) {
965         gs_font_base *pbfont = proc_data;
966 
967         if (pbfont->FAPI_font_data != 0)
968             pbfont->FAPI->release_typeface(pbfont->FAPI, pbfont->FAPI_font_data);
969     }
970     return 0;
971 }
972 
973 /*  <string|name> <font> <is_disk_font> .rebuildfontFAPI <string|name> <font> */
974 /*  Rebuild a font for handling it with an external renderer.
975 
976     The font was built as a native GS font to allow easy access
977     to font features. Then zFAPIrebuildfont sets FAPI entry
978     into gx_font_base and replaces BuildGlyph and BuildChar
979     to enforce the FAPI handling.
980 
981     This operator must not be called with devices which embed fonts.
982 
983 */
zFAPIrebuildfont(i_ctx_t * i_ctx_p)984 private int zFAPIrebuildfont(i_ctx_t *i_ctx_p)
985 {   os_ptr op = osp;
986     build_proc_refs build;
987     gs_font *pfont;
988 
989     int code = font_param(op - 1, &pfont), code1;
990     gs_font_base *pbfont = (gs_font_base *)pfont;
991     ref *v;
992     char *font_file_path = NULL, FAPI_ID[20];
993     const byte *pchars;
994     uint len;
995     font_data *pdata;
996 
997     if (code < 0)
998 	return code;
999     check_type(*op, t_boolean);
1000     if (pbfont->FAPI != 0) {
1001         /*  If the font was processed with zFAPIpassfont,
1002             it already has an attached FAPI and server_font_data.
1003             Don't change them here.
1004         */
1005     } else {
1006         if (dict_find_string(op - 1, "FAPI", &v) <= 0 || !r_has_type(v, t_name))
1007 	    return_error(e_invalidfont);
1008         obj_string_data(imemory, v, &pchars, &len);
1009         len = min(len, sizeof(FAPI_ID) - 1);
1010         strncpy(FAPI_ID, (const char *)pchars, len);
1011         FAPI_ID[len] = 0;
1012         if ((code = FAPI_find_plugin(i_ctx_p, FAPI_ID, &pbfont->FAPI)) < 0)
1013 	    return code;
1014     }
1015     pdata = (font_data *)pfont->client_data;
1016     if (dict_find_string(op - 1, "Path", &v) <= 0 || !r_has_type(v, t_string))
1017         v = NULL;
1018     if (pfont->FontType == ft_CID_encrypted && v == NULL) {
1019         if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildGlyph9", ".FAPIBuildGlyph9")) < 0)
1020 	    return code;
1021     } else
1022         if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildChar", ".FAPIBuildGlyph")) < 0)
1023 	    return code;
1024     if (name_index(imemory, &pdata->BuildChar) == name_index(imemory, &build.BuildChar)) {
1025         /* Already rebuilt - maybe a substituted font. */
1026     } else {
1027         ref_assign_new(&pdata->BuildChar, &build.BuildChar);
1028         ref_assign_new(&pdata->BuildGlyph, &build.BuildGlyph);
1029         if (v != NULL)
1030             font_file_path = ref_to_string(v, imemory_global, "font file path");
1031         code = FAPI_refine_font(i_ctx_p, op - 1, pbfont, font_file_path);
1032         if (font_file_path != NULL)
1033             gs_free_string(imemory_global, (byte *)font_file_path, r_size(v) + 1, "font file path");
1034         code1 = gs_notify_register(&pfont->notify_list, notify_remove_font, pbfont);
1035         (void)code1;  /* Recover possible error just ignoring it. */
1036     }
1037     pop(1);
1038     return code;
1039 }
1040 
array_find(const gs_memory_t * mem,ref * Encoding,ref * char_name)1041 private ulong array_find(const gs_memory_t *mem, ref *Encoding, ref *char_name) {
1042     ulong n = r_size(Encoding), i;
1043     ref v;
1044     for (i = 0; i < n; i++)
1045         if (array_get(mem, Encoding, i, &v) < 0)
1046             break;
1047         else if(r_type(char_name) == r_type(&v) && char_name->value.const_pname == v.value.const_pname)
1048             return i;
1049     return 0;
1050 }
1051 
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)1052 private 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)
1053 {   FAPI_path path_interface = path_interface_stub;
1054     FAPI_outline_handler olh;
1055     int code;
1056 
1057     olh.path = path;
1058     olh.x0 = penum_s->pgs->ctm.tx_fixed;
1059     olh.y0 = penum_s->pgs->ctm.ty_fixed;
1060     olh.close_path = close_path;
1061     olh.need_close = false;
1062     path_interface.olh = &olh;
1063     path_interface.shift = import_shift_v;
1064     if ((code = renderer_retcode(i_ctx_p, I, I->get_char_outline(I, &path_interface))) < 0)
1065 	return code;
1066     if (olh.need_close && olh.close_path)
1067         if ((code = add_closepath(&path_interface)) < 0)
1068 	    return code;
1069     return 0;
1070 }
1071 
compute_em_scale(const gs_font_base * pbfont,FAPI_metrics * metrics,double FontMatrix_div,double * em_scale_x,double * em_scale_y)1072 private void compute_em_scale(const gs_font_base *pbfont, FAPI_metrics *metrics, double FontMatrix_div, double *em_scale_x, double *em_scale_y)
1073 {   /* optimize : move this stuff to FAPI_refine_font */
1074     gs_matrix *m = &pbfont->base->FontMatrix;
1075     int rounding_x, rounding_y; /* Striking out the 'float' representation error in FontMatrix. */
1076     double sx, sy;
1077 
1078     sx = hypot(m->xx, m->xy) * metrics->em_x / FontMatrix_div;
1079     sy = hypot(m->yx, m->yy) * metrics->em_y / FontMatrix_div;
1080     rounding_x = (int)(0x00800000 / sx);
1081     rounding_y = (int)(0x00800000 / sy);
1082     *em_scale_x = (int)(sx * rounding_x + 0.5) / (double)rounding_x;
1083     *em_scale_y = (int)(sy * rounding_y + 0.5) / (double)rounding_y;
1084 }
1085 
fapi_copy_mono(gx_device * dev1,FAPI_raster * rast,int dx,int dy)1086 private int fapi_copy_mono(gx_device *dev1, FAPI_raster *rast, int dx, int dy)
1087 {   if ((rast->line_step & (align_bitmap_mod - 1)) == 0)
1088         return dev_proc(dev1, copy_mono)(dev1, rast->p, 0, rast->line_step, 0, dx, dy, rast->width, rast->height, 0, 1);
1089     else { /* bitmap data needs to be aligned, make the aligned copy : */
1090         int line_step = bitmap_raster(rast->width), code;
1091         byte *p = gs_alloc_byte_array(dev1->memory, rast->height, line_step, "fapi_copy_mono");
1092         byte *q = p, *r = rast->p, *pe;
1093         if (p == NULL)
1094             return_error(e_VMerror);
1095         pe = p + rast->height * line_step;
1096         for (; q < pe; q+=line_step, r += rast->line_step)
1097             memcpy(q, r, rast->line_step);
1098         code = dev_proc(dev1, copy_mono)(dev1, p, 0, line_step, 0, dx, dy, rast->width, rast->height, 0, 1);
1099         gs_free_object(dev1->memory, p, "fapi_copy_mono");
1100         return code;
1101     }
1102 }
1103 
1104 private const int frac_pixel_shift = 4;
1105 
fapi_finish_render_aux(i_ctx_t * i_ctx_p,gs_font_base * pbfont,FAPI_server * I)1106 private int fapi_finish_render_aux(i_ctx_t *i_ctx_p, gs_font_base *pbfont, FAPI_server *I)
1107 {   gs_text_enum_t *penum = op_show_find(i_ctx_p);
1108     gs_show_enum *penum_s = (gs_show_enum *)penum;
1109     gs_state *pgs = penum_s->pgs;
1110     gx_device *dev1 = gs_currentdevice_inline(pgs); /* Possibly changed by zchar_set_cache. */
1111     gx_device *dev = penum_s->dev;
1112     const int import_shift_v = _fixed_shift - I->frac_shift;
1113     FAPI_raster rast;
1114     int code;
1115 
1116     if (SHOW_IS(penum, TEXT_DO_NONE)) {
1117         /* do nothing */
1118     } else if (igs->in_charpath) {
1119         if ((code = outline_char(i_ctx_p, I, import_shift_v, penum_s, pgs->show_gstate->path, !pbfont->PaintType)) < 0)
1120 	    return code;
1121     } else {
1122         int code = I->get_char_raster(I, &rast);
1123         if (code == e_limitcheck) {
1124             /* The rerver provides an outline instead the raster. */
1125             gs_imager_state *pis = (gs_imager_state *)pgs->show_gstate;
1126             gs_point pt;
1127             if ((code = gs_currentpoint(pgs->show_gstate, &pt)) < 0)
1128 		return code;
1129             if ((code = outline_char(i_ctx_p, I, import_shift_v, penum_s, pgs->show_gstate->path, !pbfont->PaintType)) < 0)
1130 		return code;
1131             if ((code = gs_imager_setflat(pis, gs_char_flatness(pis, 1.0))) < 0)
1132 		return code;
1133             if (pbfont->PaintType) {
1134                 if ((code = gs_stroke(pgs->show_gstate)) < 0)
1135 		    return code;
1136             } else
1137                 if ((code = gs_fill(pgs->show_gstate)) < 0)
1138 		    return code;
1139             if ((code = gs_moveto(pgs->show_gstate, pt.x, pt.y)) < 0)
1140 		return code;
1141         } else {
1142 	    int rast_orig_x =   rast.orig_x - (int)(penum_s->fapi_glyph_shift.x * (1 << frac_pixel_shift));
1143 	    int rast_orig_y = - rast.orig_y - (int)(penum_s->fapi_glyph_shift.y * (1 << frac_pixel_shift));
1144 
1145             if ((code = renderer_retcode(i_ctx_p, I, code)) < 0)
1146 		return code;
1147             if (pgs->in_cachedevice == CACHE_DEVICE_CACHING) { /* Using GS cache */
1148                 /*  GS and renderer may transform coordinates few differently.
1149                     The best way is to make set_cache_device to take the renderer's bitmap metrics immediately,
1150                     but we need to account CDevProc, which may truncate the bitmap.
1151                     Perhaps GS overestimates the bitmap size,
1152                     so now we only add a compensating shift - the dx and dy.
1153                 */
1154                 int shift_rd = _fixed_shift  - frac_pixel_shift;
1155                 int rounding = 1 << (frac_pixel_shift - 1);
1156                 int dx = arith_rshift_slow((pgs->ctm.tx_fixed >> shift_rd) + rast_orig_x + rounding, frac_pixel_shift);
1157                 int dy = arith_rshift_slow((pgs->ctm.ty_fixed >> shift_rd) + rast_orig_y + rounding, frac_pixel_shift);
1158                 if ((code = fapi_copy_mono(dev1, &rast, dx, dy)) < 0)
1159 		    return code;
1160             } else { /* Not using GS cache */
1161 	        const gx_clip_path * pcpath = i_ctx_p->pgs->clip_path;
1162                 const gx_drawing_color * pdcolor = penum->pdcolor;
1163 	        if ((code = dev_proc(dev, fill_mask)(dev, rast.p, 0, rast.line_step, 0,
1164 			          (int)(penum_s->pgs->ctm.tx + (double)rast_orig_x / (1 << frac_pixel_shift) + 0.5),
1165 			          (int)(penum_s->pgs->ctm.ty + (double)rast_orig_y / (1 << frac_pixel_shift) + 0.5),
1166 			          rast.width, rast.height,
1167 			          pdcolor, 1, rop3_default, pcpath)) < 0)
1168 				    return code;
1169             }
1170         }
1171     }
1172     pop(2);
1173     return 0;
1174 }
1175 
fapi_finish_render(i_ctx_t * i_ctx_p)1176 private int fapi_finish_render(i_ctx_t *i_ctx_p)
1177 {   os_ptr op = osp;
1178     gs_font *pfont;
1179     int code = font_param(op - 1, &pfont);
1180 
1181     if (code == 0) {
1182         gs_font_base *pbfont = (gs_font_base *) pfont;
1183         FAPI_server *I = pbfont->FAPI;
1184         code = fapi_finish_render_aux(i_ctx_p, pbfont, I);
1185         I->release_char_data(I);
1186     }
1187     return code;
1188 }
1189 
1190 #define GET_U16_MSB(p) (((uint)((p)[0]) << 8) + (p)[1])
1191 #define GET_S16_MSB(p) (int)((GET_U16_MSB(p) ^ 0x8000) - 0x8000)
1192 
FAPI_do_char(i_ctx_t * i_ctx_p,gs_font_base * pbfont,gx_device * dev,char * font_file_path,bool bBuildGlyph,ref * charstring)1193 private 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)
1194 {   /* Stack : <font> <code|name> --> - */
1195     os_ptr op = osp;
1196     ref *pdr = op - 1;
1197     gs_text_enum_t *penum = op_show_find(i_ctx_p);
1198     gs_show_enum *penum_s = (gs_show_enum *)penum;
1199     /*
1200         fixme: the following code needs to optimize with a maintainence of scaled font objects
1201         in graphics library and in interpreter. Now we suppose that the renderer
1202         uses font cache, so redundant font opening isn't a big expense.
1203     */
1204     FAPI_char_ref cr = {0, false, NULL, 0, 0, 0, 0, 0, FAPI_METRICS_NOTDEF};
1205     const gs_matrix * ctm = &ctm_only(igs);
1206     int scale;
1207     FAPI_font_scale font_scale = {{1, 0, 0, 1, 0, 0}, {0, 0}, {1, 1}, true};
1208     FAPI_metrics metrics;
1209     FAPI_server *I = pbfont->FAPI;
1210     int client_char_code = 0;
1211     ref char_name, *SubfontId;
1212     int subfont = 0;
1213     bool is_TT_from_type42 = (pbfont->FontType == ft_TrueType && font_file_path == NULL);
1214     bool is_embedded_type1 = ((pbfont->FontType == ft_encrypted ||
1215 			       pbfont->FontType == ft_encrypted2) &&
1216 			      font_file_path == NULL);
1217     bool bCID = (IsCIDFont(pbfont) || charstring != NULL);
1218     bool bIsType1GlyphData = IsType1GlyphData(pbfont);
1219     FAPI_font ff = ff_stub;
1220     gs_log2_scale_point log2_scale = {0, 0};
1221     int alpha_bits = (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
1222     double FontMatrix_div = (bCID && bIsType1GlyphData && font_file_path == NULL ? 1000 : 1);
1223     bool bVertical = (gs_rootfont(igs)->WMode != 0), bVertical0 = bVertical;
1224     double sbw[4] = {0, 0, 0, 0};
1225     double em_scale_x, em_scale_y;
1226     gs_rect char_bbox;
1227     op_proc_t exec_cont = 0;
1228     int code;
1229     enum {
1230 	SBW_DONE,
1231 	SBW_SCALE,
1232 	SBW_FROM_RENDERER
1233     } sbw_state = SBW_SCALE;
1234 
1235     if(bBuildGlyph && !bCID) {
1236         check_type(*op, t_name);
1237     } else
1238         check_type(*op, t_integer);
1239 
1240     /* Compute the sacle : */
1241     if (!SHOW_IS(penum, TEXT_DO_NONE) && !igs->in_charpath) {
1242         gs_currentcharmatrix(igs, NULL, 1); /* make char_tm valid */
1243         penum_s->fapi_log2_scale.x = -1;
1244         gx_compute_text_oversampling(penum_s, (gs_font *)pbfont, alpha_bits, &log2_scale);
1245         penum_s->fapi_log2_scale = log2_scale;
1246     }
1247 retry_oversampling:
1248     font_scale.subpixels[0] = 1 << log2_scale.x;
1249     font_scale.subpixels[1] = 1 << log2_scale.y;
1250     font_scale.align_to_pixels = gs_currentaligntopixels(pbfont->dir);
1251     if (penum == 0)
1252 	return_error(e_undefined);
1253     scale = 1 << I->frac_shift;
1254     {   gs_matrix *base_font_matrix = &pbfont->base->FontMatrix;
1255         double dx = hypot(base_font_matrix->xx, base_font_matrix->xy);
1256         double dy = hypot(base_font_matrix->yx, base_font_matrix->yy);
1257         /*  Trick : we need to restore the font scale from ctm, pbfont->FontMatrix,
1258             and base_font_matrix. We assume that base_font_matrix is
1259             a multiple of pbfont->FontMatrix with a constant from scalefont.
1260             But we cannot devide ctm by pbfont->FontMatrix for getting
1261             a proper result: the base_font_matrix may be XY transposition,
1262             but we must not cut out the transposition from ctm.
1263             Therefore we use the norm of base_font_matrix columns as the divisors
1264             for X and Y. It is not clear what to do when base_font_matrix is anisotropic
1265             (i.e. dx != dy), but we did not meet such fonts before now.
1266         */
1267         font_scale.matrix[0] =  (FracInt)(ctm->xx * FontMatrix_div / dx * 72 / dev->HWResolution[0] * scale);
1268         font_scale.matrix[1] = -(FracInt)(ctm->xy * FontMatrix_div / dy * 72 / dev->HWResolution[0] * scale);
1269         font_scale.matrix[2] =  (FracInt)(ctm->yx * FontMatrix_div / dx * 72 / dev->HWResolution[1] * scale);
1270         font_scale.matrix[3] = -(FracInt)(ctm->yy * FontMatrix_div / dy * 72 / dev->HWResolution[1] * scale);
1271         font_scale.matrix[4] =  (FracInt)(ctm->tx * FontMatrix_div / dx * 72 / dev->HWResolution[0] * scale);
1272         font_scale.matrix[5] =  (FracInt)(ctm->ty * FontMatrix_div / dy * 72 / dev->HWResolution[1] * scale);
1273         /* Note: the ctm mapping here is upside down. */
1274     }
1275     font_scale.HWResolution[0] = (FracInt)((double)dev->HWResolution[0] * font_scale.subpixels[0] * scale);
1276     font_scale.HWResolution[1] = (FracInt)((double)dev->HWResolution[1] * font_scale.subpixels[1] * scale);
1277 
1278     /* Prepare font data : */
1279     if (dict_find_string(pdr, "SubfontId", &SubfontId) > 0 && r_has_type(SubfontId, t_integer))
1280         subfont = SubfontId->value.intval;
1281     ff.memory = pbfont->memory;
1282     ff.font_file_path = font_file_path;
1283     ff.client_font_data = pbfont;
1284     ff.client_font_data2 = pdr;
1285     ff.server_font_data = pbfont->FAPI_font_data;
1286     ff.is_type1 = bIsType1GlyphData;
1287     ff.is_cid = bCID;
1288     ff.is_mtx_skipped = (get_MetricsCount(&ff) != 0);
1289     ff.client_ctx_p = i_ctx_p;
1290     if ((code = renderer_retcode(i_ctx_p, I, I->get_scaled_font(I, &ff, subfont, &font_scale,
1291 				 NULL, bVertical,
1292 				 (!bCID || (pbfont->FontType != ft_encrypted  &&
1293 				            pbfont->FontType != ft_encrypted2)
1294 				        ? FAPI_TOPLEVEL_PREPARED : FAPI_DESCENDANT_PREPARED)))) < 0)
1295 	return code;
1296     /* fixme : it would be nice to call get_scaled_font at once for entire 'show' string. */
1297 
1298     /* Obtain the character name : */
1299     if (bCID) {
1300 	int_param(op, 0xFFFF, &client_char_code);
1301         make_null(&char_name);
1302     } else if (r_has_type(op, t_integer)) {
1303 	/* Translate from PS encoding to char name : */
1304 	ref *Encoding;
1305 	int_param(op, 0xFF, &client_char_code);
1306         if (dict_find_string(pdr, "Encoding", &Encoding) > 0 &&
1307             (r_has_type(Encoding, t_array) || r_has_type(Encoding, t_shortarray))) {
1308 	    if (array_get(imemory, Encoding, client_char_code, &char_name) < 0)
1309 	        if ((code = name_ref(imemory, (const byte *)".notdef", 7, &char_name, -1)) < 0)
1310 		    return code;
1311 	} else
1312             return_error(e_invalidfont);
1313     } else
1314 	char_name = *op;
1315 
1316     /* Obtain the character code or glyph index : */
1317     if (bCID) {
1318         if (font_file_path != NULL) {
1319             ref *Decoding, *SubstNWP, src_type, dst_type;
1320 	    uint c;
1321 
1322             if (dict_find_string(pdr, "Decoding", &Decoding) <= 0 || !r_has_type(Decoding, t_dictionary))
1323                 return_error(e_invalidfont);
1324             if (dict_find_string(pdr, "SubstNWP", &SubstNWP) <= 0 || !r_has_type(SubstNWP, t_array))
1325                 return_error(e_invalidfont);
1326 
1327 	    code = cid_to_TT_charcode(imemory, Decoding, NULL, SubstNWP,
1328 				      client_char_code, &c, &src_type, &dst_type);
1329 	    if (code < 0)
1330 		return code;
1331 	    cr.char_code = c;
1332 	    cr.is_glyph_index = (code == 0);
1333             /* fixme : process the narrow/wide/proportional mapping type,
1334 	       using src_type, dst_type. Should adjust the 'matrix' above.
1335                Call get_font_proportional_feature for proper choice.
1336             */
1337         } else
1338             cr.char_code = client_char_code;
1339     } else if (is_TT_from_type42) {
1340         /* This font must not use 'cmap', so compute glyph index from CharStrings : */
1341 	ref *CharStrings, *glyph_index;
1342         if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0 || !r_has_type(CharStrings, t_dictionary))
1343             return_error(e_invalidfont);
1344         if (dict_find(CharStrings, &char_name, &glyph_index) < 0) {
1345             cr.char_code = 0; /* .notdef */
1346             if ((code = name_ref(imemory, (const byte *)".notdef", 7, &char_name, -1)) < 0)
1347 		return code;
1348         } else if (r_has_type(glyph_index, t_integer))
1349             cr.char_code = glyph_index->value.intval;
1350         else
1351             return_error(e_invalidfont);
1352         cr.is_glyph_index = true;
1353     } else if (is_embedded_type1) {
1354         /*  Since the client passes charstring by callback using ff.char_data,
1355             the client doesn't need to provide a good cr here.
1356             Perhaps since UFST uses char codes as glyph cache keys (UFST 4.2 cannot use names),
1357             we provide font char codes equal to document's char codes.
1358             This trick assumes that Encoding can't point different glyphs
1359             for same char code. The last should be true due to
1360             PLRM3, "5.9.4 Subsetting and Incremental Definition of Glyphs".
1361         */
1362         if (r_has_type(op, t_integer))
1363             cr.char_code = client_char_code;
1364         else {
1365             /*
1366 	     * Reverse Encoding here, because it can be an incremental one.
1367 	     * Note that this can cause problems with UFST (see the comment above),
1368 	     * if the encoding doesn't contain the glyph name rendered with glyphshow.
1369 	     */
1370             ref *Encoding;
1371             if (dict_find_string(osp - 1, "Encoding", &Encoding) > 0)
1372                 cr.char_code = (uint)array_find(imemory, Encoding, op);
1373             else
1374                 return_error(e_invalidfont);
1375         }
1376     } else { /* a non-embedded font, i.e. a disk font */
1377         bool can_retrieve_char_by_name = false;
1378         obj_string_data(imemory, &char_name, &cr.char_name, &cr.char_name_length);
1379         if ((code = renderer_retcode(i_ctx_p, I, I->can_retrieve_char_by_name(I, &ff, &cr, &can_retrieve_char_by_name))) < 0)
1380 	    return code;
1381         if (!can_retrieve_char_by_name) {
1382 	    /* Translate from char name to encoding used with 3d party font technology : */
1383 	    ref *Decoding, *char_code;
1384             if (dict_find_string(osp - 1, "Decoding", &Decoding) > 0 && r_has_type(Decoding, t_dictionary)) {
1385 	        if (dict_find(Decoding, &char_name, &char_code) >= 0 && r_has_type(char_code, t_integer))
1386 		    int_param(char_code, 0xFFFF, &cr.char_code);
1387 	    }
1388         }
1389     }
1390 
1391     /* Provide glyph data for renderer : */
1392     if (!ff.is_cid) {
1393 	ref sname;
1394 	name_string_ref(imemory, &char_name, &sname);
1395         ff.char_data = sname.value.const_bytes;
1396 	ff.char_data_len = r_size(&sname);
1397     } else if (ff.is_type1)
1398         ff.char_data = charstring;
1399 
1400     /* Compute the metrics replacement : */
1401 
1402     if(bCID && !bIsType1GlyphData) {
1403 	gs_font_cid2 *pfcid = (gs_font_cid2 *)pbfont;
1404 	int MetricsCount = pfcid->cidata.MetricsCount;
1405 
1406 	if (MetricsCount > 0) {
1407 	    const byte *data_ptr;
1408 	    int l = get_GlyphDirectory_data_ptr(imemory, pdr, cr.char_code, &data_ptr);
1409 
1410 	    if (MetricsCount == 2 && l >= 4) {
1411 		if (!bVertical0) {
1412 		    cr.sb_x = GET_S16_MSB(data_ptr + 2) * scale;
1413 		    cr.aw_x = GET_U16_MSB(data_ptr + 0) * scale;
1414 		    cr.metrics_type = FAPI_METRICS_REPLACE;
1415 		}
1416 	    } else if (l >= 8){
1417 		cr.sb_y = GET_S16_MSB(data_ptr + 2) * scale;
1418 		cr.aw_y = GET_U16_MSB(data_ptr + 0) * scale;
1419 		cr.sb_x = GET_S16_MSB(data_ptr + 6) * scale;
1420 		cr.aw_x = GET_U16_MSB(data_ptr + 4) * scale;
1421 		cr.metrics_type = FAPI_METRICS_REPLACE;
1422 	    }
1423 	}
1424     }
1425     if (cr.metrics_type != FAPI_METRICS_REPLACE && bVertical) {
1426 	double pwv[4];
1427 	code = zchar_get_metrics2(pbfont, &char_name, pwv);
1428 	if (code < 0)
1429 	    return code;
1430 	if (code == metricsNone) {
1431 	    if (bCID) {
1432 		cr.sb_x = fapi_round(sbw[2] / 2 * scale);
1433 		cr.sb_y = fapi_round(pbfont->FontBBox.q.y * scale);
1434 		cr.aw_y = fapi_round(- pbfont->FontBBox.q.x * scale); /* Sic ! */
1435 		cr.metrics_scale = (bIsType1GlyphData ? 1000 : 1);
1436 		cr.metrics_type = FAPI_METRICS_REPLACE;
1437 		sbw[0] = sbw[2] / 2;
1438 		sbw[1] = pbfont->FontBBox.q.y;
1439 		sbw[2] = 0;
1440 		sbw[3] = - pbfont->FontBBox.q.x; /* Sic ! */
1441 		sbw_state = SBW_DONE;
1442 	    } else
1443 		bVertical = false;
1444 	} else {
1445 	    cr.sb_x = fapi_round(pwv[2] * scale);
1446 	    cr.sb_y = fapi_round(pwv[3] * scale);
1447 	    cr.aw_x = fapi_round(pwv[0] * scale);
1448 	    cr.aw_y = fapi_round(pwv[1] * scale);
1449 	    cr.metrics_scale = (bIsType1GlyphData ? 1000 : 1);
1450 	    cr.metrics_type = (code == metricsSideBearingAndWidth ?
1451 				FAPI_METRICS_REPLACE : FAPI_METRICS_REPLACE_WIDTH);
1452 	    sbw[0] = pwv[2];
1453 	    sbw[1] = pwv[3];
1454 	    sbw[2] = pwv[0];
1455 	    sbw[3] = pwv[1];
1456 	    sbw_state = SBW_DONE;
1457 	}
1458     }
1459     if (cr.metrics_type == FAPI_METRICS_NOTDEF && !bVertical) {
1460 	code = zchar_get_metrics(pbfont, &char_name, sbw);
1461 	if (code < 0)
1462 	    return code;
1463 	if (code == metricsNone) {
1464 	    sbw_state = SBW_FROM_RENDERER;
1465 	    if (pbfont->FontType == 2) {
1466 		gs_font_type1 *pfont1 = (gs_font_type1 *)pbfont;
1467 
1468 		cr.aw_x = export_shift(pfont1->data.defaultWidthX, _fixed_shift - I->frac_shift);
1469 		cr.metrics_scale = 1000;
1470 		cr.metrics_type = FAPI_METRICS_ADD;
1471 	    }
1472 	} else {
1473 	    cr.sb_x = fapi_round(sbw[2] * scale);
1474 	    cr.sb_y = fapi_round(sbw[3] * scale);
1475 	    cr.aw_x = fapi_round(sbw[0] * scale);
1476 	    cr.aw_y = fapi_round(sbw[1] * scale);
1477 	    cr.metrics_scale = (bIsType1GlyphData ? 1000 : 1);
1478 	    cr.metrics_type = (code == metricsSideBearingAndWidth ?
1479 				FAPI_METRICS_REPLACE : FAPI_METRICS_REPLACE_WIDTH);
1480 	    sbw_state = SBW_DONE;
1481 	}
1482     }
1483 
1484     /* Take metrics from font : */
1485     if (SHOW_IS(penum, TEXT_DO_NONE)) {
1486 	if ((code = renderer_retcode(i_ctx_p, I, I->get_char_width(I, &ff, &cr, &metrics))) < 0)
1487 	    return code;
1488     } else if (igs->in_charpath) {
1489         if ((code = renderer_retcode(i_ctx_p, I, I->get_char_outline_metrics(I, &ff, &cr, &metrics))) < 0)
1490 	    return code;
1491     } else {
1492         code = I->get_char_raster_metrics(I, &ff, &cr, &metrics);
1493         if (code == e_limitcheck) {
1494             if(log2_scale.x > 0 || log2_scale.y > 0) {
1495                 penum_s->fapi_log2_scale.x = log2_scale.x = penum_s->fapi_log2_scale.y = log2_scale.y = 0;
1496                 I->release_char_data(I);
1497                 goto retry_oversampling;
1498             }
1499             if ((code = renderer_retcode(i_ctx_p, I, I->get_char_outline_metrics(I, &ff, &cr, &metrics))) < 0)
1500 		return code;
1501         } else {
1502             if ((code = renderer_retcode(i_ctx_p, I, code)) < 0)
1503 		return code;
1504         }
1505     }
1506     compute_em_scale(pbfont, &metrics, FontMatrix_div, &em_scale_x, &em_scale_y);
1507     char_bbox.p.x = metrics.bbox_x0 / em_scale_x;
1508     char_bbox.p.y = metrics.bbox_y0 / em_scale_y;
1509     char_bbox.q.x = metrics.bbox_x1 / em_scale_x;
1510     char_bbox.q.y = metrics.bbox_y1 / em_scale_y;
1511     penum_s->fapi_glyph_shift.x = penum_s->fapi_glyph_shift.y = 0;
1512     if (sbw_state == SBW_FROM_RENDERER) {
1513 	sbw[2] = metrics.escapement / em_scale_x;
1514 	if (pbfont->FontType == 2) {
1515 	    gs_font_type1 *pfont1 = (gs_font_type1 *)pbfont;
1516 
1517 	    sbw[2] += fixed2float(pfont1->data.defaultWidthX);
1518 	}
1519     } else if (sbw_state == SBW_SCALE) {
1520 	sbw[0] = (double)cr.sb_x / scale / em_scale_x;
1521 	sbw[1] = (double)cr.sb_y / scale / em_scale_y;
1522 	sbw[2] = (double)cr.aw_x / scale / em_scale_x;
1523 	sbw[3] = (double)cr.aw_y / scale / em_scale_y;
1524     }
1525 
1526     /* Setup cache and render : */
1527     if (cr.metrics_type == FAPI_METRICS_REPLACE) {
1528 	/*
1529 	 * Here we don't take care of replaced advance width
1530 	 * because gs_text_setcachedevice handles it.
1531 	 */
1532 	int can_replace_metrics;
1533 
1534         if ((code = renderer_retcode(i_ctx_p, I, I->can_replace_metrics(I, &ff, &cr, &can_replace_metrics))) < 0)
1535 	    return code;
1536 	if (!can_replace_metrics) {
1537 	    /*
1538 	     * The renderer should replace the lsb, but it can't.
1539 	     * To work around we compute a displacement in integral pixels
1540 	     * and later shift the bitmap to it. The raster will be inprecise
1541 	     * with non-integral pixels shift.
1542 	     */
1543 	    char_bbox.q.x -= char_bbox.p.x;
1544 	    char_bbox.p.x = 0;
1545 	    gs_distance_transform((metrics.bbox_x0 / em_scale_x - sbw[0]),
1546 				  0, ctm, &penum_s->fapi_glyph_shift);
1547 	    penum_s->fapi_glyph_shift.x *= font_scale.subpixels[0];
1548 	    penum_s->fapi_glyph_shift.y *= font_scale.subpixels[1];
1549 	}
1550     }
1551     /*
1552      * We assume that if bMetricsFromGlyphDirectory is true,
1553      * the font does not specify Metrics[2] and/or CDevProc
1554      * If someday we meet a font contradicting this assumption,
1555      * zchar_set_cache to be improved with additional flag,
1556      * to ignore Metrics[2] and CDevProc.
1557      *
1558      * Note that for best quality the result of CDevProc
1559      * to be passed to I->get_char_raster_metrics, because
1560      * both raster and metrics depend on replaced lsb.
1561      * Perhaps in many cases the metrics from font is
1562      * used as an argument for CDevProc. Only way to resolve
1563      * is to call I->get_char_raster_metrics twice (before
1564      * and after CDevProc), or better to split it into
1565      * smaller functions. Unfortunately UFST cannot retrieve metrics
1566      * quickly and separately from raster. Only way to resolve is
1567      * to devide the replaced lsb into 2 parts, which correspond to
1568      * integral and fractinal pixels, then pass the fractional shift
1569      * to renderer and apply the integer shift after it.
1570      *
1571      * Besides that, we are not sure what to do if a font
1572      * contains both Metrics[2] and CDevProc. Should
1573      * CDevProc to be applied to Metrics[2] or to the metrics
1574      * from glyph code ? Currently we keep a compatibility
1575      * to the native GS font renderer without a deep analyzis.
1576      */
1577     code = zchar_set_cache(i_ctx_p, pbfont, &char_name,
1578 		           NULL, sbw + 2, &char_bbox,
1579 			   fapi_finish_render, &exec_cont, sbw);
1580     if (code >= 0 && exec_cont != 0)
1581 	code = (*exec_cont)(i_ctx_p);
1582     if (code != 0) {
1583         if (code < 0) {
1584             /* An error */
1585             I->release_char_data(I);
1586         } else {
1587             /* Callout to CDevProc, zsetcachedevice2, fapi_finish_render. */
1588         }
1589     }
1590     return code;
1591 }
1592 
FAPI_char(i_ctx_t * i_ctx_p,bool bBuildGlyph,ref * charstring)1593 private int FAPI_char(i_ctx_t *i_ctx_p, bool bBuildGlyph, ref *charstring)
1594 {   /* Stack : <font> <code|name> --> - */
1595     ref *v;
1596     char *font_file_path = NULL;
1597     gx_device *dev = gs_currentdevice_inline(igs);
1598     gs_font *pfont;
1599     int code = font_param(osp - 1, &pfont);
1600 
1601     if (code == 0) {
1602         gs_font_base *pbfont = (gs_font_base *) pfont;
1603         if (dict_find_string(osp - 1, "Path", &v) > 0 && r_has_type(v, t_string))
1604             font_file_path = ref_to_string(v, imemory, "font file path");
1605         code = FAPI_do_char(i_ctx_p, pbfont, dev, font_file_path, bBuildGlyph, charstring);
1606         if (font_file_path != NULL)
1607             gs_free_string(imemory, (byte *)font_file_path, r_size(v) + 1, "font file path");
1608     }
1609     return code;
1610 }
1611 
FAPIBuildGlyph9aux(i_ctx_t * i_ctx_p)1612 private int FAPIBuildGlyph9aux(i_ctx_t *i_ctx_p)
1613 {   os_ptr op = osp;                  /* <font0> <cid> <font9> <cid> */
1614     ref font9 = *pfont_dict(gs_currentfont(igs));
1615     ref *rFDArray, f;
1616     int font_index;
1617     int code;
1618 
1619     if ((code = ztype9mapcid(i_ctx_p)) < 0)
1620 	return code;  /* <font0> <cid> <charstring> <font_index> */
1621     /* fixme: what happens if the charstring is absent ?
1622        Can FDArray contain 'null' (see %Type9BuildGlyph in gs_cidfn.ps)? */
1623     font_index = op[0].value.intval;
1624     if (dict_find_string(&font9, "FDArray", &rFDArray) <= 0 || r_type(rFDArray) != t_array)
1625         return_error(e_invalidfont);
1626     if(array_get(imemory, rFDArray, font_index, &f) < 0 || r_type(&f) != t_dictionary)
1627         return_error(e_invalidfont);
1628     op[0] = op[-2];
1629     op[-2] = op[-1]; /* Keep the charstring on ostack for the garbager. */
1630     op[-1] = f;                       /* <font0> <charstring> <subfont> <cid> */
1631     if ((code = FAPI_char(i_ctx_p, true, op - 2)) < 0)
1632 	return code;
1633                                       /* <font0> <charstring> */
1634     return 0;
1635 }
1636 
1637 /* <font> <code> .FAPIBuildChar - */
zFAPIBuildChar(i_ctx_t * i_ctx_p)1638 private int zFAPIBuildChar(i_ctx_t *i_ctx_p)
1639 {   return FAPI_char(i_ctx_p, false, NULL);
1640 }
1641 
1642 /* non-CID : <font> <code> .FAPIBuildGlyph - */
1643 /*     CID : <font> <name> .FAPIBuildGlyph - */
zFAPIBuildGlyph(i_ctx_t * i_ctx_p)1644 private int zFAPIBuildGlyph(i_ctx_t *i_ctx_p)
1645 {   return FAPI_char(i_ctx_p, true, NULL);
1646 }
1647 
1648 /* <font> <cid> .FAPIBuildGlyph9 - */
zFAPIBuildGlyph9(i_ctx_t * i_ctx_p)1649 private int zFAPIBuildGlyph9(i_ctx_t *i_ctx_p)
1650 {   /*  The alghorithm is taken from %Type9BuildGlyph - see gs_cidfn.ps .  */
1651     os_ptr op = osp;
1652     int cid, code;
1653     avm_space s = ialloc_space(idmemory);
1654 
1655     check_type(op[ 0], t_integer);
1656     check_type(op[-1], t_dictionary);
1657     cid = op[0].value.intval;
1658     push(2);
1659     op[-1] = *pfont_dict(gs_currentfont(igs));
1660     op[0] = op[-2];                   /* <font0> <cid> <font9> <cid> */
1661     ialloc_set_space(idmemory, (r_is_local(op - 3) ? avm_global : avm_local)); /* for ztype9mapcid */
1662     code = FAPIBuildGlyph9aux(i_ctx_p);
1663     if (code != 0) {                  /* <font0> <dirty> <dirty> <dirty> */
1664         /* Adjust ostack for the correct error handling : */
1665         make_int(op - 2, cid);
1666         pop(2);                       /* <font0> <cid> */
1667     } else {                          /* <font0> <dirty> */
1668         pop(2);                       /* */
1669         /*  Note that this releases the charstring, and it may be garbage-collected
1670             before the interpreter calls fapi_finish_render. This requires the server
1671             to keep glyph raster internally between calls to get_char_raster_metrics
1672             and get_char_raster. Perhaps UFST cannot provide metrics without
1673             building a raster, so this constraint actually goes from UFST.
1674         */
1675     }
1676     ialloc_set_space(idmemory, s);
1677     return code;
1678 }
1679 
do_FAPIpassfont(i_ctx_t * i_ctx_p,char * font_file_path,bool * success)1680 private int do_FAPIpassfont(i_ctx_t *i_ctx_p, char *font_file_path, bool *success)
1681 {   ref *pdr = osp;  /* font dict */
1682     gs_font *pfont;
1683     int code = font_param(osp, &pfont);
1684     gs_font_base *pbfont;
1685     int BBox[4];
1686     i_plugin_holder *h = i_plugin_get_list(i_ctx_p);
1687     char *xlatmap = NULL;
1688     FAPI_font_scale font_scale = {{1, 0, 0, 1, 0, 0}, {0, 0}, {1, 1}, true};
1689     const char *decodingID = NULL;
1690 
1691     if (code < 0)
1692 	return code;
1693     code = FAPI_get_xlatmap(i_ctx_p, &xlatmap);	/* Useful for emulated fonts hooked with FAPI. */
1694     if (code < 0)
1695 	return code;
1696     pbfont = (gs_font_base *)pfont;
1697     *success = false;
1698     for (; h != 0; h = h->next) {
1699 	ref FAPI_ID;
1700         FAPI_server *I;
1701        	if (strcmp(h->I->d->type, "FAPI"))
1702             continue;
1703         I = (FAPI_server *)h->I;
1704         if ((code = renderer_retcode(i_ctx_p, I, I->ensure_open(I))) < 0)
1705 	    return code;
1706 	font_scale.HWResolution[0] = font_scale.HWResolution[1] = 72 << I->frac_shift;
1707 	font_scale.matrix[0] = font_scale.matrix[3] = 1 << I->frac_shift;
1708 
1709 	code = FAPI_prepare_font(i_ctx_p, I, pdr, pbfont, font_file_path, &font_scale, xlatmap, BBox, &decodingID);
1710 	if (code < 0) {
1711             /* Failed, skip this renderer : */
1712 	    continue;
1713 	}
1714         pbfont->FAPI = I; /* We found a good renderer, so go with it */
1715         if ((code = name_ref(imemory, (const byte *)I->ig.d->subtype, strlen(I->ig.d->subtype), &FAPI_ID, false)) < 0)
1716 	    return code;
1717 	if ((code = dict_put_string(pdr, "FAPI", &FAPI_ID, NULL)) < 0)
1718 	    return code; /* Insert FAPI entry to font dictionary. */
1719 	*success = true;
1720 	return 0;
1721     }
1722     /* Could not find renderer, return with false success. */
1723     return 0;
1724 }
1725 
1726 /* <font_dict> .FAPIpassfont bool <font_dict> */
1727 /* must insert /FAPI to font dictionary */
1728 /* This operator must not be called with devices which embed fonts. */
zFAPIpassfont(i_ctx_t * i_ctx_p)1729 private int zFAPIpassfont(i_ctx_t *i_ctx_p)
1730 {   os_ptr op = osp;
1731     int code;
1732     bool found;
1733     char *font_file_path = NULL;
1734     ref *v;
1735 
1736     /* Normally embedded fonts have no Path, but if a CID font is
1737      * emulated with a TT font, and it is hooked with FAPI,
1738      * the path presents and is neccessary to access the full font data.
1739      */
1740     check_type(*op, t_dictionary);
1741     if (dict_find_string(op, "Path", &v) > 0 && r_has_type(v, t_string))
1742         font_file_path = ref_to_string(v, imemory_global, "font file path");
1743     code = do_FAPIpassfont(i_ctx_p, font_file_path, &found);
1744     if (font_file_path != NULL)
1745         gs_free_string(imemory_global, (byte *)font_file_path, r_size(v) + 1, "font file path");
1746     if(code != 0)
1747 	return code;
1748     push(1);
1749     make_bool(op, found);
1750     return 0;
1751 }
1752 
1753 const op_def zfapi_op_defs[] =
1754 {   {"2.FAPIavailable",   zFAPIavailable},
1755     {"2.FAPIpassfont",    zFAPIpassfont},
1756     {"2.FAPIrebuildfont", zFAPIrebuildfont},
1757     {"2.FAPIBuildChar",   zFAPIBuildChar},
1758     {"2.FAPIBuildGlyph",  zFAPIBuildGlyph},
1759     {"2.FAPIBuildGlyph9", zFAPIBuildGlyph9},
1760     op_def_end(0)
1761 };
1762 
1763