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