xref: /plan9/sys/src/cmd/gs/src/fapiufst.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: fapiufst.c,v 1.24 2004/02/18 14:41:50 igor Exp $ */
18 /* Agfa UFST plugin */
19 
20 /* GS includes : */
21 #include "stdio_.h"
22 #include "memory_.h"
23 #include "math_.h"
24 #include "ierrors.h"
25 #include "iplugin.h"
26 #include "ifapi.h"
27 /* UFST includes : */
28 #include "cgconfig.h"
29 #include "port.h"
30 #include "shareinc.h"
31 #include "t1isfnt.h"
32 #include "cgmacros.h"
33 #include "sfntenum.h"
34 #define DOES_ANYONE_USE_THIS_STRUCTURE /* see TTPCLEO.H, UFST 4.2 */
35 #include "ttpcleo.h"
36 #undef  DOES_ANYONE_USE_THIS_STRUCTURE
37 /* GS includes : */
38 #include "gxfapi.h"
39 
40 GLOBAL const SW16 trace_sw = 0; /* UFST 4.3 wants it. */
41 
42 GLOBAL UW16  PCLswapHdr( FSP LPUB8 p, UW16 gifct ); /* UFST header doesn't define it. */
43 
44 typedef struct pcleo_glyph_list_elem_s pcleo_glyph_list_elem;
45 struct pcleo_glyph_list_elem_s {
46     UW16 chId;
47     pcleo_glyph_list_elem *next;
48     /* more data follows here depending on font type */
49 };
50 
51 typedef struct fco_list_elem_s fco_list_elem;
52 struct fco_list_elem_s {
53     int open_count;
54     SW16 fcHandle;
55     char *file_path;
56     fco_list_elem *next;
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[12];
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 typedef struct fapi_ufst_server_s fapi_ufst_server;
78 struct fapi_ufst_server_s {
79     FAPI_server If;
80     int bInitialized;
81     FAPI_font *ff;
82     i_plugin_client_memory client_mem;
83     IF_STATE IFS;
84     FONTCONTEXT fc;
85     void *char_data;
86     bool bRaster;
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 private 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 private 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 private 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         CHARfree(&r->IFS, (MEM_HANDLE)r->char_data);
120         r->char_data = 0;
121     }
122 }
123 
open_UFST(fapi_ufst_server * r)124 private FAPI_retcode open_UFST(fapi_ufst_server *r)
125 {   IFCONFIG   config_block;
126     int code;
127 
128     if ((code = CGIFinit(&r->IFS)) != 0)
129 	return code;
130     r->IFS.mem_avail[BUFFER_POOL]  = 6000000L; /* For Asian TT fonts with vertical writing mode. */
131     config_block.num_files = 10;
132     config_block.bit_map_width = 1;
133     if ((code = CGIFconfig(&r->IFS, &config_block)) != 0)
134 	return code;
135     if ((code = CGIFenter(&r->IFS)) != 0)
136 	return code;
137     return 0;
138 }
139 
ensure_open(FAPI_server * server)140 private FAPI_retcode ensure_open(FAPI_server *server)
141 {   fapi_ufst_server *r = If_to_I(server);
142 
143     if (r->bInitialized)
144         return 0;
145     r->bInitialized = 1;
146     return open_UFST(r);
147 }
148 
get_font_type(FILE * f)149 private UW16 get_font_type(FILE *f)
150 {   char buf[20], mark_PS[]="%!";
151     int i;
152 
153     if (fread(buf, 1, sizeof(buf), f) != sizeof(buf))
154         return 0;
155     if (buf[0] == 0x13 || buf[0] == 0x14) /* fixme : don't know how to do correctly. */
156         return FC_FCO_TYPE;
157     for (i = 0; i < sizeof(buf) - sizeof(mark_PS); i++)
158         if(!memcmp(buf + i, mark_PS, sizeof(mark_PS) - 1))
159             return FC_PST1_TYPE;
160     if (buf[0] == '\0' && buf[1] == '\1')
161         return FC_TT_TYPE;
162     if (buf[0] == 't' && buf[1] == 't')
163         return FC_TT_TYPE;
164     return 0; /* fixme : unknown type - actually an error. */
165 }
166 
167 
choose_decoding_PS(fapi_ufst_server * r,ufst_common_font_data * d,const char * cmapId)168 private int choose_decoding_PS(fapi_ufst_server *r, ufst_common_font_data *d, const char *cmapId)
169 { strncpy(d->decodingID, "Latin1", sizeof(d->decodingID));
170   /*    fixme : must depend on charset used in the font.
171         Particulartly Symbol fonts need a different decoding.
172   */
173   return 1;
174 }
175 
choose_decoding_TT(fapi_ufst_server * r,ufst_common_font_data * d,const char * cmapId)176 private int choose_decoding_TT(fapi_ufst_server *r, ufst_common_font_data *d, const char *cmapId)
177 {   int platId, specId, i;
178     CMAP_QUERY q;
179     UW16 font_access;
180     bool failed;
181     void *p = (d->is_disk_font ? (void *)(d + 1) : (void *)((UB8 *)d + d->tt_font_body_offset));
182 
183     if (sscanf(cmapId, "%d.%d", &platId, &specId) != 2)
184         return 0;
185     font_access = r->IFS.font_access;
186     r->IFS.font_access = (d->is_disk_font ? DISK_ACCESS : ROM_ACCESS);
187     failed = CGIFtt_cmap_query(&r->IFS, p, r->fc.ttc_index, &q);
188     r->IFS.font_access = font_access;
189     if(failed)
190         return 0;
191     for (i = 0; i < q.numCmap; i++)
192         if (q.entry[i].platId == platId && q.entry[i].specId == specId) {
193             d->platformId = platId;
194             d->specificId = specId;
195             return 1;
196         }
197     return 0;
198 }
199 
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))200 private void scan_xlatmap(fapi_ufst_server *r, ufst_common_font_data *d, const char *xlatmap, const char *font_kind,
201                                     int (*choose_proc)(fapi_ufst_server *r, ufst_common_font_data *d, const char *cmapId))
202 {   const char *p = xlatmap;
203 
204     while(*p) {
205         int good_kind =!strcmp(p, font_kind);
206         p += strlen(p) + 2;
207         while(*p) {
208             const char *cmapId = p, *decodingID = p + strlen(p) + 1;
209             strncpy(d->decodingID, decodingID, sizeof(d->decodingID));
210             if (!decodingID[0])
211                 break;
212             p = decodingID + strlen(decodingID) + 1;
213             if (good_kind)
214                 if (choose_proc(r, d, cmapId))
215                     return;
216         }
217     }
218     d->decodingID[0] = 0;
219 }
220 
choose_decoding(fapi_ufst_server * r,ufst_common_font_data * d,const char * xlatmap)221 private void choose_decoding(fapi_ufst_server *r, ufst_common_font_data *d, const char *xlatmap)
222 {   if (xlatmap != 0)
223         switch (d->font_type) {
224             case FC_IF_TYPE: /* fixme */ break;
225             case FC_PST1_TYPE: scan_xlatmap(r, d, xlatmap, "PostScript", choose_decoding_PS); break;
226             case FC_TT_TYPE:   scan_xlatmap(r, d, xlatmap, "TrueType", choose_decoding_TT); break;
227             case FC_FCO_TYPE:  scan_xlatmap(r, d, xlatmap, "PostScript", choose_decoding_PS/* fixme */); break;
228         }
229 }
230 
store_word(byte ** p,ushort w)231 private inline void store_word(byte **p, ushort w)
232 {   *((*p)++) = w / 256;
233     *((*p)++) = w % 256;
234 
235 }
236 
get_TT_glyph(fapi_ufst_server * r,FAPI_font * ff,UW16 chId)237 private LPUB8 get_TT_glyph(fapi_ufst_server *r, FAPI_font *ff, UW16 chId)
238 {   pcleo_glyph_list_elem *g;
239     PCLETTO_CHDR *h;
240     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
241     LPUB8 q;
242     ushort glyph_length = ff->get_glyph(ff, chId, 0, 0);
243     bool use_XL_format = ff->is_mtx_skipped;
244 
245     /*
246      * The client must set ff->is_mtx_skipped iff
247      * it requests replaced lsb for True Type.
248      * If it is set, replaced width to be supplied.
249      * This constraing is derived from UFST restriction :
250      * the font header format must be compatible with
251      * glyph header format.
252      */
253 
254     if (glyph_length == (ushort)-1) {
255         r->callback_error = e_invalidfont;
256         return 0;
257     }
258     g = (pcleo_glyph_list_elem *)r->client_mem.alloc(&r->client_mem,
259 	    sizeof(pcleo_glyph_list_elem) +
260 	    (use_XL_format ? 12 : sizeof(PCLETTO_CHDR)) + glyph_length + 2,
261 	    "PCLETTO char");
262     if (g == 0) {
263         r->callback_error = e_VMerror;
264         return 0;
265     }
266     g->chId = chId;
267     g->next = d->glyphs;
268     d->glyphs = g;
269     h = (PCLETTO_CHDR *)(g + 1);
270     h->h.format = 15;
271     if (use_XL_format) {
272 	h->h.continuation = 2;
273 	q = (LPUB8)h + 2;
274 	store_word(&q, (ushort)(glyph_length + 10));
275 	store_word(&q, (ushort)(r->sb_x >> r->If.frac_shift)); /* see can_replace_metrics */
276 	store_word(&q, (ushort)(r->aw_x >> r->If.frac_shift));
277 	store_word(&q, 0);
278 	store_word(&q, chId);
279     } else {
280 	h->h.continuation = 0;
281 	h->h.descriptorsize = 4;
282 	h->h.class = 15;
283 	h->add_data = 0;
284 	q = (LPUB8)&h->charDataSize;
285 	store_word(&q, (ushort)(glyph_length + 4));
286 	store_word(&q, chId);
287     }
288     if (ff->get_glyph(ff, chId, (LPUB8)q, glyph_length) == (ushort)-1) {
289         r->callback_error = e_invalidfont;
290         return 0;
291     }
292     q += glyph_length;
293     store_word(&q, 0); /* checksum */
294     return (LPUB8)h;
295     /*
296      * The metrics replacement here is done only for the case
297      * corresponding to non-disk TT fonts with MetricsCount != 0;
298      * Other cases are not supported because UFST cannot handle them.
299      * Here we don't take care of cases which can_replace_metrics rejects.
300      *
301      * We don't care of metrics for subglyphs, because
302      * it is ignored by TT interpreter.
303      */
304 }
305 
get_T1_glyph(fapi_ufst_server * r,FAPI_font * ff,UW16 chId)306 private LPUB8 get_T1_glyph(fapi_ufst_server *r, FAPI_font *ff, UW16 chId)
307 {   ushort glyph_length = ff->get_glyph(ff, chId, 0, 0);
308     LPUB8 q;
309     pcleo_glyph_list_elem *g = (pcleo_glyph_list_elem *)r->client_mem.alloc(&r->client_mem, sizeof(pcleo_glyph_list_elem) + sizeof(PS_CHAR_HDR) + 2 + 2 + glyph_length + 1, "PSEO char");
310     PS_CHAR_HDR *h;
311     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
312 
313     if (g == 0 || glyph_length == (ushort)-1) {
314         r->callback_error = e_invalidfont;
315         return 0;
316     }
317     g->chId = chId;
318     g->next = d->glyphs;
319     d->glyphs = g;
320     h = (PS_CHAR_HDR *)(g + 1);
321     h->format = 30;           /* raster=4, DJ=5, IF=10, TT=15, PS=30 */
322     h->continuation = 0;     /* always 0 */
323     h->descriptorsize = 2;   /* always 2 */
324     h->class = 11;           /* contour=3, compound=4, tt=10, ps=11 */
325     h->len = 0;              /* # of bytes to follow (not including csum) */
326     q = (byte *)h + sizeof(*h);
327     q[0] = 0; /* Namelen */
328     q[1] = 0; /* Namelen */
329     q[2] = (glyph_length) / 256; /* Datalen */
330     q[3] = (glyph_length) % 256; /* Datalen */
331     /* Glyph name goes here, but we don't use it. */
332     q+=4;
333     glyph_length = ff->get_glyph(ff, chId, q, glyph_length);
334     q += glyph_length;
335     *q = 1; /* Decrypt flag */
336     return (LPUB8)h;
337 }
338 
find_glyph(ufst_common_font_data * d,UW16 chId)339 private pcleo_glyph_list_elem * find_glyph(ufst_common_font_data *d, UW16 chId)
340 {   pcleo_glyph_list_elem *e;
341 
342     for (e = d->glyphs; e != 0; e = e->next)
343         if (e->chId == chId)
344             return e;
345     return 0;
346 }
347 
gs_PCLEO_charptr(LPUB8 pfont_hdr,UW16 sym_code)348 private LPUB8 gs_PCLEO_charptr(LPUB8 pfont_hdr, UW16  sym_code)
349 {   /* never called */
350     /*  We would like to do this :
351         r->callback_error = e_unregistered;
352         (see gs_PCLglyphID2Ptr)
353         but we can't due to the reentrancy problem of UFST.
354     */
355     return 0;
356 }
357 
gs_PCLchId2ptr(IF_STATE * pIFS,UW16 chId)358 private LPUB8 gs_PCLchId2ptr(IF_STATE *pIFS, UW16 chId)
359 {   fapi_ufst_server *r = IFS_to_I(pIFS);
360     FAPI_font *ff = r->ff;
361     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
362     pcleo_glyph_list_elem *g = find_glyph(d, chId);
363     LPUB8 result = 0;
364 
365     if (g != 0)
366         result = (LPUB8)(g + 1);
367     if ((r->fc.format & FC_FONTTYPE_MASK) == FC_PST1_TYPE)
368         result = get_T1_glyph(r, ff, chId);
369     if ((r->fc.format & FC_FONTTYPE_MASK) == FC_TT_TYPE)
370         result = get_TT_glyph(r, ff, chId);
371     return result;
372 }
373 
gs_PCLglyphID2Ptr(IF_STATE * pIFS,UW16 glyphID)374 private LPUB8 gs_PCLglyphID2Ptr(IF_STATE *pIFS, UW16 glyphID)
375 {   return gs_PCLchId2ptr(pIFS, glyphID);
376 }
377 
pack_word(LPUB8 * p,UW16 v)378 private inline void pack_word(LPUB8 *p, UW16 v)
379 {   LPUB8 q = (LPUB8)&v;
380 
381 #if (BYTEORDER == LOHI) /* defied in UFST includes */
382          (*p)[1] = q[0];
383          (*p)[0] = q[1];
384 #else
385         *(UW16 *)(*p) = v;
386 #endif
387     *p += 2;
388 }
389 
pack_long(LPUB8 * p,UL32 v)390 private inline void pack_long(LPUB8 *p, UL32 v)
391 {   LPUB8 q = (LPUB8)&v;
392 
393 #if (BYTEORDER == LOHI) /* defied in UFST includes */
394          (*p)[3] = q[0];
395          (*p)[2] = q[1];
396          (*p)[1] = q[2];
397          (*p)[0] = q[3];
398 #else
399         *(UL32 *)(*p) = v;
400 #endif
401     *p += 4;
402 }
403 
pack_float(LPUB8 * p,float v)404 private inline void pack_float(LPUB8 *p, float v)
405 {   sprintf((char *)(*p), "%f", v);
406     *p += strlen((const char *)*p) + 1;
407 }
408 
409 #define PACK_ZERO(p) *(p++) = 0
410 #define PACK_BYTE(p, c) *(p++) = c
411 #define PACK_WORD(p, i, var) pack_word(&p, ff->get_word(ff, var, i))
412 #define PACK_LONG(p, i, var) pack_long(&p, ff->get_long(ff, var, i))
413 
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)414 private void 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)
415 {   UW16 k = min(ff->get_word(ff, count_id, 0), max_count), j;
416 
417     pack_word(p, k);
418     for (j = 0; j < k; j++)
419         PACK_WORD(*p, j, array_id);
420     for (; j < max_count; j++)
421         pack_word(p, 0);
422 }
423 
pack_pseo_fhdr(fapi_ufst_server * r,FAPI_font * ff,UB8 * p)424 private void pack_pseo_fhdr(fapi_ufst_server *r, FAPI_font *ff, UB8 *p)
425 {   ushort j, n, skip = 0;
426 
427     while ((UL32)p & 0x03) /* align to QUADWORD */
428 	PACK_ZERO(p);
429     pack_long(&p, 1);  /* format = 1 */
430     for (j = 0; j < 6; j++)
431         pack_float(&p, ff->get_float(ff, FAPI_FONT_FEATURE_FontMatrix, j));
432     while ((UL32)p & 0x03) /* align to QUADWORD */
433 	PACK_ZERO(p);
434     /* UFST has no definition for PSEO structure, so implement serialization : */
435     PACK_LONG(p, 0, FAPI_FONT_FEATURE_UniqueID);
436     PACK_LONG(p, 0, FAPI_FONT_FEATURE_BlueScale);
437     PACK_WORD(p, 0, FAPI_FONT_FEATURE_Weight);
438     PACK_WORD(p, 0, FAPI_FONT_FEATURE_ItalicAngle);
439     PACK_WORD(p, 0, FAPI_FONT_FEATURE_IsFixedPitch);
440     PACK_WORD(p, 0, FAPI_FONT_FEATURE_UnderLinePosition);
441     PACK_WORD(p, 0, FAPI_FONT_FEATURE_UnderlineThickness);
442     PACK_WORD(p, 0, FAPI_FONT_FEATURE_FontType);
443     PACK_WORD(p, 0, FAPI_FONT_FEATURE_FontBBox);
444     PACK_WORD(p, 1, FAPI_FONT_FEATURE_FontBBox);
445     PACK_WORD(p, 2, FAPI_FONT_FEATURE_FontBBox);
446     PACK_WORD(p, 3, FAPI_FONT_FEATURE_FontBBox);
447     pack_pseo_word_array(r, ff, &p, 14, FAPI_FONT_FEATURE_BlueValues_count, FAPI_FONT_FEATURE_BlueValues);
448     pack_pseo_word_array(r, ff, &p, 10, FAPI_FONT_FEATURE_OtherBlues_count, FAPI_FONT_FEATURE_OtherBlues);
449     pack_pseo_word_array(r, ff, &p, 14, FAPI_FONT_FEATURE_FamilyBlues_count, FAPI_FONT_FEATURE_FamilyBlues);
450     pack_pseo_word_array(r, ff, &p, 10, FAPI_FONT_FEATURE_FamilyOtherBlues_count, FAPI_FONT_FEATURE_FamilyOtherBlues);
451     PACK_WORD(p, 0, FAPI_FONT_FEATURE_BlueShift);
452     PACK_WORD(p, 0, FAPI_FONT_FEATURE_BlueFuzz);
453     PACK_WORD(p, 0, FAPI_FONT_FEATURE_StdHW);
454     PACK_WORD(p, 0, FAPI_FONT_FEATURE_StdVW);
455     pack_pseo_word_array(r, ff, &p, 12, FAPI_FONT_FEATURE_StemSnapH_count, FAPI_FONT_FEATURE_StemSnapH);
456     pack_pseo_word_array(r, ff, &p, 12, FAPI_FONT_FEATURE_StemSnapV_count, FAPI_FONT_FEATURE_StemSnapV);
457     PACK_WORD(p, 0, FAPI_FONT_FEATURE_ForceBold);
458     PACK_WORD(p, 0, FAPI_FONT_FEATURE_LanguageGroup);
459     PACK_WORD(p, 0, FAPI_FONT_FEATURE_lenIV);
460     for (j = 0; j < 12; j++)
461         PACK_ZERO(p), PACK_ZERO(p);     /* Reserved2 */
462     /* max data size = 107 words + 6 floats in ASCII */
463     n = ff->get_word(ff, FAPI_FONT_FEATURE_Subrs_count, 0);
464     pack_word(&p, n);
465     for (j = 0; j < n; j++) {
466         ushort subr_len = ff->get_subr(ff, j, 0, 0);
467         if (subr_len != 0) {
468             pack_word(&p, j);
469             pack_word(&p, subr_len);
470             PACK_BYTE(p, 1); /* is_decrypted */
471             ff->get_subr(ff, j, p, subr_len);
472             p += subr_len;
473         } else
474             skip = 1;
475     }
476     if (skip)
477         pack_word(&p, 0xFFFF);
478 }
479 
enumerate_fco(fapi_ufst_server * r,const char * font_file_path)480 private void enumerate_fco(fapi_ufst_server *r, const char *font_file_path)
481 {   /* development perpose only */
482 #if 0
483         UW16 i;
484         for (i = 0; ; i++) {
485             UW16 size;
486             TTFONTINFOTYPE *pBuffer;
487             UW16 code = CGIFfco_Access(&r->IFS, (LPUB8)font_file_path, i, TFATRIB_KEY, &size, NULL);
488             if (code)
489                 break;
490             pBuffer = (TTFONTINFOTYPE *)malloc(size);
491             if (pBuffer == 0)
492                 break;
493             code = CGIFfco_Access(&r->IFS, (LPUB8)font_file_path, i, TFATRIB_KEY, &size, (SB8 *)pBuffer);
494             if (code)
495                 break;
496             {   char *tfName          = (char *)pBuffer + pBuffer->tfName;
497                 char *pcltTypeface    = (char *)pBuffer + pBuffer->pcltTypeface;
498                 char *pcltFileName    = (char *)pBuffer + pBuffer->pcltFileName;
499                 char *familyName      = (char *)pBuffer + pBuffer->familyName;
500                 char *weightName      = (char *)pBuffer + pBuffer->weightName;
501                 char *copyrightNotice = (char *)pBuffer + pBuffer->copyrightNotice;
502                 pBuffer += 0; /* a place for breakpoint */
503             }
504             free(pBuffer);
505             (void)code;
506         }
507 #endif
508 }
509 
my_strdup(fapi_ufst_server * r,const char * s,const char * cname)510 private char *my_strdup(fapi_ufst_server *r, const char *s, const char *cname)
511 {   int l = strlen(s) + 1;
512     char *p = (char *)r->client_mem.alloc(&r->client_mem, l, cname);
513 
514     if (p != 0)
515         memcpy(p, s, l);
516     return p;
517 }
518 
fco_open(fapi_ufst_server * r,const char * font_file_path,fco_list_elem ** result)519 private FAPI_retcode fco_open(fapi_ufst_server *r, const char *font_file_path, fco_list_elem **result)
520 {   fco_list_elem *e = r->fco_list;
521     int code;
522 
523     for (; e != 0; e = e->next) {
524         if (!strcmp(e->file_path, font_file_path))
525             break;
526     }
527     if (e == 0) {
528         SW16 fcHandle;
529         if ((code = CGIFfco_Open(&r->IFS, (UB8 *)font_file_path, &fcHandle)) != 0)
530 	    return code;
531         e = (fco_list_elem *)r->client_mem.alloc(&r->client_mem, sizeof(*e), "fco_list_elem");
532         if (e == 0) {
533             CGIFfco_Close(&r->IFS, fcHandle);
534             return e_VMerror;
535         }
536         e->open_count = 0;
537         e->fcHandle = fcHandle;
538         e->file_path = my_strdup(r, font_file_path, "fco_file_path");
539         if (e->file_path == 0) {
540             CGIFfco_Close(&r->IFS, fcHandle);
541             r->client_mem.free(&r->client_mem, e, "fco_list_elem");
542             return e_VMerror;
543         }
544         e->next = r->fco_list;
545         r->fco_list = e;
546     }
547     e->open_count++;
548     *result = e;
549     return 0;
550 }
551 
make_font_data(fapi_ufst_server * r,const char * font_file_path,int subfont,FAPI_font * ff,ufst_common_font_data ** return_data)552 private FAPI_retcode make_font_data(fapi_ufst_server *r, const char *font_file_path, int subfont, FAPI_font *ff, ufst_common_font_data **return_data)
553 {   ulong area_length = sizeof(ufst_common_font_data), tt_size = 0;
554     LPUB8 buf;
555     PCLETTO_FHDR *h;
556     ufst_common_font_data *d;
557     bool use_XL_format = ff->is_mtx_skipped;
558     int code;
559 
560     *return_data = 0;
561     r->fc.ttc_index = subfont;
562     if (ff->font_file_path == NULL) {
563         area_length += PCLETTOFONTHDRSIZE;
564         if (ff->is_type1) {
565             int subrs_count  = ff->get_word(ff, FAPI_FONT_FEATURE_Subrs_count, 0);
566             int subrs_length = ff->get_long(ff, FAPI_FONT_FEATURE_Subrs_total_size, 0);
567             int subrs_area_size = subrs_count * 5 + subrs_length + 2;
568             area_length += 360 + subrs_area_size; /* some inprecise - see pack_pseo_fhdr */
569         } else {
570             tt_size  = ff->get_long(ff, FAPI_FONT_FEATURE_TT_size, 0);
571             if (tt_size == 0)
572                 return e_invalidfont;
573             area_length += tt_size + (use_XL_format ? 6 : 4) + 4 + 2;
574         }
575     } else
576         area_length += strlen(font_file_path) + 1;
577     buf = r->client_mem.alloc(&r->client_mem, area_length, "ufst font data");
578     if (buf == 0)
579         return e_VMerror;
580     d = (ufst_common_font_data *)buf;
581     d->tt_font_body_offset = 0;
582     d->platformId = 0;
583     d->specificId = 0;
584     d->decodingID[0] = 0;
585     d->glyphs = 0;
586     d->font_id = 0;
587     d->is_disk_font = (ff->font_file_path != NULL);
588     if (d->is_disk_font) {
589         FILE *f = fopen(font_file_path, "rb"); /* note: gp_fopen isn't better since UFST calls fopen. */
590         if (f == NULL)
591             return e_undefinedfilename;
592         memcpy(d + 1, font_file_path, strlen(font_file_path) + 1);
593         d->font_type = get_font_type(f);
594         fclose(f);
595         if (d->font_type == FC_FCO_TYPE) {
596             fco_list_elem *e;
597             if ((code = fco_open(r, font_file_path, &e)) != 0)
598 		return code;
599             enumerate_fco(r, font_file_path); /* development perpose only */
600             d->font_id = (e->fcHandle << 16) | subfont;
601         }
602     } else {
603         d->font_type = (ff->is_type1 ? FC_PST1_TYPE : FC_TT_TYPE);
604         h = (PCLETTO_FHDR *)(buf + sizeof(ufst_common_font_data));
605         h->fontDescriptorSize = PCLETTOFONTHDRSIZE;
606         h->descriptorFormat = 15;
607         h->fontType = 11; /* wrong */                /*  3- 11=Unicode; 0,1,2 also possible */
608         h->style_msb = 0; /* wrong */               /*  4- from PCLT table in TrueType font */
609         h->reserved1 = 0;
610         h->baselinePosition = 0; /* wrong */        /*  6- from head table in TT font; = 0 */
611         h->cellWidth = 1024; /* wrong */               /*  8- head, use xMax - xMin */
612         h->cellHeight = 1024; /* wrong */             /* 10- head, use yMax - yMin */
613         h->orientation = 0;             /* 12- 0 */
614         h->spacing = 1; /* wrong */                 /* 13- 1=proportional, 0-fixed pitch */
615         h->characterSet = 56; /* wrong */            /* 14- same as symSetCode; =56 if unbound. */
616         h->pitch = 1024; /* wrong */                   /* 16- PCLT */
617         h->height = 0;                  /* 18- 0 if TrueType */
618         h->xHeight = 512; /* wrong */                 /* 20- PCLT */
619         h->widthType = 0; /* wrong */               /* 22- PCLT */
620         h->style_lsb = 0; /* wrong */               /* 23- PCLT */
621         h->strokeWeight = 0; /* wrong */            /* 24- PCLT */
622         h->typeface_lsb = 0; /* wrong */            /* 25- PCLT */
623         h->typeface_msb = 0; /* wrong */           /* 26- PCLT */
624         h->serifStyle = 0; /* wrong */              /* 27- PCLT */
625         h->quality = 0; /* wrong */                 /* 28- 2 if TrueType */
626         h->placement = 0; /* wronfg */               /* 29- 0 if TrueType */
627         h->underlinePosition = 0;       /* 30- 0 */
628         h->underlineHeight = 0;         /* 31- 0 */
629         h->textHeight = 102; /* wrong */              /* 32- from OS/2 table in TT font */
630         h->textWidth = 1024; /* wrong */              /* 34- OS/2 */
631         h->firstCode = 0;               /* 36- set to 0 if unbound */
632         h->lastCode = 255; /* wrong */                /* 38- max number of downloadable chars if unbound */
633         h->pitch_ext = 0;               /* 40- 0 if TrueType */
634         h->height_ext = 0;              /* 41- 0 if TrueType */
635         h->capHeight = 1024; /* wrong */               /* 42- PCLT */
636         h->fontNumber = 0; /* wrong */             /* 44- PCLT */
637         h->fontName[0] = 0; /* wrong */            /* 48- PCLT */
638         h->scaleFactor = 1024; /* wrong */             /* 64- head:unitsPerEm */
639         h->masterUnderlinePosition = 0; /* wrong */ /* 66- post table, or -20% of em */
640         h->masterUnderlineHeight = 0; /* wrong */   /* 68- post table, or 5% of em */
641         h->fontScalingTechnology = 1;   /* 70- 1=TrueType; 0=Intellifont */
642         h->variety = 0;                 /* 71- 0 if TrueType */
643         memset((LPUB8)h + PCLETTOFONTHDRSIZE, 0 ,8); /* work around bug in PCLswapHdr : it wants format 10 */
644         /*  fixme : Most fields above being marked "wrong" look unused by UFST.
645             Need to check for sure.
646         */
647         /*  fixme : This code assumes 1-byte alignment for PCLETTO_FHDR structure.
648             Use PACK_* macros to improve.
649         */
650         PCLswapHdr(&r->IFS, (UB8 *)h, 0);
651         if (ff->is_type1) {
652             LPUB8 fontdata = (LPUB8)h + PCLETTOFONTHDRSIZE;
653             pack_pseo_fhdr(r, ff, fontdata);
654         } else {
655             LPUB8 pseg = (LPUB8)h + PCLETTOFONTHDRSIZE;
656             LPUB8 fontdata = pseg + (use_XL_format ? 6 : 4);
657             if (tt_size > 65000)
658                 return e_unregistered; /* Must not happen because we skept 'glyp', 'loca' and 'cmap'. */
659             pseg[0] = 'G';
660             pseg[1] = 'T';
661 	    if (use_XL_format) {
662 		pseg[2] = tt_size >> 24;
663 		pseg[3] = (tt_size >> 16) % 256;
664 		pseg[4] = (tt_size >> 8) % 256;
665 		pseg[5] = tt_size % 256;
666 	    } else {
667 		pseg[2] = tt_size / 256;
668 		pseg[3] = tt_size % 256;
669 	    }
670             d->tt_font_body_offset = (LPUB8)fontdata - (LPUB8)d;
671             if (ff->serialize_tt_font(ff, fontdata, tt_size))
672                 return e_invalidfont;
673             *(fontdata + tt_size    ) = 255;
674             *(fontdata + tt_size + 1) = 255;
675             *(fontdata + tt_size + 2) = 0;
676             *(fontdata + tt_size + 3) = 0;
677             *(fontdata + tt_size + 4) = 0;
678             *(fontdata + tt_size + 5) = 0;  /* checksum */
679         }
680     }
681     *return_data = d;
682     return 0;
683 }
684 
prepare_typeface(fapi_ufst_server * r,ufst_common_font_data * d)685 private void prepare_typeface(fapi_ufst_server *r, ufst_common_font_data *d)
686 {   r->fc.format = d->font_type;
687     r->fc.font_id = d->font_id;
688     r->fc.font_hdr = (UB8 *)(d + 1);
689     if (!d->is_disk_font)
690         r->fc.format |= FC_EXTERN_TYPE;
691 }
692 
get_scaled_font(FAPI_server * server,FAPI_font * ff,int subfont,const FAPI_font_scale * font_scale,const char * xlatmap,bool bVertical,FAPI_descendant_code dc)693 private FAPI_retcode get_scaled_font(FAPI_server *server, FAPI_font *ff, int subfont,
694          const FAPI_font_scale *font_scale, const char *xlatmap, bool bVertical, FAPI_descendant_code dc)
695 {   fapi_ufst_server *r = If_to_I(server);
696     FONTCONTEXT *fc = &r->fc;
697     /*  Note : UFST doesn't provide handles for opened fonts,
698         but copies FONTCONTEXT to IFSTATE and caches it.
699         Due to this the plugin cannot provide a handle for the font.
700         This assumes that only one font context is active at a moment.
701     */
702     ufst_common_font_data *d = (ufst_common_font_data *)ff->server_font_data;
703     const double scale = F_ONE;
704     double hx, hy, sx, sy;
705     FAPI_retcode code;
706     bool use_XL_format = ff->is_mtx_skipped;
707 
708     if (ff->is_cid && ff->is_type1 && ff->font_file_path == NULL &&
709         (dc == FAPI_TOPLEVEL_BEGIN || dc == FAPI_TOPLEVEL_COMPLETE)) {
710 	/* Don't need any processing for the top level font of a non-disk CIDFontType 0.
711 	   See comment in FAPI_prepare_font.
712 	   Will do with its subfonts individually.
713 	 */
714 	return 0;
715     }
716     ff->need_decrypt = 1;
717     if (d == 0) {
718         if ((code = make_font_data(r, ff->font_file_path, subfont, ff, &d)) != 0)
719 	    return code;
720         ff->server_font_data = d;
721         prepare_typeface(r, d);
722         if (ff->font_file_path != NULL || ff->is_type1) /* such fonts don't use RAW_GLYPH */
723             choose_decoding(r, d, xlatmap);
724     } else
725         prepare_typeface(r, d);
726     r->tran_xx = font_scale->matrix[0] / scale, r->tran_xy = font_scale->matrix[1] / scale;
727     r->tran_yx = font_scale->matrix[2] / scale, r->tran_yy = font_scale->matrix[3] / scale;
728     hx = hypot(r->tran_xx, r->tran_xy), hy = hypot(r->tran_yx, r->tran_yy);
729     sx = r->tran_xx * r->tran_yx + r->tran_xy * r->tran_yy;
730     sy = r->tran_xx * r->tran_yy - r->tran_xy * r->tran_yx;
731     fc->xspot     = F_ONE;
732     fc->yspot     = F_ONE;
733     fc->fc_type   = FC_MAT2_TYPE;
734     /* Round towards zero for a better view of mirrored characters : */
735     fc->s.m2.m[0] = (int)((double)font_scale->matrix[0] / hx + 0.5);
736     fc->s.m2.m[1] = (int)((double)font_scale->matrix[1] / hx + 0.5);
737     fc->s.m2.m[2] = (int)((double)font_scale->matrix[2] / hy + 0.5);
738     fc->s.m2.m[3] = (int)((double)font_scale->matrix[3] / hy + 0.5);
739     fc->s.m2.matrix_scale = 16;
740     fc->s.m2.xworld_res = font_scale->HWResolution[0] >> 16;
741     fc->s.m2.yworld_res = font_scale->HWResolution[1] >> 16;
742     fc->s.m2.world_scale = 0;
743     fc->s.m2.point_size   = (int)(hy * 8 + 0.5); /* 1/8ths of pixels */
744     fc->s.m2.set_size     = (int)(hx * 8 + 0.5);
745     fc->numXsubpixels = font_scale->subpixels[0];
746     fc->numYsubpixels = font_scale->subpixels[1];
747     fc->alignment = (font_scale->align_to_pixels ? GAGG : GAPP);
748     fc->ssnum = 0x8000; /* no symset mapping */
749     if (ff->font_file_path == NULL && !ff->is_type1)
750         fc->ssnum = RAW_GLYPH;
751     else if (ff->font_file_path != NULL && ff->is_cid) {
752          if (d->platformId == 3) {
753             switch (d->specificId) {
754                 case 1 : fc->ssnum = UNICODE;   break;
755                 case 2 : fc->ssnum = SHIFT_JIS; break;
756                 case 3 : fc->ssnum = GB;        break;
757                 case 4 : fc->ssnum = BIG5;      break;
758                 case 5 : fc->ssnum = WANSUNG;   break;
759                 case 6 : fc->ssnum = JOHAB;     break;
760             }
761         } else {
762             /* fixme : other platform IDs */
763         }
764     }
765     fc->format      |= FC_NON_Z_WIND;   /* NON_ZERO Winding required for TrueType */
766     fc->format      |= FC_INCHES_TYPE;  /* output in units per inch */
767     fc->user_platID = d->platformId;
768     fc->user_specID = d->specificId;
769     fc->ExtndFlags = EF_TT_CMAPTABL;
770     if (use_XL_format)
771 	fc->ExtndFlags |= EF_XLFONT_TYPE;
772     if (bVertical)
773         fc->ExtndFlags |= EF_UFSTVERT_TYPE;
774     fc->dl_ssnum = (d->specificId << 4) | d->platformId;
775     fc->ttc_index   = subfont;
776     r->callback_error = 0;
777     gx_set_UFST_Callbacks(gs_PCLEO_charptr, gs_PCLchId2ptr, gs_PCLglyphID2Ptr);
778     code = CGIFfont(&r->IFS, fc);
779     if (r->callback_error != 0)
780 	return r->callback_error;
781     return code;
782 }
783 
get_decodingID(FAPI_server * server,FAPI_font * ff,const char ** decodingID_result)784 private FAPI_retcode get_decodingID(FAPI_server *server, FAPI_font *ff, const char **decodingID_result)
785 {   fapi_ufst_server *r = If_to_I(server);
786     ufst_common_font_data *d = (ufst_common_font_data *)r->fc.font_hdr - 1;
787 
788     *decodingID_result = d->decodingID;
789     return 0;
790 }
791 
get_font_bbox(FAPI_server * server,FAPI_font * ff,int BBox[4])792 private FAPI_retcode get_font_bbox(FAPI_server *server, FAPI_font *ff, int BBox[4])
793 {   fapi_ufst_server *r = If_to_I(server);
794     SW16 VLCPower = 0;
795     int code;
796 
797     if ((code = CGIFbound_box(&r->IFS, BBox, &VLCPower)) < 0)
798 	return code;
799     /*  UFST expands bbox for internal needs, and retrives the expanded bbox.
800         We believe it's bug in UFST.
801         Now we collapse it back to the correct size :
802     */
803     BBox[0] += 2;
804     BBox[1] += 2;
805     BBox[2] -= 2;
806     BBox[3] -= 2;
807     BBox[0] >>= VLCPower;
808     BBox[1] >>= VLCPower;
809     BBox[2] >>= VLCPower;
810     BBox[3] >>= VLCPower;
811     return 0;
812 }
813 
get_font_proportional_feature(FAPI_server * server,FAPI_font * ff,int subfont,bool * bProportional)814 private FAPI_retcode get_font_proportional_feature(FAPI_server *server, FAPI_font *ff, int subfont, bool *bProportional)
815 {   fapi_ufst_server *r = If_to_I(server);
816     UB8 buf[74];
817     UL32 length = sizeof(buf);
818     *bProportional = false;
819 
820     if (ff->font_file_path == NULL || ff->is_type1)
821         return 0;
822     if (CGIFtt_query(&r->IFS, (UB8 *)ff->font_file_path, *(UL32 *)"OS/2", (UW16)subfont, &length, buf) != 0)
823         return 0; /* No OS/2 table - no chance to get the info. Use default == false. */
824     *bProportional = (buf[35] == 9);
825     return 0;
826 }
827 
make_asciiz_char_name(char * buf,int buf_length,FAPI_char_ref * c)828 private inline void make_asciiz_char_name(char *buf, int buf_length, FAPI_char_ref *c)
829 {   int len = min(buf_length - 1, c->char_name_length);
830 
831     memcpy(buf, c->char_name, len);
832     buf[len] = 0;
833 }
834 
835 #define MAX_CHAR_NAME_LENGTH 30
836 
can_retrieve_char_by_name(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,int * result)837 private FAPI_retcode can_retrieve_char_by_name(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, int *result)
838 {   fapi_ufst_server *r = If_to_I(server);
839 
840     *result = 0;
841     switch (r->fc.format & FC_FONTTYPE_MASK) {
842         case FC_PST1_TYPE :
843             *result = 1;
844             break;
845         case FC_TT_TYPE :
846 #if 0 /* Doesn't work because Agfa can't retrive characters by name.
847                      It wants a char code together with the name. */
848                 if (ff->font_file_path != NULL) {
849                     UB8 buf[2];
850                     UL32 l = sizeof(buf);
851                     UW16 code = CGIFtt_query(&r->IFS, r->fc.font_hdr, tag_Postscript, r->fc.ttc_index, &l, buf);
852                     *result = (code == 0);
853                 }
854 #endif
855             break;
856     }
857     return 0;
858 }
859 
can_replace_metrics(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,int * result)860 private FAPI_retcode can_replace_metrics(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, int *result)
861 {   *result = (!ff->is_type1 && ff->font_file_path == NULL &&
862 	       c->metrics_scale == 0 && c->metrics_type == FAPI_METRICS_REPLACE);
863     return 0;
864 }
865 
release_glyphs(fapi_ufst_server * r,ufst_common_font_data * d)866 private void release_glyphs(fapi_ufst_server *r, ufst_common_font_data *d)
867 {   while (d->glyphs != 0) {
868         pcleo_glyph_list_elem *e = d->glyphs;
869         d->glyphs = e->next;
870         r->client_mem.free(&r->client_mem, e, "PCLEO char");
871     }
872 }
873 
get_char_width(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,FAPI_metrics * metrics)874 private FAPI_retcode get_char_width(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, FAPI_metrics *metrics)
875 {   fapi_ufst_server *r = If_to_I(server);
876     UW16 buffer[2];
877     UW16 cc = (UW16)c->char_code;
878     char PSchar_name[MAX_CHAR_NAME_LENGTH];
879     int code;
880 
881     make_asciiz_char_name(PSchar_name, sizeof(PSchar_name), c);
882     r->ff = ff;
883     CGIFchIdptr(&r->IFS, &cc, PSchar_name);
884     if ((code = CGIFwidth(&r->IFS, cc, 1, 4, buffer)) != 0)
885 	return code;
886     r->ff = 0;
887     release_glyphs(r, (ufst_common_font_data *)ff->server_font_data);
888     metrics->escapement = buffer[0];
889     metrics->em_x = metrics->em_y = buffer[1];
890     return 0;
891 }
892 
export_outline(fapi_ufst_server * r,PIFOUTLINE pol,FAPI_path * p)893 private int export_outline(fapi_ufst_server *r, PIFOUTLINE pol, FAPI_path *p)
894 {   POUTLINE_CHAR outchar;
895     SW16 num_contrs,num_segmts;
896     LPSB8 segment;
897     PINTRVECTOR points;
898     SW16  i,j;
899 
900     if (pol == NULL)
901         return 0;
902     p->shift += r->If.frac_shift + pol->VLCpower;
903     outchar = &pol->ol;
904     num_contrs = outchar->num_loops;
905     for(i=0; i<num_contrs; i++) {
906      	num_segmts = outchar->loop[i].num_segmts;
907         segment = (LPSB8)((LPSB8)(outchar->loop) + outchar->loop[i].segmt_offset);
908         points = (PINTRVECTOR)((LPSB8)(outchar->loop) + outchar->loop[i].coord_offset);
909         for(j=0; j<num_segmts; j++) {
910 	    int code;
911 
912             if(*segment == 0x00) {
913              	if ((code = p->moveto(p, points->x, points->y)) != 0)
914 		    return code;
915                 points++;
916             } else if (*segment == 0x01) {
917 		if ((code = p->lineto(p, points->x, points->y)) != 0)
918 		    return code;
919                 points++;
920             } else if (*segment == 0x02) {
921                 points+=2;
922                 return e_invalidfont; /* This must not happen */
923             } else if (*segment == 0x03) {
924 		if ((code = p->curveto(p, points[0].x, points[0].y,
925 					points[1].x, points[1].y,
926 					points[2].x, points[2].y)) < 0)
927 		    return code;
928                 points+=3;
929             } else
930                 return e_invalidfont; /* This must not happen */
931             segment++;
932         }
933     }
934     return 0;
935 }
936 
set_metrics(fapi_ufst_server * r,FAPI_metrics * metrics,SL32 design_bbox[4],SW16 design_escapement,int escapement,SW16 du_emx,SW16 du_emy)937 private inline void set_metrics(fapi_ufst_server *r, FAPI_metrics *metrics, SL32 design_bbox[4], SW16 design_escapement, int escapement, SW16 du_emx, SW16 du_emy)
938 {   metrics->escapement = design_escapement;
939     metrics->em_x = du_emx;
940     metrics->em_y = du_emy;
941     metrics->bbox_x0 = design_bbox[0];
942     metrics->bbox_y0 = design_bbox[1];
943     metrics->bbox_x1 = design_bbox[2];
944     metrics->bbox_y1 = design_bbox[3];
945 }
946 
get_char(fapi_ufst_server * r,FAPI_font * ff,FAPI_char_ref * c,FAPI_path * p,FAPI_metrics * metrics,UW16 format)947 private FAPI_retcode get_char(fapi_ufst_server *r, FAPI_font *ff, FAPI_char_ref *c, FAPI_path *p, FAPI_metrics *metrics, UW16 format)
948 {   UW16 code;
949     UW16 cc = (UW16)c->char_code;
950     SL32 design_bbox[4];
951     SW16 design_escapement;
952     char PSchar_name[MAX_CHAR_NAME_LENGTH];
953     MEM_HANDLE result;
954 
955     memset(metrics, 0, sizeof(*metrics));
956     metrics->bbox_x1 = -1;
957     make_asciiz_char_name(PSchar_name, sizeof(PSchar_name), c);
958     CGIFchIdptr(&r->IFS, &cc, PSchar_name);
959     {   /* hack : Changing UFST internal data. Change to r->fc doesn't help, because Agfa thinks that the "outline/raster" is a property of current font. */
960         r->IFS.fcCur.format &= ~FC_OUTPUT_MASK;
961         r->IFS.fcCur.format |= format;
962     }
963     r->bRaster = false;
964     r->ff = ff;
965     r->callback_error = 0;
966     r->sb_x = c->sb_x;
967     r->aw_x = c->aw_x;
968     r->metrics_type = c->metrics_type;
969     code = CGIFchar_with_design_bbox(&r->IFS, cc, &result, (SW16)0, design_bbox, &design_escapement);
970     if (code == ERR_find_cgnum) {
971         /* There is no such char in the font, try the glyph 0 (notdef) : */
972         const void *client_char_data = ff->char_data;
973         UW16 c1 = 0, ssnum = r->IFS.fcCur.ssnum;
974         /* hack : Changing UFST internal data - see above. */
975         r->IFS.fcCur.ssnum = RAW_GLYPH;
976         r->callback_error = 0;
977         ff->char_data = NULL;
978         CGIFchIdptr(&r->IFS, &c1, (char *)".notdef");
979         code = CGIFchar_with_design_bbox(&r->IFS, c1, &result, (SW16)0, design_bbox, &design_escapement);
980         r->IFS.fcCur.ssnum = ssnum;
981         ff->char_data = client_char_data;
982     }
983     r->ff = 0;
984     release_glyphs(r, (ufst_common_font_data *)ff->server_font_data);
985     if (code != ERR_fixed_space && code != 0)
986 	return code;
987     if (r->callback_error != 0)
988 	return r->callback_error;
989     if (format == FC_BITMAP_TYPE) {
990         IFBITMAP *pbm = (IFBITMAP *)result;
991         set_metrics(r, metrics, design_bbox, design_escapement, pbm->escapement, pbm->du_emx, pbm->du_emy);
992         r->char_data = pbm;
993         r->bRaster = true;
994     } else {
995         IFOUTLINE *pol = (IFOUTLINE *)result;
996         set_metrics(r, metrics, design_bbox, design_escapement, pol->escapement, pol->du_emx, pol->du_emy);
997         r->char_data = (IFOUTLINE *)result;
998     }
999     if (code == ERR_fixed_space)
1000         release_char_data_inline(r);
1001     return 0;
1002 }
1003 
get_char_outline_metrics(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,FAPI_metrics * metrics)1004 private FAPI_retcode get_char_outline_metrics(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, FAPI_metrics *metrics)
1005 {   fapi_ufst_server *r = If_to_I(server);
1006 
1007     release_char_data_inline(r);
1008     return get_char(r, ff, c, NULL, metrics, FC_CUBIC_TYPE);
1009     /*	UFST cannot render enough metrics information without generating raster or outline.
1010 	r->char_data keeps an outline after calling this function.
1011     */
1012 }
1013 
get_char_outline(FAPI_server * server,FAPI_path * p)1014 private FAPI_retcode get_char_outline(FAPI_server *server, FAPI_path *p)
1015 {   fapi_ufst_server *r = If_to_I(server);
1016 
1017     return export_outline(r, (IFOUTLINE *)r->char_data, p);
1018 }
1019 
get_char_raster_metrics(FAPI_server * server,FAPI_font * ff,FAPI_char_ref * c,FAPI_metrics * metrics)1020 private FAPI_retcode get_char_raster_metrics(FAPI_server *server, FAPI_font *ff, FAPI_char_ref *c, FAPI_metrics *metrics)
1021 {   fapi_ufst_server *r = If_to_I(server);
1022     int code;
1023 
1024     release_char_data_inline(r);
1025     code = get_char(r, ff, c, NULL, metrics, FC_BITMAP_TYPE);
1026     if (code == ERR_bm_buff || code == ERR_bm_too_big) /* Too big character ? */
1027         return e_limitcheck;
1028     return code;
1029     /*	UFST cannot render enough metrics information without generating raster or outline.
1030 	r->char_data keeps a raster after calling this function.
1031     */
1032 }
1033 
get_char_raster(FAPI_server * server,FAPI_raster * rast)1034 private FAPI_retcode get_char_raster(FAPI_server *server, FAPI_raster *rast)
1035 {   fapi_ufst_server *r = If_to_I(server);
1036 
1037     if (!r->bRaster)
1038         return e_limitcheck;
1039     else if (r->char_data == NULL) {
1040 	rast->height = rast->width = rast->line_step = 0;
1041 	rast->p = 0;
1042     } else {
1043         IFBITMAP *pbm = (IFBITMAP *)r->char_data;
1044         rast->p = pbm->bm;
1045         rast->height = pbm->depth;
1046         rast->width = pbm->width << CHUNK_SHIFT;
1047         rast->line_step = (pbm->width + (1 << (CHUNK_SHIFT - 3)) - 1) >> (CHUNK_SHIFT - 3);
1048         if (rast->width != 0) {
1049             rast->orig_x = pbm->left_indent * 16 + pbm->xorigin;
1050             rast->orig_y = pbm->top_indent  * 16 + pbm->yorigin;
1051         } else
1052             rast->orig_x = rast->orig_y = 0;
1053     }
1054     return 0;
1055 }
1056 
release_char_data(FAPI_server * server)1057 private FAPI_retcode release_char_data(FAPI_server *server)
1058 {   fapi_ufst_server *r = If_to_I(server);
1059 
1060     release_char_data_inline(r);
1061     return 0;
1062 }
1063 
release_fco(fapi_ufst_server * r,SW16 fcHandle)1064 private void release_fco(fapi_ufst_server *r, SW16 fcHandle)
1065 {   fco_list_elem **e = &r->fco_list;
1066 
1067     for (; *e != 0; )
1068         if ((*e)->fcHandle == fcHandle && (--(*e)->open_count) == 0) {
1069             fco_list_elem *ee = *e;
1070             *e = ee->next;
1071             CGIFfco_Close(&r->IFS, ee->fcHandle);
1072             r->client_mem.free(&r->client_mem, ee->file_path, "fco_file_path");
1073             r->client_mem.free(&r->client_mem, ee, "fco_list_elem");
1074         } else
1075             e = &(*e)->next;
1076 }
1077 
release_typeface(FAPI_server * server,void * font_data)1078 private FAPI_retcode release_typeface(FAPI_server *server, void *font_data)
1079 {   fapi_ufst_server *r = If_to_I(server);
1080     ufst_common_font_data *d;
1081     FAPI_retcode code = 0;
1082 
1083     release_char_data_inline(r);
1084     if (font_data == 0)
1085         return 0;
1086     d = (ufst_common_font_data *)font_data;
1087     prepare_typeface(r, d);
1088     if (d->is_disk_font)
1089         code = CGIFhdr_font_purge(&r->IFS, &r->fc);
1090     else
1091         code = CGIFfont_purge(&r->IFS, &r->fc);
1092     release_glyphs(r, d);
1093     release_fco(r, (SW16)(d->font_id >> 16));
1094     r->client_mem.free(&r->client_mem, font_data, "ufst font data");
1095     return code;
1096 }
1097 
1098 /* --------------------- The plugin definition : ------------------------- */
1099 
1100 
1101 private void gs_fapiufst_finit(i_plugin_instance *instance, i_plugin_client_memory *mem);
1102 
1103 private const i_plugin_descriptor ufst_descriptor = {
1104     "FAPI",
1105     "AgfaUFST",
1106     gs_fapiufst_finit
1107 };
1108 
1109 private const FAPI_server If0 = {
1110     {   &ufst_descriptor
1111     },
1112     16, /* frac_shift */
1113     ensure_open,
1114     get_scaled_font,
1115     get_decodingID,
1116     get_font_bbox,
1117     get_font_proportional_feature,
1118     can_retrieve_char_by_name,
1119     can_replace_metrics,
1120     get_char_width,
1121     get_char_raster_metrics,
1122     get_char_raster,
1123     get_char_outline_metrics,
1124     get_char_outline,
1125     release_char_data,
1126     release_typeface
1127 };
1128 
1129 plugin_instantiation_proc(gs_fapiufst_instantiate);      /* check prototype */
1130 
gs_fapiufst_instantiate(i_ctx_t * i_ctx_p,i_plugin_client_memory * client_mem,i_plugin_instance ** p_instance)1131 int gs_fapiufst_instantiate(i_ctx_t *i_ctx_p, i_plugin_client_memory *client_mem, i_plugin_instance **p_instance)
1132 {   fapi_ufst_server *r = (fapi_ufst_server *)client_mem->alloc(client_mem, sizeof(fapi_ufst_server), "fapi_ufst_server");
1133 
1134     if (r == 0)
1135         return e_Fatal;
1136     memset(r, 0, sizeof(*r));
1137     r->If = If0;
1138     r->client_mem = *client_mem;
1139     *p_instance = &r->If.ig;
1140     return 0;
1141 }
1142 
gs_fapiufst_finit(i_plugin_instance * this,i_plugin_client_memory * mem)1143 private void gs_fapiufst_finit(i_plugin_instance *this, i_plugin_client_memory *mem)
1144 {   fapi_ufst_server *r = (fapi_ufst_server *)this;
1145 
1146     if (r->If.ig.d != &ufst_descriptor)
1147         return; /* safety */
1148     release_char_data_inline(r);
1149     if (r->bInitialized) {
1150         CGIFexit(&r->IFS);
1151     }
1152     mem->free(mem, r, "fapi_ufst_server");
1153 }
1154 
1155