1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /*
18    GhostScript Font API plug-in that allows fonts to be rendered by FreeType.
19    Started by Graham Asher, 6th June 2002.
20  */
21 
22 /* GhostScript headers. */
23 #include "stdio_.h"
24 #include "malloc_.h"
25 #include "write_t1.h"
26 #include "write_t2.h"
27 #include "math_.h"
28 #include "gserrors.h"
29 #include "gsmemory.h"
30 #include "gsmalloc.h"
31 #include "gxfixed.h"
32 #include "gdebug.h"
33 #include "gxbitmap.h"
34 #include "gsmchunk.h"
35 #include "gxfont.h"
36 #include "gxfont1.h"
37 
38 #include "stream.h"
39 #include "gxiodev.h"            /* must come after stream.h */
40 
41 #include "gsfname.h"
42 
43 #include "gxfapi.h"
44 
45 
46 /* FreeType headers */
47 #include <ft2build.h>
48 #include FT_FREETYPE_H
49 #include FT_INCREMENTAL_H
50 #include FT_GLYPH_H
51 #include FT_SYSTEM_H
52 #include FT_MODULE_H
53 #include FT_TRIGONOMETRY_H
54 #include FT_BBOX_H
55 #include FT_OUTLINE_H
56 #include FT_IMAGE_H
57 #include FT_BITMAP_H
58 #include FT_TRUETYPE_DRIVER_H
59 #include FT_MULTIPLE_MASTERS_H
60 #include FT_TYPE1_TABLES_H
61 
62 /* Note: structure definitions here start with FF_, which stands for 'FAPI FreeType". */
63 
64 #define ft_emprintf(m,s) { outflush(m); emprintf(m, s); outflush(m); }
65 #define ft_emprintf1(m,s,d) { outflush(m); emprintf1(m, s, d); outflush(m); }
66 
67 typedef struct ff_server_s
68 {
69     gs_fapi_server fapi_server;
70     FT_Library freetype_library;
71     FT_OutlineGlyph outline_glyph;
72     FT_BitmapGlyph bitmap_glyph;
73     gs_memory_t *mem;
74     FT_Memory ftmemory;
75     struct FT_MemoryRec_ ftmemory_rec;
76 } ff_server;
77 
78 
79 
80 typedef struct ff_face_s
81 {
82     FT_Face ft_face;
83 
84     /* Currently in force scaling/transform for this face */
85     FT_Matrix ft_transform;
86     FT_F26Dot6 width, height;
87     FT_UInt horz_res;
88     FT_UInt vert_res;
89 
90     /* If non-null, the incremental interface object passed to FreeType. */
91     FT_Incremental_InterfaceRec *ft_inc_int;
92     /* If non-null, we're using a custom stream object for Freetype to read the font file */
93     FT_Stream ftstrm;
94     /* Non-null if font data is owned by this object. */
95     unsigned char *font_data;
96     int font_data_len;
97     bool data_owned;
98     ff_server *server;
99 } ff_face;
100 
101 /* Here we define the struct FT_Incremental that is used as an opaque type
102  * inside FreeType. This structure has to have the tag FT_IncrementalRec_
103  * to be compatible with the functions defined in FT_Incremental_FuncsRec.
104  */
105 typedef struct FT_IncrementalRec_
106 {
107     gs_fapi_font *fapi_font;    /* The font. */
108 
109     /* If it is already in use glyph data is allocated on the heap. */
110     unsigned char *glyph_data;  /* A one-shot buffer for glyph data. */
111     size_t glyph_data_length;   /* Length in bytes of glyph_data. */
112     bool glyph_data_in_use;     /* True if glyph_data is already in use. */
113 
114     FT_Incremental_MetricsRec glyph_metrics;    /* Incremental glyph metrics supplied by Ghostscript. */
115     unsigned long glyph_metrics_index;  /* contains data for this glyph index unless it is 0xFFFFFFFF. */
116     gs_fapi_metrics_type metrics_type;  /* determines whether metrics are replaced, added, etc. */
117 } FT_IncrementalRec;
118 
119 
120 static void
121 delete_inc_int(gs_fapi_server * a_server,
122                FT_Incremental_InterfaceRec * a_inc_int);
123 
124 static void
125 delete_inc_int_info(gs_fapi_server * a_server,
126                     FT_IncrementalRec * a_inc_int_info);
127 
128 static void *
FF_alloc(FT_Memory memory,long size)129 FF_alloc(FT_Memory memory, long size)
130 {
131     gs_memory_t *mem = (gs_memory_t *) memory->user;
132 
133     return (gs_malloc(mem, size, 1, "FF_alloc"));
134 }
135 
136 static void *
FF_realloc(FT_Memory memory,long cur_size,long new_size,void * block)137     FF_realloc(FT_Memory memory, long cur_size, long new_size, void *block)
138 {
139     gs_memory_t *mem = (gs_memory_t *) memory->user;
140     void *tmp;
141 
142     if (cur_size == new_size) {
143         return (block);
144     }
145 
146     tmp = gs_malloc(mem, new_size, 1, "FF_realloc");
147     if (tmp && block) {
148         memcpy(tmp, block, min(cur_size, new_size));
149 
150         gs_free(mem, block, 0, 0, "FF_realloc");
151     }
152 
153     return (tmp);
154 }
155 
156 static void
FF_free(FT_Memory memory,void * block)157     FF_free(FT_Memory memory, void *block)
158 {
159     gs_memory_t *mem = (gs_memory_t *) memory->user;
160 
161     gs_free(mem, block, 0, 0, "FF_free");
162 }
163 
164 /* The following three functions are used in providing a custom stream
165  * object to Freetype, so file access happens through Ghostscript's
166  * file i/o. Most importantly, this gives Freetype direct access to
167  * files in the romfs
168  */
169 static FT_ULong
FF_stream_read(FT_Stream str,unsigned long offset,unsigned char * buffer,unsigned long count)170 FF_stream_read(FT_Stream str, unsigned long offset, unsigned char *buffer,
171                unsigned long count)
172 {
173     stream *ps = (stream *) str->descriptor.pointer;
174     unsigned int rlen = 0;
175     int status = 0;
176 
177     if (sseek(ps, (gs_offset_t)offset) < 0)
178         return_error(-1);
179 
180     if (count) {
181         status = sgets(ps, buffer, count, &rlen);
182 
183         if (status < 0 && status != EOFC)
184             return_error (-1);
185     }
186     return (rlen);
187 }
188 
189 static void
FF_stream_close(FT_Stream str)190 FF_stream_close(FT_Stream str)
191 {
192     stream *ps = (stream *) str->descriptor.pointer;
193 
194     (void)sclose(ps);
195 }
196 
197 extern const uint file_default_buffer_size;
198 
199 static int
FF_open_read_stream(gs_memory_t * mem,char * fname,FT_Stream * fts)200 FF_open_read_stream(gs_memory_t * mem, char *fname, FT_Stream * fts)
201 {
202     int code = 0;
203     gs_parsed_file_name_t pfn;
204     stream *ps = (stream *)NULL;
205     gs_offset_t length;
206     FT_Stream ftstrm = NULL;
207 
208     code = gs_parse_file_name(&pfn, (const char *)fname, strlen(fname), mem);
209     if (code < 0) {
210         goto error_out;
211     }
212 
213     if (!pfn.fname) {
214         code = gs_error_undefinedfilename;
215         goto error_out;
216     }
217 
218     if (pfn.iodev == NULL) {
219         pfn.iodev = iodev_default(mem);
220     }
221 
222     if (pfn.iodev) {
223         gx_io_device *const iodev = pfn.iodev;
224 
225         iodev_proc_open_file((*open_file)) = iodev->procs.open_file;
226 
227         if (open_file) {
228             code = open_file(iodev, pfn.fname, pfn.len, "r", &ps, mem);
229             if (code < 0) {
230                 goto error_out;
231             }
232         }
233         else {
234             code =
235                 file_open_stream(pfn.fname, pfn.len, "r",
236                                  file_default_buffer_size, &ps, pfn.iodev,
237                                  pfn.iodev->procs.gp_fopen, mem);
238             if (code < 0) {
239                 goto error_out;
240             }
241         }
242     }
243     else {
244         goto error_out;
245     }
246 
247     if ((code = savailable(ps, &length)) < 0) {
248         goto error_out;
249     }
250 
251     ftstrm = gs_malloc(mem, sizeof(FT_StreamRec), 1, "FF_open_read_stream");
252     if (!ftstrm) {
253         code = gs_error_VMerror;
254         goto error_out;
255     }
256     memset(ftstrm, 0x00, sizeof(FT_StreamRec));
257 
258     ftstrm->descriptor.pointer = ps;
259     ftstrm->read = FF_stream_read;
260     ftstrm->close = FF_stream_close;
261     ftstrm->size = (long)length;
262     *fts = ftstrm;
263 
264   error_out:
265     if (code < 0) {
266         if (ps)
267             (void)sclose(ps);
268         if (ftstrm)
269             gs_free(mem, ftstrm, 0, 0, "FF_open_read_stream");
270     }
271     return (code);
272 }
273 
274 
275 static ff_face *
new_face(gs_fapi_server * a_server,FT_Face a_ft_face,FT_Incremental_InterfaceRec * a_ft_inc_int,FT_Stream ftstrm,unsigned char * a_font_data,int a_font_data_len,bool data_owned)276 new_face(gs_fapi_server * a_server, FT_Face a_ft_face,
277          FT_Incremental_InterfaceRec * a_ft_inc_int, FT_Stream ftstrm,
278          unsigned char *a_font_data, int a_font_data_len, bool data_owned)
279 {
280     ff_server *s = (ff_server *) a_server;
281 
282     ff_face *face = (ff_face *) FF_alloc(s->ftmemory, sizeof(ff_face));
283 
284     if (face) {
285         face->ft_face = a_ft_face;
286         face->ft_inc_int = a_ft_inc_int;
287         face->font_data = a_font_data;
288         face->font_data_len = a_font_data_len;
289         face->data_owned = data_owned;
290         face->ftstrm = ftstrm;
291         face->server = (ff_server *) a_server;
292     }
293     return face;
294 }
295 
296 static void
delete_face(gs_fapi_server * a_server,ff_face * a_face)297 delete_face(gs_fapi_server * a_server, ff_face * a_face)
298 {
299     if (a_face) {
300         ff_server *s = (ff_server *) a_server;
301         if (a_face->ft_inc_int) {
302             FT_Incremental a_info = a_face->ft_inc_int->object;
303 
304             if (a_info->glyph_data) {
305                 gs_free(s->mem, a_info->glyph_data, 0, 0, "delete_face");
306             }
307             a_info->glyph_data = NULL;
308             a_info->glyph_data_length = 0;
309             delete_inc_int(a_server, a_face->ft_inc_int);
310             a_face->ft_inc_int = NULL;
311         }
312         FT_Done_Face(a_face->ft_face);
313 
314         FF_free(s->ftmemory, a_face->ft_inc_int);
315         if (a_face->data_owned)
316             FF_free(s->ftmemory, a_face->font_data);
317         if (a_face->ftstrm) {
318             FF_free(s->ftmemory, a_face->ftstrm);
319         }
320         FF_free(s->ftmemory, a_face);
321     }
322 }
323 
324 static FT_IncrementalRec *
new_inc_int_info(gs_fapi_server * a_server,gs_fapi_font * a_fapi_font)325 new_inc_int_info(gs_fapi_server * a_server, gs_fapi_font * a_fapi_font)
326 {
327     ff_server *s = (ff_server *) a_server;
328 
329     FT_IncrementalRec *info =
330         (FT_IncrementalRec *) FF_alloc(s->ftmemory,
331                                        sizeof(FT_IncrementalRec));
332     if (info) {
333         info->fapi_font = a_fapi_font;
334         info->glyph_data = NULL;
335         info->glyph_data_length = 0;
336         info->glyph_data_in_use = false;
337         info->glyph_metrics_index = 0xFFFFFFFF;
338         info->metrics_type = gs_fapi_metrics_notdef;
339     }
340     return info;
341 }
342 
343 static void
delete_inc_int_info(gs_fapi_server * a_server,FT_IncrementalRec * a_inc_int_info)344 delete_inc_int_info(gs_fapi_server * a_server,
345                     FT_IncrementalRec * a_inc_int_info)
346 {
347     ff_server *s = (ff_server *) a_server;
348 
349     if (a_inc_int_info) {
350         FF_free(s->ftmemory, a_inc_int_info->glyph_data);
351         FF_free(s->ftmemory, a_inc_int_info);
352     }
353 }
354 
355 static FT_Error
get_fapi_glyph_data(FT_Incremental a_info,FT_UInt a_index,FT_Data * a_data)356 get_fapi_glyph_data(FT_Incremental a_info, FT_UInt a_index, FT_Data * a_data)
357 {
358     gs_fapi_font *ff = a_info->fapi_font;
359     int length = 0;
360     ff_face *face = (ff_face *) ff->server_font_data;
361     gs_memory_t *mem = (gs_memory_t *) face->server->mem;
362 
363     /* Tell the FAPI interface that we need to decrypt the glyph data. */
364     ff->need_decrypt = true;
365 
366     /* If glyph_data is already in use (as will happen for composite glyphs)
367      * create a new buffer on the heap.
368      */
369     if (a_info->glyph_data_in_use) {
370         unsigned char *buffer = NULL;
371 
372         length = ff->get_glyph(ff, a_index, NULL, 0);
373         if (length == gs_fapi_glyph_invalid_format
374             || length == gs_fapi_glyph_invalid_index)
375             return FT_Err_Invalid_Glyph_Index;
376 
377         buffer = gs_malloc(mem, length, 1, "get_fapi_glyph_data");
378         if (!buffer)
379             return FT_Err_Out_Of_Memory;
380 
381         length = ff->get_glyph(ff, a_index, buffer, length);
382         if (length == gs_fapi_glyph_invalid_format) {
383             gs_free((gs_memory_t *) mem, buffer, 0, 0,
384                     "get_fapi_glyph_data");
385             return FT_Err_Invalid_Glyph_Index;
386         }
387         a_data->pointer = buffer;
388     }
389     else {
390         /* Save ff->char_data, which is set to null by FAPI_FF_get_glyph as part of a hack to
391          * make the deprecated Type 2 endchar ('seac') work, so that it can be restored
392          * if we need to try again with a longer buffer.
393          */
394         const void *saved_char_data = ff->char_data;
395 
396         /* Get as much of the glyph data as possible into the buffer */
397         length =
398             ff->get_glyph(ff, a_index, a_info->glyph_data,
399                           (ushort) a_info->glyph_data_length);
400         if (length == gs_fapi_glyph_invalid_format) {
401             ff->char_data = saved_char_data;
402             return FT_Err_Unknown_File_Format;
403         }
404 
405         if (length == gs_fapi_glyph_invalid_index) {
406             ff->char_data = saved_char_data;
407             return FT_Err_Invalid_Glyph_Index;
408         }
409 
410         /* If the buffer was too small enlarge it and try again. */
411         if (length > a_info->glyph_data_length) {
412             if (a_info->glyph_data) {
413                 gs_free((gs_memory_t *) mem,
414                         a_info->glyph_data, 0, 0, "get_fapi_glyph_data");
415             }
416 
417             a_info->glyph_data =
418                 gs_malloc(mem, length, 1, "get_fapi_glyph_data");
419 
420             if (!a_info->glyph_data) {
421                 a_info->glyph_data_length = 0;
422                 return FT_Err_Out_Of_Memory;
423             }
424             a_info->glyph_data_length = length;
425             ff->char_data = saved_char_data;
426             length = ff->get_glyph(ff, a_index, a_info->glyph_data, length);
427             if (length == gs_fapi_glyph_invalid_format)
428                 return FT_Err_Unknown_File_Format;
429             if (length == gs_fapi_glyph_invalid_index)
430                 return FT_Err_Invalid_Glyph_Index;
431         }
432 
433         /* Set the returned pointer and length. */
434         a_data->pointer = a_info->glyph_data;
435 
436         a_info->glyph_data_in_use = true;
437     }
438 
439     a_data->length = length;
440     return 0;
441 }
442 
443 static void
free_fapi_glyph_data(FT_Incremental a_info,FT_Data * a_data)444 free_fapi_glyph_data(FT_Incremental a_info, FT_Data * a_data)
445 {
446     gs_fapi_font *ff = a_info->fapi_font;
447     ff_face *face = (ff_face *) ff->server_font_data;
448     gs_memory_t *mem = (gs_memory_t *) face->server->mem;
449 
450     if (a_data->pointer == (const FT_Byte *)a_info->glyph_data)
451         a_info->glyph_data_in_use = false;
452     else
453         gs_free(mem, (FT_Byte *) a_data->pointer, 0, 0, "free_fapi_glyph_data");
454 }
455 
456 static FT_Error
get_fapi_glyph_metrics(FT_Incremental a_info,FT_UInt a_glyph_index,FT_Bool bVertical,FT_Incremental_MetricsRec * a_metrics)457 get_fapi_glyph_metrics(FT_Incremental a_info, FT_UInt a_glyph_index,
458                        FT_Bool bVertical,
459                        FT_Incremental_MetricsRec * a_metrics)
460 {
461     /* FreeType will create synthetic vertical metrics, including a vertical
462      * advance, if none is present. We don't want this, so if the font uses Truetype outlines
463      * and the WMode is not 1 (vertical) we ignore the advance by setting it to 0
464      */
465     if (bVertical && !a_info->fapi_font->is_type1)
466         a_metrics->advance = 0;
467 
468     if (a_info->glyph_metrics_index == a_glyph_index) {
469         switch (a_info->metrics_type) {
470             case gs_fapi_metrics_add:
471                 a_metrics->advance += a_info->glyph_metrics.advance;
472                 break;
473             case gs_fapi_metrics_replace_width:
474                 a_metrics->advance = a_info->glyph_metrics.advance;
475                 break;
476             case gs_fapi_metrics_replace:
477                 *a_metrics = a_info->glyph_metrics;
478                 /* We are replacing the horizontal metrics, so the vertical must be 0 */
479                 a_metrics->advance_v = 0;
480                 break;
481             default:
482                 /* This can't happen. */
483                 return FT_Err_Invalid_Argument;
484         }
485     }
486     return 0;
487 }
488 
489 static const FT_Incremental_FuncsRec TheFAPIIncrementalInterfaceFuncs = {
490     get_fapi_glyph_data,
491     free_fapi_glyph_data,
492     get_fapi_glyph_metrics
493 };
494 
495 static FT_Incremental_InterfaceRec *
new_inc_int(gs_fapi_server * a_server,gs_fapi_font * a_fapi_font)496 new_inc_int(gs_fapi_server * a_server, gs_fapi_font * a_fapi_font)
497 {
498     ff_server *s = (ff_server *) a_server;
499 
500     FT_Incremental_InterfaceRec *i =
501         (FT_Incremental_InterfaceRec *) FF_alloc(s->ftmemory,
502                                                  sizeof
503                                                  (FT_Incremental_InterfaceRec));
504     if (i) {
505         i->funcs = &TheFAPIIncrementalInterfaceFuncs;
506         i->object = (FT_Incremental) new_inc_int_info(a_server, a_fapi_font);
507 
508         if (!i->object) {
509             FF_free(s->ftmemory, i);
510             i = NULL;
511         }
512     }
513     return i;
514 }
515 
516 static void
delete_inc_int(gs_fapi_server * a_server,FT_Incremental_InterfaceRec * a_inc_int)517 delete_inc_int(gs_fapi_server * a_server,
518                FT_Incremental_InterfaceRec * a_inc_int)
519 {
520     ff_server *s = (ff_server *) a_server;
521 
522     if (a_inc_int) {
523         delete_inc_int_info(a_server, a_inc_int->object);
524         FF_free(s->ftmemory, a_inc_int);
525     }
526 }
527 
528 /* Convert FreeType error codes to GhostScript ones.
529  * Very rudimentary because most don't correspond.
530  */
531 static int
ft_to_gs_error(FT_Error a_error)532 ft_to_gs_error(FT_Error a_error)
533 {
534     if (a_error) {
535         if (a_error == FT_Err_Out_Of_Memory)
536             return_error(gs_error_VMerror);
537         else
538             return_error(gs_error_unknownerror);
539     }
540     return 0;
541 }
542 
543 /* Load a glyph and optionally rasterize it. Return its metrics in a_metrics.
544  * If a_bitmap is true convert the glyph to a bitmap.
545  */
546 static gs_fapi_retcode
load_glyph(gs_fapi_server * a_server,gs_fapi_font * a_fapi_font,const gs_fapi_char_ref * a_char_ref,gs_fapi_metrics * a_metrics,FT_Glyph * a_glyph,bool a_bitmap,int max_bitmap)547 load_glyph(gs_fapi_server * a_server, gs_fapi_font * a_fapi_font,
548            const gs_fapi_char_ref * a_char_ref, gs_fapi_metrics * a_metrics,
549            FT_Glyph * a_glyph, bool a_bitmap, int max_bitmap)
550 {
551     ff_server *s = (ff_server *) a_server;
552     FT_Error ft_error = 0;
553     FT_Error ft_error_fb = 1;
554     ff_face *face = (ff_face *) a_fapi_font->server_font_data;
555     FT_Face ft_face = face->ft_face;
556     int index = a_char_ref->char_codes[0];
557     FT_Long w;
558     FT_Long h;
559     FT_Long fflags;
560     FT_Int32 load_flags = 0;
561     FT_Vector  delta = {0,0};
562 
563     /* Save a_fapi_font->char_data, which is set to null by FAPI_FF_get_glyph as part of a hack to
564      * make the deprecated Type 2 endchar ('seac') work, so that it can be restored
565      * after the first call to FT_Load_Glyph.
566      */
567     const void *saved_char_data = a_fapi_font->char_data;
568     const int saved_char_data_len = a_fapi_font->char_data_len;
569 
570     if (s->bitmap_glyph) {
571         FT_Bitmap_Done(s->freetype_library, &s->bitmap_glyph->bitmap);
572         FF_free(s->ftmemory, s->bitmap_glyph);
573         s->bitmap_glyph = NULL;
574     }
575     if (s->outline_glyph) {
576         FT_Outline_Done(s->freetype_library, &s->outline_glyph->outline);
577         FF_free(s->ftmemory, s->outline_glyph);
578         s->outline_glyph = NULL;
579     }
580 
581     if (!a_char_ref->is_glyph_index) {
582         if (ft_face->num_charmaps)
583             index = FT_Get_Char_Index(ft_face, index);
584         else {
585             /* If there are no character maps and no glyph index, loading the glyph will still work
586              * properly if both glyph data and metrics are supplied by the incremental interface.
587              * In that case we use a dummy glyph index which will be passed
588              * back to FAPI_FF_get_glyph by get_fapi_glyph_data.
589              *
590              * Type 1 fonts don't use the code and can appear to FreeType to have only one glyph,
591              * so we have to set the index to 0.
592              *
593              * For other font types, FAPI_FF_get_glyph requires the character code
594              * when getting data.
595              */
596             if (a_fapi_font->is_type1)
597                 index = 0;
598             else
599                 index = a_char_ref->char_codes[0];
600         }
601     }
602     else {
603         /* This is a heuristic to try to avoid using the TTF notdef (empty rectangle), and replace it
604            with a non-marking glyph instead. This is only required for fonts where we don't use the
605            FT incremental interface - when we are using the incremental interface, we handle it in
606            our own glyph lookup code.
607          */
608         if (!a_fapi_font->is_cid && !face->ft_inc_int &&
609             (index == 0 ||
610             (a_char_ref->client_char_code != gs_no_char &&
611             FT_Get_Char_Index(ft_face, a_char_ref->client_char_code) <= 0))) {
612             int tmp_ind;
613 
614             if ((tmp_ind = FT_Get_Char_Index(ft_face, 32)) > 0) {
615                 index = tmp_ind;
616             }
617         }
618     }
619     /* Refresh the pointer to the FAPI_font held by the incremental interface. */
620     if (face->ft_inc_int)
621         face->ft_inc_int->object->fapi_font = a_fapi_font;
622 
623     /* Store the overriding metrics if they have been supplied. */
624     if (face->ft_inc_int
625         && a_char_ref->metrics_type != gs_fapi_metrics_notdef) {
626 
627         FT_Incremental_MetricsRec *m =
628             &face->ft_inc_int->object->glyph_metrics;
629         m->bearing_x = a_char_ref->sb_x >> 16;
630         m->bearing_y = a_char_ref->sb_y >> 16;
631         m->advance = a_char_ref->aw_x >> 16;
632         face->ft_inc_int->object->glyph_metrics_index = index;
633         face->ft_inc_int->object->metrics_type = a_char_ref->metrics_type;
634 
635         /* we only want this for fonts with TT outlines */
636         if (!a_fapi_font->is_type1) {
637             delta.y = 0;
638             delta.x = FT_MulFix(a_char_ref->sb_x, ft_face->size->metrics.x_scale);
639             FT_Vector_Transform( &delta, &face->ft_transform);
640        }
641     }
642     else if (face->ft_inc_int)
643         /* Make sure we don't leave this set to the last value, as we may then use inappropriate metrics values */
644         face->ft_inc_int->object->glyph_metrics_index = 0xFFFFFFFF;
645 
646     /* We have to load the glyph, scale it correctly, and render it if we need a bitmap. */
647     if (!ft_error) {
648         /* We disable loading bitmaps because if we allow it then FreeType invents metrics for them, which messes up our glyph positioning */
649         /* Also the bitmaps tend to look somewhat different (though more readable) than FreeType's rendering. By disabling them we */
650         /* maintain consistency better.  (FT_LOAD_NO_BITMAP) */
651         a_fapi_font->char_data = saved_char_data;
652         if (!a_fapi_font->is_mtx_skipped && !a_fapi_font->is_type1) {
653             /* grid_fit == 1 is the default - use font's native hints
654              * with freetype, 1 & 3 are, in practice, the same.
655              */
656 
657             if (a_server->grid_fit == 0) {
658                 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT;
659             }
660             else if (a_server->grid_fit == 2) {
661                 load_flags = FT_LOAD_FORCE_AUTOHINT;
662             }
663             load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_NO_BITMAP | FT_LOAD_LINEAR_DESIGN;
664         }
665         else {
666             /* Current FreeType hinting for type 1 fonts is so poor we are actually better off without it (fewer files render incorrectly) (FT_LOAD_NO_HINTING) */
667             /* We also need to disable hinting for XL format embedded truetypes */
668             load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_LINEAR_DESIGN;
669         }
670 
671         ft_error = FT_Load_Glyph(ft_face, index, load_flags);
672         if (ft_error == FT_Err_Unknown_File_Format) {
673             return index + 1;
674         }
675     }
676 
677     if (ft_error == FT_Err_Invalid_Argument
678         || ft_error == FT_Err_Invalid_Reference
679         || ft_error == FT_Err_Invalid_Glyph_Index
680         || (ft_error >= FT_Err_Invalid_Opcode
681             && ft_error <= FT_Err_Too_Many_Instruction_Defs)) {
682 
683         a_fapi_font->char_data = saved_char_data;
684 
685         /* We want to prevent hinting, even for a "tricky" font - it shouldn't matter for the notdef */
686         fflags = ft_face->face_flags;
687         ft_face->face_flags &= ~FT_FACE_FLAG_TRICKY;
688         load_flags |= FT_LOAD_NO_HINTING;
689         ft_error = FT_Load_Glyph(ft_face, index, load_flags);
690 
691         ft_face->face_flags = fflags;
692     }
693 
694     if (ft_error == FT_Err_Out_Of_Memory
695         || ft_error == FT_Err_Array_Too_Large) {
696         return (gs_error_VMerror);
697     }
698 
699     /* If FT gives us an error, try to fall back to the notdef - if that doesn't work, we'll throw an error over to Ghostscript */
700     if (ft_error) {
701         gs_string notdef_str;
702 
703         notdef_str.data = (byte *)".notdef";
704         notdef_str.size = 7;
705 
706         a_fapi_font->char_data = (void *)(&notdef_str);
707         a_fapi_font->char_data_len = 0;
708 
709         /* We want to prevent hinting, even for a "tricky" font - it shouldn't matter for the notdef */
710         fflags = ft_face->face_flags;
711         ft_face->face_flags &= ~FT_FACE_FLAG_TRICKY;
712 
713         ft_error_fb = FT_Load_Glyph(ft_face, 0, load_flags);
714 
715         ft_face->face_flags = fflags;
716 
717         a_fapi_font->char_data = saved_char_data;
718         a_fapi_font->char_data_len = saved_char_data_len;
719     }
720 
721     if ((!ft_error || !ft_error_fb) && (delta.x != 0 || delta.y != 0)) {
722         FT_Outline_Translate( &ft_face->glyph->outline, delta.x >> 16, delta.y >> 16 );
723     }
724 
725     /* Previously we interpreted the glyph unscaled, and derived the metrics from that. Now we only interpret it
726      * once, and work out the metrics from the scaled/hinted outline.
727      */
728     if ((!ft_error || !ft_error_fb) && a_metrics) {
729         FT_Long hx;
730         FT_Long hy;
731         FT_Long vadv;
732 
733         /* In order to get the metrics in the form we need them, we have to remove the size scaling
734          * the resolution scaling, and convert to points.
735          */
736         hx = (FT_Long) (((double)ft_face->glyph->metrics.horiBearingX *
737                          ft_face->units_per_EM * 72.0) /
738                         ((double)face->width * face->horz_res));
739         hy = (FT_Long) (((double)ft_face->glyph->metrics.horiBearingY *
740                          ft_face->units_per_EM * 72.0) /
741                         ((double)face->height * face->vert_res));
742 
743         w = (FT_Long) (((double)ft_face->glyph->metrics.width *
744                         ft_face->units_per_EM * 72.0) / ((double)face->width *
745                                                          face->horz_res));
746         h = (FT_Long) (((double)ft_face->glyph->metrics.height *
747                         ft_face->units_per_EM * 72.0) /
748                        ((double)face->height * face->vert_res));
749 
750         /* Ugly. FreeType creates verticla metrics for TT fonts, normally we override them in the
751          * metrics callbacks, but those only work for incremental interface fonts, and TrueType fonts
752          * loaded as CIDFont replacements are not incrementally handled. So here, if its a CIDFont, and
753          * its not type 1 outlines, and its not a vertical mode fotn, ignore the advance.
754          */
755         if (a_fapi_font->is_type1
756            || ((a_fapi_font->full_font_buf || a_fapi_font->font_file_path)
757            && a_fapi_font->is_vertical &&  FT_HAS_VERTICAL(ft_face))) {
758 
759             vadv = ft_face->glyph->linearVertAdvance;
760         }
761         else {
762             vadv = 0;
763         }
764 
765         a_metrics->bbox_x0 = hx;
766         a_metrics->bbox_y0 = hy - h;
767         a_metrics->bbox_x1 = a_metrics->bbox_x0 + w;
768         a_metrics->bbox_y1 = a_metrics->bbox_y0 + h;
769         a_metrics->escapement = ft_face->glyph->linearHoriAdvance;
770         a_metrics->v_escapement = vadv;
771         a_metrics->em_x = ft_face->units_per_EM;
772         a_metrics->em_y = ft_face->units_per_EM;
773     }
774 
775     if ((!ft_error || !ft_error_fb)) {
776 
777         FT_BBox cbox;
778 
779         /* compute the control box, and grid fit it - lifted from ft_raster1_render() */
780         FT_Outline_Get_CBox(&ft_face->glyph->outline, &cbox);
781 
782         /* These round operations are only to preserve behaviour compared to the 9.00 release
783            which used the bitmap dimensions as calculated by Freetype.
784            But FT_PIX_FLOOR/FT_PIX_CEIL aren't public.
785          */
786         cbox.xMin = ((cbox.xMin) & ~63);        /* FT_PIX_FLOOR( cbox.xMin ) */
787         cbox.yMin = ((cbox.yMin) & ~63);
788         cbox.xMax = (((cbox.xMax) + 63) & ~63);
789         cbox.yMax = (((cbox.yMax) + 63) & ~63); /* FT_PIX_CEIL( cbox.yMax ) */
790 
791         w = (FT_UInt) ((cbox.xMax - cbox.xMin) >> 6);
792         h = (FT_UInt) ((cbox.yMax - cbox.yMin) >> 6);
793 
794         if (!a_fapi_font->metrics_only && a_bitmap == true && ft_face->glyph->format != FT_GLYPH_FORMAT_BITMAP
795             && ft_face->glyph->format != FT_GLYPH_FORMAT_COMPOSITE) {
796             if ((bitmap_raster(w) * h) < max_bitmap) {
797                 FT_Render_Mode mode = FT_RENDER_MODE_MONO;
798 
799                 ft_error = FT_Render_Glyph(ft_face->glyph, mode);
800             }
801             else {
802                 (*a_glyph) = NULL;
803                 return (gs_error_VMerror);
804             }
805         }
806     }
807 
808     if (!a_fapi_font->metrics_only) {
809         /* The following works around the fact that at the scales we deal with
810          * these values may not fit in a 16.16 fixed point value, and thus cause
811          * freetype to error due to overflow - but we don't use these values
812          * and neither does freetype, we can set them to zero and avoid the error
813          */
814         ft_face->glyph->advance.x = ft_face->glyph->advance.y = 0;
815         if ((!ft_error || !ft_error_fb) && a_glyph) {
816             ft_error = FT_Get_Glyph(ft_face->glyph, a_glyph);
817         }
818         else {
819             if (ft_face->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
820                 FT_BitmapGlyph bmg;
821 
822                 ft_error = FT_Get_Glyph(ft_face->glyph, (FT_Glyph *) & bmg);
823                 if (!ft_error) {
824                     FT_Bitmap_Done(s->freetype_library, &bmg->bitmap);
825                     FF_free(s->ftmemory, bmg);
826                 }
827             }
828             else {
829                 FT_OutlineGlyph olg;
830 
831                 ft_error = FT_Get_Glyph(ft_face->glyph, (FT_Glyph *) & olg);
832                 if (!ft_error) {
833                     FT_Outline_Done(s->freetype_library, &olg->outline);
834                     FF_free(s->ftmemory, olg);
835                 }
836             }
837         }
838     }
839 
840     if (ft_error == FT_Err_Too_Many_Hints) {
841 #ifdef DEBUG
842         if (gs_debug_c('1')) {
843             ft_emprintf1(a_fapi_font->memory,
844                       "TrueType glyph %"PRId64" uses more instructions than the declared maximum in the font.",
845                       a_char_ref->char_codes[0]);
846 
847             if (!ft_error_fb) {
848                 ft_emprintf(a_fapi_font->memory,
849                          " Continuing, falling back to notdef\n\n");
850             }
851         }
852 #endif
853         if (!ft_error_fb)
854             ft_error = 0;
855     }
856     if (ft_error == FT_Err_Invalid_Argument) {
857 #ifdef DEBUG
858         if (gs_debug_c('1')) {
859             ft_emprintf1(a_fapi_font->memory,
860                       "TrueType parsing error in glyph %"PRId64" in the font.",
861                       a_char_ref->char_codes[0]);
862 
863             if (!ft_error_fb) {
864                 ft_emprintf(a_fapi_font->memory,
865                          " Continuing, falling back to notdef\n\n");
866             }
867         }
868 #endif
869         if (!ft_error_fb)
870             ft_error = 0;
871     }
872     if (ft_error == FT_Err_Too_Many_Function_Defs) {
873 #ifdef DEBUG
874         if (gs_debug_c('1')) {
875             ft_emprintf1(a_fapi_font->memory,
876                       "TrueType instruction error in glyph %"PRId64" in the font.",
877                       a_char_ref->char_codes[0]);
878 
879             if (!ft_error_fb) {
880                 ft_emprintf(a_fapi_font->memory,
881                          " Continuing, falling back to notdef\n\n");
882             }
883         }
884 #endif
885         if (!ft_error_fb)
886             ft_error = 0;
887     }
888     if (ft_error == FT_Err_Invalid_Glyph_Index) {
889 #ifdef DEBUG
890         if (gs_debug_c('1')) {
891             ft_emprintf1(a_fapi_font->memory,
892                       "FreeType is unable to find the glyph %"PRId64" in the font.",
893                       a_char_ref->char_codes[0]);
894 
895             if (!ft_error_fb) {
896                 ft_emprintf(a_fapi_font->memory,
897                          " Continuing, falling back to notdef\n\n");
898             }
899         }
900 #endif
901         if (!ft_error_fb)
902             ft_error = 0;
903     }
904     return ft_to_gs_error(ft_error);
905 }
906 
907 /*
908  * Ensure that the rasterizer is open.
909  *
910  * In the case of FreeType this means creating the FreeType library object.
911  */
912 static gs_fapi_retcode
gs_fapi_ft_ensure_open(gs_fapi_server * a_server,const char * server_param,int server_param_size)913 gs_fapi_ft_ensure_open(gs_fapi_server * a_server, const char * server_param,
914                        int server_param_size)
915 {
916     ff_server *s = (ff_server *) a_server;
917     FT_UInt tt_ins_version = TT_INTERPRETER_VERSION_35;
918     FT_Error ft_error;
919 
920     if (s->freetype_library)
921         return 0;
922 
923     /* As we want FT to use our memory management, we cannot use the convenience of
924      * FT_Init_FreeType(), we have to do each stage "manually"
925      */
926     s->ftmemory->user = s->mem;
927     s->ftmemory->alloc = FF_alloc;
928     s->ftmemory->free = FF_free;
929     s->ftmemory->realloc = FF_realloc;
930 
931     ft_error = FT_New_Library(s->ftmemory, &s->freetype_library);
932     if (ft_error)
933         return ft_to_gs_error(ft_error);
934 
935     FT_Add_Default_Modules(s->freetype_library);
936     FT_Property_Set( s->freetype_library, "truetype", "interpreter-version", &tt_ins_version);
937 
938     return 0;
939 }
940 
941 #if 0                           /* Not currently used */
942 static void
943 transform_concat(FT_Matrix * a_A, const FT_Matrix * a_B)
944 {
945     FT_Matrix result = *a_B;
946 
947     FT_Matrix_Multiply(a_A, &result);
948     *a_A = result;
949 }
950 
951 /* Create a transform representing an angle defined as a vector. */
952 static void
953 make_rotation(FT_Matrix * a_transform, const FT_Vector * a_vector)
954 {
955     FT_Fixed length, cos, sin;
956 
957     if (a_vector->x >= 0 && a_vector->y == 0) {
958         a_transform->xx = a_transform->yy = 65536;
959         a_transform->xy = a_transform->yx = 0;
960         return;
961     }
962 
963     length = FT_Vector_Length((FT_Vector *) a_vector);
964     cos = FT_DivFix(a_vector->x, length);
965     sin = FT_DivFix(a_vector->y, length);
966     a_transform->xx = a_transform->yy = cos;
967     a_transform->xy = -sin;
968     a_transform->yx = sin;
969 }
970 #endif /* Not currently used */
971 
972 /* Divide a transformation into a scaling part and a rotation-and-shear part.
973  * The scaling part is used for setting the pixel size for hinting.
974  */
975 static void
transform_decompose(FT_Matrix * a_transform,FT_UInt * xresp,FT_UInt * yresp,FT_Fixed * a_x_scale,FT_Fixed * a_y_scale,int units_per_EM)976 transform_decompose(FT_Matrix * a_transform, FT_UInt * xresp, FT_UInt * yresp,
977                     FT_Fixed * a_x_scale, FT_Fixed * a_y_scale, int units_per_EM)
978 {
979     double scalex, scaley, fact = 1.0;
980     double factx = 1.0, facty = 1.0;
981     FT_Matrix ftscale_mat;
982     FT_UInt xres;
983     FT_UInt yres;
984     /* We have to account for units_per_EM as we fiddle with the scaling
985      * in order to avoid underflow (mostly in the TTF hinting code), but
986      * we also want to clamp to a lower value (512, admittedly arrived at
987      * via experimentation) in order to preserve the fidelity of the outlines.
988      */
989     double upe = units_per_EM > 512 ? (float)units_per_EM : 512.0;
990 
991     scalex = hypot((double)a_transform->xx, (double)a_transform->xy);
992     scaley = hypot((double)a_transform->yx, (double)a_transform->yy);
993 
994     /* In addition to all the wrangling below, we have to make sure that
995      * that the contents of a_transform can also be understood by Freetype.
996      */
997     if (scalex < 64.0 || scaley < 64.0) {
998         factx = 64.0/scalex;
999         facty = 64.0/scaley;
1000 
1001         ftscale_mat.xx = (FT_Fixed)(a_transform->xx * factx);
1002         ftscale_mat.xy = (FT_Fixed)(a_transform->xy * facty);
1003         ftscale_mat.yx = (FT_Fixed)(a_transform->yx * factx);
1004         ftscale_mat.yy = (FT_Fixed)(a_transform->yy * facty);
1005         memcpy(a_transform, &ftscale_mat, sizeof(ftscale_mat));
1006         scalex = hypot((double)a_transform->xx, (double)a_transform->xy);
1007         scaley = hypot((double)a_transform->yx, (double)a_transform->yy);
1008     }
1009 
1010     if (*xresp != *yresp) {
1011         /* To get good results, we have to pull the implicit scaling from
1012          * non-square resolutions, and apply it in the matrix. This means
1013          * we get the correct "shearing" effect for rotated glyphs.
1014          * The previous solution was only effective for for glyphs whose
1015          * axes were coincident with the axes of the page.
1016          */
1017         bool use_x = true;
1018 
1019         if (*xresp < *yresp) {
1020             use_x = false;
1021         }
1022 
1023         ftscale_mat.xx =
1024             (int)(((double)(*xresp) /
1025                    ((double)(use_x ? (*xresp) : (*yresp)))) * 65536);
1026         ftscale_mat.xy = ftscale_mat.yx = 0;
1027         ftscale_mat.yy =
1028             (int)(((double)(*yresp) /
1029                    ((double)(use_x ? (*xresp) : (*yresp)))) * 65536);
1030 
1031         FT_Matrix_Multiply(&ftscale_mat, a_transform);
1032 
1033         xres = yres = (use_x ? (*xresp) : (*yresp));
1034         xres = (FT_UInt)(xres / factx);
1035         yres = (FT_UInt)(yres / facty);
1036     }
1037     else {
1038         /* Life is considerably easier when square resolutions are in use! */
1039         xres = (FT_UInt)(*xresp / factx);
1040         yres = (FT_UInt)(*yresp / facty);
1041     }
1042 
1043     scalex *= 1.0 / 65536.0;
1044     scaley *= 1.0 / 65536.0;
1045 
1046     if (scalex < scaley) {
1047         scaley = scalex;
1048     }
1049     else if (scalex > scaley) {
1050         scalex = scaley;
1051     }
1052 
1053     /* FT clamps the width and height to a lower limit of 1.0 units
1054      * (note: as FT stores it in 64ths of a unit, that is 64)
1055      * So if either the width or the height are <1.0 here, we scale
1056      * the width and height appropriately, and then compensate using
1057      * the "final" matrix for FT
1058      */
1059     /* We use 1 1/64th to calculate the scale, so that we *guarantee* the
1060      * scalex/y we calculate will be >64 after rounding.
1061      */
1062 
1063     if (scalex < 10.0) {
1064         fact = 10.016 / scalex;
1065         scalex = scalex * fact;
1066         scaley = scaley * fact;
1067     }
1068 
1069     /* see above */
1070     if (scalex * xres < 2268.0 / 64.0) {
1071         fact = (2400.0 / 64.0) / (xres * scalex);
1072         scaley *= fact;
1073         scalex *= fact;
1074     }
1075 
1076     /* see above */
1077     fact = 1.0;
1078     while (scaley * yres > (double)upe * 72.0 && (xres > 0 && yres > 0)
1079            && (scalex > 0.0 && scaley > 0.0)) {
1080         if (scaley < yres) {
1081             xres >>= 1;
1082             yres >>= 1;
1083             fact *= 2.0;
1084         }
1085         else {
1086             scalex /= 1.25;
1087             scaley /= 1.25;
1088         }
1089     }
1090 
1091     ftscale_mat.xx = (FT_Fixed) ((65536.0 / scalex) * fact);
1092     ftscale_mat.xy = 0;
1093     ftscale_mat.yx = 0;
1094     ftscale_mat.yy = (FT_Fixed) ((65536.0 / scaley) * fact);
1095 
1096     FT_Matrix_Multiply(a_transform, &ftscale_mat);
1097     memcpy(a_transform, &ftscale_mat, sizeof(FT_Matrix));
1098 
1099     *xresp = xres;
1100     *yresp = yres;
1101     /* Return values ready scaled for FT */
1102     *a_x_scale = (FT_Fixed) (scalex * 64);
1103     *a_y_scale = (FT_Fixed) (scaley * 64);
1104 }
1105 
1106 /*
1107  * Open a font and set its size.
1108  */
1109 static gs_fapi_retcode
gs_fapi_ft_get_scaled_font(gs_fapi_server * a_server,gs_fapi_font * a_font,const gs_fapi_font_scale * a_font_scale,const char * a_map,gs_fapi_descendant_code a_descendant_code)1110 gs_fapi_ft_get_scaled_font(gs_fapi_server * a_server, gs_fapi_font * a_font,
1111                 const gs_fapi_font_scale * a_font_scale,
1112                 const char *a_map, gs_fapi_descendant_code a_descendant_code)
1113 {
1114     ff_server *s = (ff_server *) a_server;
1115     ff_face *face = (ff_face *) a_font->server_font_data;
1116     FT_Error ft_error = 0;
1117     int i, j;
1118     FT_CharMap cmap = NULL;
1119     bool data_owned = true;
1120 
1121     if (s->bitmap_glyph) {
1122         FT_Bitmap_Done(s->freetype_library, &s->bitmap_glyph->bitmap);
1123         FF_free(s->ftmemory, s->bitmap_glyph);
1124         s->bitmap_glyph = NULL;
1125     }
1126     if (s->outline_glyph) {
1127         FT_Outline_Done(s->freetype_library, &s->outline_glyph->outline);
1128         FF_free(s->ftmemory, s->outline_glyph);
1129         s->outline_glyph = NULL;
1130     }
1131 
1132     /* dpf("gs_fapi_ft_get_scaled_font enter: is_type1=%d is_cid=%d font_file_path='%s' a_descendant_code=%d\n",
1133        a_font->is_type1, a_font->is_cid, a_font->font_file_path ? a_font->font_file_path : "", a_descendant_code); */
1134 
1135     /* If this font is the top level font of an embedded CID type 0 font (font type 9)
1136      * do nothing. See the comment in FAPI_prepare_font. The descendant fonts are
1137      * passed in individually.
1138      */
1139     if (a_font->is_cid && a_font->is_type1 && a_font->font_file_path == NULL
1140         && (a_descendant_code == gs_fapi_toplevel_begin
1141             || a_descendant_code == gs_fapi_toplevel_complete)) {
1142         /* dpf("gs_fapi_ft_get_scaled_font return 0\n"); */
1143         return 0;
1144     }
1145 
1146     /* Create the face if it doesn't already exist. */
1147     if (!face) {
1148         FT_Face ft_face = NULL;
1149         FT_Parameter ft_param;
1150         FT_Incremental_InterfaceRec *ft_inc_int = NULL;
1151         unsigned char *own_font_data = NULL;
1152         int own_font_data_len = -1;
1153         FT_Stream ft_strm = NULL;
1154 
1155         /* dpf("gs_fapi_ft_get_scaled_font creating face\n"); */
1156 
1157         if (a_font->full_font_buf) {
1158 
1159             own_font_data =
1160                 gs_malloc(((gs_memory_t *) (s->ftmemory->user)),
1161                           a_font->full_font_buf_len, 1,
1162                           "gs_fapi_ft_get_scaled_font - full font buf");
1163             if (!own_font_data) {
1164                 return_error(gs_error_VMerror);
1165             }
1166 
1167             own_font_data_len = a_font->full_font_buf_len;
1168             memcpy(own_font_data, a_font->full_font_buf,
1169                    a_font->full_font_buf_len);
1170 
1171             ft_error =
1172                 FT_New_Memory_Face(s->freetype_library,
1173                                    (const FT_Byte *)own_font_data,
1174                                    own_font_data_len, a_font->subfont,
1175                                    &ft_face);
1176 
1177             if (ft_error) {
1178                 gs_memory_t * mem = (gs_memory_t *) s->ftmemory->user;
1179                 gs_free(mem, own_font_data, 0, 0, "FF_open_read_stream");
1180                 return ft_to_gs_error(ft_error);
1181             }
1182         }
1183         /* Load a typeface from a file. */
1184         else if (a_font->font_file_path) {
1185             FT_Open_Args args;
1186             int code;
1187 
1188             memset(&args, 0x00, sizeof(args));
1189 
1190             if ((code =
1191                  FF_open_read_stream((gs_memory_t *) (s->ftmemory->user),
1192                                      (char *)a_font->font_file_path,
1193                                      &ft_strm)) < 0) {
1194                 return (code);
1195             }
1196 
1197             args.flags = FT_OPEN_STREAM;
1198             args.stream = ft_strm;
1199 
1200             ft_error =
1201                 FT_Open_Face(s->freetype_library, &args, a_font->subfont,
1202                              &ft_face);
1203             if (ft_error) {
1204                 /* in the event of an error, Freetype should cleanup the stream */
1205                 return ft_to_gs_error(ft_error);
1206             }
1207         }
1208 
1209         /* Load a typeface from a representation in GhostScript's memory. */
1210         else {
1211             FT_Open_Args open_args;
1212 
1213             open_args.flags = FT_OPEN_MEMORY;
1214             open_args.stream = NULL;
1215 
1216             if (a_font->is_type1) {
1217                 long length;
1218                 int type =
1219                     a_font->get_word(a_font, gs_fapi_font_feature_FontType,
1220                                      0);
1221 
1222                 /* Tell the FAPI interface that we need to decrypt the /Subrs data. */
1223                 a_font->need_decrypt = true;
1224 
1225                 /*
1226                    Serialise a type 1 font in PostScript source form, or
1227                    a Type 2 font in binary form, so that FreeType can read it.
1228                  */
1229                 if (type == 1)
1230                     length = gs_fapi_serialize_type1_font(a_font, NULL, 0);
1231                 else
1232                     length = gs_fapi_serialize_type2_font(a_font, NULL, 0);
1233                 open_args.memory_base = own_font_data =
1234                     FF_alloc(s->ftmemory, length);
1235                 if (!open_args.memory_base)
1236                     return_error(gs_error_VMerror);
1237                 own_font_data_len = length;
1238                 if (type == 1)
1239                     open_args.memory_size =
1240                         gs_fapi_serialize_type1_font(a_font, own_font_data,
1241                                                      length);
1242                 else
1243                     open_args.memory_size =
1244                         gs_fapi_serialize_type2_font(a_font, own_font_data,
1245                                                      length);
1246                 if (open_args.memory_size != length)
1247                     return_error(gs_error_unregistered);        /* Must not happen. */
1248                 ft_inc_int = new_inc_int(a_server, a_font);
1249                 if (!ft_inc_int) {
1250                     FF_free(s->ftmemory, own_font_data);
1251                     return_error(gs_error_VMerror);
1252                 }
1253             }
1254 
1255             /* It must be type 42 (see code in FAPI_FF_get_glyph in zfapi.c). */
1256             else {
1257                 /* Get the length of the TrueType data. */
1258                 open_args.memory_size =
1259                     a_font->get_long(a_font, gs_fapi_font_feature_TT_size, 0);
1260                 if (open_args.memory_size == 0)
1261                     return_error(gs_error_invalidfont);
1262 
1263                 /* Load the TrueType data into a single buffer. */
1264                 open_args.memory_base = own_font_data =
1265                     FF_alloc(s->ftmemory, open_args.memory_size);
1266                 if (!own_font_data)
1267                     return_error(gs_error_VMerror);
1268 
1269                 own_font_data_len = open_args.memory_size;
1270 
1271                 if (a_font->
1272                     serialize_tt_font(a_font, own_font_data,
1273                                       open_args.memory_size))
1274                     return_error(gs_error_invalidfont);
1275 
1276                 /* We always load incrementally. */
1277                 ft_inc_int = new_inc_int(a_server, a_font);
1278                 if (!ft_inc_int) {
1279                     FF_free(s->ftmemory, own_font_data);
1280                     return_error(gs_error_VMerror);
1281                 }
1282             }
1283 
1284             if (ft_inc_int) {
1285                 open_args.flags =
1286                     (FT_UInt) (open_args.flags | FT_OPEN_PARAMS);
1287                 ft_param.tag = FT_PARAM_TAG_INCREMENTAL;
1288                 ft_param.data = ft_inc_int;
1289                 open_args.num_params = 1;
1290                 open_args.params = &ft_param;
1291             }
1292             ft_error =
1293                 FT_Open_Face(s->freetype_library, &open_args, a_font->subfont,
1294                              &ft_face);
1295             if (ft_error) {
1296                 delete_inc_int (a_server, ft_inc_int);
1297                 FF_free(s->ftmemory, own_font_data);
1298                 return ft_to_gs_error(ft_error);
1299             }
1300         }
1301 
1302         if (ft_face) {
1303             face =
1304                 new_face(a_server, ft_face, ft_inc_int, ft_strm,
1305                          own_font_data, own_font_data_len, data_owned);
1306             if (!face) {
1307                 FF_free(s->ftmemory, own_font_data);
1308                 FT_Done_Face(ft_face);
1309                 delete_inc_int(a_server, ft_inc_int);
1310                 return_error(gs_error_VMerror);
1311             }
1312             a_font->server_font_data = face;
1313         }
1314         else
1315             a_font->server_font_data = NULL;
1316     }
1317 
1318     /* Set the point size and transformation.
1319      * The matrix is scaled by the shift specified in the server, 16,
1320      * so we divide by 65536 when converting to a gs_matrix.
1321      */
1322     if (face) {
1323         /* Convert the GS transform into an FT transform.
1324          * Ignore the translation elements because they contain very large values
1325          * derived from the current transformation matrix and so are of no use.
1326          */
1327         face->ft_transform.xx = a_font_scale->matrix[0];
1328         face->ft_transform.xy = a_font_scale->matrix[2];
1329         face->ft_transform.yx = a_font_scale->matrix[1];
1330         face->ft_transform.yy = a_font_scale->matrix[3];
1331 
1332         face->horz_res = a_font_scale->HWResolution[0] >> 16;
1333         face->vert_res = a_font_scale->HWResolution[1] >> 16;
1334 
1335         /* Split the transform into scale factors and a rotation-and-shear
1336          * transform.
1337          */
1338         transform_decompose(&face->ft_transform, &face->horz_res,
1339                             &face->vert_res, &face->width, &face->height, face->ft_face->units_per_EM);
1340 
1341         ft_error = FT_Set_Char_Size(face->ft_face, face->width, face->height,
1342                                     face->horz_res, face->vert_res);
1343 
1344         if (ft_error) {
1345             /* The code originally cleaned up the face data here, but the "top level"
1346                font object still has references to the face data, and we've no way
1347                to tell it it's gone. So we defer releasing the data until the garbage
1348                collector collects the font object, and the font's finalize call will
1349                free the data correctly for us.
1350              */
1351             return ft_to_gs_error(ft_error);
1352         }
1353 
1354         /* Concatenate the transform to a reflection around (y=0) so that it
1355          * produces a glyph that is upside down in FreeType terms, with its
1356          * first row at the bottom. That is what GhostScript needs.
1357          */
1358 
1359         FT_Set_Transform(face->ft_face, &face->ft_transform, NULL);
1360 
1361         if (!a_font->is_type1) {
1362             for (i = 0; i < GS_FAPI_NUM_TTF_CMAP_REQ && !cmap; i++) {
1363                 if (a_font->ttf_cmap_req[i].platform_id > 0) {
1364                     for (j = 0; j < face->ft_face->num_charmaps; j++) {
1365                         if (face->ft_face->charmaps[j]->platform_id == a_font->ttf_cmap_req[i].platform_id
1366                          && face->ft_face->charmaps[j]->encoding_id == a_font->ttf_cmap_req[i].encoding_id) {
1367 
1368                             cmap = face->ft_face->charmaps[j];
1369                             break;
1370                         }
1371                     }
1372                 }
1373                 else {
1374                     break;
1375                 }
1376             }
1377             if (cmap) {
1378                 (void)FT_Set_Charmap(face->ft_face, cmap);
1379             }
1380             else if (a_font->full_font_buf != NULL || a_font->font_file_path != NULL) {
1381                 /* If we've passed a complete TTF to Freetype, but *haven't* requested a
1382                  * specific cmap table above, try to use a Unicode one
1383                  * If that doesn't work, just leave the default in place.
1384                  */
1385                 (void)FT_Select_Charmap(face->ft_face, ft_encoding_unicode);
1386             }
1387             /* For PDF, we have to know which cmap table actually was selected */
1388             if (face->ft_face->charmap != NULL) {
1389                 a_font->ttf_cmap_selected.platform_id = face->ft_face->charmap->platform_id;
1390                 a_font->ttf_cmap_selected.encoding_id = face->ft_face->charmap->encoding_id;
1391             }
1392             else {
1393                 /* Just in case */
1394                 a_font->ttf_cmap_selected.platform_id = -1;
1395                 a_font->ttf_cmap_selected.encoding_id = -1;
1396             }
1397         }
1398         else {
1399             /* Just in case */
1400             a_font->ttf_cmap_selected.platform_id = -1;
1401             a_font->ttf_cmap_selected.encoding_id = -1;
1402         }
1403     }
1404 
1405     /* dpf("gs_fapi_ft_get_scaled_font return %d\n", a_font->server_font_data ? 0 : -1); */
1406     return a_font->server_font_data ? 0 : -1;
1407 }
1408 
1409 /*
1410  * Return the name of a resource which maps names to character codes. Do this
1411  * by setting a_decoding_id to point to a null-terminated string. The resource
1412  * is in the 'decoding' directory in the directory named by /GenericResourceDir
1413  * in lib/gs_res.ps.
1414  */
1415 static gs_fapi_retcode
gs_fapi_ft_get_decodingID(gs_fapi_server * a_server,gs_fapi_font * a_font,const char ** a_decoding_id)1416 gs_fapi_ft_get_decodingID(gs_fapi_server * a_server, gs_fapi_font * a_font,
1417                const char **a_decoding_id)
1418 {
1419     *a_decoding_id = "Unicode";
1420     return 0;
1421 }
1422 
1423 /*
1424  * Get the font bounding box in font units.
1425  */
1426 static gs_fapi_retcode
gs_fapi_ft_get_font_bbox(gs_fapi_server * a_server,gs_fapi_font * a_font,int a_box[4],int unitsPerEm[2])1427 gs_fapi_ft_get_font_bbox(gs_fapi_server * a_server, gs_fapi_font * a_font, int a_box[4], int unitsPerEm[2])
1428 {
1429     ff_face *face = (ff_face *) a_font->server_font_data;
1430 
1431     a_box[0] = face->ft_face->bbox.xMin;
1432     a_box[1] = face->ft_face->bbox.yMin;
1433     a_box[2] = face->ft_face->bbox.xMax;
1434     a_box[3] = face->ft_face->bbox.yMax;
1435 
1436     unitsPerEm[0] = unitsPerEm[1] = face->ft_face->units_per_EM;
1437 
1438     return 0;
1439 }
1440 
1441 /*
1442  * Return a boolean value in a_proportional stating whether the font is proportional
1443  * or fixed-width.
1444  */
1445 static gs_fapi_retcode
gs_fapi_ft_get_font_proportional_feature(gs_fapi_server * a_server,gs_fapi_font * a_font,bool * a_proportional)1446 gs_fapi_ft_get_font_proportional_feature(gs_fapi_server * a_server,
1447                               gs_fapi_font * a_font, bool * a_proportional)
1448 {
1449     *a_proportional = true;
1450     return 0;
1451 }
1452 
1453 /* Convert the character name in a_char_ref.char_name to a character code or
1454  * glyph index and put it in a_char_ref.char_code, setting
1455  * a_char_ref.is_glyph_index as appropriate. If this is possible set a_result
1456  * to true, otherwise set it to false.  The return value is a standard error
1457  * return code.
1458  */
1459 static gs_fapi_retcode
gs_fapi_ft_can_retrieve_char_by_name(gs_fapi_server * a_server,gs_fapi_font * a_font,gs_fapi_char_ref * a_char_ref,bool * a_result)1460 gs_fapi_ft_can_retrieve_char_by_name(gs_fapi_server * a_server, gs_fapi_font * a_font,
1461                           gs_fapi_char_ref * a_char_ref, bool * a_result)
1462 {
1463     ff_face *face = (ff_face *) a_font->server_font_data;
1464     char name[128];
1465 
1466     if (FT_HAS_GLYPH_NAMES(face->ft_face)
1467         && a_char_ref->char_name_length < sizeof(name)) {
1468         memcpy(name, a_char_ref->char_name, a_char_ref->char_name_length);
1469         name[a_char_ref->char_name_length] = 0;
1470         a_char_ref->char_codes[0] = FT_Get_Name_Index(face->ft_face, name);
1471         *a_result = a_char_ref->char_codes[0] != 0;
1472         if (*a_result)
1473             a_char_ref->is_glyph_index = true;
1474     }
1475     else
1476         *a_result = false;
1477     return 0;
1478 }
1479 
1480 /*
1481  * Return non-zero if the metrics can be replaced.
1482  */
1483 static gs_fapi_retcode
gs_fapi_ft_can_replace_metrics(gs_fapi_server * a_server,gs_fapi_font * a_font,gs_fapi_char_ref * a_char_ref,int * a_result)1484 gs_fapi_ft_can_replace_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1485                     gs_fapi_char_ref * a_char_ref, int *a_result)
1486 {
1487     /* Replace metrics only if the metrics are supplied in font units. */
1488     *a_result = 1;
1489     return 0;
1490 }
1491 
1492 /*
1493  * Retrieve the metrics of a_char_ref and put them in a_metrics.
1494  */
1495 static gs_fapi_retcode
gs_fapi_ft_get_char_width(gs_fapi_server * a_server,gs_fapi_font * a_font,gs_fapi_char_ref * a_char_ref,gs_fapi_metrics * a_metrics)1496 gs_fapi_ft_get_char_width(gs_fapi_server * a_server, gs_fapi_font * a_font,
1497                gs_fapi_char_ref * a_char_ref, gs_fapi_metrics * a_metrics)
1498 {
1499     ff_server *s = (ff_server *) a_server;
1500 
1501     return load_glyph(a_server, a_font, a_char_ref, a_metrics,
1502                       (FT_Glyph *) & s->outline_glyph,
1503                       false, a_server->max_bitmap);
1504 }
1505 
1506 static gs_fapi_retcode
gs_fapi_ft_get_fontmatrix(gs_fapi_server * server,gs_matrix * m)1507 gs_fapi_ft_get_fontmatrix(gs_fapi_server * server, gs_matrix * m)
1508 {
1509     m->xx = 1.0;
1510     m->xy = 0.0;
1511     m->yx = 0.0;
1512     m->yy = 1.0;
1513     m->tx = 0.0;
1514     m->ty = 0.0;
1515     return 0;
1516 }
1517 
1518 /*
1519  * Rasterize the character a_char and return its metrics. Do not return the
1520  * bitmap but store this. It can be retrieved by a subsequent call to
1521  * gs_fapi_ft_get_char_raster.
1522  */
1523 static gs_fapi_retcode
gs_fapi_ft_get_char_raster_metrics(gs_fapi_server * a_server,gs_fapi_font * a_font,gs_fapi_char_ref * a_char_ref,gs_fapi_metrics * a_metrics)1524 gs_fapi_ft_get_char_raster_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1525                         gs_fapi_char_ref * a_char_ref,
1526                         gs_fapi_metrics * a_metrics)
1527 {
1528     ff_server *s = (ff_server *) a_server;
1529     gs_fapi_retcode error =
1530         load_glyph(a_server, a_font, a_char_ref, a_metrics,
1531                    (FT_Glyph *) & s->bitmap_glyph, true,
1532                    a_server->max_bitmap);
1533     return error;
1534 }
1535 
1536 /*
1537  * Return the bitmap created by the last call to gs_fapi_ft_get_char_raster_metrics.
1538  */
1539 static gs_fapi_retcode
gs_fapi_ft_get_char_raster(gs_fapi_server * a_server,gs_fapi_raster * a_raster)1540 gs_fapi_ft_get_char_raster(gs_fapi_server * a_server, gs_fapi_raster * a_raster)
1541 {
1542     ff_server *s = (ff_server *) a_server;
1543 
1544     if (!s->bitmap_glyph)
1545         return(gs_error_unregistered);
1546     a_raster->p = s->bitmap_glyph->bitmap.buffer;
1547     a_raster->width = s->bitmap_glyph->bitmap.width;
1548     a_raster->height = s->bitmap_glyph->bitmap.rows;
1549     a_raster->line_step = s->bitmap_glyph->bitmap.pitch;
1550     a_raster->orig_x = s->bitmap_glyph->left * 16;
1551     a_raster->orig_y = s->bitmap_glyph->top * 16;
1552     a_raster->left_indent = a_raster->top_indent = a_raster->black_height =
1553         a_raster->black_width = 0;
1554     return 0;
1555 }
1556 
1557 /*
1558  * Create an outline for the character a_char and return its metrics. Do not
1559  * return the outline but store this.
1560  * It can be retrieved by a subsequent call to gs_fapi_ft_get_char_outline.
1561  */
1562 static gs_fapi_retcode
gs_fapi_ft_get_char_outline_metrics(gs_fapi_server * a_server,gs_fapi_font * a_font,gs_fapi_char_ref * a_char_ref,gs_fapi_metrics * a_metrics)1563 gs_fapi_ft_get_char_outline_metrics(gs_fapi_server * a_server, gs_fapi_font * a_font,
1564                          gs_fapi_char_ref * a_char_ref,
1565                          gs_fapi_metrics * a_metrics)
1566 {
1567     ff_server *s = (ff_server *) a_server;
1568 
1569     return load_glyph(a_server, a_font, a_char_ref, a_metrics,
1570                       (FT_Glyph *) & s->outline_glyph, false,
1571                       a_server->max_bitmap);
1572 }
1573 
1574 typedef struct FF_path_info_s
1575 {
1576     gs_fapi_path *path;
1577     int64_t x;
1578     int64_t y;
1579     FT_Vector currentp;
1580 } FF_path_info;
1581 
1582 static inline int
FF_points_equal(const FT_Vector * p1,const FT_Vector * p2)1583 FF_points_equal(const FT_Vector *p1, const FT_Vector *p2)
1584 {
1585     if (p1->x == p2->x && p1->y == p2->y)
1586         return 1;
1587     else
1588         return 0;
1589 }
1590 
1591 static int
move_to(const FT_Vector * aTo,void * aObject)1592 move_to(const FT_Vector * aTo, void *aObject)
1593 {
1594     FF_path_info *p = (FF_path_info *) aObject;
1595 
1596     p->currentp = *aTo;
1597 
1598     /* FAPI expects that co-ordinates will be as implied by frac_shift
1599      * in our case 16.16 fixed precision. True for 'low level' FT
1600      * routines (apparently), it isn't true for these routines where
1601      * FT returns a 26.6 format. Rescale to 16.16 so that FAPI will
1602      * be able to convert to GS co-ordinates properly.
1603      */
1604     /* FAPI now expects these coordinates in 32.32 */
1605     p->x = ((int64_t) aTo->x) << 26;
1606     p->y = ((int64_t) aTo->y) << 26;
1607 
1608     return p->path->moveto(p->path, p->x, p->y) ? -1 : 0;
1609 }
1610 
1611 static int
line_to(const FT_Vector * aTo,void * aObject)1612 line_to(const FT_Vector * aTo, void *aObject)
1613 {
1614     FF_path_info *p = (FF_path_info *) aObject;
1615 
1616     if (!FF_points_equal(&p->currentp, aTo)) {
1617         p->currentp = *aTo;
1618 
1619         /* See move_to() above */
1620         p->x = ((int64_t) aTo->x) << 26;
1621         p->y = ((int64_t) aTo->y) << 26;
1622 
1623         return p->path->lineto(p->path, p->x, p->y) ? -1 : 0;
1624     }
1625     return 0;
1626 }
1627 
1628 static int
conic_to(const FT_Vector * aControl,const FT_Vector * aTo,void * aObject)1629 conic_to(const FT_Vector * aControl, const FT_Vector * aTo, void *aObject)
1630 {
1631     FF_path_info *p = (FF_path_info *) aObject;
1632     double x, y, Controlx, Controly;
1633     int64_t Control1x, Control1y, Control2x, Control2y;
1634     double sx, sy;
1635 
1636     if (!FF_points_equal(&p->currentp, aControl) ||
1637         !FF_points_equal(&p->currentp, aTo) ||
1638         !FF_points_equal(aControl, aTo)) {
1639         p->currentp = *aTo;
1640 
1641         /* More complicated than above, we need to do arithmetic on the
1642          * co-ordinates, so we want them as floats and we will convert the
1643          * result into 16.16 fixed precision for FAPI
1644          *
1645          * NB this code is funcitonally the same as the original, but I don't believe
1646          * the comment (below) to be what the code is actually doing....
1647          *
1648          * NB2: the comment below was wrong, even though the code was correct(!!)
1649          * The comment has now been amended.
1650          *
1651          * Convert a quadratic spline to a cubic. Do this by changing the three points
1652          * A, B and C to A, 2/3(B,A), 2/3(B,C), C - that is, the two cubic control points are
1653          * a third of the way from the single quadratic control point to the end points. This
1654          * gives the same curve as the original quadratic.
1655          */
1656 
1657         sx = (double) (p->x >> 32);
1658         sy = (double) (p->y >> 32);
1659 
1660         x = aTo->x / 64.0;
1661         p->x = ((int64_t) float2fixed(x)) << 24;
1662         y = aTo->y / 64.0;
1663         p->y = ((int64_t) float2fixed(y)) << 24;
1664         Controlx = aControl->x / 64.0;
1665         Controly = aControl->y / 64.0;
1666 
1667         Control1x = ((int64_t) float2fixed((sx + Controlx * 2) / 3)) << 24;
1668         Control1y = ((int64_t) float2fixed((sy + Controly * 2) / 3)) << 24;
1669         Control2x = ((int64_t) float2fixed((x + Controlx * 2) / 3)) << 24;
1670         Control2y = ((int64_t) float2fixed((y + Controly * 2) / 3)) << 24;
1671 
1672         return p->path->curveto(p->path, Control1x,
1673                                 Control1y,
1674                                 Control2x, Control2y, p->x, p->y) ? -1 : 0;
1675     }
1676     return 0;
1677 }
1678 
1679 static int
cubic_to(const FT_Vector * aControl1,const FT_Vector * aControl2,const FT_Vector * aTo,void * aObject)1680 cubic_to(const FT_Vector * aControl1, const FT_Vector * aControl2,
1681          const FT_Vector * aTo, void *aObject)
1682 {
1683     FF_path_info *p = (FF_path_info *) aObject;
1684     int64_t Control1x, Control1y, Control2x, Control2y;
1685 
1686     if (!FF_points_equal(&p->currentp, aControl1) ||
1687         !FF_points_equal(&p->currentp, aControl2) ||
1688         !FF_points_equal(&p->currentp, aTo) ||
1689         !FF_points_equal(aControl1, aControl2) ||
1690         !FF_points_equal(aControl1, aTo) ||
1691         !FF_points_equal(aControl2, aTo)) {
1692         p->currentp = *aTo;
1693 
1694         /* See move_to() above */
1695         p->x = ((int64_t) aTo->x) << 26;
1696         p->y = ((int64_t) aTo->y) << 26;
1697 
1698         Control1x = ((int64_t) aControl1->x) << 26;
1699         Control1y = ((int64_t) aControl1->y) << 26;
1700         Control2x = ((int64_t) aControl2->x) << 26;
1701         Control2y = ((int64_t) aControl2->y) << 26;
1702         return p->path->curveto(p->path, Control1x, Control1y, Control2x,
1703                                 Control2y, p->x, p->y) ? -1 : 0;
1704     }
1705     return 0;
1706 }
1707 
1708 static const FT_Outline_Funcs TheFtOutlineFuncs = {
1709     move_to,
1710     line_to,
1711     conic_to,
1712     cubic_to,
1713     0,
1714     0
1715 };
1716 
1717 /*
1718  * Return the outline created by the last call to gs_fapi_ft_get_char_outline_metrics.
1719  */
1720 static gs_fapi_retcode
gs_fapi_ft_get_char_outline(gs_fapi_server * a_server,gs_fapi_path * a_path)1721 gs_fapi_ft_get_char_outline(gs_fapi_server * a_server, gs_fapi_path * a_path)
1722 {
1723     ff_server *s = (ff_server *) a_server;
1724     FF_path_info p;
1725     FT_Error ft_error = 0;
1726 
1727     p.path = a_path;
1728     p.x = 0;
1729     p.y = 0;
1730     /* If we got an error during glyph creation, we can get
1731      * here with s->outline_glyph == NULL
1732      */
1733     if (s->outline_glyph) {
1734         ft_error =
1735             FT_Outline_Decompose(&s->outline_glyph->outline, &TheFtOutlineFuncs,
1736                                  &p);
1737     }
1738     else {
1739         a_path->moveto(a_path, 0, 0);
1740     }
1741 
1742     if (a_path->gs_error == 0)
1743         a_path->closepath(a_path);
1744     return ft_to_gs_error(ft_error);
1745 }
1746 
1747 static gs_fapi_retcode
gs_fapi_ft_release_char_data(gs_fapi_server * a_server)1748 gs_fapi_ft_release_char_data(gs_fapi_server * a_server)
1749 {
1750     ff_server *s = (ff_server *) a_server;
1751 
1752     if (s->outline_glyph) {
1753         FT_Outline_Done(s->freetype_library, &s->outline_glyph->outline);
1754         FF_free(s->ftmemory, s->outline_glyph);
1755     }
1756 
1757     if (s->bitmap_glyph) {
1758         FT_Bitmap_Done(s->freetype_library, &s->bitmap_glyph->bitmap);
1759         FF_free(s->ftmemory, s->bitmap_glyph);
1760     }
1761 
1762     s->outline_glyph = NULL;
1763     s->bitmap_glyph = NULL;
1764     return 0;
1765 }
1766 
1767 static gs_fapi_retcode
gs_fapi_ft_release_typeface(gs_fapi_server * a_server,void * a_server_font_data)1768 gs_fapi_ft_release_typeface(gs_fapi_server * a_server, void *a_server_font_data)
1769 {
1770     ff_face *face = (ff_face *) a_server_font_data;
1771 
1772     delete_face(a_server, face);
1773     return 0;
1774 }
1775 
1776 static gs_fapi_retcode
gs_fapi_ft_check_cmap_for_GID(gs_fapi_server * server,uint * index)1777 gs_fapi_ft_check_cmap_for_GID(gs_fapi_server * server, uint * index)
1778 {
1779     ff_face *face = (ff_face *) (server->ff.server_font_data);
1780     FT_Face ft_face = face->ft_face;
1781 
1782     *index = FT_Get_Char_Index(ft_face, *index);
1783     return 0;
1784 }
1785 
1786 static gs_fapi_retcode
gs_fapi_ft_set_mm_weight_vector(gs_fapi_server * server,gs_fapi_font * ff,float * wvector,int length)1787 gs_fapi_ft_set_mm_weight_vector(gs_fapi_server *server, gs_fapi_font *ff, float *wvector, int length)
1788 {
1789 #if defined(SHARE_FT) && SHARE_FT == 1 && \
1790     FREETYPE_MAJOR <= 2 && FREETYPE_MINOR <= 9 && FREETYPE_PATCH <= 1
1791 
1792     return gs_error_invalidaccess;
1793 #else
1794     ff_face *face = (ff_face *) ff->server_font_data;
1795     FT_Fixed nwv[16] = {0};
1796     FT_Fixed cwv[16] = {0};
1797     FT_UInt len = 16;
1798     int i;
1799     bool setit = false;
1800     FT_Error ft_error;
1801     (void)server;
1802 
1803     ft_error = FT_Get_MM_WeightVector(face->ft_face, &len, cwv);
1804     if (ft_error != 0) return_error(gs_error_invalidaccess);
1805 
1806     for (i = 0; i < length; i++) {
1807         nwv[i] = (FT_Fixed)(wvector[i] * 65536.0);
1808         if (nwv[i] != cwv[i]) {
1809             setit = true;
1810         }
1811     }
1812 
1813     if (setit == true) {
1814         ft_error = FT_Set_MM_WeightVector(face->ft_face, length, nwv);
1815         if (ft_error != 0) return_error(gs_error_invalidaccess);
1816     }
1817 
1818     return 0;
1819 #endif
1820 }
1821 
1822 static void gs_fapi_freetype_destroy(gs_fapi_server ** serv);
1823 
1824 static const gs_fapi_server_descriptor freetypedescriptor = {
1825     (const char *)"FAPI",
1826     (const char *)"FreeType",
1827     gs_fapi_freetype_destroy
1828 };
1829 
1830 static const gs_fapi_server freetypeserver = {
1831     {&freetypedescriptor},
1832     NULL,                       /* client_ctx_p */
1833     16,                         /* frac_shift */
1834     {gs_no_id},
1835     {0},
1836     0,
1837     false,
1838     1,
1839     {1, 0, 0, 1, 0, 0},
1840     gs_fapi_ft_ensure_open,
1841     gs_fapi_ft_get_scaled_font,
1842     gs_fapi_ft_get_decodingID,
1843     gs_fapi_ft_get_font_bbox,
1844     gs_fapi_ft_get_font_proportional_feature,
1845     gs_fapi_ft_can_retrieve_char_by_name,
1846     gs_fapi_ft_can_replace_metrics,
1847     NULL,                       /* can_simulate_style */
1848     gs_fapi_ft_get_fontmatrix,
1849     gs_fapi_ft_get_char_width,
1850     gs_fapi_ft_get_char_raster_metrics,
1851     gs_fapi_ft_get_char_raster,
1852     gs_fapi_ft_get_char_outline_metrics,
1853     gs_fapi_ft_get_char_outline,
1854     gs_fapi_ft_release_char_data,
1855     gs_fapi_ft_release_typeface,
1856     gs_fapi_ft_check_cmap_for_GID,
1857     NULL,                        /* get_font_info */
1858     gs_fapi_ft_set_mm_weight_vector,
1859 };
1860 
1861 int gs_fapi_ft_init(gs_memory_t * mem, gs_fapi_server ** server);
1862 
1863 int
gs_fapi_ft_init(gs_memory_t * mem,gs_fapi_server ** server)1864 gs_fapi_ft_init(gs_memory_t * mem, gs_fapi_server ** server)
1865 {
1866     ff_server *serv;
1867     int code = 0;
1868     gs_memory_t *cmem = mem->non_gc_memory;
1869 
1870     code = gs_memory_chunk_wrap(&(cmem), mem);
1871     if (code != 0) {
1872         return (code);
1873     }
1874 
1875 
1876     serv = (ff_server *) gs_alloc_bytes_immovable(cmem, sizeof(ff_server), "gs_fapi_ft_init");
1877     if (!serv) {
1878         gs_memory_chunk_release(cmem);
1879         return_error(gs_error_VMerror);
1880     }
1881     memset(serv, 0, sizeof(*serv));
1882     serv->mem = cmem;
1883     serv->fapi_server = freetypeserver;
1884 
1885     serv->ftmemory = (FT_Memory) (&(serv->ftmemory_rec));
1886 
1887     (*server) = (gs_fapi_server *) serv;
1888     return (0);
1889 }
1890 
1891 
1892 void
gs_fapi_freetype_destroy(gs_fapi_server ** serv)1893 gs_fapi_freetype_destroy(gs_fapi_server ** serv)
1894 {
1895     ff_server *server = (ff_server *) * serv;
1896     gs_memory_t *cmem = server->mem;
1897 
1898     FT_Done_Glyph(&server->outline_glyph->root);
1899     FT_Done_Glyph(&server->bitmap_glyph->root);
1900 
1901     /* As with initialization: since we're supplying memory management to
1902      * FT, we cannot just to use FT_Done_FreeType (), we have to use
1903      * FT_Done_Library () and then discard the memory ourselves
1904      */
1905     FT_Done_Library(server->freetype_library);
1906     gs_free(cmem, *serv, 0, 0, "gs_fapi_freetype_destroy: ff_server");
1907     *serv = NULL;
1908     gs_memory_chunk_release(cmem);
1909 }
1910