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 /* Agfa UFST plugin */
18 
19 /* GS includes : */
20 #include "stdio_.h"
21 #include "stream.h"
22 #include "strmio.h"
23 
24 #include "memory_.h"
25 #include "gsmemory.h"
26 #include "math_.h"
27 #include "stat_.h" /* include before definition of esp macro, bug 691123 */
28 #include "ghost.h"
29 #include "gp.h"
30 #include "oper.h"
31 #include "gxdevice.h"
32 #include "gxfont.h"
33 #include "gxfont1.h"
34 #include "gxchar.h"
35 #include "gxpath.h"
36 #include "gxfcache.h"
37 #include "gxchrout.h"
38 #include "gximask.h"
39 #include "gscoord.h"
40 #include "gspaint.h"
41 #include "gsfont.h"
42 #include "gspath.h"
43 #include "bfont.h"
44 #include "dstack.h"
45 #include "estack.h"
46 #include "ichar.h"
47 #include "idict.h"
48 #include "iname.h"
49 #include "ifont.h"
50 #include "icid.h"
51 #include "igstate.h"
52 #include "icharout.h"
53 #include "ifapi.h"
54 #include "iplugin.h"
55 #include "store.h"
56 #include "gzstate.h"
57 #include "gdevpsf.h"
58 #include "stream.h"		/* for files.h */
59 #include "gscrypt1.h"
60 #include "gxfcid.h"
61 #include "gsstype.h"
62 #include "gxchar.h"		/* for st_gs_show_enum */
63 #include "ipacked.h"	    /* for packed_next */
64 #include "iddict.h"
65 #include "ifont42.h"        /* for string_array_access_proc */
66 #include "gsmalloc.h"
67 #include "gsmchunk.h"
68 
69 #undef frac_bits
70 
71 #ifndef _MSC_VER
72 #define _MSC_VER 0
73 #endif
74 
75 /* UFST includes : */
76 #include "cgconfig.h"
77 #include "ufstport.h"
78 #include "dbg_ufst.h"
79 #include "shareinc.h"
80 #include "t1isfnt.h"
81 #include "cgmacros.h"
82 #include "sfntenum.h"
83 #define DOES_ANYONE_USE_THIS_STRUCTURE /* see TTPCLEO.H, UFST 4.2 */
84 #include "ttpcleo.h"
85 #undef  DOES_ANYONE_USE_THIS_STRUCTURE
86 #include "gxfapiu.h"
87 
88 /* more gs includes */
89 #include "iref.h"
90 #include "ialloc.h"
91 #include "imemory.h"
92 #include "iname.h"
93 #include "iapi.h"
94 #include "iminst.h"
95 #include "imain.h"
96 #include "igstate.h"
97 #include "idict.h"
98 #include "dstack.h"
99 #include "store.h"
100 
101 #if UFST_VERSION_MAJOR >= 6 && UFST_VERSION_MINOR >= 2
102 #include "t1itype1.h"
103 #endif
104 
105 #if UFST_VERSION_MAJOR >= 6 && UFST_VERSION_MINOR >= 2
106 #undef true
107 #undef false
108 
109 #define false FALSE
110 #define true TRUE
111 #define UNICODE UFST_UNICODE
112 #endif
113 
114 #ifndef UFSTFONTDIR
115 #define UFSTFONTDIR ""
116 #endif
117 
118 #define UFST_PlugIn_Str "UFST_PlugIn"
119 #define UFST_PlugIn_Path "mtfonts/pcl45/mt3/plug__xi.fco"
120 
121 #define FCOfontfilePath "mtfonts/pclps2/mt3/pclp2_xj.fco"
122 #define FCOfontfileStr "FCOfontfile"
123 
124 #define FCOfontfile2Str "FCOfontfile2"
125 #define FCOfontfile2Path "mtfonts/pcl45/mt3/wd____xh.fco"
126 
127 #define FAPIfontmapStr  "FAPIfontmap"
128 #define FAPIfontmap  "FCOfontmap-PCLPS2"
129 
130 /* Prior to 6.2, prototypes had empty parameter lists, causing problems
131  * when passing 64 bit pointers into the UFST functions.
132  * Prototype "properly" here.
133  */
134 #if UFST_VERSION_MAJOR < 6
135 #if defined (ANSI_DEFS)
136 UW16 CGENTRY CGIFFfont (FSP PFONTCONTEXT fc);
137 #else
138 UW16 CGENTRY CGIFFfont (fc);
139     PFONTCONTEXT  fc;
140 #endif /* ANSI_DEFS */
141 #endif
142 
143 typedef struct fapi_ufst_server_s fapi_ufst_server;
144 
145 static unsigned int font_ids = 0x7fffffff;
146 
147 #if UFST_REENTRANT
148 #define FSA_FROM_SERVER IF_STATE *pIFS = &r->IFS
149 #else
150 EXTERN IF_STATE if_state;
151 #define FSA_FROM_SERVER IF_STATE *pIFS = &if_state;    (void)r; (void)pIFS;
152 static fapi_ufst_server *static_server_ptr_for_ufst_callback = 0;
153 #endif
154 
155 GLOBAL UW16  PCLswapHdr( FSP LPUB8 p, UW16 gifct ); /* UFST header doesn't define it. */
156 
157 typedef struct pcleo_glyph_list_elem_s pcleo_glyph_list_elem;
158 struct pcleo_glyph_list_elem_s {
159     UW16 chId;
160     pcleo_glyph_list_elem *next;
161     /* more data follows here depending on font type */
162 };
163 
164 typedef struct {
165     SL32 font_id;
166     uint tt_font_body_offset;
167     UW16 is_disk_font;
168     UW16 font_type;
169     UW16 platformId;
170     UW16 specificId;
171     pcleo_glyph_list_elem *glyphs;
172     char decodingID[40];
173 } ufst_common_font_data;
174 
175 typedef struct {
176     PCLETTO_CHR_HDR h;
177     UW16   add_data;
178     UW16   charDataSize;
179     UW16   glyphID;
180 } PCLETTO_CHDR;
181 
182 struct fapi_ufst_server_s {
183     FAPI_server If;
184     int bInitialized;
185     FAPI_font *ff;
186     gs_memory_t *mem;
187     byte *param;
188     int param_size;
189     IF_STATE IFS;
190     FONTCONTEXT fc;
191     void *char_data;
192     bool bRaster;
193     bool ufst_is_singleton;
194     double tran_xx, tran_xy, tran_yx, tran_yy;
195     fco_list_elem *fco_list;
196     FAPI_retcode callback_error;
197     FAPI_metrics_type metrics_type;
198     FracInt sb_x, aw_x; /* replaced PS metrics. */
199 };
200 
201 static inline void release_char_data_inline(fapi_ufst_server *r);
202 static void release_glyphs(fapi_ufst_server *r, ufst_common_font_data *d);
203 
204 /* Type casts : */
205 
If_to_I(FAPI_server * If)206 static inline fapi_ufst_server *If_to_I(FAPI_server *If)
207 {   return (fapi_ufst_server *)If;
208 }
209 
IFS_to_I(IF_STATE * pIFS)210 static inline fapi_ufst_server *IFS_to_I(IF_STATE *pIFS)
211 {   return (fapi_ufst_server *)((char *)pIFS - offset_of(fapi_ufst_server, IFS));
212 }
213 
214 /* assign font_id not based on fchandle value, nor read from font */
assign_font_id(void)215 static inline int assign_font_id(void)
216 {
217     /* We're only allowed 5 open FCOs at one time
218      * so make sure we don't clash with those
219      */
220      if ((--font_ids) <= (5 << 16)) {
221          /* When we clash with the expected values for FCO's
222           * wrap around. No will ever have enough concurrent
223           * fonts for this to be a problem!
224           */
225          font_ids = 0x7fffffff;
226      }
227      return(font_ids);
228 }
229 
230 /*------------------ FAPI_server members ------------------------------------*/
231 
release_char_data_inline(fapi_ufst_server * r)232 static inline void release_char_data_inline(fapi_ufst_server *r)
233 {   /*  The server keeps character raster between calls to get_char_raster_metrics
234         and get_char_raster, as well as between calls to get_char_outline_metrics
235         and get_char_outline. Meanwhile this regular
236         sequence of calls may be interrupted by an error in CDefProc or setchachedevice2,
237         which may be invoked between them. In this case Ghostscript
238         is unable to provide a signal to FAPI that the data are not
239         longer needed. This would cause memory leaks in UFST heap.
240         To work around this, appropriate server's entries check whether
241         raster data were left after a previous call, and ultimately release them.
242         This function provides it.
243     */
244     if (r->char_data != NULL) {
245         FSA_FROM_SERVER;
246 
247         CHARfree(FSA (MEM_HANDLE)r->char_data);
248         r->char_data = 0;
249     }
250 }
251 
252 /*
253  * In the language switch build (which we detect because PSI_INCLUDED
254  * is defined), we use the gx_UFST_init() call to initialize the UFST,
255  * rather than calling into the UFST directly. That has the advantage
256  * that the same UFST configuration is used for PCL and PS, but the
257  * disadvantage that the dynamic parameters set in server_param are
258  * not available. Thus, it is switched through this compile time option.
259 */
open_UFST(fapi_ufst_server * r,const byte * server_param,int server_param_size)260 static FAPI_retcode open_UFST(fapi_ufst_server *r, const byte *server_param, int server_param_size)
261 {
262     int code;
263     SW16 fcHandle;
264     int l;
265     char ufst_root_dir[1024] = "";
266     char sPlugIn[1024] = "";
267     bool bSSdir = FALSE, bPlugIn = FALSE;
268     const char *keySSdir = "UFST_SSdir=";
269     const int keySSdir_length = strlen(keySSdir);
270     const char *keyPlugIn = "UFST_PlugIn=";
271     const int keyPlugIn_length = strlen(keyPlugIn);
272     const char sep = gp_file_name_list_separator;
273     const byte *p = server_param, *e = server_param + server_param_size, *q;
274     FSA_FROM_SERVER;
275 
276     if (server_param_size > 0 && server_param) {
277         r->param = (byte *)gs_malloc(r->mem, server_param_size, 1, "server_params");
278         if (!r->param) {
279             return_error (e_VMerror);
280         }
281         memcpy(r->param, server_param, server_param_size);
282         r->param_size = server_param_size;
283     }
284 
285     for (; p < e ; p = q + 1) {
286         for (q = p; q < e && *q != sep; q++)
287             /* DO_NOTHING */;
288         l = q - p;
289         if (l > keySSdir_length && !memcmp(p, keySSdir, keySSdir_length)) {
290             l = q - p - keySSdir_length;
291             if (l > sizeof(ufst_root_dir) - 1)
292                 l = sizeof(ufst_root_dir) - 1;
293             memcpy(ufst_root_dir, p + keySSdir_length, l);
294             ufst_root_dir[l] = 0;
295             bSSdir = TRUE;
296         } else if (l > keyPlugIn_length && !memcmp(p, keyPlugIn, keyPlugIn_length)) {
297             l = q - p - keyPlugIn_length;
298             if (l > sizeof(sPlugIn) - 1)
299                 l = sizeof(sPlugIn) - 1;
300             memcpy(sPlugIn, p + keyPlugIn_length, l);
301             sPlugIn[l] = 0;
302             bPlugIn = TRUE;
303         } else
304             emprintf(r->mem,
305                      "Warning: Unknown UFST parameter ignored.\n");
306     }
307 #if !NO_SYMSET_MAPPING
308     if (!bSSdir) {
309         strcpy(ufst_root_dir, ".");
310         emprintf(r->mem,
311                  "Warning: UFST_SSdir is not specified, will search *.ss files in the curent directory.\n");
312     }
313 #endif
314     code = gx_UFST_init(r->mem, (const UB8 *)ufst_root_dir);
315     if (code < 0)
316         return code;
317     r->ufst_is_singleton = (code == 1);
318     CGIFfont_access (FSA DISK_ACCESS);
319     if (bPlugIn) {
320         if ((code = gx_UFST_open_static_fco(sPlugIn, &fcHandle)) != 0)
321             return code;
322         if ((code = CGIFfco_Plugin(FSA fcHandle)) != 0)
323             return code;
324     } else {
325 #ifdef FCO_RDR
326         emprintf(r->mem,
327                  "Warning: UFST_PlugIn is not specified, some characters may be missing.\n");
328 #endif
329     }
330     return 0;
331 }
332 
333 static LPUB8 impl_PCLchId2ptr(FSP UW16 chId);
334 
ensure_open(FAPI_server * server,const byte * server_param,int server_param_size)335 static FAPI_retcode ensure_open(FAPI_server *server, const byte *server_param, int server_param_size)
336 {   fapi_ufst_server *r = If_to_I(server);
337     int code;
338 
339     if (r->bInitialized)
340         return 0;
341     r->bInitialized = 1;
342     {
343         code = open_UFST(r, server_param, server_param_size);
344         if (code < 0) {
345             emprintf(r->mem, "Error opening the UFST font server.\n");
346             return code;
347         }
348     }
349     gx_set_UFST_Callbacks(NULL, impl_PCLchId2ptr, impl_PCLchId2ptr);
350     return 0;
351 }
352 
get_font_type(stream * f)353 static UW16 get_font_type(stream *f)
354 {   char buf[20], mark_PS[]="%!";
355     int i;
356 
357     if (sfread(buf, 1, sizeof(buf), f) != sizeof(buf))
358         return 0;
359     if (buf[0] == 0x15 || buf[0] == 0x00) /* fixme : don't know how to do correctly. */
360         return FC_FCO_TYPE;
361     for (i = 0; i < sizeof(buf) - sizeof(mark_PS); i++)
362         if(!memcmp(buf + i, mark_PS, sizeof(mark_PS) - 1))
363             return FC_PST1_TYPE;
364     if (buf[0] == '\0' && buf[1] == '\1')
365         return FC_TT_TYPE;
366     if (buf[0] == 't' && buf[1] == 't')
367         return FC_TT_TYPE;
368     return 0; /* fixme : unknown type - actually an error. */
369 }
370 
choose_decoding_general(fapi_ufst_server * r,ufst_common_font_data * d,const char * cmapId)371 static int choose_decoding_general(fapi_ufst_server *r, ufst_common_font_data *d, const char *cmapId)
372 {
373     if (!d->decodingID[0])
374         strncpy(d->decodingID, "Unicode", sizeof(d->decodingID));
375     /*    fixme : must depend on charset used in the font.  */
376     return 1;
377 }
378 
choose_decoding_TT(fapi_ufst_server * r,ufst_common_font_data * d,const char * cmapId)379 static int choose_decoding_TT(fapi_ufst_server *r, ufst_common_font_data *d, const char *cmapId)
380 {
381 #if TT_ROM || TT_DISK
382     int platId, specId, i;
383     CMAP_QUERY q;
384     UW16 font_access;
385     bool failed;
386     void *p = (d->is_disk_font ? (void *)(d + 1) : (void *)((UB8 *)d + d->tt_font_body_offset));
387     FSA_FROM_SERVER;
388 
389     if (sscanf(cmapId, "%d.%d", &platId, &specId) != 2)
390         return 0;
391     font_access = pIFS->font_access;
392     pIFS->font_access = (d->is_disk_font ? DISK_ACCESS : ROM_ACCESS);
393     failed = CGIFtt_cmap_query(FSA p, r->fc.ttc_index, &q);
394     pIFS->font_access = font_access;
395     if(failed)
396         return 0;
397     for (i = 0; i < q.numCmap; i++)
398         if (q.entry[i].platId == platId && q.entry[i].specId == specId) {
399             d->platformId = platId;
400             d->specificId = specId;
401             return 1;
402         }
403     return 0;
404 #else
405     if (!d->decodingID[0])
406         strncpy(d->decodingID, "Unicode", sizeof(d->decodingID));
407     return 1;
408 #endif
409 }
410 
scan_xlatmap(fapi_ufst_server * r,ufst_common_font_data * d,const char * xlatmap,const char * font_kind,int (* choose_proc)(fapi_ufst_server * r,ufst_common_font_data * d,const char * cmapId))411 static void scan_xlatmap(fapi_ufst_server *r, ufst_common_font_data *d, const char *xlatmap, const char *font_kind,
412                                     int (*choose_proc)(fapi_ufst_server *r, ufst_common_font_data *d, const char *cmapId))
413 {   const char *p = xlatmap;
414 
415     while(*p) {
416         int good_kind =!strcmp(p, font_kind);
417         p += strlen(p) + 2;
418         while(*p) {
419             const char *cmapId = p, *decodingID = p + strlen(p) + 1;
420             strncpy(d->decodingID, decodingID, sizeof(d->decodingID));
421             if (!decodingID[0])
422                 break;
423             p = decodingID + strlen(decodingID) + 1;
424             if (good_kind)
425                 if (choose_proc(r, d, cmapId))
426                     return;
427         }
428     }
429     d->decodingID[0] = 0;
430 }
431 
choose_decoding(fapi_ufst_server * r,ufst_common_font_data * d,const char * xlatmap)432 static void choose_decoding(fapi_ufst_server *r, ufst_common_font_data *d, const char *xlatmap)
433 {   if (xlatmap != 0)
434         switch (d->font_type) {
435             case FC_IF_TYPE: /* fixme */ break;
436             case FC_PST1_TYPE: scan_xlatmap(r, d, xlatmap, "PostScript", choose_decoding_general); break;
437             case FC_TT_TYPE:   scan_xlatmap(r, d, xlatmap, "TrueType", choose_decoding_TT); break;
438             case FC_FCO_TYPE:  scan_xlatmap(r, d, xlatmap, "Microtype", choose_decoding_general); break;
439         }
440 }
441 
store_word(byte ** p,ushort w)442 static inline void store_word(byte **p, ushort w)
443 {   *((*p)++) = w / 256;
444     *((*p)++) = w % 256;
445 
446 }
447 
get_TT_glyph(fapi_ufst_server * r,FAPI_font * ff,UW16 chId)448 static LPUB8 get_TT_glyph(fapi_ufst_server *r, FAPI_font *ff, UW16 chId)
449 {   pcleo_glyph_list_elem *g;
450     PCLETTO_CHDR *h;
451     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
452     LPUB8 q;
453     ushort glyph_length = ff->get_glyph(ff, chId, 0, 0);
454     bool use_XL_format = ff->is_mtx_skipped;
455 
456     /*
457      * The client must set ff->is_mtx_skipped iff
458      * it requests a replaced lsb for True Type.
459      * If it is set, a replaced width to be supplied.
460      * This constraint is derived from UFST restriction :
461      * the font header format must be compatible with
462      * glyph header format.
463      */
464 
465     if (glyph_length == (ushort)-1) {
466         r->callback_error = e_invalidfont;
467         return 0;
468     }
469     g = (pcleo_glyph_list_elem *)gs_malloc(r->mem,
470             sizeof(pcleo_glyph_list_elem) +
471             (use_XL_format ? 12 : sizeof(PCLETTO_CHDR)) + glyph_length + 2, 1,
472             "PCLETTO char");
473     if (g == 0) {
474         r->callback_error = e_VMerror;
475         return 0;
476     }
477     g->chId = chId;
478     g->next = d->glyphs;
479     d->glyphs = g;
480     h = (PCLETTO_CHDR *)(g + 1);
481     h->h.format = 15;
482     if (use_XL_format) {
483         h->h.continuation = 2;
484         q = (LPUB8)h + 2;
485         store_word(&q, (ushort)(glyph_length + 10));
486         store_word(&q, (ushort)(r->sb_x >> r->If.frac_shift)); /* see can_replace_metrics */
487         store_word(&q, (ushort)(r->aw_x >> r->If.frac_shift));
488         store_word(&q, 0);
489         store_word(&q, chId);
490     } else {
491         h->h.continuation = 0;
492         h->h.descriptorsize = 4;
493         h->h.ch_class = 15;
494         h->add_data = 0;
495         q = (LPUB8)&h->charDataSize;
496         store_word(&q, (ushort)(glyph_length + 4));
497         store_word(&q, chId);
498     }
499     if (ff->get_glyph(ff, chId, (LPUB8)q, glyph_length) == (ushort)-1) {
500         r->callback_error = e_invalidfont;
501         return 0;
502     }
503     q += glyph_length;
504     store_word(&q, 0); /* checksum */
505     return (LPUB8)h;
506     /*
507      * The metrics replacement here is done only for the case
508      * corresponding to non-disk TT fonts with MetricsCount != 0;
509      * Other cases are not supported because UFST cannot handle them.
510      * Here we don't take care of cases which can_replace_metrics rejects.
511      *
512      * We don't care of metrics for subglyphs, because
513      * it is ignored by TT interpreter.
514      */
515 }
516 
get_T1_glyph(fapi_ufst_server * r,FAPI_font * ff,UW16 chId)517 static LPUB8 get_T1_glyph(fapi_ufst_server *r, FAPI_font *ff, UW16 chId)
518 {
519 #if PST1_SFNTI
520 #if UFST_VERSION_MAJOR >= 6 && UFST_VERSION_MINOR >= 2
521     ushort glyph_length = ff->get_glyph(ff, chId, 0, 0);
522     CDATASTR charstring;
523     PCDATASTR_DEMO pcharstring;
524     byte *cstring;
525     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
526     MEM_HANDLE hndl;
527     FSA_FROM_SERVER;
528 
529     d->glyphs = NULL;
530 
531     charstring.len = glyph_length;
532     charstring.hdata = BUFalloc(charstring.len);
533     if (!charstring.hdata)
534     {
535         r->callback_error = e_VMerror;
536         return (NULL);
537     }
538 
539     cstring = (unsigned char *)MEMptr(charstring.hdata);
540 
541     if (ff->get_glyph(ff, chId, cstring, glyph_length) != glyph_length)
542     {
543         r->callback_error = e_VMerror;
544         BUFfree(charstring.hdata);
545         return (NULL);
546     }
547 
548     hndl = BUFalloc (FSA (SL32)(sizeof (CDATASTR)));
549     if (!hndl)
550     {
551         r->callback_error = e_VMerror;
552         BUFfree(charstring.hdata);
553         return (NULL);
554     }
555 
556     pcharstring = (PCDATASTR_DEMO)MEMptr(hndl);
557 
558     pcharstring->len = charstring.len; /* Datalen */
559     pcharstring->hdata = charstring.hdata;
560     pcharstring->decrypted = 1;
561 
562     return ((LPUB8) pcharstring);
563 #else
564     ushort glyph_length = ff->get_glyph(ff, chId, 0, 0);
565     LPUB8 q;
566     pcleo_glyph_list_elem *g = (pcleo_glyph_list_elem *)gs_malloc(r->mem,
567                     sizeof(pcleo_glyph_list_elem) + sizeof(PS_CHAR_HDR) + 2 + 2 + glyph_length + 1, 1, "PSEO char");
568     PS_CHAR_HDR *h;
569     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
570     FSA_FROM_SERVER;
571 
572     if (g == 0 || glyph_length == (ushort)-1) {
573         r->callback_error = e_invalidfont;
574         return 0;
575     }
576     g->chId = chId;
577     g->next = d->glyphs;
578     d->glyphs = g;
579     h = (PS_CHAR_HDR *)(g + 1);
580     h->format = 30;           /* raster=4, DJ=5, IF=10, TT=15, PS=30 */
581     h->continuation = 0;     /* always 0 */
582     h->descriptorsize = 2;   /* always 2 */
583     h->ch_class = 11;           /* contour=3, compound=4, tt=10, ps=11 */
584     h->len = 0;              /* # of bytes to follow (not including csum) */
585     q = (byte *)h + sizeof(*h);
586     /* A workaround for UFST4.6 bug in t1idecod.c (UNPACK_WORD uses pIFS->ph instead ph) :
587        setting Namelen=4, rather normally it must be 0. */
588     q[0] = 0; /* Namelen */
589     q[1] = 4; /* Namelen */
590     q[2] = (glyph_length) / 256; /* Datalen */
591     q[3] = (glyph_length) % 256; /* Datalen */
592     /* Glyph name goes here, but we don't use it. */
593     q += 4;
594     glyph_length = ff->get_glyph(ff, chId, q, glyph_length);
595     q += glyph_length;
596     *q = 1; /* Decrypt flag */
597     pIFS->ph = (byte *)h + sizeof(*h); /* A workaround for UFST4.6 bug in t1idecod.c (UNPACK_WORD uses pIFS->ph instead ph) */
598     return (LPUB8)h;
599 #endif
600 #else
601     return 0;
602 #endif
603 }
604 
find_glyph(ufst_common_font_data * d,UW16 chId)605 static pcleo_glyph_list_elem * find_glyph(ufst_common_font_data *d, UW16 chId)
606 {   pcleo_glyph_list_elem *e;
607 
608     for (e = d->glyphs; e != 0; e = e->next)
609         if (e->chId == chId)
610             return e;
611     return 0;
612 }
613 
614 /* UFST callback : */
impl_PCLchId2ptr(FSP UW16 chId)615 static LPUB8 impl_PCLchId2ptr(FSP UW16 chId)
616 {
617 #if UFST_REENTRANT
618     fapi_ufst_server *r = IFS_to_I(pIFS);
619 #else
620     fapi_ufst_server *r = static_server_ptr_for_ufst_callback;
621 #endif
622     FAPI_font *ff = r->ff;
623     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
624     pcleo_glyph_list_elem *g = find_glyph(d, chId);
625     LPUB8 result = 0;
626 
627     if (g != 0)
628         result = (LPUB8)(g + 1);
629     if ((r->fc.format & FC_FONTTYPE_MASK) == FC_PST1_TYPE)
630         result = get_T1_glyph(r, ff, chId);
631     if ((r->fc.format & FC_FONTTYPE_MASK) == FC_TT_TYPE)
632         result = get_TT_glyph(r, ff, chId);
633     return result;
634 }
635 
pack_word(LPUB8 * p,UW16 v)636 static inline void pack_word(LPUB8 *p, UW16 v)
637 {   LPUB8 q = (LPUB8)&v;
638 
639 #if (BYTEORDER == LOHI) /* defied in UFST includes */
640          (*p)[1] = q[0];
641          (*p)[0] = q[1];
642 #else
643         *(UW16 *)(*p) = v;
644 #endif
645     *p += 2;
646 }
647 
pack_long(LPUB8 * p,UL32 v)648 static inline void pack_long(LPUB8 *p, UL32 v)
649 {   LPUB8 q = (LPUB8)&v;
650 
651 #if (BYTEORDER == LOHI) /* defied in UFST includes */
652          (*p)[3] = q[0];
653          (*p)[2] = q[1];
654          (*p)[1] = q[2];
655          (*p)[0] = q[3];
656 #else
657         *(UL32 *)(*p) = v;
658 #endif
659     *p += 4;
660 }
661 
pack_float(LPUB8 * p,float v)662 static inline void pack_float(LPUB8 *p, float v)
663 {   sprintf((char *)(*p), "%f", v);
664     *p += strlen((const char *)*p) + 1;
665 }
666 
667 #define PACK_ZERO(p) *(p++) = 0
668 #define PACK_BYTE(p, c) *(p++) = c
669 #define PACK_WORD(p, i, var) pack_word(&p, ff->get_word(ff, var, i))
670 #define PACK_LONG(p, i, var) pack_long(&p, ff->get_long(ff, var, i))
671 
pack_pseo_word_array(fapi_ufst_server * r,FAPI_font * ff,UB8 ** p,UW16 max_count,fapi_font_feature count_id,fapi_font_feature array_id)672 static void pack_pseo_word_array(fapi_ufst_server *r, FAPI_font *ff, UB8 **p,
673                                   UW16 max_count, fapi_font_feature count_id, fapi_font_feature array_id)
674 {   UW16 k = min(ff->get_word(ff, count_id, 0), max_count), j;
675 
676     pack_word(p, k);
677     for (j = 0; j < k; j++)
678         PACK_WORD(*p, j, array_id);
679     for (; j < max_count; j++)
680         pack_word(p, 0);
681 }
682 
pack_pseo_fhdr(fapi_ufst_server * r,FAPI_font * ff,UB8 * p)683 static void pack_pseo_fhdr(fapi_ufst_server *r, FAPI_font *ff, UB8 *p)
684 {   ushort j, n, skip = 0;
685 
686     while (((uint64_t)p) & 0x03) /* align to QUADWORD */
687         PACK_ZERO(p);
688     pack_long(&p, 1);  /* format = 1 */
689     for (j = 0; j < 6; j++)
690         pack_float(&p, ff->get_float(ff, FAPI_FONT_FEATURE_FontMatrix, j));
691     while (((uint64_t)p) & 0x03) /* align to QUADWORD */
692         PACK_ZERO(p);
693     /* UFST has no definition for PSEO structure, so implement serialization : */
694     PACK_LONG(p, 0, FAPI_FONT_FEATURE_UniqueID);
695     PACK_LONG(p, 0, FAPI_FONT_FEATURE_BlueScale);
696     PACK_WORD(p, 0, FAPI_FONT_FEATURE_Weight);
697     PACK_WORD(p, 0, FAPI_FONT_FEATURE_ItalicAngle);
698     PACK_WORD(p, 0, FAPI_FONT_FEATURE_IsFixedPitch);
699     PACK_WORD(p, 0, FAPI_FONT_FEATURE_UnderLinePosition);
700     PACK_WORD(p, 0, FAPI_FONT_FEATURE_UnderlineThickness);
701     PACK_WORD(p, 0, FAPI_FONT_FEATURE_FontType);
702     PACK_WORD(p, 0, FAPI_FONT_FEATURE_FontBBox);
703     PACK_WORD(p, 1, FAPI_FONT_FEATURE_FontBBox);
704     PACK_WORD(p, 2, FAPI_FONT_FEATURE_FontBBox);
705     PACK_WORD(p, 3, FAPI_FONT_FEATURE_FontBBox);
706     pack_pseo_word_array(r, ff, &p, 14, FAPI_FONT_FEATURE_BlueValues_count, FAPI_FONT_FEATURE_BlueValues);
707     pack_pseo_word_array(r, ff, &p, 10, FAPI_FONT_FEATURE_OtherBlues_count, FAPI_FONT_FEATURE_OtherBlues);
708     pack_pseo_word_array(r, ff, &p, 14, FAPI_FONT_FEATURE_FamilyBlues_count, FAPI_FONT_FEATURE_FamilyBlues);
709     pack_pseo_word_array(r, ff, &p, 10, FAPI_FONT_FEATURE_FamilyOtherBlues_count, FAPI_FONT_FEATURE_FamilyOtherBlues);
710     PACK_WORD(p, 0, FAPI_FONT_FEATURE_BlueShift);
711     PACK_WORD(p, 0, FAPI_FONT_FEATURE_BlueFuzz);
712     PACK_WORD(p, 0, FAPI_FONT_FEATURE_StdHW);
713     PACK_WORD(p, 0, FAPI_FONT_FEATURE_StdVW);
714     pack_pseo_word_array(r, ff, &p, 12, FAPI_FONT_FEATURE_StemSnapH_count, FAPI_FONT_FEATURE_StemSnapH);
715     pack_pseo_word_array(r, ff, &p, 12, FAPI_FONT_FEATURE_StemSnapV_count, FAPI_FONT_FEATURE_StemSnapV);
716     PACK_WORD(p, 0, FAPI_FONT_FEATURE_ForceBold);
717     PACK_WORD(p, 0, FAPI_FONT_FEATURE_LanguageGroup);
718     PACK_WORD(p, 0, FAPI_FONT_FEATURE_lenIV);
719     for (j = 0; j < 12; j++)
720         PACK_ZERO(p), PACK_ZERO(p);     /* Reserved2 */
721     /* max data size = 107 words + 6 floats in ASCII */
722     n = ff->get_word(ff, FAPI_FONT_FEATURE_Subrs_count, 0);
723     pack_word(&p, n);
724     for (j = 0; j < n; j++) {
725         ushort subr_len = ff->get_subr(ff, j, 0, 0);
726         if (subr_len != 0) {
727             pack_word(&p, j);
728             pack_word(&p, subr_len);
729             PACK_BYTE(p, 1); /* is_decrypted */
730             ff->get_subr(ff, j, p, subr_len);
731             p += subr_len;
732         } else
733             skip = 1;
734     }
735     n = ff->get_word(ff, FAPI_FONT_FEATURE_GlobalSubrs_count, 0);
736     /* get_word() doesn't have an error return value, so I've used an unlikely value */
737     if (n != 65535) {
738         pack_word(&p, n);
739         for (j = 0; j < n; j++) {
740             ushort subr_len = ff->get_gsubr(ff, j, 0, 0);
741             if (subr_len != 0) {
742                 pack_word(&p, j);
743                 pack_word(&p, subr_len);
744                 PACK_BYTE(p, 1); /* is_decrypted */
745                 ff->get_gsubr(ff, j, p, subr_len);
746                 p += subr_len;
747             } else
748                 skip = 1;
749         }
750     }
751     if (skip)
752         pack_word(&p, 0xFFFF);
753 }
754 
my_strdup(fapi_ufst_server * r,const char * s,const char * cname)755 static char *my_strdup(fapi_ufst_server *r, const char *s, const char *cname)
756 {   int len = strlen(s) + 1;
757     char *p = (char *)gs_malloc(r->mem, len, 1, cname);
758 
759     if (p != 0)
760         memcpy(p, s, len);
761     return p;
762 }
763 
fco_open(fapi_ufst_server * r,const char * font_file_path,fco_list_elem ** result)764 static FAPI_retcode fco_open(fapi_ufst_server *r, const char *font_file_path, fco_list_elem **result)
765 {   int code;
766     fco_list_elem *e = gx_UFST_find_static_fco(font_file_path);
767 
768     if (e != NULL) {
769         *result = e;
770         return 0;
771     }
772     for (e = r->fco_list; e != 0; e = e->next) {
773         if (!strcmp(e->file_path, font_file_path))
774             break;
775     }
776     if (e == 0) {
777         SW16 fcHandle;
778         FSA_FROM_SERVER;
779 
780         if ((code = CGIFfco_Open(FSA (UB8 *)font_file_path, &fcHandle)) != 0)
781             return code;
782         e = (fco_list_elem *)gs_malloc(r->mem, sizeof(*e), 1, "fco_list_elem");
783         if (e == 0) {
784             CGIFfco_Close(FSA fcHandle);
785             return e_VMerror;
786         }
787         e->open_count = 0;
788         e->fcHandle = fcHandle;
789         e->file_path = my_strdup(r, font_file_path, "fco_file_path");
790         if (e->file_path == 0) {
791             CGIFfco_Close(FSA fcHandle);
792             gs_free(r->mem, e, 0, 0, "fco_list_elem");
793             return e_VMerror;
794         }
795         e->next = r->fco_list;
796         r->fco_list = e;
797     }
798     e->open_count++;
799     *result = e;
800     return 0;
801 }
802 
make_font_data(fapi_ufst_server * r,const char * font_file_path,FAPI_font * ff,ufst_common_font_data ** return_data)803 static FAPI_retcode make_font_data(fapi_ufst_server *r, const char *font_file_path, FAPI_font *ff, ufst_common_font_data **return_data)
804 {   ulong area_length = sizeof(ufst_common_font_data), tt_size = 0;
805     LPUB8 buf;
806     PCLETTO_FHDR *h;
807     ufst_common_font_data *d;
808     bool use_XL_format = ff->is_mtx_skipped;
809     int code;
810     FSA_FROM_SERVER;
811 
812     *return_data = 0;
813     r->fc.ttc_index = ff->subfont;
814     if (ff->font_file_path == NULL) {
815 #if UFST_VERSION_MAJOR < 6
816         return(e_invalidaccess);
817 #else
818         area_length += PCLETTOFONTHDRSIZE;
819         if (ff->is_type1) {
820             int subrs_count  = ff->get_word(ff, FAPI_FONT_FEATURE_Subrs_count, 0);
821             int subrs_length = ff->get_long(ff, FAPI_FONT_FEATURE_Subrs_total_size, 0);
822             int subrs_area_size;
823             int gsubrs_count = ff->get_word(ff, FAPI_FONT_FEATURE_GlobalSubrs_count, 0);
824 
825             /* get_word() doesn't have an error return value, so I've used an unlikely value */
826             if (gsubrs_count != 65535)
827                 subrs_count  += gsubrs_count;
828 
829             subrs_area_size = subrs_count * 5 + subrs_length + 2;
830             area_length += 360 + subrs_area_size; /* some inprecise - see pack_pseo_fhdr */
831         } else {
832             tt_size  = ff->get_long(ff, FAPI_FONT_FEATURE_TT_size, 0);
833             if (tt_size == 0)
834                 return e_invalidfont;
835             area_length += tt_size + (use_XL_format ? 6 : 4) + 4 + 2;
836         }
837 #endif
838     } else {
839 #if UFST_VERSION_MAJOR < 6
840         int sind = strlen(font_file_path) - 1;
841 
842         if ((font_file_path[sind] != 'o' || font_file_path[sind] != 'O') &&
843             (font_file_path[sind - 1] != 'c' || font_file_path[sind - 1] != 'C') &&
844             (font_file_path[sind - 2] != 'f' || font_file_path[sind - 2] != 'F') &&
845             font_file_path[sind - 3] != '.') {
846             return(e_invalidaccess);
847         }
848 #endif
849         area_length += strlen(font_file_path) + 1;
850     }
851     buf = gs_malloc(r->mem, area_length, 1, "ufst font data");
852     if (buf == 0)
853         return e_VMerror;
854 
855     memset(buf, 0x00, area_length);
856 
857     d = (ufst_common_font_data *)buf;
858     d->tt_font_body_offset = 0;
859     d->platformId = 0;
860     d->specificId = 0;
861     d->decodingID[0] = 0;
862     d->glyphs = 0;
863     d->is_disk_font = (ff->font_file_path != NULL);
864     if (d->is_disk_font) {
865          fco_list_elem *e = gx_UFST_find_static_fco(font_file_path);
866 
867          if (e != NULL) {
868              memcpy(d + 1, font_file_path, strlen(font_file_path) + 1);
869              d->font_id = (e->fcHandle << 16) | ff->subfont;
870              d->font_type = FC_FCO_TYPE;
871          } else {
872             stream *f = sfopen(font_file_path, "rb", r->mem);
873             if (f == NULL) {
874                 emprintf1(r->mem,
875                           "fapiufst: Can't open %s\n",
876                           font_file_path);
877                 return e_undefinedfilename;
878             }
879             memcpy(d + 1, font_file_path, strlen(font_file_path) + 1);
880             d->font_type = get_font_type(f);
881             sfclose(f);
882             if (d->font_type == FC_FCO_TYPE) {
883                 fco_list_elem *e;
884                 if ((code = fco_open(r, font_file_path, &e)) != 0)
885                     return code;
886                 d->font_id = (e->fcHandle << 16) | ff->subfont;
887             }
888         }
889     } else {
890         d->font_type = (ff->is_type1 ? FC_PST1_TYPE : FC_TT_TYPE);
891         d->font_id = ff->get_long(ff, FAPI_FONT_FEATURE_UniqueID, 0);
892         if (d->font_id < 0) {
893             d->font_id = assign_font_id();
894         }
895         h = (PCLETTO_FHDR *)(buf + sizeof(ufst_common_font_data));
896         h->fontDescriptorSize = PCLETTOFONTHDRSIZE;
897         h->descriptorFormat = 15;
898         h->fontType = 11; /* wrong */                /*  3- 11=Unicode; 0,1,2 also possible */
899         h->style_msb = 0; /* wrong */               /*  4- from PCLT table in TrueType font */
900         h->reserved1 = 0;
901         h->baselinePosition = 0; /* wrong */        /*  6- from head table in TT font; = 0 */
902         h->cellWidth = 1024; /* wrong */               /*  8- head, use xMax - xMin */
903         h->cellHeight = 1024; /* wrong */             /* 10- head, use yMax - yMin */
904         h->orientation = 0;             /* 12- 0 */
905         h->spacing = 1; /* wrong */                 /* 13- 1=proportional, 0-fixed pitch */
906         h->characterSet = 56; /* wrong */            /* 14- same as symSetCode; =56 if unbound. */
907         h->pitch = 1024; /* wrong */                   /* 16- PCLT */
908         h->height = 0;                  /* 18- 0 if TrueType */
909         h->xHeight = 512; /* wrong */                 /* 20- PCLT */
910         h->widthType = 0; /* wrong */               /* 22- PCLT */
911         h->style_lsb = 0; /* wrong */               /* 23- PCLT */
912         h->strokeWeight = 0; /* wrong */            /* 24- PCLT */
913         h->typeface_lsb = 0; /* wrong */            /* 25- PCLT */
914         h->typeface_msb = 0; /* wrong */           /* 26- PCLT */
915         h->serifStyle = 0; /* wrong */              /* 27- PCLT */
916         h->quality = 0; /* wrong */                 /* 28- 2 if TrueType */
917         h->placement = 0; /* wronfg */               /* 29- 0 if TrueType */
918         h->underlinePosition = 0;       /* 30- 0 */
919         h->underlineHeight = 0;         /* 31- 0 */
920         h->textHeight = 102; /* wrong */              /* 32- from OS/2 table in TT font */
921         h->textWidth = 1024; /* wrong */              /* 34- OS/2 */
922         h->firstCode = 0;               /* 36- set to 0 if unbound */
923         h->lastCode = 255; /* wrong */                /* 38- max number of downloadable chars if unbound */
924         h->pitch_ext = 0;               /* 40- 0 if TrueType */
925         h->height_ext = 0;              /* 41- 0 if TrueType */
926         h->capHeight = 1024; /* wrong */               /* 42- PCLT */
927         h->fontNumber = d->font_id;              /* 44- PCLT */
928         h->fontName[0] = 0; /* wrong */            /* 48- PCLT */
929         h->scaleFactor = 1024; /* wrong */             /* 64- head:unitsPerEm */
930         h->masterUnderlinePosition = 0; /* wrong */ /* 66- post table, or -20% of em */
931         h->masterUnderlineHeight = 0; /* wrong */   /* 68- post table, or 5% of em */
932         h->fontScalingTechnology = 1;   /* 70- 1=TrueType; 0=Intellifont */
933         h->variety = 0;                 /* 71- 0 if TrueType */
934         memset((LPUB8)h + PCLETTOFONTHDRSIZE, 0 ,8); /* work around bug in PCLswapHdr : it wants format 10 */
935         /*  fixme : Most fields above being marked "wrong" look unused by UFST.
936             Need to check for sure.
937         */
938         /*  fixme : This code assumes 1-byte alignment for PCLETTO_FHDR structure.
939             Use PACK_* macros to improve.
940         */
941         PCLswapHdr(FSA (UB8 *)h, 0);
942         if (ff->is_type1) {
943             LPUB8 fontdata = (LPUB8)h + PCLETTOFONTHDRSIZE;
944             pack_pseo_fhdr(r, ff, fontdata);
945         } else {
946             LPUB8 pseg = (LPUB8)h + PCLETTOFONTHDRSIZE;
947             LPUB8 fontdata = pseg + (use_XL_format ? 6 : 4);
948             if (tt_size > 65000)
949                 return e_unregistered; /* Must not happen because we skept 'glyp', 'loca' and 'cmap'. */
950             pseg[0] = 'G';
951             pseg[1] = 'T';
952             if (use_XL_format) {
953                 pseg[2] = tt_size >> 24;
954                 pseg[3] = (tt_size >> 16) % 256;
955                 pseg[4] = (tt_size >> 8) % 256;
956                 pseg[5] = tt_size % 256;
957             } else {
958                 pseg[2] = tt_size / 256;
959                 pseg[3] = tt_size % 256;
960             }
961             d->tt_font_body_offset = (LPUB8)fontdata - (LPUB8)d;
962             if (ff->serialize_tt_font(ff, fontdata, tt_size))
963                 return e_invalidfont;
964             *(fontdata + tt_size    ) = 255;
965             *(fontdata + tt_size + 1) = 255;
966             *(fontdata + tt_size + 2) = 0;
967             *(fontdata + tt_size + 3) = 0;
968             *(fontdata + tt_size + 4) = 0;
969             *(fontdata + tt_size + 5) = 0;  /* checksum */
970         }
971     }
972     *return_data = d;
973     return 0;
974 }
975 
prepare_typeface(fapi_ufst_server * r,ufst_common_font_data * d)976 static void prepare_typeface(fapi_ufst_server *r, ufst_common_font_data *d)
977 {   r->fc.format = d->font_type;
978     r->fc.font_id = d->font_id;
979     r->fc.font_hdr = (UB8 *)(d + 1);
980     if (!d->is_disk_font)
981         r->fc.format |= FC_EXTERN_TYPE;
982 }
983 
get_scaled_font(FAPI_server * server,FAPI_font * ff,const FAPI_font_scale * font_scale,const char * xlatmap,FAPI_descendant_code dc)984 static FAPI_retcode get_scaled_font(FAPI_server *server, FAPI_font *ff,
985          const FAPI_font_scale *font_scale, const char *xlatmap, FAPI_descendant_code dc)
986 {   fapi_ufst_server *r = If_to_I(server);
987     FONTCONTEXT *fc = &r->fc;
988     /*  Note : UFST doesn't provide handles for opened fonts,
989         but copies FONTCONTEXT to IFSTATE and caches it.
990         Due to this the plugin cannot provide a handle for the font.
991         This assumes that only one font context is active at a moment.
992     */
993     ufst_common_font_data *d = (ufst_common_font_data *)ff->server_font_data;
994     const double scale = F_ONE;
995     double hx, hy;
996     FAPI_retcode code = 0;
997     bool use_XL_format = ff->is_mtx_skipped;
998     int world_scale = 0;
999     FONT_METRICS fm;
1000     FSA_FROM_SERVER;
1001 
1002     if (ff->is_cid && ff->is_type1 && ff->font_file_path == NULL &&
1003         (dc == FAPI_TOPLEVEL_BEGIN || dc == FAPI_TOPLEVEL_COMPLETE)) {
1004         /* Don't need any processing for the top level font of a non-disk CIDFontType 0.
1005            See comment in FAPI_prepare_font.
1006            Will do with its subfonts individually.
1007          */
1008         return 0;
1009     }
1010 
1011     ff->need_decrypt = 1;
1012     if (d == 0) {
1013         if ((code = make_font_data(r, ff->font_file_path, ff, &d)) != 0)
1014             return code;
1015         ff->server_font_data = d;
1016         prepare_typeface(r, d);
1017         if (ff->font_file_path != NULL || ff->is_type1) /* such fonts don't use RAW_GLYPH */
1018             choose_decoding(r, d, xlatmap);
1019     }
1020     else {
1021         prepare_typeface(r, d);
1022         if (ff->font_file_path != NULL || ff->is_type1) /* such fonts don't use RAW_GLYPH */
1023             choose_decoding(r, d, xlatmap);
1024     }
1025 
1026     r->tran_xx = font_scale->matrix[0] / scale, r->tran_xy = font_scale->matrix[1] / scale;
1027     r->tran_yx = font_scale->matrix[2] / scale, r->tran_yy = font_scale->matrix[3] / scale;
1028     hx = hypot(r->tran_xx, r->tran_xy), hy = hypot(r->tran_yx, r->tran_yy);
1029     fc->xspot     = F_ONE;
1030     fc->yspot     = F_ONE;
1031     fc->fc_type   = FC_MAT2_TYPE;
1032 
1033     fc->s.m2.m[0] = (int)((double)font_scale->matrix[0] / hx + 0.5);
1034     fc->s.m2.m[1] = (int)((double)font_scale->matrix[1] / hx + 0.5);
1035     fc->s.m2.m[2] = (int)((double)font_scale->matrix[2] / hy + 0.5);
1036     fc->s.m2.m[3] = (int)((double)font_scale->matrix[3] / hy + 0.5);
1037     fc->s.m2.matrix_scale = 16;
1038     fc->s.m2.xworld_res = font_scale->HWResolution[0] >> 16;
1039     fc->s.m2.yworld_res = font_scale->HWResolution[1] >> 16;
1040 
1041     if ((hx > 0 && hy > 0) && (hx < 1.5 || hy < 1.5)) {
1042         world_scale = 8;
1043         hx *= 256;
1044         hy *= 256;
1045 
1046         while (hx < 1.5 || hy < 1.5) {
1047             world_scale += 8;
1048             hx *= 256;
1049             hy *= 256;
1050         }
1051     }
1052     fc->s.m2.world_scale = world_scale;
1053     fc->s.m2.point_size   = (int)(hy * 8 + 0.5); /* 1/8ths of pixels */
1054     fc->s.m2.set_size     = (int)(hx * 8 + 0.5);
1055     fc->numXsubpixels = font_scale->subpixels[0];
1056     fc->numYsubpixels = font_scale->subpixels[1];
1057     fc->alignment = (font_scale->align_to_pixels ? GAGG : GAPP);
1058     fc->ExtndFlags = 0;
1059     if (d->font_type == FC_TT_TYPE)
1060         fc->ssnum = USER_CMAP;
1061     else if (d->font_type == FC_FCO_TYPE) {
1062         fc->ssnum = UNICODE;
1063     } else if (d->font_type == FC_PST1_TYPE) {
1064         fc->ssnum = T1ENCODING;
1065     }
1066 
1067     if (d->font_type != FC_TT_TYPE && d->font_type != FC_FCO_TYPE) {
1068         fc->ExtndFlags = EF_NOSYMSETMAP;
1069     }
1070     fc->ExtndFlags |= EF_SUBSTHOLLOWBOX_TYPE;
1071     fc->format      |= FC_NON_Z_WIND;   /* NON_ZERO Winding required for TrueType */
1072     fc->format      |= FC_INCHES_TYPE;  /* output in units per inch */
1073     fc->user_platID = d->platformId;
1074     fc->user_specID = d->specificId;
1075     if (use_XL_format)
1076         fc->ExtndFlags |= EF_XLFONT_TYPE;
1077     if (ff->is_vertical)
1078         fc->ExtndFlags |= EF_UFSTVERT_TYPE;
1079     fc->dl_ssnum = (d->specificId << 4) | d->platformId;
1080     fc->ttc_index   = ff->subfont;
1081     r->callback_error = 0;
1082 
1083     code = CGIFfont(FSA fc);
1084     if (r->callback_error != 0)
1085         return r->callback_error;
1086 
1087     code = CGIFfont_metrics(&fm);
1088     if (r->callback_error != 0)
1089         return r->callback_error;
1090 
1091     return code;
1092 }
1093 
get_decodingID(FAPI_server * server,FAPI_font * ff,const char ** decodingID_result)1094 static FAPI_retcode get_decodingID(FAPI_server *server, FAPI_font *ff, const char **decodingID_result)
1095 {   fapi_ufst_server *r = If_to_I(server);
1096     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
1097 
1098     *decodingID_result = d->decodingID;
1099     return 0;
1100 }
1101 
get_font_bbox(FAPI_server * server,FAPI_font * ff,int BBox[4])1102 static FAPI_retcode get_font_bbox(FAPI_server *server, FAPI_font *ff, int BBox[4])
1103 {   fapi_ufst_server *r = If_to_I(server);
1104     SW16 VLCPower = 0;
1105     int code;
1106     FSA_FROM_SERVER;
1107 
1108     if ((code = CGIFbound_box(FSA BBox, &VLCPower)) < 0)
1109         return code;
1110     /*  UFST expands bbox for internal needs, and retrives the expanded bbox.
1111         We believe it's bug in UFST.
1112         Now we collapse it back to the correct size :
1113     */
1114     BBox[0] += 2;
1115     BBox[1] += 2;
1116     BBox[2] -= 2;
1117     BBox[3] -= 2;
1118     BBox[0] >>= VLCPower;
1119     BBox[1] >>= VLCPower;
1120     BBox[2] >>= VLCPower;
1121     BBox[3] >>= VLCPower;
1122     return 0;
1123 }
1124 
get_font_proportional_feature(FAPI_server * server,FAPI_font * ff,bool * bProportional)1125 static FAPI_retcode get_font_proportional_feature(FAPI_server *server, FAPI_font *ff, bool *bProportional)
1126 {   fapi_ufst_server *r = If_to_I(server);
1127     FSA_FROM_SERVER;
1128 
1129     *bProportional = FALSE;
1130     if (ff->font_file_path == NULL || ff->is_type1)
1131         return 0;
1132 #if TT_ROM || TT_DISK
1133     {
1134         UB8 buf[74];
1135         UL32 length = sizeof(buf);
1136 
1137     if (CGIFtt_query(FSA (UB8 *)ff->font_file_path, *(UL32 *)"OS/2", (UW16)ff->subfont, &length, buf) != 0)
1138         return 0; /* No OS/2 table - no chance to get the info. Use default == FALSE. */
1139     *bProportional = (buf[35] == 9);
1140     }
1141 #endif
1142     return 0;
1143 }
1144 
make_asciiz_char_name(char * buf,int buf_length,FAPI_char_ref * c)1145 static inline void make_asciiz_char_name(char *buf, int buf_length, FAPI_char_ref *c)
1146 {   int len = min(buf_length - 1, c->char_name_length);
1147 
1148     memcpy(buf, c->char_name, len);
1149     buf[len] = 0;
1150 }
1151 
1152 #define MAX_CHAR_NAME_LENGTH 30
1153 
can_retrieve_char_by_name(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,int * result)1154 static FAPI_retcode can_retrieve_char_by_name(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, int *result)
1155 {   fapi_ufst_server *r = If_to_I(server);
1156     FSA_FROM_SERVER;
1157 
1158     *result = 0;
1159 
1160     switch (r->fc.format & FC_FONTTYPE_MASK) {
1161         case FC_PST1_TYPE :
1162             *result = 1;
1163             break;
1164         case FC_TT_TYPE :
1165             break;
1166     }
1167 
1168     return 0;
1169 }
1170 
can_replace_metrics(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,int * result)1171 static FAPI_retcode can_replace_metrics(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, int *result)
1172 {   *result = (!ff->is_type1 && ff->font_file_path == NULL &&
1173                c->metrics_scale == 0 && c->metrics_type == FAPI_METRICS_REPLACE);
1174     return 0;
1175 }
1176 
release_glyphs(fapi_ufst_server * r,ufst_common_font_data * d)1177 static void release_glyphs(fapi_ufst_server *r, ufst_common_font_data *d)
1178 {
1179     if (d) {
1180         while (d->glyphs != 0) {
1181             pcleo_glyph_list_elem *e = d->glyphs;
1182             d->glyphs = e->next;
1183             gs_free(r->mem, e, 0, 0, "PCLEO char");
1184         }
1185         d->glyphs = NULL;
1186     }
1187 }
1188 
get_fontmatrix(FAPI_server * I,gs_matrix * m)1189 static FAPI_retcode get_fontmatrix(FAPI_server *I, gs_matrix *m)
1190 {
1191     fapi_ufst_server *r = If_to_I(I);
1192     ufst_common_font_data *d = (ufst_common_font_data *)I->ff.server_font_data;
1193     FAPI_retcode code = 0;
1194 
1195     if (d == 0) {
1196         if ((code = make_font_data(r, I->ff.font_file_path, &(I->ff), &d)) != 0)
1197             return (code);
1198         I->ff.server_font_data = d;
1199         prepare_typeface(r, d);
1200     }
1201 
1202     /* There are PS jobs that rely on the standard fonts having
1203      * a FontMatrix of [0.001 0 0 0.001 0 0], but MT fonts actually
1204      * have an identity matrix. We need to compensate here. Other
1205      * fonts need an identity matrix returned here, as we apply the
1206      * font matrix explicitly in the scale calculation in zfapi.c
1207      */
1208     if (d->font_type & FC_FCO_TYPE) {
1209         m->xx = 0.001;
1210         m->xy = 0.0;
1211         m->yx = 0.0;
1212         m->yy = 0.001;
1213         m->tx = 0.0;
1214         m->ty = 0.0;
1215     }
1216     else {
1217         m->xx = 1.0;
1218         m->xy = 0.0;
1219         m->yx = 0.0;
1220         m->yy = 1.0;
1221         m->tx = 0.0;
1222         m->ty = 0.0;
1223     }
1224 
1225 #if 0
1226     gs_matrix *base_font_matrix = &I->initial_FontMatrix;
1227     m->xx = I->initial_FontMatrix.xx;
1228     m->xy = I->initial_FontMatrix.xy;
1229     m->yx = I->initial_FontMatrix.yx;
1230     m->yy = I->initial_FontMatrix.yy;
1231     m->tx = I->initial_FontMatrix.tx;
1232     m->ty = I->initial_FontMatrix.ty;
1233 #endif
1234     return (code);
1235 
1236 }
1237 
export_outline(fapi_ufst_server * r,PIFOUTLINE pol,FAPI_path * p)1238 static int export_outline(fapi_ufst_server *r, PIFOUTLINE pol, FAPI_path *p)
1239 {   POUTLINE_CHAR outchar;
1240     SW16 num_contrs,num_segmts;
1241     LPSB8 segment;
1242     PINTRVECTOR points;
1243     SW16  i,j;
1244 
1245     if (pol == NULL)
1246         return 0;
1247     p->shift += r->If.frac_shift + pol->VLCpower;
1248     outchar = &pol->ol;
1249     num_contrs = outchar->num_loops;
1250     for(i = 0; i<num_contrs; i++) {
1251         num_segmts = outchar->loop[i].num_segmts;
1252         segment = (LPSB8)((LPSB8)(outchar->loop) + outchar->loop[i].segmt_offset);
1253         points = (PINTRVECTOR)((LPSB8)(outchar->loop) + outchar->loop[i].coord_offset);
1254         for(j=0; j<num_segmts; j++) {
1255 
1256             if(*segment == 0x00) {
1257                 if ((p->gs_error = p->moveto(p, ((int64_t)points->x) << 16, ((int64_t)points->y) << 16)) != 0)
1258                     return p->gs_error;
1259                 points++;
1260             } else if (*segment == 0x01) {
1261                 if ((p->gs_error = p->lineto(p, ((int64_t)points->x) << 16, ((int64_t)points->y) << 16)) != 0)
1262                     return p->gs_error;
1263                 points++;
1264             } else if (*segment == 0x02) {
1265                 points+=2;
1266                 return e_invalidfont; /* This must not happen */
1267             } else if (*segment == 0x03) {
1268                 if ((p->gs_error = p->curveto(p, ((int64_t)points[0].x) << 16, ((int64_t)points[0].y) << 16,
1269                                         ((int64_t)points[1].x) << 16, ((int64_t)points[1].y) << 16,
1270                                         ((int64_t)points[2].x) << 16, ((int64_t)points[2].y)<< 16) < 0))
1271                     return p->gs_error;
1272                 points+=3;
1273             } else
1274                 return e_invalidfont; /* This must not happen */
1275             segment++;
1276         }
1277     }
1278     return 0;
1279 }
1280 
set_metrics(fapi_ufst_server * r,FAPI_metrics * metrics,SL32 design_bbox[4],SW16 design_escapement[2],SW16 du_emx,SW16 du_emy)1281 static inline void set_metrics(fapi_ufst_server *r, FAPI_metrics *metrics, SL32 design_bbox[4], SW16 design_escapement[2], SW16 du_emx, SW16 du_emy)
1282 {
1283 
1284     metrics->escapement = design_escapement[0];
1285     metrics->v_escapement = design_escapement[1];
1286     metrics->em_x = du_emx;
1287     metrics->em_y = du_emy;
1288     metrics->bbox_x0 = design_bbox[0];
1289     metrics->bbox_y0 = design_bbox[1];
1290     metrics->bbox_x1 = design_bbox[2];
1291     metrics->bbox_y1 = design_bbox[3];
1292 }
1293 
get_char(fapi_ufst_server * r,FAPI_font * ff,FAPI_char_ref * c,FAPI_path * p,FAPI_metrics * metrics,UW16 format)1294 static FAPI_retcode get_char(fapi_ufst_server *r, FAPI_font *ff, FAPI_char_ref *c, FAPI_path *p, FAPI_metrics *metrics, UW16 format)
1295 {
1296     UW16 code = 0, code2 = 0;
1297     UW16 cc = (UW16)c->char_code;
1298     SL32 design_bbox[4];
1299     char PSchar_name[MAX_CHAR_NAME_LENGTH];
1300     MEM_HANDLE result;
1301     ufst_common_font_data *d = (ufst_common_font_data *)ff->server_font_data;
1302     SW16 design_escapement[2];
1303     SW16 du_emx, du_emy;
1304     const char *notdef = ".notdef";
1305     const void *client_char_data = ff->char_data;
1306     const int client_char_data_len = ff->char_data_len;
1307     bool need_decrypt = ff->need_decrypt;
1308     int length;
1309     FSA_FROM_SERVER;
1310 
1311     design_escapement[0] = design_escapement[1] = 0;
1312 
1313     if (ff->is_type1) {
1314         /* If a charstring in a Type 1 has been replaced with a PS procedure
1315          * get_glyph will return -1. We can then return char_code + 1 which
1316          * tells the FAPI code we might be dealing with a procedure, and to
1317          * try executing it as such.
1318          */
1319         ff->need_decrypt = false;
1320         length = ff->get_glyph(ff, c->char_code, NULL, 0);
1321         ff->need_decrypt = need_decrypt;
1322         if (length == -1) {
1323             return(c->char_code + 1);
1324         }
1325     }
1326 
1327     memset(metrics, 0, sizeof(*metrics));
1328     metrics->bbox_x1 = -1;
1329 
1330     if (ff->is_type1 && !ff->is_cid) {
1331         int len = min(ff->char_data_len, sizeof(PSchar_name) - 1);
1332         memcpy (PSchar_name, ff->char_data, len);
1333         PSchar_name[len] = 0;
1334     } else {
1335         make_asciiz_char_name(PSchar_name, sizeof(PSchar_name), c);
1336     }
1337 
1338     CGIFchIdptr(FSA &cc, PSchar_name); /* fixme : Likely only FC_PST1_TYPE needs it. */
1339     {   /* hack : Changing UFST internal data. Change to r->fc doesn't help,
1340            because UFST thinks that the "outline/raster" is a property of current font. */
1341         pIFS->fcCur.format &= ~FC_OUTPUT_MASK;
1342         pIFS->fcCur.format |= format;
1343     }
1344     r->bRaster = FALSE;
1345     r->ff = ff;
1346     r->callback_error = 0;
1347     r->sb_x = c->sb_x;
1348     r->aw_x = c->aw_x;
1349     r->metrics_type = c->metrics_type;
1350     if (d->font_type == FC_FCO_TYPE && r->fc.ExtndFlags & EF_SUBSTHOLLOWBOX_TYPE) {
1351         if (c->char_name != NULL && c->char_name_length == 7 &&
1352                 !memcmp(c->char_name, ".notdef", 7)) {
1353             /* With EF_SUBSTHOLLOWBOX_TYPE and FCO,
1354                UFST paints a hollow box insted .notdef .
1355                For Adobe compatibility we substitute a space,
1356                because Adobe Type 1 fonts define .notdef as a space . */
1357             cc = 32;
1358         }
1359     }
1360 #if !UFST_REENTRANT
1361     static_server_ptr_for_ufst_callback = r;
1362 #endif
1363     code = CGIFchar_handle(FSA cc, &result, (SW16)0);
1364     if (code && code != ERR_fixed_space && code != ERR_bm_buff && code != ERR_bm_too_big) {
1365         /* There is no such char in the font, try the glyph 0 (notdef) : */
1366         UW16 c1 = 0, ssnum = pIFS->fcCur.ssnum;
1367 
1368         if (d->font_type == FC_FCO_TYPE) {
1369             /* EF_SUBSTHOLLOWBOX_TYPE must work against it.
1370                Ensure the plugin plug__xi.fco is loaded. */
1371             /* fixme : Due to unknown reason EF_SUBSTHOLLOWBOX_TYPE
1372                doesn't work for Symbol, Dingbats, Wingdings.
1373                hack : render the space character. */
1374             c1 = 32;
1375         } else {
1376             /* hack : Changing UFST internal data - see above. */
1377             pIFS->fcCur.ssnum = RAW_GLYPH;
1378         }
1379         r->callback_error = 0;
1380         ff->char_data = (void *)notdef;
1381         ff->char_data_len = strlen(notdef);
1382         CGIFchIdptr(FSA (void *)&c1, (void *)notdef);
1383         code2 = CGIFchar_handle(FSA c1, &result, (SW16)0);
1384         if (code2 && code2 != ERR_fixed_space && code2 != ERR_bm_buff && code2 != ERR_bm_too_big) {
1385             ff->char_data = (void *)"space";
1386             ff->char_data_len = strlen("space");
1387             CGIFchIdptr(FSA (void *)&c1, (void *)"space");
1388             code2 = CGIFchar_handle(FSA c1, &result, (SW16)0);
1389         }
1390         if (!code2 || code2 == ERR_fixed_space) {
1391             code = code2;
1392         }
1393         pIFS->fcCur.ssnum = ssnum;
1394     }
1395     ff->char_data = client_char_data;
1396     ff->char_data_len = client_char_data_len;
1397 
1398 #if !UFST_REENTRANT
1399     static_server_ptr_for_ufst_callback = 0;
1400 #endif
1401     r->ff = 0;
1402     release_glyphs(r, (ufst_common_font_data *)ff->server_font_data);
1403     if (code != ERR_fixed_space && code != 0)
1404         return code;
1405     if (r->callback_error != 0)
1406         return r->callback_error;
1407     if (format == FC_BITMAP_TYPE) {
1408         IFBITMAP *pbm = (IFBITMAP *)result;
1409 
1410         du_emx = pbm->du_emx;
1411         du_emy = pbm->du_emy;
1412         r->char_data = pbm;
1413         r->bRaster = TRUE;
1414 
1415                 design_escapement[0] = pbm->escapement;
1416 
1417 #if UFST_VERSION_MAJOR >= 6 && UFST_VERSION_MINOR >= 2
1418 
1419         design_bbox[0] = pIFS->glyphMetricsDU.bbox.BBox[0];
1420         design_bbox[1] = pIFS->glyphMetricsDU.bbox.BBox[1];
1421         design_bbox[2] = pIFS->glyphMetricsDU.bbox.BBox[2];
1422         design_bbox[3] = pIFS->glyphMetricsDU.bbox.BBox[3];
1423         if (d->font_type != FC_FCO_TYPE) {
1424             design_escapement[0] = pIFS->glyphMetricsDU.aw.x;
1425             design_escapement[1] = pIFS->glyphMetricsDU.aw.y;
1426         }
1427 #endif
1428 
1429     } else {
1430         IFOUTLINE *pol = (IFOUTLINE *)result;
1431 
1432         design_escapement[0] = pol->escapement;
1433         du_emx = pol->du_emx;
1434         du_emy = pol->du_emy;
1435         r->char_data = (IFOUTLINE *)result;
1436     }
1437 #if 1 /* UFST 5.0 */
1438     if (USBOUNDBOX && d->font_type == FC_FCO_TYPE) {
1439         if (pIFS->USBBOXorigScaleFactor /* fixme : Must we check this ? */
1440             && pIFS->USBBOXorigScaleFactor != pIFS->USBBOXscaleFactor) {
1441             /* See fco_make_gaso_and_stats in fc_if.c . Debugged with hollow box in Helvetica. */
1442             /* Fixme : this looses a precision, an UFST bug has been reported. */
1443             int w = pIFS->USBBOXorigScaleFactor / 2;
1444 
1445             design_bbox[0] = pIFS->USBBOXxmin * pIFS->USBBOXscaleFactor / pIFS->USBBOXorigScaleFactor;
1446             design_bbox[1] = pIFS->USBBOXymin * pIFS->USBBOXscaleFactor / pIFS->USBBOXorigScaleFactor;
1447             design_bbox[2] = (pIFS->USBBOXxmax * pIFS->USBBOXscaleFactor + w) / pIFS->USBBOXorigScaleFactor;
1448             design_bbox[3] = (pIFS->USBBOXymax * pIFS->USBBOXscaleFactor + w) / pIFS->USBBOXorigScaleFactor;
1449         } else {
1450             design_bbox[0] = pIFS->USBBOXxmin;
1451             design_bbox[1] = pIFS->USBBOXymin;
1452             design_bbox[2] = pIFS->USBBOXxmax;
1453             design_bbox[3] = pIFS->USBBOXymax;
1454         }
1455     } else {
1456 #if UFST_VERSION_MAJOR >= 6 && UFST_VERSION_MINOR >= 2
1457 #else
1458         /* fixme: UFST 5.0 doesn't provide this data.
1459            Stubbing with Em box.
1460            Non-FCO fonts may be cropped if a glyph goes outside Em box
1461            (or occupy negative coordinates, such as 'y'.).
1462            Non-FCO fonts may be uncached if Em box is much bigger than the glyph.
1463          */
1464         design_bbox[0] = 0;
1465         design_bbox[1] = 0;
1466         design_bbox[2] = du_emx;
1467         design_bbox[3] = du_emy;
1468 #endif
1469     }
1470 #endif
1471     {	/* UFST performs a dual rounding of the glyph origin : first
1472            the scaled glyph design origin is rounded to pixels with floor(x + 0.5),
1473            second the glyph position is rounded to pixels with floor(x + 0.5).
1474            Ghostscript rounds with floor(x) due to the pixel-center-inside rule.
1475 
1476            A right way would be to specify the half pixel offset to the glyph
1477            origin for the rendering glyph, but UFST has no interface for doing that.
1478            Instead that, to prevent a possible cropping while copying a glyph to cache cell,
1479            we expand the design bbox in a value of a pixel size.
1480            We could not determine the necessary expansion theoretically,
1481            and choosen expansion coefficients empirically,
1482            which appears equal to 2 pixels.
1483 
1484            fixme: Actually the expansion is the FONTCONTEXT property,
1485            so it could be computed at once when the scaled font is created.
1486          */
1487         const double expansion_x = 2, expansion_y = 2; /* pixels */ /* adesso5.pdf */
1488         const double XX = r->tran_xx * (r->fc.s.m2.xworld_res >> 16) / 72 / du_emx;
1489         const double XY = r->tran_xy * (r->fc.s.m2.yworld_res >> 16) / 72 / du_emy;
1490         const double YX = r->tran_yx * (r->fc.s.m2.xworld_res >> 16) / 72 / du_emx;
1491         const double YY = r->tran_yy * (r->fc.s.m2.yworld_res >> 16) / 72 / du_emy;
1492         const double det = XX * YY - XY * YX;
1493         const double deta = det < 0 ? -det : det;
1494 
1495         if (deta > 0.0000000001) {
1496             const double xx =  YY / det, xy = -XY / det;
1497             const double yx = -YX / det, yy =  XX / det;
1498             const double dx = -(expansion_x * xx + expansion_y * xy);
1499             const double dy = -(expansion_x * yx + expansion_y * yy);
1500             const SL32 dxa = (SL32)((dx < 0 ? -dx : dx) + 0.5);
1501             const SL32 dya = (SL32)((dy < 0 ? -dy : dy) + 0.5);
1502 
1503             design_bbox[0] -= dxa;
1504             design_bbox[1] -= dya;
1505             design_bbox[2] += dxa;
1506             design_bbox[3] += dya;
1507         }
1508     }
1509     set_metrics(r, metrics, design_bbox, design_escapement, du_emx, du_emy);
1510     if (code == ERR_fixed_space)
1511         release_char_data_inline(r);
1512     return 0;
1513 }
1514 
get_char_outline_metrics(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,FAPI_metrics * metrics)1515 static FAPI_retcode get_char_outline_metrics(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, FAPI_metrics *metrics)
1516 {   fapi_ufst_server *r = If_to_I(server);
1517 
1518     release_char_data_inline(r);
1519     return get_char(r, ff, c, NULL, metrics, FC_CUBIC_TYPE);
1520     /*	UFST cannot render enough metrics information without generating raster or outline.
1521         r->char_data keeps an outline after calling this function.
1522     */
1523 }
1524 
get_char_outline(FAPI_server * server,FAPI_path * p)1525 static FAPI_retcode get_char_outline(FAPI_server *server, FAPI_path *p)
1526 {   fapi_ufst_server *r = If_to_I(server);
1527 
1528     return export_outline(r, (IFOUTLINE *)r->char_data, p);
1529 }
1530 
get_char_raster_metrics(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,FAPI_metrics * metrics)1531 static FAPI_retcode get_char_raster_metrics(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, FAPI_metrics *metrics)
1532 {
1533     fapi_ufst_server *r = If_to_I(server);
1534     int code;
1535 
1536     release_char_data_inline(r);
1537     code = get_char(r, ff, c, NULL, metrics, FC_BITMAP_TYPE);
1538     if (code == ERR_bm_buff || code == ERR_bm_too_big) /* Too big character ? */
1539         return (e_VMerror);
1540     return code;
1541     /*	UFST cannot render enough metrics information without generating raster or outline.
1542         r->char_data keeps a raster after calling this function.
1543     */
1544 }
1545 
get_char_width(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,FAPI_metrics * metrics)1546 static FAPI_retcode get_char_width(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, FAPI_metrics *metrics)
1547 {
1548     fapi_ufst_server *r = If_to_I(server);
1549     int code;
1550 
1551     release_char_data_inline(r);
1552     code = get_char(r, ff, c, NULL, metrics, server->use_outline ? FC_CUBIC_TYPE : FC_BITMAP_TYPE);
1553     if (code == ERR_bm_buff || code == ERR_bm_too_big) /* Too big character ? */
1554         return (e_VMerror);
1555     return code;
1556     /*	UFST cannot render enough metrics information without generating raster or outline.
1557         r->char_data keeps a raster after calling this function.
1558     */
1559 }
1560 
1561 
get_char_raster(FAPI_server * server,FAPI_raster * rast)1562 static FAPI_retcode get_char_raster(FAPI_server *server, FAPI_raster *rast)
1563 {   fapi_ufst_server *r = If_to_I(server);
1564 
1565     if (!r->bRaster)
1566         return e_limitcheck;
1567     else if (r->char_data == NULL) {
1568         rast->height = rast->width = rast->line_step = 0;
1569         rast->p = 0;
1570     } else {
1571         IFBITMAP *pbm = (IFBITMAP *)r->char_data;
1572         rast->p = pbm->bm;
1573         rast->height = pbm->top_indent + pbm->black_depth;
1574         rast->width = pbm->left_indent + pbm->black_width;
1575         rast->line_step = pbm->width;
1576         rast->left_indent = pbm->left_indent;
1577         rast->top_indent = pbm->top_indent;
1578         rast->black_width = pbm->black_width;
1579         rast->black_height = pbm->black_depth;
1580         if (rast->width != 0) {
1581             rast->orig_x = pbm->xorigin;
1582             rast->orig_y = pbm->yorigin;
1583         } else
1584             rast->orig_x = rast->orig_y = 0;
1585     }
1586     return 0;
1587 }
1588 
release_char_data(FAPI_server * server)1589 static FAPI_retcode release_char_data(FAPI_server *server)
1590 {   fapi_ufst_server *r = If_to_I(server);
1591 
1592     release_char_data_inline(r);
1593     return 0;
1594 }
1595 
release_fco(fapi_ufst_server * r,SW16 fcHandle)1596 static void release_fco(fapi_ufst_server *r, SW16 fcHandle)
1597 {
1598     fco_list_elem **e;
1599 
1600     if(gx_UFST_find_static_fco_handle(fcHandle) != NULL)
1601         return;
1602     for (e = &r->fco_list; *e != 0; )
1603         if ((*e)->fcHandle == fcHandle && (--(*e)->open_count) == 0) {
1604             fco_list_elem *ee = *e;
1605             FSA_FROM_SERVER;
1606 
1607             *e = ee->next;
1608             CGIFfco_Close(FSA ee->fcHandle);
1609             gs_free(r->mem, ee->file_path, 0, 0, "fco_file_path");
1610             gs_free(r->mem, ee, 0, 0, "fco_list_elem");
1611         } else
1612             e = &(*e)->next;
1613 }
1614 
FAPIU_release_typeface(FAPI_server * server,void * font_data)1615 static FAPI_retcode FAPIU_release_typeface(FAPI_server *server, void *font_data)
1616 {   fapi_ufst_server *r = If_to_I(server);
1617     ufst_common_font_data *d;
1618     FAPI_retcode code = 0;
1619     FSA_FROM_SERVER;
1620 
1621     release_char_data_inline(r);
1622     if (font_data == 0)
1623         return 0;
1624     d = (ufst_common_font_data *)font_data;
1625 #if 0
1626     prepare_typeface(r, d);
1627     if (d->is_disk_font)
1628         code = CGIFhdr_font_purge(FSA &r->fc);
1629     else
1630         code = CGIFfont_purge(FSA &r->fc);
1631 #endif
1632 
1633     release_glyphs(r, d);
1634     release_fco(r, (SW16)(d->font_id >> 16));
1635     gs_free(r->mem, font_data, 0, 0, "ufst font data");
1636     return code;
1637 }
1638 
check_cmap_for_GID(FAPI_server * server,uint * index)1639 static FAPI_retcode check_cmap_for_GID(FAPI_server *server, uint *index)
1640 {
1641     return 0;
1642 }
1643 
1644 /* --------------------- The plugin definition : ------------------------- */
1645 
1646 static void gs_fapiufst_finit(i_plugin_instance *instance, i_plugin_client_memory *mem);
1647 
1648 static const i_plugin_descriptor ufst_descriptor = {
1649     "FAPI",
1650     "UFST",
1651     gs_fapiufst_finit
1652 };
1653 
1654 static const FAPI_server If0 = {
1655     {   &ufst_descriptor
1656     },
1657     16, /* frac_shift */
1658     {gs_no_id},
1659     {0},
1660     0,
1661     false,
1662     {1, 0, 0, 1, 0, 0},
1663     ensure_open,
1664     get_scaled_font,
1665     get_decodingID,
1666     get_font_bbox,
1667     get_font_proportional_feature,
1668     can_retrieve_char_by_name,
1669     can_replace_metrics,
1670     get_fontmatrix,
1671     get_char_width,
1672     get_char_raster_metrics,
1673     get_char_raster,
1674     get_char_outline_metrics,
1675     get_char_outline,
1676     release_char_data,
1677     FAPIU_release_typeface,
1678     check_cmap_for_GID
1679 };
1680 
fapiu_make_string(i_ctx_t * i_ctx_p,const char * str,ref * obj)1681 static int fapiu_make_string (i_ctx_t *i_ctx_p, const char *str, ref *obj)
1682 {
1683     int len = strlen(str);
1684     byte *sbody;
1685 
1686     sbody = ialloc_string(len, "fapiu_make_string");
1687     if (!sbody) {
1688         return(e_VMerror);
1689     }
1690     memcpy (sbody, str, len);
1691 
1692     make_string(obj, a_all | icurrent_space, len, sbody);
1693 
1694     return(0);
1695 }
1696 
1697 plugin_instantiation_proc(gs_fapiufst_instantiate);      /* check prototype */
1698 
gs_fapiufst_instantiate(i_plugin_client_memory * client_mem,i_plugin_instance ** p_instance)1699 int gs_fapiufst_instantiate(i_plugin_client_memory *client_mem, i_plugin_instance **p_instance)
1700 {
1701     fapi_ufst_server *r = (fapi_ufst_server *)client_mem->alloc(client_mem, sizeof(fapi_ufst_server), "fapi_ufst_server");
1702     i_ctx_t *i_ctx_p = NULL;
1703     gs_main_instance *inst;
1704     ref entry;
1705     char tmppath[gp_file_name_sizeof];
1706     int code = 0;
1707 
1708     if (r == 0)
1709         return e_Fatal;
1710     memset(r, 0, sizeof(*r));
1711     r->If = If0;
1712 
1713     code = gs_memory_chunk_wrap(&(r->mem), client_mem->client_data);
1714     if (code != 0) {
1715         return(code);
1716     }
1717 
1718     *p_instance = &r->If.ig;
1719 
1720     inst = get_minst_from_memory((const gs_memory_t *)(client_mem->client_data));
1721     i_ctx_p = inst->i_ctx_p;
1722 
1723     /* The following entries will get overwritten if the user specifies alternative settings
1724      * on the command line.
1725      */
1726     strncpy(tmppath, UFSTFONTDIR, gp_file_name_sizeof);
1727     strncat(tmppath, UFST_PlugIn_Path, gp_file_name_sizeof - strlen(tmppath));
1728 
1729     fapiu_make_string (i_ctx_p, (const char *)tmppath, &entry);
1730     (void)dict_put_string(systemdict, UFST_PlugIn_Str, &entry, NULL);
1731 
1732     strncpy(tmppath, UFSTFONTDIR, gp_file_name_sizeof);
1733     strncat(tmppath, FCOfontfilePath, gp_file_name_sizeof - strlen(tmppath));
1734 
1735     fapiu_make_string (i_ctx_p, (const char *)tmppath, &entry);
1736     (void)dict_put_string(systemdict, FCOfontfileStr, &entry, NULL);
1737 
1738     strncpy(tmppath, UFSTFONTDIR, gp_file_name_sizeof);
1739     strncat(tmppath, FCOfontfile2Path, gp_file_name_sizeof - strlen(tmppath));
1740 
1741     fapiu_make_string (i_ctx_p, (const char *)tmppath, &entry);
1742     (void)dict_put_string(systemdict, FCOfontfile2Str, &entry, NULL);
1743 
1744     fapiu_make_string (i_ctx_p, FAPIfontmap, &entry);
1745     (void)dict_put_string(systemdict, FAPIfontmapStr, &entry, NULL);
1746 
1747     return 0;
1748 }
1749 
1750 #ifndef UFST_MEMORY_CHECKING
1751 #define UFST_MEMORY_CHECKING 0
1752 #endif
1753 
1754 #if UFST_MEMORY_CHECKING
1755 extern unsigned long maxmem;
1756 #endif
1757 
gs_fapiufst_finit(i_plugin_instance * this,i_plugin_client_memory * mem)1758 static void gs_fapiufst_finit(i_plugin_instance *this, i_plugin_client_memory *mem)
1759 {   fapi_ufst_server *r = (fapi_ufst_server *)this;
1760     FSA_FROM_SERVER;
1761 
1762 #if UFST_MEMORY_CHECKING
1763     dprintf1("UFST used %Lf kb\n", ((long double)maxmem) / 1024);
1764 #endif
1765 
1766     if (r->If.ig.d != &ufst_descriptor)
1767         return; /* safety */
1768 #if 0 /* Disabled against a reentrancy problem
1769          in a single language build for host-based applications. */
1770     gx_set_UFST_Callbacks(NULL, NULL, NULL);
1771 #endif
1772     release_char_data_inline(r);
1773     if (r->bInitialized && !r->ufst_is_singleton)
1774         gx_UFST_fini();
1775     if (r->param) {
1776         gs_free (r->mem, r->param, 0, 0, "server_params");
1777     }
1778     gs_memory_chunk_release (r->mem);
1779 
1780     mem->free(mem, r, "fapi_ufst_server");
1781 }
1782