1 /* Copyright (C) 2001-2006 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, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: fapiufst.c 10653 2010-01-28 14:32:52Z ken $ */
15 /* Agfa UFST plugin */
16 
17 /* GS includes : */
18 #include "stdio_.h"
19 #include "memory_.h"
20 #include "math_.h"
21 #include "ierrors.h"
22 #include "iplugin.h"
23 #include "ifapi.h"
24 #include "strmio.h"
25 /* UFST includes : */
26 #undef true	/* GS/UFST definition conflict. */
27 #undef false	/* GS/UFST definition conflict. */
28 #include "cgconfig.h"
29 #include "ufstport.h"
30 #include "dbg_ufst.h"
31 #include "shareinc.h"
32 #include "t1isfnt.h"
33 #include "cgmacros.h"
34 #include "sfntenum.h"
35 #define DOES_ANYONE_USE_THIS_STRUCTURE /* see TTPCLEO.H, UFST 4.2 */
36 #include "ttpcleo.h"
37 #undef  DOES_ANYONE_USE_THIS_STRUCTURE
38 #include "gxfapiu.h"
39 
40 typedef struct fapi_ufst_server_s fapi_ufst_server;
41 
42 #if UFST_REENTRANT
43 #define FSA_FROM_SERVER IF_STATE *pIFS = &r->IFS
44 #else
45 EXTERN IF_STATE if_state;
46 #define FSA_FROM_SERVER IF_STATE *pIFS = &if_state;    (void)r; (void)pIFS;
47 static fapi_ufst_server *static_server_ptr_for_ufst_callback = 0;
48 #endif
49 
50 GLOBAL UW16  PCLswapHdr( FSP LPUB8 p, UW16 gifct ); /* UFST header doesn't define it. */
51 
52 typedef struct pcleo_glyph_list_elem_s pcleo_glyph_list_elem;
53 struct pcleo_glyph_list_elem_s {
54     UW16 chId;
55     pcleo_glyph_list_elem *next;
56     /* more data follows here depending on font type */
57 };
58 
59 typedef struct {
60     SL32 font_id;
61     uint tt_font_body_offset;
62     UW16 is_disk_font;
63     UW16 font_type;
64     UW16 platformId;
65     UW16 specificId;
66     pcleo_glyph_list_elem *glyphs;
67     char decodingID[40];
68 } ufst_common_font_data;
69 
70 typedef struct {
71     PCLETTO_CHR_HDR h;
72     UW16   add_data;
73     UW16   charDataSize;
74     UW16   glyphID;
75 } PCLETTO_CHDR;
76 
77 struct fapi_ufst_server_s {
78     FAPI_server If;
79     int bInitialized;
80     FAPI_font *ff;
81     i_plugin_client_memory client_mem;
82     IF_STATE IFS;
83     FONTCONTEXT fc;
84     void *char_data;
85     bool bRaster;
86     bool ufst_is_singleton;
87     double tran_xx, tran_xy, tran_yx, tran_yy;
88     fco_list_elem *fco_list;
89     FAPI_retcode callback_error;
90     FAPI_metrics_type metrics_type;
91     FracInt sb_x, aw_x; /* replaced PS metrics. */
92 };
93 
94 /* Type casts : */
95 
If_to_I(FAPI_server * If)96 static inline fapi_ufst_server *If_to_I(FAPI_server *If)
97 {   return (fapi_ufst_server *)If;
98 }
99 
IFS_to_I(IF_STATE * pIFS)100 static inline fapi_ufst_server *IFS_to_I(IF_STATE *pIFS)
101 {   return (fapi_ufst_server *)((char *)pIFS - offset_of(fapi_ufst_server, IFS));
102 }
103 
104 /*------------------ FAPI_server members ------------------------------------*/
105 
release_char_data_inline(fapi_ufst_server * r)106 static inline void release_char_data_inline(fapi_ufst_server *r)
107 {   /*  The server keeps character raster between calls to get_char_raster_metrics
108         and get_char_raster, as well as between calls to get_char_outline_metrics
109         and get_char_outline. Meanwhile this regular
110         sequence of calls may be interrupted by an error in CDefProc or setchachedevice2,
111         which may be invoked between them. In this case Ghostscript
112         is unable to provide a signal to FAPI that the data are not
113         longer needed. This would cause memory leaks in UFST heap.
114         To work around this, appropriate server's entries check whether
115         raster data were left after a previous call, and ultimately release them.
116         This function provides it.
117     */
118     if (r->char_data != NULL) {
119 	FSA_FROM_SERVER;
120 
121         CHARfree(FSA (MEM_HANDLE)r->char_data);
122         r->char_data = 0;
123     }
124 }
125 
126 /*
127  * In the language switch build (which we detect because PSI_INCLUDED
128  * is defined), we use the gx_UFST_init() call to initialize the UFST,
129  * rather than calling into the UFST directly. That has the advantage
130  * that the same UFST configuration is used for PCL and PS, but the
131  * disadvantage that the dynamic parameters set in server_param are
132  * not available. Thus, it is switched through this compile time option.
133 */
open_UFST(fapi_ufst_server * r,const byte * server_param,int server_param_size)134 static FAPI_retcode open_UFST(fapi_ufst_server *r, const byte *server_param, int server_param_size)
135 {
136     int code;
137     SW16 fcHandle;
138     int l;
139     char ufst_root_dir[1024] = "";
140     char sPlugIn[1024] = "";
141     bool bSSdir = false, bPlugIn = false;
142     const char *keySSdir = "UFST_SSdir=";
143     const int keySSdir_length = strlen(keySSdir);
144     const char *keyPlugIn = "UFST_PlugIn=";
145     const int keyPlugIn_length = strlen(keyPlugIn);
146     const char sep = gp_file_name_list_separator;
147     const byte *p = server_param, *e = server_param + server_param_size, *q;
148     FSA_FROM_SERVER;
149 
150     for (; p < e ; p = q + 1) {
151 	for (q = p; q < e && *q != sep; q++)
152 	    /* DO_NOTHING */;
153 	l = q - p;
154 	if (l > keySSdir_length && !memcmp(p, keySSdir, keySSdir_length)) {
155 	    l = q - p - keySSdir_length;
156 	    if (l > sizeof(ufst_root_dir) - 1)
157 		l = sizeof(ufst_root_dir) - 1;
158 	    memcpy(ufst_root_dir, p + keySSdir_length, l);
159 	    ufst_root_dir[l] = 0;
160 	    bSSdir = true;
161 	} else if (l > keyPlugIn_length && !memcmp(p, keyPlugIn, keyPlugIn_length)) {
162 	    l = q - p - keyPlugIn_length;
163 	    if (l > sizeof(sPlugIn) - 1)
164 		l = sizeof(sPlugIn) - 1;
165 	    memcpy(sPlugIn, p + keyPlugIn_length, l);
166 	    sPlugIn[l] = 0;
167 	    bPlugIn = true;
168 	} else
169 	    eprintf("Warning: Unknown UFST parameter ignored.\n");
170     }
171 #if !NO_SYMSET_MAPPING
172     if (!bSSdir) {
173 	strcpy(ufst_root_dir, ".");
174 	eprintf("Warning: UFST_SSdir is not specified, will search *.ss files in the curent directory.\n");
175     }
176 #endif
177     code = gx_UFST_init((const UB8 *)ufst_root_dir);
178     if (code < 0)
179 	return code;
180     r->ufst_is_singleton = (code == 1);
181     if (bPlugIn) {
182 	if ((code = gx_UFST_open_static_fco(sPlugIn, &fcHandle)) != 0)
183 	    return code;
184 	if ((code = CGIFfco_Plugin(FSA fcHandle)) != 0)
185 	    return code;
186     } else {
187 #ifdef FCO_RDR
188 	eprintf("Warning: UFST_PlugIn is not specified, some characters may be missing.\n");
189 #endif
190     }
191     return 0;
192 }
193 
194 static LPUB8 impl_PCLchId2ptr(FSP UW16 chId);
195 
ensure_open(FAPI_server * server,const byte * server_param,int server_param_size)196 static FAPI_retcode ensure_open(FAPI_server *server, const byte *server_param, int server_param_size)
197 {   fapi_ufst_server *r = If_to_I(server);
198     int code;
199 
200     if (r->bInitialized)
201         return 0;
202     r->bInitialized = 1;
203     {
204 	code = open_UFST(r, server_param, server_param_size);
205 	if (code < 0) {
206 	    eprintf("Error opening the UFST font server.\n");
207 	    return code;
208 	}
209     }
210     gx_set_UFST_Callbacks(NULL, impl_PCLchId2ptr, impl_PCLchId2ptr);
211     return 0;
212 }
213 
get_font_type(stream * f)214 static UW16 get_font_type(stream *f)
215 {   char buf[20], mark_PS[]="%!";
216     int i;
217 
218     if (sfread(buf, 1, sizeof(buf), f) != sizeof(buf))
219         return 0;
220     if (buf[0] == 0x15 || buf[0] == 0x00) /* fixme : don't know how to do correctly. */
221         return FC_FCO_TYPE;
222     for (i = 0; i < sizeof(buf) - sizeof(mark_PS); i++)
223         if(!memcmp(buf + i, mark_PS, sizeof(mark_PS) - 1))
224             return FC_PST1_TYPE;
225     if (buf[0] == '\0' && buf[1] == '\1')
226         return FC_TT_TYPE;
227     if (buf[0] == 't' && buf[1] == 't')
228         return FC_TT_TYPE;
229     return 0; /* fixme : unknown type - actually an error. */
230 }
231 
232 
choose_decoding_general(fapi_ufst_server * r,ufst_common_font_data * d,const char * cmapId)233 static int choose_decoding_general(fapi_ufst_server *r, ufst_common_font_data *d, const char *cmapId)
234 {
235     if (!d->decodingID[0])
236 	strncpy(d->decodingID, "Unicode", sizeof(d->decodingID));
237     /*    fixme : must depend on charset used in the font.  */
238     return 1;
239 }
240 
choose_decoding_TT(fapi_ufst_server * r,ufst_common_font_data * d,const char * cmapId)241 static int choose_decoding_TT(fapi_ufst_server *r, ufst_common_font_data *d, const char *cmapId)
242 {
243 #if TT_ROM || TT_DISK
244     int platId, specId, i;
245     CMAP_QUERY q;
246     UW16 font_access;
247     bool failed;
248     void *p = (d->is_disk_font ? (void *)(d + 1) : (void *)((UB8 *)d + d->tt_font_body_offset));
249     FSA_FROM_SERVER;
250 
251     if (sscanf(cmapId, "%d.%d", &platId, &specId) != 2)
252         return 0;
253     font_access = pIFS->font_access;
254     pIFS->font_access = (d->is_disk_font ? DISK_ACCESS : ROM_ACCESS);
255     failed = CGIFtt_cmap_query(FSA p, r->fc.ttc_index, &q);
256     pIFS->font_access = font_access;
257     if(failed)
258         return 0;
259     for (i = 0; i < q.numCmap; i++)
260         if (q.entry[i].platId == platId && q.entry[i].specId == specId) {
261             d->platformId = platId;
262             d->specificId = specId;
263             return 1;
264         }
265     return 0;
266 #else
267     if (!d->decodingID[0])
268 	strncpy(d->decodingID, "Unicode", sizeof(d->decodingID));
269     return 1;
270 #endif
271 }
272 
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))273 static void scan_xlatmap(fapi_ufst_server *r, ufst_common_font_data *d, const char *xlatmap, const char *font_kind,
274                                     int (*choose_proc)(fapi_ufst_server *r, ufst_common_font_data *d, const char *cmapId))
275 {   const char *p = xlatmap;
276 
277     while(*p) {
278         int good_kind =!strcmp(p, font_kind);
279         p += strlen(p) + 2;
280         while(*p) {
281             const char *cmapId = p, *decodingID = p + strlen(p) + 1;
282             strncpy(d->decodingID, decodingID, sizeof(d->decodingID));
283             if (!decodingID[0])
284                 break;
285             p = decodingID + strlen(decodingID) + 1;
286             if (good_kind)
287                 if (choose_proc(r, d, cmapId))
288                     return;
289         }
290     }
291     d->decodingID[0] = 0;
292 }
293 
choose_decoding(fapi_ufst_server * r,ufst_common_font_data * d,const char * xlatmap)294 static void choose_decoding(fapi_ufst_server *r, ufst_common_font_data *d, const char *xlatmap)
295 {   if (xlatmap != 0)
296         switch (d->font_type) {
297             case FC_IF_TYPE: /* fixme */ break;
298             case FC_PST1_TYPE: scan_xlatmap(r, d, xlatmap, "PostScript", choose_decoding_general); break;
299             case FC_TT_TYPE:   scan_xlatmap(r, d, xlatmap, "TrueType", choose_decoding_TT); break;
300             case FC_FCO_TYPE:  scan_xlatmap(r, d, xlatmap, "Microtype", choose_decoding_general); break;
301         }
302 }
303 
store_word(byte ** p,ushort w)304 static inline void store_word(byte **p, ushort w)
305 {   *((*p)++) = w / 256;
306     *((*p)++) = w % 256;
307 
308 }
309 
get_TT_glyph(fapi_ufst_server * r,FAPI_font * ff,UW16 chId)310 static LPUB8 get_TT_glyph(fapi_ufst_server *r, FAPI_font *ff, UW16 chId)
311 {   pcleo_glyph_list_elem *g;
312     PCLETTO_CHDR *h;
313     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
314     LPUB8 q;
315     ushort glyph_length = ff->get_glyph(ff, chId, 0, 0);
316     bool use_XL_format = ff->is_mtx_skipped;
317 
318     /*
319      * The client must set ff->is_mtx_skipped iff
320      * it requests a replaced lsb for True Type.
321      * If it is set, a replaced width to be supplied.
322      * This constraint is derived from UFST restriction :
323      * the font header format must be compatible with
324      * glyph header format.
325      */
326 
327     if (glyph_length == (ushort)-1) {
328         r->callback_error = e_invalidfont;
329         return 0;
330     }
331     g = (pcleo_glyph_list_elem *)r->client_mem.alloc(&r->client_mem,
332 	    sizeof(pcleo_glyph_list_elem) +
333 	    (use_XL_format ? 12 : sizeof(PCLETTO_CHDR)) + glyph_length + 2,
334 	    "PCLETTO char");
335     if (g == 0) {
336         r->callback_error = e_VMerror;
337         return 0;
338     }
339     g->chId = chId;
340     g->next = d->glyphs;
341     d->glyphs = g;
342     h = (PCLETTO_CHDR *)(g + 1);
343     h->h.format = 15;
344     if (use_XL_format) {
345 	h->h.continuation = 2;
346 	q = (LPUB8)h + 2;
347 	store_word(&q, (ushort)(glyph_length + 10));
348 	store_word(&q, (ushort)(r->sb_x >> r->If.frac_shift)); /* see can_replace_metrics */
349 	store_word(&q, (ushort)(r->aw_x >> r->If.frac_shift));
350 	store_word(&q, 0);
351 	store_word(&q, chId);
352     } else {
353 	h->h.continuation = 0;
354 	h->h.descriptorsize = 4;
355 	h->h.ch_class = 15;
356 	h->add_data = 0;
357 	q = (LPUB8)&h->charDataSize;
358 	store_word(&q, (ushort)(glyph_length + 4));
359 	store_word(&q, chId);
360     }
361     if (ff->get_glyph(ff, chId, (LPUB8)q, glyph_length) == (ushort)-1) {
362         r->callback_error = e_invalidfont;
363         return 0;
364     }
365     q += glyph_length;
366     store_word(&q, 0); /* checksum */
367     return (LPUB8)h;
368     /*
369      * The metrics replacement here is done only for the case
370      * corresponding to non-disk TT fonts with MetricsCount != 0;
371      * Other cases are not supported because UFST cannot handle them.
372      * Here we don't take care of cases which can_replace_metrics rejects.
373      *
374      * We don't care of metrics for subglyphs, because
375      * it is ignored by TT interpreter.
376      */
377 }
378 
get_T1_glyph(fapi_ufst_server * r,FAPI_font * ff,UW16 chId)379 static LPUB8 get_T1_glyph(fapi_ufst_server *r, FAPI_font *ff, UW16 chId)
380 {
381 #if PST1_SFNTI
382     ushort glyph_length = ff->get_glyph(ff, chId, 0, 0);
383     LPUB8 q;
384     pcleo_glyph_list_elem *g = (pcleo_glyph_list_elem *)r->client_mem.alloc(&r->client_mem,
385 		    sizeof(pcleo_glyph_list_elem) + sizeof(PS_CHAR_HDR) + 2 + 2 + glyph_length + 1, "PSEO char");
386     PS_CHAR_HDR *h;
387     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
388     FSA_FROM_SERVER;
389 
390     if (g == 0 || glyph_length == (ushort)-1) {
391         r->callback_error = e_invalidfont;
392         return 0;
393     }
394     g->chId = chId;
395     g->next = d->glyphs;
396     d->glyphs = g;
397     h = (PS_CHAR_HDR *)(g + 1);
398     h->format = 30;           /* raster=4, DJ=5, IF=10, TT=15, PS=30 */
399     h->continuation = 0;     /* always 0 */
400     h->descriptorsize = 2;   /* always 2 */
401     h->ch_class = 11;           /* contour=3, compound=4, tt=10, ps=11 */
402     h->len = 0;              /* # of bytes to follow (not including csum) */
403     q = (byte *)h + sizeof(*h);
404     /* A workaround for UFST4.6 bug in t1idecod.c (UNPACK_WORD uses pIFS->ph instead ph) :
405        setting Namelen=4, rather normally it must be 0. */
406     q[0] = 0; /* Namelen */
407     q[1] = 4; /* Namelen */
408     q[2] = (glyph_length) / 256; /* Datalen */
409     q[3] = (glyph_length) % 256; /* Datalen */
410     /* Glyph name goes here, but we don't use it. */
411     q += 4;
412     glyph_length = ff->get_glyph(ff, chId, q, glyph_length);
413     q += glyph_length;
414     *q = 1; /* Decrypt flag */
415     pIFS->ph = (byte *)h + sizeof(*h); /* A workaround for UFST4.6 bug in t1idecod.c (UNPACK_WORD uses pIFS->ph instead ph) */
416     return (LPUB8)h;
417 #else
418     return 0;
419 #endif
420 }
421 
find_glyph(ufst_common_font_data * d,UW16 chId)422 static pcleo_glyph_list_elem * find_glyph(ufst_common_font_data *d, UW16 chId)
423 {   pcleo_glyph_list_elem *e;
424 
425     for (e = d->glyphs; e != 0; e = e->next)
426         if (e->chId == chId)
427             return e;
428     return 0;
429 }
430 
431 /* UFST callback : */
impl_PCLchId2ptr(FSP UW16 chId)432 static LPUB8 impl_PCLchId2ptr(FSP UW16 chId)
433 {
434 #if UFST_REENTRANT
435     fapi_ufst_server *r = IFS_to_I(pIFS);
436 #else
437     fapi_ufst_server *r = static_server_ptr_for_ufst_callback;
438 #endif
439     FAPI_font *ff = r->ff;
440     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
441     pcleo_glyph_list_elem *g = find_glyph(d, chId);
442     LPUB8 result = 0;
443 
444     if (g != 0)
445         result = (LPUB8)(g + 1);
446     if ((r->fc.format & FC_FONTTYPE_MASK) == FC_PST1_TYPE)
447         result = get_T1_glyph(r, ff, chId);
448     if ((r->fc.format & FC_FONTTYPE_MASK) == FC_TT_TYPE)
449         result = get_TT_glyph(r, ff, chId);
450     return result;
451 }
452 
pack_word(LPUB8 * p,UW16 v)453 static inline void pack_word(LPUB8 *p, UW16 v)
454 {   LPUB8 q = (LPUB8)&v;
455 
456 #if (BYTEORDER == LOHI) /* defied in UFST includes */
457          (*p)[1] = q[0];
458          (*p)[0] = q[1];
459 #else
460         *(UW16 *)(*p) = v;
461 #endif
462     *p += 2;
463 }
464 
pack_long(LPUB8 * p,UL32 v)465 static inline void pack_long(LPUB8 *p, UL32 v)
466 {   LPUB8 q = (LPUB8)&v;
467 
468 #if (BYTEORDER == LOHI) /* defied in UFST includes */
469          (*p)[3] = q[0];
470          (*p)[2] = q[1];
471          (*p)[1] = q[2];
472          (*p)[0] = q[3];
473 #else
474         *(UL32 *)(*p) = v;
475 #endif
476     *p += 4;
477 }
478 
pack_float(LPUB8 * p,float v)479 static inline void pack_float(LPUB8 *p, float v)
480 {   sprintf((char *)(*p), "%f", v);
481     *p += strlen((const char *)*p) + 1;
482 }
483 
484 #define PACK_ZERO(p) *(p++) = 0
485 #define PACK_BYTE(p, c) *(p++) = c
486 #define PACK_WORD(p, i, var) pack_word(&p, ff->get_word(ff, var, i))
487 #define PACK_LONG(p, i, var) pack_long(&p, ff->get_long(ff, var, i))
488 
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)489 static void pack_pseo_word_array(fapi_ufst_server *r, FAPI_font *ff, UB8 **p,
490 				  UW16 max_count, fapi_font_feature count_id, fapi_font_feature array_id)
491 {   UW16 k = min(ff->get_word(ff, count_id, 0), max_count), j;
492 
493     pack_word(p, k);
494     for (j = 0; j < k; j++)
495         PACK_WORD(*p, j, array_id);
496     for (; j < max_count; j++)
497         pack_word(p, 0);
498 }
499 
pack_pseo_fhdr(fapi_ufst_server * r,FAPI_font * ff,UB8 * p)500 static void pack_pseo_fhdr(fapi_ufst_server *r, FAPI_font *ff, UB8 *p)
501 {   ushort j, n, skip = 0;
502 
503     while ((UL32)p & 0x03) /* align to QUADWORD */
504 	PACK_ZERO(p);
505     pack_long(&p, 1);  /* format = 1 */
506     for (j = 0; j < 6; j++)
507         pack_float(&p, ff->get_float(ff, FAPI_FONT_FEATURE_FontMatrix, j));
508     while ((UL32)p & 0x03) /* align to QUADWORD */
509 	PACK_ZERO(p);
510     /* UFST has no definition for PSEO structure, so implement serialization : */
511     PACK_LONG(p, 0, FAPI_FONT_FEATURE_UniqueID);
512     PACK_LONG(p, 0, FAPI_FONT_FEATURE_BlueScale);
513     PACK_WORD(p, 0, FAPI_FONT_FEATURE_Weight);
514     PACK_WORD(p, 0, FAPI_FONT_FEATURE_ItalicAngle);
515     PACK_WORD(p, 0, FAPI_FONT_FEATURE_IsFixedPitch);
516     PACK_WORD(p, 0, FAPI_FONT_FEATURE_UnderLinePosition);
517     PACK_WORD(p, 0, FAPI_FONT_FEATURE_UnderlineThickness);
518     PACK_WORD(p, 0, FAPI_FONT_FEATURE_FontType);
519     PACK_WORD(p, 0, FAPI_FONT_FEATURE_FontBBox);
520     PACK_WORD(p, 1, FAPI_FONT_FEATURE_FontBBox);
521     PACK_WORD(p, 2, FAPI_FONT_FEATURE_FontBBox);
522     PACK_WORD(p, 3, FAPI_FONT_FEATURE_FontBBox);
523     pack_pseo_word_array(r, ff, &p, 14, FAPI_FONT_FEATURE_BlueValues_count, FAPI_FONT_FEATURE_BlueValues);
524     pack_pseo_word_array(r, ff, &p, 10, FAPI_FONT_FEATURE_OtherBlues_count, FAPI_FONT_FEATURE_OtherBlues);
525     pack_pseo_word_array(r, ff, &p, 14, FAPI_FONT_FEATURE_FamilyBlues_count, FAPI_FONT_FEATURE_FamilyBlues);
526     pack_pseo_word_array(r, ff, &p, 10, FAPI_FONT_FEATURE_FamilyOtherBlues_count, FAPI_FONT_FEATURE_FamilyOtherBlues);
527     PACK_WORD(p, 0, FAPI_FONT_FEATURE_BlueShift);
528     PACK_WORD(p, 0, FAPI_FONT_FEATURE_BlueFuzz);
529     PACK_WORD(p, 0, FAPI_FONT_FEATURE_StdHW);
530     PACK_WORD(p, 0, FAPI_FONT_FEATURE_StdVW);
531     pack_pseo_word_array(r, ff, &p, 12, FAPI_FONT_FEATURE_StemSnapH_count, FAPI_FONT_FEATURE_StemSnapH);
532     pack_pseo_word_array(r, ff, &p, 12, FAPI_FONT_FEATURE_StemSnapV_count, FAPI_FONT_FEATURE_StemSnapV);
533     PACK_WORD(p, 0, FAPI_FONT_FEATURE_ForceBold);
534     PACK_WORD(p, 0, FAPI_FONT_FEATURE_LanguageGroup);
535     PACK_WORD(p, 0, FAPI_FONT_FEATURE_lenIV);
536     for (j = 0; j < 12; j++)
537         PACK_ZERO(p), PACK_ZERO(p);     /* Reserved2 */
538     /* max data size = 107 words + 6 floats in ASCII */
539     n = ff->get_word(ff, FAPI_FONT_FEATURE_Subrs_count, 0);
540     pack_word(&p, n);
541     for (j = 0; j < n; j++) {
542         ushort subr_len = ff->get_subr(ff, j, 0, 0);
543         if (subr_len != 0) {
544             pack_word(&p, j);
545             pack_word(&p, subr_len);
546             PACK_BYTE(p, 1); /* is_decrypted */
547             ff->get_subr(ff, j, p, subr_len);
548             p += subr_len;
549         } else
550             skip = 1;
551     }
552     if (skip)
553         pack_word(&p, 0xFFFF);
554 }
555 
my_strdup(fapi_ufst_server * r,const char * s,const char * cname)556 static char *my_strdup(fapi_ufst_server *r, const char *s, const char *cname)
557 {   int l = strlen(s) + 1;
558     char *p = (char *)r->client_mem.alloc(&r->client_mem, l, cname);
559 
560     if (p != 0)
561         memcpy(p, s, l);
562     return p;
563 }
564 
fco_open(fapi_ufst_server * r,const char * font_file_path,fco_list_elem ** result)565 static FAPI_retcode fco_open(fapi_ufst_server *r, const char *font_file_path, fco_list_elem **result)
566 {   int code;
567     fco_list_elem *e = gx_UFST_find_static_fco(font_file_path);
568 
569     if (e != NULL) {
570 	*result = e;
571 	return 0;
572     }
573     for (e = r->fco_list; e != 0; e = e->next) {
574         if (!strcmp(e->file_path, font_file_path))
575             break;
576     }
577     if (e == 0) {
578         SW16 fcHandle;
579 	FSA_FROM_SERVER;
580 
581 	if ((code = CGIFfco_Open(FSA (UB8 *)font_file_path, &fcHandle)) != 0)
582 	    return code;
583         e = (fco_list_elem *)r->client_mem.alloc(&r->client_mem, sizeof(*e), "fco_list_elem");
584         if (e == 0) {
585             CGIFfco_Close(FSA fcHandle);
586             return e_VMerror;
587         }
588         e->open_count = 0;
589         e->fcHandle = fcHandle;
590         e->file_path = my_strdup(r, font_file_path, "fco_file_path");
591         if (e->file_path == 0) {
592             CGIFfco_Close(FSA fcHandle);
593             r->client_mem.free(&r->client_mem, e, "fco_list_elem");
594             return e_VMerror;
595         }
596         e->next = r->fco_list;
597         r->fco_list = e;
598     }
599     e->open_count++;
600     *result = e;
601     return 0;
602 }
603 
make_font_data(fapi_ufst_server * r,const char * font_file_path,FAPI_font * ff,ufst_common_font_data ** return_data)604 static FAPI_retcode make_font_data(fapi_ufst_server *r, const char *font_file_path, FAPI_font *ff, ufst_common_font_data **return_data)
605 {   ulong area_length = sizeof(ufst_common_font_data), tt_size = 0;
606     LPUB8 buf;
607     PCLETTO_FHDR *h;
608     ufst_common_font_data *d;
609     bool use_XL_format = ff->is_mtx_skipped;
610     int code;
611     FSA_FROM_SERVER;
612 
613     *return_data = 0;
614     r->fc.ttc_index = ff->subfont;
615     if (ff->font_file_path == NULL) {
616         area_length += PCLETTOFONTHDRSIZE;
617         if (ff->is_type1) {
618             int subrs_count  = ff->get_word(ff, FAPI_FONT_FEATURE_Subrs_count, 0);
619             int subrs_length = ff->get_long(ff, FAPI_FONT_FEATURE_Subrs_total_size, 0);
620             int subrs_area_size = subrs_count * 5 + subrs_length + 2;
621             area_length += 360 + subrs_area_size; /* some inprecise - see pack_pseo_fhdr */
622         } else {
623             tt_size  = ff->get_long(ff, FAPI_FONT_FEATURE_TT_size, 0);
624             if (tt_size == 0)
625                 return e_invalidfont;
626             area_length += tt_size + (use_XL_format ? 6 : 4) + 4 + 2;
627         }
628     } else
629         area_length += strlen(font_file_path) + 1;
630     buf = r->client_mem.alloc(&r->client_mem, area_length, "ufst font data");
631     if (buf == 0)
632         return e_VMerror;
633     d = (ufst_common_font_data *)buf;
634     d->tt_font_body_offset = 0;
635     d->platformId = 0;
636     d->specificId = 0;
637     d->decodingID[0] = 0;
638     d->glyphs = 0;
639     d->is_disk_font = (ff->font_file_path != NULL);
640     if (d->is_disk_font) {
641 	 fco_list_elem *e = gx_UFST_find_static_fco(font_file_path);
642 
643 	 if (e != NULL) {
644 	     memcpy(d + 1, font_file_path, strlen(font_file_path) + 1);
645 	     d->font_id = (e->fcHandle << 16) | ff->subfont;
646 	     d->font_type = FC_FCO_TYPE;
647 	 } else {
648 	    stream *f = sfopen(font_file_path, "rb", (gs_memory_t *)(r->client_mem.client_data));
649 	    if (f == NULL) {
650 		eprintf1("fapiufst: Can't open %s\n", font_file_path);
651 		return e_undefinedfilename;
652 	    }
653 	    memcpy(d + 1, font_file_path, strlen(font_file_path) + 1);
654 	    d->font_type = get_font_type(f);
655 	    sfclose(f);
656 	    if (d->font_type == FC_FCO_TYPE) {
657 		fco_list_elem *e;
658 		if ((code = fco_open(r, font_file_path, &e)) != 0)
659 		    return code;
660 		d->font_id = (e->fcHandle << 16) | ff->subfont;
661 	    }
662 	}
663     } else {
664         d->font_type = (ff->is_type1 ? FC_PST1_TYPE : FC_TT_TYPE);
665 	d->font_id = ff->get_long(ff, FAPI_FONT_FEATURE_UniqueID, 0);
666         h = (PCLETTO_FHDR *)(buf + sizeof(ufst_common_font_data));
667         h->fontDescriptorSize = PCLETTOFONTHDRSIZE;
668         h->descriptorFormat = 15;
669         h->fontType = 11; /* wrong */                /*  3- 11=Unicode; 0,1,2 also possible */
670         h->style_msb = 0; /* wrong */               /*  4- from PCLT table in TrueType font */
671         h->reserved1 = 0;
672         h->baselinePosition = 0; /* wrong */        /*  6- from head table in TT font; = 0 */
673         h->cellWidth = 1024; /* wrong */               /*  8- head, use xMax - xMin */
674         h->cellHeight = 1024; /* wrong */             /* 10- head, use yMax - yMin */
675         h->orientation = 0;             /* 12- 0 */
676         h->spacing = 1; /* wrong */                 /* 13- 1=proportional, 0-fixed pitch */
677         h->characterSet = 56; /* wrong */            /* 14- same as symSetCode; =56 if unbound. */
678         h->pitch = 1024; /* wrong */                   /* 16- PCLT */
679         h->height = 0;                  /* 18- 0 if TrueType */
680         h->xHeight = 512; /* wrong */                 /* 20- PCLT */
681         h->widthType = 0; /* wrong */               /* 22- PCLT */
682         h->style_lsb = 0; /* wrong */               /* 23- PCLT */
683         h->strokeWeight = 0; /* wrong */            /* 24- PCLT */
684         h->typeface_lsb = 0; /* wrong */            /* 25- PCLT */
685         h->typeface_msb = 0; /* wrong */           /* 26- PCLT */
686         h->serifStyle = 0; /* wrong */              /* 27- PCLT */
687         h->quality = 0; /* wrong */                 /* 28- 2 if TrueType */
688         h->placement = 0; /* wronfg */               /* 29- 0 if TrueType */
689         h->underlinePosition = 0;       /* 30- 0 */
690         h->underlineHeight = 0;         /* 31- 0 */
691         h->textHeight = 102; /* wrong */              /* 32- from OS/2 table in TT font */
692         h->textWidth = 1024; /* wrong */              /* 34- OS/2 */
693         h->firstCode = 0;               /* 36- set to 0 if unbound */
694         h->lastCode = 255; /* wrong */                /* 38- max number of downloadable chars if unbound */
695         h->pitch_ext = 0;               /* 40- 0 if TrueType */
696         h->height_ext = 0;              /* 41- 0 if TrueType */
697         h->capHeight = 1024; /* wrong */               /* 42- PCLT */
698         h->fontNumber = d->font_id;              /* 44- PCLT */
699         h->fontName[0] = 0; /* wrong */            /* 48- PCLT */
700         h->scaleFactor = 1024; /* wrong */             /* 64- head:unitsPerEm */
701         h->masterUnderlinePosition = 0; /* wrong */ /* 66- post table, or -20% of em */
702         h->masterUnderlineHeight = 0; /* wrong */   /* 68- post table, or 5% of em */
703         h->fontScalingTechnology = 1;   /* 70- 1=TrueType; 0=Intellifont */
704         h->variety = 0;                 /* 71- 0 if TrueType */
705         memset((LPUB8)h + PCLETTOFONTHDRSIZE, 0 ,8); /* work around bug in PCLswapHdr : it wants format 10 */
706         /*  fixme : Most fields above being marked "wrong" look unused by UFST.
707             Need to check for sure.
708         */
709         /*  fixme : This code assumes 1-byte alignment for PCLETTO_FHDR structure.
710             Use PACK_* macros to improve.
711         */
712         PCLswapHdr(FSA (UB8 *)h, 0);
713         if (ff->is_type1) {
714             LPUB8 fontdata = (LPUB8)h + PCLETTOFONTHDRSIZE;
715             pack_pseo_fhdr(r, ff, fontdata);
716         } else {
717             LPUB8 pseg = (LPUB8)h + PCLETTOFONTHDRSIZE;
718             LPUB8 fontdata = pseg + (use_XL_format ? 6 : 4);
719             if (tt_size > 65000)
720                 return e_unregistered; /* Must not happen because we skept 'glyp', 'loca' and 'cmap'. */
721             pseg[0] = 'G';
722             pseg[1] = 'T';
723 	    if (use_XL_format) {
724 		pseg[2] = tt_size >> 24;
725 		pseg[3] = (tt_size >> 16) % 256;
726 		pseg[4] = (tt_size >> 8) % 256;
727 		pseg[5] = tt_size % 256;
728 	    } else {
729 		pseg[2] = tt_size / 256;
730 		pseg[3] = tt_size % 256;
731 	    }
732             d->tt_font_body_offset = (LPUB8)fontdata - (LPUB8)d;
733             if (ff->serialize_tt_font(ff, fontdata, tt_size))
734                 return e_invalidfont;
735             *(fontdata + tt_size    ) = 255;
736             *(fontdata + tt_size + 1) = 255;
737             *(fontdata + tt_size + 2) = 0;
738             *(fontdata + tt_size + 3) = 0;
739             *(fontdata + tt_size + 4) = 0;
740             *(fontdata + tt_size + 5) = 0;  /* checksum */
741         }
742     }
743     *return_data = d;
744     return 0;
745 }
746 
prepare_typeface(fapi_ufst_server * r,ufst_common_font_data * d)747 static void prepare_typeface(fapi_ufst_server *r, ufst_common_font_data *d)
748 {   r->fc.format = d->font_type;
749     r->fc.font_id = d->font_id;
750     r->fc.font_hdr = (UB8 *)(d + 1);
751     if (!d->is_disk_font)
752         r->fc.format |= FC_EXTERN_TYPE;
753 }
754 
get_scaled_font(FAPI_server * server,FAPI_font * ff,const FAPI_font_scale * font_scale,const char * xlatmap,FAPI_descendant_code dc)755 static FAPI_retcode get_scaled_font(FAPI_server *server, FAPI_font *ff,
756          const FAPI_font_scale *font_scale, const char *xlatmap, FAPI_descendant_code dc)
757 {   fapi_ufst_server *r = If_to_I(server);
758     FONTCONTEXT *fc = &r->fc;
759     /*  Note : UFST doesn't provide handles for opened fonts,
760         but copies FONTCONTEXT to IFSTATE and caches it.
761         Due to this the plugin cannot provide a handle for the font.
762         This assumes that only one font context is active at a moment.
763     */
764     ufst_common_font_data *d = (ufst_common_font_data *)ff->server_font_data;
765     const double scale = F_ONE;
766     double hx, hy;
767     FAPI_retcode code;
768     bool use_XL_format = ff->is_mtx_skipped;
769     FSA_FROM_SERVER;
770 
771     if (ff->is_cid && ff->is_type1 && ff->font_file_path == NULL &&
772         (dc == FAPI_TOPLEVEL_BEGIN || dc == FAPI_TOPLEVEL_COMPLETE)) {
773 	/* Don't need any processing for the top level font of a non-disk CIDFontType 0.
774 	   See comment in FAPI_prepare_font.
775 	   Will do with its subfonts individually.
776 	 */
777 	return 0;
778     }
779     ff->need_decrypt = 1;
780     if (d == 0) {
781         if ((code = make_font_data(r, ff->font_file_path, ff, &d)) != 0)
782 	    return code;
783         ff->server_font_data = d;
784         prepare_typeface(r, d);
785         if (ff->font_file_path != NULL || ff->is_type1) /* such fonts don't use RAW_GLYPH */
786             choose_decoding(r, d, xlatmap);
787     } else
788         prepare_typeface(r, d);
789     r->tran_xx = font_scale->matrix[0] / scale, r->tran_xy = font_scale->matrix[1] / scale;
790     r->tran_yx = font_scale->matrix[2] / scale, r->tran_yy = font_scale->matrix[3] / scale;
791     hx = hypot(r->tran_xx, r->tran_xy), hy = hypot(r->tran_yx, r->tran_yy);
792     fc->xspot     = F_ONE;
793     fc->yspot     = F_ONE;
794     fc->fc_type   = FC_MAT2_TYPE;
795     fc->s.m2.m[0] = (int)((double)font_scale->matrix[0] / hx + 0.5);
796     fc->s.m2.m[1] = (int)((double)font_scale->matrix[1] / hx + 0.5);
797     fc->s.m2.m[2] = (int)((double)font_scale->matrix[2] / hy + 0.5);
798     fc->s.m2.m[3] = (int)((double)font_scale->matrix[3] / hy + 0.5);
799     fc->s.m2.matrix_scale = 16;
800     fc->s.m2.xworld_res = font_scale->HWResolution[0] >> 16;
801     fc->s.m2.yworld_res = font_scale->HWResolution[1] >> 16;
802     fc->s.m2.world_scale = 0;
803     fc->s.m2.point_size   = (int)(hy * 8 + 0.5); /* 1/8ths of pixels */
804     fc->s.m2.set_size     = (int)(hx * 8 + 0.5);
805     fc->numXsubpixels = font_scale->subpixels[0];
806     fc->numYsubpixels = font_scale->subpixels[1];
807     fc->alignment = (font_scale->align_to_pixels ? GAGG : GAPP);
808     fc->ExtndFlags = 0;
809     if (d->font_type == FC_TT_TYPE)
810 	fc->ssnum = USER_CMAP;
811     else if (d->font_type == FC_FCO_TYPE) {
812 	fc->ssnum = UNICODE;
813     } else
814 	fc->ExtndFlags = EF_NOSYMSETMAP;
815     fc->ExtndFlags |= EF_SUBSTHOLLOWBOX_TYPE;
816     fc->format      |= FC_NON_Z_WIND;   /* NON_ZERO Winding required for TrueType */
817     fc->format      |= FC_INCHES_TYPE;  /* output in units per inch */
818     fc->user_platID = d->platformId;
819     fc->user_specID = d->specificId;
820     if (use_XL_format)
821 	fc->ExtndFlags |= EF_XLFONT_TYPE;
822     if (ff->is_vertical)
823         fc->ExtndFlags |= EF_UFSTVERT_TYPE;
824     fc->dl_ssnum = (d->specificId << 4) | d->platformId;
825     fc->ttc_index   = ff->subfont;
826     r->callback_error = 0;
827     code = CGIFfont(FSA fc);
828     if (r->callback_error != 0)
829 	return r->callback_error;
830     return code;
831 }
832 
get_decodingID(FAPI_server * server,FAPI_font * ff,const char ** decodingID_result)833 static FAPI_retcode get_decodingID(FAPI_server *server, FAPI_font *ff, const char **decodingID_result)
834 {   fapi_ufst_server *r = If_to_I(server);
835     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
836 
837     *decodingID_result = d->decodingID;
838     return 0;
839 }
840 
get_font_bbox(FAPI_server * server,FAPI_font * ff,int BBox[4])841 static FAPI_retcode get_font_bbox(FAPI_server *server, FAPI_font *ff, int BBox[4])
842 {   fapi_ufst_server *r = If_to_I(server);
843     SW16 VLCPower = 0;
844     int code;
845     FSA_FROM_SERVER;
846 
847     if ((code = CGIFbound_box(FSA BBox, &VLCPower)) < 0)
848 	return code;
849     /*  UFST expands bbox for internal needs, and retrives the expanded bbox.
850         We believe it's bug in UFST.
851         Now we collapse it back to the correct size :
852     */
853     BBox[0] += 2;
854     BBox[1] += 2;
855     BBox[2] -= 2;
856     BBox[3] -= 2;
857     BBox[0] >>= VLCPower;
858     BBox[1] >>= VLCPower;
859     BBox[2] >>= VLCPower;
860     BBox[3] >>= VLCPower;
861     return 0;
862 }
863 
get_font_proportional_feature(FAPI_server * server,FAPI_font * ff,bool * bProportional)864 static FAPI_retcode get_font_proportional_feature(FAPI_server *server, FAPI_font *ff, bool *bProportional)
865 {   fapi_ufst_server *r = If_to_I(server);
866     FSA_FROM_SERVER;
867 
868     *bProportional = false;
869     if (ff->font_file_path == NULL || ff->is_type1)
870         return 0;
871 #if TT_ROM || TT_DISK
872     {
873 	UB8 buf[74];
874 	UL32 length = sizeof(buf);
875 
876     if (CGIFtt_query(FSA (UB8 *)ff->font_file_path, *(UL32 *)"OS/2", (UW16)ff->subfont, &length, buf) != 0)
877         return 0; /* No OS/2 table - no chance to get the info. Use default == false. */
878     *bProportional = (buf[35] == 9);
879     }
880 #endif
881     return 0;
882 }
883 
make_asciiz_char_name(char * buf,int buf_length,FAPI_char_ref * c)884 static inline void make_asciiz_char_name(char *buf, int buf_length, FAPI_char_ref *c)
885 {   int len = min(buf_length - 1, c->char_name_length);
886 
887     memcpy(buf, c->char_name, len);
888     buf[len] = 0;
889 }
890 
891 #define MAX_CHAR_NAME_LENGTH 30
892 
can_retrieve_char_by_name(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,int * result)893 static FAPI_retcode can_retrieve_char_by_name(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, int *result)
894 {   fapi_ufst_server *r = If_to_I(server);
895     FSA_FROM_SERVER;
896 
897     *result = 0;
898     switch (r->fc.format & FC_FONTTYPE_MASK) {
899         case FC_PST1_TYPE :
900             *result = 1;
901             break;
902         case FC_TT_TYPE :
903             break;
904     }
905     return 0;
906 }
907 
can_replace_metrics(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,int * result)908 static FAPI_retcode can_replace_metrics(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, int *result)
909 {   *result = (!ff->is_type1 && ff->font_file_path == NULL &&
910 	       c->metrics_scale == 0 && c->metrics_type == FAPI_METRICS_REPLACE);
911     return 0;
912 }
913 
release_glyphs(fapi_ufst_server * r,ufst_common_font_data * d)914 static void release_glyphs(fapi_ufst_server *r, ufst_common_font_data *d)
915 {   while (d->glyphs != 0) {
916         pcleo_glyph_list_elem *e = d->glyphs;
917         d->glyphs = e->next;
918         r->client_mem.free(&r->client_mem, e, "PCLEO char");
919     }
920 }
921 
get_char_width(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,FAPI_metrics * metrics)922 static FAPI_retcode get_char_width(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, FAPI_metrics *metrics)
923 {   fapi_ufst_server *r = If_to_I(server);
924     UW16 buffer[2];
925     UW16 cc = (UW16)c->char_code;
926     WIDTH_LIST_INPUT_ENTRY li[1];
927     char PSchar_name[MAX_CHAR_NAME_LENGTH];
928     int code;
929     FSA_FROM_SERVER;
930 
931 #if !UFST_REENTRANT
932     static_server_ptr_for_ufst_callback = r;
933 #endif
934     make_asciiz_char_name(PSchar_name, sizeof(PSchar_name), c);
935     r->ff = ff;
936     CGIFchIdptr(FSA &cc, PSchar_name);
937     li[0]. CharType.IF_cgnum = cc;
938     if ((code = CGIFwidth(FSA li, 1, 4, buffer)) != 0)
939 	return code;
940     r->ff = 0;
941     release_glyphs(r, (ufst_common_font_data *)ff->server_font_data);
942     metrics->escapement = buffer[0];
943     metrics->em_x = metrics->em_y = buffer[1];
944     return 0;
945 }
946 
export_outline(fapi_ufst_server * r,PIFOUTLINE pol,FAPI_path * p)947 static int export_outline(fapi_ufst_server *r, PIFOUTLINE pol, FAPI_path *p)
948 {   POUTLINE_CHAR outchar;
949     SW16 num_contrs,num_segmts;
950     LPSB8 segment;
951     PINTRVECTOR points;
952     SW16  i,j;
953 
954     if (pol == NULL)
955         return 0;
956     p->shift += r->If.frac_shift + pol->VLCpower;
957     outchar = &pol->ol;
958     num_contrs = outchar->num_loops;
959     for(i = 0; i<num_contrs; i++) {
960      	num_segmts = outchar->loop[i].num_segmts;
961         segment = (LPSB8)((LPSB8)(outchar->loop) + outchar->loop[i].segmt_offset);
962         points = (PINTRVECTOR)((LPSB8)(outchar->loop) + outchar->loop[i].coord_offset);
963         for(j=0; j<num_segmts; j++) {
964 	    int code;
965 
966             if(*segment == 0x00) {
967              	if ((code = p->moveto(p, points->x, points->y)) != 0)
968 		    return code;
969                 points++;
970             } else if (*segment == 0x01) {
971 		if ((code = p->lineto(p, points->x, points->y)) != 0)
972 		    return code;
973                 points++;
974             } else if (*segment == 0x02) {
975                 points+=2;
976                 return e_invalidfont; /* This must not happen */
977             } else if (*segment == 0x03) {
978 		if ((code = p->curveto(p, points[0].x, points[0].y,
979 					points[1].x, points[1].y,
980 					points[2].x, points[2].y)) < 0)
981 		    return code;
982                 points+=3;
983             } else
984                 return e_invalidfont; /* This must not happen */
985             segment++;
986         }
987     }
988     return 0;
989 }
990 
set_metrics(fapi_ufst_server * r,FAPI_metrics * metrics,SL32 design_bbox[4],SW16 design_escapement,SW16 du_emx,SW16 du_emy)991 static inline void set_metrics(fapi_ufst_server *r, FAPI_metrics *metrics, SL32 design_bbox[4], SW16 design_escapement, SW16 du_emx, SW16 du_emy)
992 {   metrics->escapement = design_escapement;
993     metrics->em_x = du_emx;
994     metrics->em_y = du_emy;
995     metrics->bbox_x0 = design_bbox[0];
996     metrics->bbox_y0 = design_bbox[1];
997     metrics->bbox_x1 = design_bbox[2];
998     metrics->bbox_y1 = design_bbox[3];
999 }
1000 
get_char(fapi_ufst_server * r,FAPI_font * ff,FAPI_char_ref * c,FAPI_path * p,FAPI_metrics * metrics,UW16 format)1001 static FAPI_retcode get_char(fapi_ufst_server *r, FAPI_font *ff, FAPI_char_ref *c, FAPI_path *p, FAPI_metrics *metrics, UW16 format)
1002 {   UW16 code;
1003     UW16 cc = (UW16)c->char_code;
1004     SL32 design_bbox[4];
1005     char PSchar_name[MAX_CHAR_NAME_LENGTH];
1006     MEM_HANDLE result;
1007     ufst_common_font_data *d = (ufst_common_font_data *)ff->server_font_data;
1008     SW16 design_escapement;
1009     SW16 du_emx, du_emy;
1010     FSA_FROM_SERVER;
1011 
1012     memset(metrics, 0, sizeof(*metrics));
1013     metrics->bbox_x1 = -1;
1014     make_asciiz_char_name(PSchar_name, sizeof(PSchar_name), c);
1015     CGIFchIdptr(FSA &cc, PSchar_name); /* fixme : Likely only FC_PST1_TYPE needs it. */
1016     {   /* hack : Changing UFST internal data. Change to r->fc doesn't help,
1017 	   because UFST thinks that the "outline/raster" is a property of current font. */
1018         pIFS->fcCur.format &= ~FC_OUTPUT_MASK;
1019         pIFS->fcCur.format |= format;
1020     }
1021     r->bRaster = false;
1022     r->ff = ff;
1023     r->callback_error = 0;
1024     r->sb_x = c->sb_x;
1025     r->aw_x = c->aw_x;
1026     r->metrics_type = c->metrics_type;
1027     if (d->font_type == FC_FCO_TYPE && r->fc.ExtndFlags & EF_SUBSTHOLLOWBOX_TYPE) {
1028 	if (c->char_name != NULL && c->char_name_length == 7 &&
1029 		!memcmp(c->char_name, ".notdef", 7)) {
1030 	    /* With EF_SUBSTHOLLOWBOX_TYPE and FCO,
1031 	       UFST paints a hollow box insted .notdef .
1032 	       For Adobe compatibility we substitute a space,
1033 	       because Adobe Type 1 fonts define .notdef as a space . */
1034 	    cc = 32;
1035 	}
1036     }
1037 #if !UFST_REENTRANT
1038     static_server_ptr_for_ufst_callback = r;
1039 #endif
1040     code = CGIFchar_handle(FSA cc, &result, (SW16)0);
1041     if (code == ERR_find_cgnum) {
1042         /* There is no such char in the font, try the glyph 0 (notdef) : */
1043         const void *client_char_data = ff->char_data;
1044         UW16 c1 = 0, ssnum = pIFS->fcCur.ssnum;
1045 
1046 	if (d->font_type == FC_FCO_TYPE) {
1047 	    /* EF_SUBSTHOLLOWBOX_TYPE must work against it.
1048 	       Ensure the plugin plug__xi.fco is loaded. */
1049 	    /* fixme : Due to unknown reason EF_SUBSTHOLLOWBOX_TYPE
1050 	       doesn't work for Symbol, Dingbats, Wingdings.
1051 	       hack : render the space character. */
1052 	    c1 = 32;
1053 	} else {
1054 	    /* hack : Changing UFST internal data - see above. */
1055 	    pIFS->fcCur.ssnum = RAW_GLYPH;
1056 	}
1057         r->callback_error = 0;
1058         ff->char_data = NULL;
1059         CGIFchIdptr(FSA &c1, (char *)".notdef");
1060 	code = CGIFchar_handle(FSA c1, &result, (SW16)0);
1061         pIFS->fcCur.ssnum = ssnum;
1062         ff->char_data = client_char_data;
1063     }
1064 #if !UFST_REENTRANT
1065     static_server_ptr_for_ufst_callback = 0;
1066 #endif
1067     r->ff = 0;
1068     release_glyphs(r, (ufst_common_font_data *)ff->server_font_data);
1069     if (code != ERR_fixed_space && code != 0)
1070 	return code;
1071     if (r->callback_error != 0)
1072 	return r->callback_error;
1073     if (format == FC_BITMAP_TYPE) {
1074         IFBITMAP *pbm = (IFBITMAP *)result;
1075 
1076         design_escapement = pbm->escapement;
1077 	du_emx = pbm->du_emx;
1078 	du_emy = pbm->du_emy;
1079         r->char_data = pbm;
1080         r->bRaster = true;
1081     } else {
1082         IFOUTLINE *pol = (IFOUTLINE *)result;
1083 
1084         design_escapement = pol->escapement;
1085 	du_emx = pol->du_emx;
1086 	du_emy = pol->du_emy;
1087         r->char_data = (IFOUTLINE *)result;
1088     }
1089 #if 1 /* UFST 5.0 */
1090     if (USBOUNDBOX && d->font_type == FC_FCO_TYPE) {
1091 	if (pIFS->USBBOXorigScaleFactor /* fixme : Must we check this ? */
1092 	    && pIFS->USBBOXorigScaleFactor != pIFS->USBBOXscaleFactor) {
1093 	    /* See fco_make_gaso_and_stats in fc_if.c . Debugged with hollow box in Helvetica. */
1094 	    /* Fixme : this looses a precision, an UFST bug has been reported. */
1095 	    int w = pIFS->USBBOXorigScaleFactor / 2;
1096 
1097 	    design_bbox[0] = pIFS->USBBOXxmin * pIFS->USBBOXscaleFactor / pIFS->USBBOXorigScaleFactor;
1098 	    design_bbox[1] = pIFS->USBBOXymin * pIFS->USBBOXscaleFactor / pIFS->USBBOXorigScaleFactor;
1099 	    design_bbox[2] = (pIFS->USBBOXxmax * pIFS->USBBOXscaleFactor + w) / pIFS->USBBOXorigScaleFactor;
1100 	    design_bbox[3] = (pIFS->USBBOXymax * pIFS->USBBOXscaleFactor + w) / pIFS->USBBOXorigScaleFactor;
1101 	} else {
1102 	    design_bbox[0] = pIFS->USBBOXxmin;
1103 	    design_bbox[1] = pIFS->USBBOXymin;
1104 	    design_bbox[2] = pIFS->USBBOXxmax;
1105 	    design_bbox[3] = pIFS->USBBOXymax;
1106 	}
1107     } else {
1108 	/* fixme: UFST 5.0 doesn't provide this data.
1109 	   Stubbing with Em box.
1110 	   Non-FCO fonts may be cropped if a glyph goes outside Em box
1111 	   (or occupy negative coordinates, such as 'y'.).
1112 	   Non-FCO fonts may be uncached if Em box is much bigger than the glyph.
1113 	 */
1114 	design_bbox[0] = 0;
1115 	design_bbox[1] = 0;
1116 	design_bbox[2] = du_emx;
1117 	design_bbox[3] = du_emy;
1118     }
1119 #endif
1120     {	/* UFST performs a dual rounding of the glyph origin : first
1121 	   the scaled glyph design origin is rounded to pixels with floor(x + 0.5),
1122 	   second the glyph position is rounded to pixels with floor(x + 0.5).
1123 	   Ghostscript rounds with floor(x) due to the pixel-center-inside rule.
1124 
1125 	   A right way would be to specify the half pixel offset to the glyph
1126 	   origin for the rendering glyph, but UFST has no interface for doing that.
1127 	   Instead that, to prevent a possible cropping while copying a glyph to cache cell,
1128 	   we expand the design bbox in a value of a pixel size.
1129 	   We could not determine the necessary expansion theoretically,
1130 	   and choosen expansion coefficients empirically,
1131 	   which appears equal to 2 pixels.
1132 
1133 	   fixme: Actually the expansion is the FONTCONTEXT property,
1134 	   so it could be computed at once when the scaled font is created.
1135 	 */
1136 	const double expansion_x = 2, expansion_y = 2; /* pixels */ /* adesso5.pdf */
1137 	const double XX = r->tran_xx * r->fc.s.m2.xworld_res / 72 / du_emx;
1138 	const double XY = r->tran_xy * r->fc.s.m2.yworld_res / 72 / du_emy;
1139 	const double YX = r->tran_yx * r->fc.s.m2.xworld_res / 72 / du_emx;
1140 	const double YY = r->tran_yy * r->fc.s.m2.yworld_res / 72 / du_emy;
1141 	const double det = XX * YY - XY * YX;
1142 	const double deta = det < 0 ? -det : det;
1143 
1144 	if (deta > 0.0000000001) {
1145 	    const double xx =  YY / det, xy = -XY / det;
1146 	    const double yx = -YX / det, yy =  XX / det;
1147 	    const double dx = -(expansion_x * xx + expansion_y * xy);
1148 	    const double dy = -(expansion_x * yx + expansion_y * yy);
1149 	    const SL32 dxa = (SL32)((dx < 0 ? -dx : dx) + 0.5);
1150 	    const SL32 dya = (SL32)((dy < 0 ? -dy : dy) + 0.5);
1151 
1152 	    design_bbox[0] -= dxa;
1153 	    design_bbox[1] -= dya;
1154 	    design_bbox[2] += dxa;
1155 	    design_bbox[3] += dya;
1156 	}
1157     }
1158     set_metrics(r, metrics, design_bbox, design_escapement, du_emx, du_emy);
1159     if (code == ERR_fixed_space)
1160         release_char_data_inline(r);
1161     return 0;
1162 }
1163 
get_char_outline_metrics(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,FAPI_metrics * metrics)1164 static FAPI_retcode get_char_outline_metrics(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, FAPI_metrics *metrics)
1165 {   fapi_ufst_server *r = If_to_I(server);
1166 
1167     release_char_data_inline(r);
1168     return get_char(r, ff, c, NULL, metrics, FC_CUBIC_TYPE);
1169     /*	UFST cannot render enough metrics information without generating raster or outline.
1170 	r->char_data keeps an outline after calling this function.
1171     */
1172 }
1173 
get_char_outline(FAPI_server * server,FAPI_path * p)1174 static FAPI_retcode get_char_outline(FAPI_server *server, FAPI_path *p)
1175 {   fapi_ufst_server *r = If_to_I(server);
1176 
1177     return export_outline(r, (IFOUTLINE *)r->char_data, p);
1178 }
1179 
get_char_raster_metrics(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,FAPI_metrics * metrics)1180 static FAPI_retcode get_char_raster_metrics(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, FAPI_metrics *metrics)
1181 {   fapi_ufst_server *r = If_to_I(server);
1182     int code;
1183 
1184     release_char_data_inline(r);
1185     code = get_char(r, ff, c, NULL, metrics, FC_BITMAP_TYPE);
1186     if (code == ERR_bm_buff || code == ERR_bm_too_big) /* Too big character ? */
1187         return e_limitcheck;
1188     return code;
1189     /*	UFST cannot render enough metrics information without generating raster or outline.
1190 	r->char_data keeps a raster after calling this function.
1191     */
1192 }
1193 
get_char_raster(FAPI_server * server,FAPI_raster * rast)1194 static FAPI_retcode get_char_raster(FAPI_server *server, FAPI_raster *rast)
1195 {   fapi_ufst_server *r = If_to_I(server);
1196 
1197     if (!r->bRaster)
1198         return e_limitcheck;
1199     else if (r->char_data == NULL) {
1200 	rast->height = rast->width = rast->line_step = 0;
1201 	rast->p = 0;
1202     } else {
1203         IFBITMAP *pbm = (IFBITMAP *)r->char_data;
1204         rast->p = pbm->bm;
1205         rast->height = pbm->top_indent + pbm->black_depth;
1206         rast->width = pbm->left_indent + pbm->black_width;
1207         rast->line_step = pbm->width;
1208 	rast->left_indent = pbm->left_indent;
1209 	rast->top_indent = pbm->top_indent;
1210 	rast->black_width = pbm->black_width;
1211 	rast->black_height = pbm->black_depth;
1212         if (rast->width != 0) {
1213             rast->orig_x = pbm->xorigin;
1214             rast->orig_y = pbm->yorigin;
1215         } else
1216             rast->orig_x = rast->orig_y = 0;
1217     }
1218     return 0;
1219 }
1220 
release_char_data(FAPI_server * server)1221 static FAPI_retcode release_char_data(FAPI_server *server)
1222 {   fapi_ufst_server *r = If_to_I(server);
1223 
1224     release_char_data_inline(r);
1225     return 0;
1226 }
1227 
release_fco(fapi_ufst_server * r,SW16 fcHandle)1228 static void release_fco(fapi_ufst_server *r, SW16 fcHandle)
1229 {
1230     fco_list_elem **e;
1231 
1232     if(gx_UFST_find_static_fco_handle(fcHandle) != NULL)
1233 	return;
1234     for (e = &r->fco_list; *e != 0; )
1235         if ((*e)->fcHandle == fcHandle && (--(*e)->open_count) == 0) {
1236             fco_list_elem *ee = *e;
1237 	    FSA_FROM_SERVER;
1238 
1239             *e = ee->next;
1240             CGIFfco_Close(FSA ee->fcHandle);
1241             r->client_mem.free(&r->client_mem, ee->file_path, "fco_file_path");
1242             r->client_mem.free(&r->client_mem, ee, "fco_list_elem");
1243         } else
1244             e = &(*e)->next;
1245 }
1246 
release_typeface(FAPI_server * server,void * font_data)1247 static FAPI_retcode release_typeface(FAPI_server *server, void *font_data)
1248 {   fapi_ufst_server *r = If_to_I(server);
1249     ufst_common_font_data *d;
1250     FAPI_retcode code = 0;
1251     FSA_FROM_SERVER;
1252 
1253     release_char_data_inline(r);
1254     if (font_data == 0)
1255         return 0;
1256     d = (ufst_common_font_data *)font_data;
1257     prepare_typeface(r, d);
1258     if (d->is_disk_font)
1259         code = CGIFhdr_font_purge(FSA &r->fc);
1260     else
1261         code = CGIFfont_purge(FSA &r->fc);
1262     release_glyphs(r, d);
1263     release_fco(r, (SW16)(d->font_id >> 16));
1264     r->client_mem.free(&r->client_mem, font_data, "ufst font data");
1265     return code;
1266 }
1267 
check_cmap_for_GID(FAPI_server * server,uint index)1268 static FAPI_retcode check_cmap_for_GID(FAPI_server *server, uint index)
1269 {
1270     return 0;
1271 }
1272 
1273 /* --------------------- The plugin definition : ------------------------- */
1274 
1275 
1276 static void gs_fapiufst_finit(i_plugin_instance *instance, i_plugin_client_memory *mem);
1277 
1278 static const i_plugin_descriptor ufst_descriptor = {
1279     "FAPI",
1280     "UFST",
1281     gs_fapiufst_finit
1282 };
1283 
1284 static const FAPI_server If0 = {
1285     {   &ufst_descriptor
1286     },
1287     16, /* frac_shift */
1288     {gs_no_id},
1289     {0},
1290     {1, 0, 0, 1, 0, 0},
1291     ensure_open,
1292     get_scaled_font,
1293     get_decodingID,
1294     get_font_bbox,
1295     get_font_proportional_feature,
1296     can_retrieve_char_by_name,
1297     can_replace_metrics,
1298     get_char_width,
1299     get_char_raster_metrics,
1300     get_char_raster,
1301     get_char_outline_metrics,
1302     get_char_outline,
1303     release_char_data,
1304     release_typeface,
1305     check_cmap_for_GID
1306 };
1307 
1308 plugin_instantiation_proc(gs_fapiufst_instantiate);      /* check prototype */
1309 
gs_fapiufst_instantiate(i_plugin_client_memory * client_mem,i_plugin_instance ** p_instance)1310 int gs_fapiufst_instantiate(i_plugin_client_memory *client_mem, i_plugin_instance **p_instance)
1311 {   fapi_ufst_server *r = (fapi_ufst_server *)client_mem->alloc(client_mem, sizeof(fapi_ufst_server), "fapi_ufst_server");
1312 
1313     if (r == 0)
1314         return e_Fatal;
1315     memset(r, 0, sizeof(*r));
1316     r->If = If0;
1317     r->client_mem = *client_mem;
1318     *p_instance = &r->If.ig;
1319     return 0;
1320 }
1321 
gs_fapiufst_finit(i_plugin_instance * this,i_plugin_client_memory * mem)1322 static void gs_fapiufst_finit(i_plugin_instance *this, i_plugin_client_memory *mem)
1323 {   fapi_ufst_server *r = (fapi_ufst_server *)this;
1324     FSA_FROM_SERVER;
1325 
1326     if (r->If.ig.d != &ufst_descriptor)
1327         return; /* safety */
1328 #if 0 /* Disabled against a reentrancy problem
1329 	 in a single language build for host-based applications. */
1330     gx_set_UFST_Callbacks(NULL, NULL, NULL);
1331 #endif
1332     release_char_data_inline(r);
1333     if (r->bInitialized && !r->ufst_is_singleton)
1334 	gx_UFST_fini();
1335     mem->free(mem, r, "fapi_ufst_server");
1336 }
1337