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