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