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