1 /* Copyright (C) 2001-2006 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, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 /* $Id: fapi_ft.c 10653 2010-01-28 14:32:52Z ken $ */
14
15 /*
16 GhostScript Font API plug-in that allows fonts to be rendered by FreeType.
17 Started by Graham Asher, 6th June 2002.
18 */
19
20 /* GhostScript headers. */
21 #include "stdio_.h"
22 #include "malloc_.h"
23 #include "ierrors.h"
24 #include "ifapi.h"
25 #include "write_t1.h"
26 #include "write_t2.h"
27 #include "math_.h"
28 #include "gserror.h"
29 #include "gxfixed.h"
30
31 /* FreeType headers */
32 #include <ft2build.h>
33 #include FT_FREETYPE_H
34 #include FT_INCREMENTAL_H
35 #include FT_GLYPH_H
36
37 /* Note: structure definitions here start with FF_, which stands for 'FAPI FreeType". */
38
39 typedef struct FF_server_s
40 {
41 FAPI_server fapi_server;
42 FT_Library freetype_library;
43 FT_OutlineGlyph outline_glyph;
44 FT_BitmapGlyph bitmap_glyph;
45 } FF_server;
46
47 typedef struct FF_face_s
48 {
49 FT_Face ft_face;
50
51 /* If non-null, the incremental interface object passed to FreeType. */
52 FT_Incremental_InterfaceRec *ft_inc_int;
53
54 /* Non-null if font data is owned by this object. */
55 unsigned char *font_data;
56 } FF_face;
57
58 /* Here we define the struct FT_Incremental that is used as an opaque type
59 * inside FreeType. This structure has to have the tag FT_IncrementalRec_
60 * to be compatible with the functions defined in FT_Incremental_FuncsRec.
61 */
62 typedef struct FT_IncrementalRec_
63 {
64 FAPI_font *fapi_font; /* The font. */
65
66 /* If it is already in use glyph data is allocated on the heap. */
67 unsigned char *glyph_data; /* A one-shot buffer for glyph data. */
68 size_t glyph_data_length; /* Length in bytes of glyph_data. */
69 bool glyph_data_in_use; /* True if glyph_data is already in use. */
70
71 FT_Incremental_MetricsRec glyph_metrics; /* Incremental glyph metrics supplied by Ghostscript. */
72 unsigned long glyph_metrics_index; /* contains data for this glyph index unless it is 0xFFFFFFFF. */
73 FAPI_metrics_type metrics_type; /* determines whether metrics are replaced, added, etc. */
74 } FT_IncrementalRec;
75
76 static FF_face *
new_face(FT_Face a_ft_face,FT_Incremental_InterfaceRec * a_ft_inc_int,unsigned char * a_font_data)77 new_face(FT_Face a_ft_face, FT_Incremental_InterfaceRec *a_ft_inc_int, unsigned char *a_font_data)
78 {
79 FF_face *face = (FF_face *)malloc(sizeof(FF_face));
80 if (face)
81 {
82 face->ft_face = a_ft_face;
83 face->ft_inc_int = a_ft_inc_int;
84 face->font_data = a_font_data;
85 }
86 return face;
87 }
88
89 static void
delete_face(FF_face * a_face)90 delete_face(FF_face *a_face)
91 {
92 if (a_face)
93 {
94 FT_Done_Face(a_face->ft_face);
95 free(a_face->ft_inc_int);
96 free(a_face->font_data);
97 free(a_face);
98 }
99 }
100
101 static FT_IncrementalRec *
new_inc_int_info(FAPI_font * a_fapi_font)102 new_inc_int_info(FAPI_font *a_fapi_font)
103 {
104 FT_IncrementalRec *info = (FT_IncrementalRec*)malloc(sizeof(FT_IncrementalRec));
105 if (info)
106 {
107 info->fapi_font = a_fapi_font;
108 info->glyph_data = NULL;
109 info->glyph_data_length = 0;
110 info->glyph_data_in_use = false;
111 info->glyph_metrics_index = 0xFFFFFFFF;
112 info->metrics_type = FAPI_METRICS_NOTDEF;
113 }
114 return info;
115 }
116
117 static void
delete_inc_int_info(FT_IncrementalRec * a_inc_int_info)118 delete_inc_int_info(FT_IncrementalRec *a_inc_int_info)
119 {
120 if (a_inc_int_info)
121 {
122 free(a_inc_int_info->glyph_data);
123 free(a_inc_int_info);
124 }
125 }
126
127 static FT_Error
get_fapi_glyph_data(FT_Incremental a_info,FT_UInt a_index,FT_Data * a_data)128 get_fapi_glyph_data(FT_Incremental a_info, FT_UInt a_index, FT_Data *a_data)
129 {
130 FAPI_font *ff = a_info->fapi_font;
131 ushort length = 0;
132
133 /* Tell the FAPI interface that we need to decrypt the glyph data. */
134 ff->need_decrypt = true;
135
136 /* If glyph_data is already in use (as will happen for composite glyphs)
137 * create a new buffer on the heap.
138 */
139 if (a_info->glyph_data_in_use)
140 {
141 unsigned char *buffer = NULL;
142 length = ff->get_glyph(ff, a_index, NULL, 0);
143 if (length == 65535)
144 return FT_Err_Invalid_Glyph_Index;
145 buffer = malloc(length);
146 if (!buffer)
147 return FT_Err_Out_Of_Memory;
148 if (ff->get_glyph(ff, a_index, buffer, length) == 65535) {
149 free (buffer);
150 return FT_Err_Invalid_Glyph_Index;
151 }
152 a_data->pointer = buffer;
153 }
154 else
155 {
156 /* Save ff->char_data, which is set to null by FAPI_FF_get_glyph as part of a hack to
157 * make the deprecated Type 2 endchar ('seac') work, so that it can be restored
158 * if we need to try again with a longer buffer.
159 */
160 const void *saved_char_data = ff->char_data;
161
162 /* Get as much of the glyph data as possible into the buffer */
163 length = ff->get_glyph(ff, a_index, a_info->glyph_data, (ushort)a_info->glyph_data_length);
164
165 /* If the buffer was too small enlarge it and try again. */
166 if (length > a_info->glyph_data_length)
167 {
168 a_info->glyph_data = realloc(a_info->glyph_data, length);
169 if (!a_info->glyph_data)
170 {
171 a_info->glyph_data_length = 0;
172 return FT_Err_Out_Of_Memory;
173 }
174 a_info->glyph_data_length = length;
175 ff->char_data = saved_char_data;
176 ff->get_glyph(ff, a_index, a_info->glyph_data, length);
177 }
178
179 /* Set the returned pointer and length. */
180 a_data->pointer = a_info->glyph_data;
181
182 a_info->glyph_data_in_use = true;
183 }
184
185 a_data->length = length;
186 return 0;
187 }
188
189 static void
free_fapi_glyph_data(FT_Incremental a_info,FT_Data * a_data)190 free_fapi_glyph_data(FT_Incremental a_info, FT_Data *a_data)
191 {
192 if (a_data->pointer == (const FT_Byte*)a_info->glyph_data)
193 a_info->glyph_data_in_use = false;
194 else
195 free((FT_Byte*)a_data->pointer);
196 }
197
198 static FT_Error
get_fapi_glyph_metrics(FT_Incremental a_info,FT_UInt a_glyph_index,FT_Bool bVertical,FT_Incremental_MetricsRec * a_metrics)199 get_fapi_glyph_metrics(FT_Incremental a_info, FT_UInt a_glyph_index,
200 FT_Bool bVertical, FT_Incremental_MetricsRec *a_metrics)
201 {
202 /* fixme : bVertical is not implemented. */
203 if (a_info->glyph_metrics_index == a_glyph_index)
204 {
205 switch (a_info->metrics_type)
206 {
207 case FAPI_METRICS_ADD:
208 a_metrics->advance += a_info->glyph_metrics.advance;
209 break;
210 case FAPI_METRICS_REPLACE_WIDTH:
211 a_metrics->advance = a_info->glyph_metrics.advance;
212 break;
213 case FAPI_METRICS_REPLACE:
214 *a_metrics = a_info->glyph_metrics;
215 break;
216 default:
217 /* This can't happen. */
218 return FT_Err_Invalid_Argument;
219 }
220 }
221 return 0;
222 }
223
224 static const
225 FT_Incremental_FuncsRec TheFAPIIncrementalInterfaceFuncs =
226 {
227 get_fapi_glyph_data,
228 free_fapi_glyph_data,
229 get_fapi_glyph_metrics
230 };
231
232 static FT_Incremental_InterfaceRec *
new_inc_int(FAPI_font * a_fapi_font)233 new_inc_int(FAPI_font *a_fapi_font)
234 {
235 FT_Incremental_InterfaceRec *i =
236 (FT_Incremental_InterfaceRec*) malloc(sizeof(FT_Incremental_InterfaceRec)); /* malloc!? /Tor */
237 if (i)
238 {
239 i->object = (FT_Incremental)new_inc_int_info(a_fapi_font);
240 i->funcs = &TheFAPIIncrementalInterfaceFuncs;
241 }
242 if (!i->object)
243 {
244 free(i);
245 i = NULL;
246 }
247 return i;
248 }
249
250 static void
delete_inc_int(FT_Incremental_InterfaceRec * a_inc_int)251 delete_inc_int(FT_Incremental_InterfaceRec *a_inc_int)
252 {
253 if (a_inc_int)
254 {
255 delete_inc_int_info(a_inc_int->object);
256 free(a_inc_int);
257 }
258 }
259
260 /* Convert FreeType error codes to GhostScript ones.
261 * Very rudimentary because most don't correspond.
262 */
263 static int
ft_to_gs_error(FT_Error a_error)264 ft_to_gs_error(FT_Error a_error)
265 {
266 if (a_error)
267 {
268 if (a_error == FT_Err_Out_Of_Memory)
269 return e_VMerror;
270 else
271 return e_unknownerror;
272 }
273 return 0;
274 }
275
276 /* Load a glyph and optionally rasterize it. Return its metrics in a_metrics.
277 * If a_bitmap is true convert the glyph to a bitmap.
278 */
279 static FAPI_retcode
load_glyph(FAPI_font * a_fapi_font,const FAPI_char_ref * a_char_ref,FAPI_metrics * a_metrics,FT_Glyph * a_glyph,bool a_bitmap)280 load_glyph(FAPI_font *a_fapi_font, const FAPI_char_ref *a_char_ref,
281 FAPI_metrics *a_metrics, FT_Glyph *a_glyph, bool a_bitmap)
282 {
283 FT_Error ft_error = 0;
284 FF_face *face = (FF_face*)a_fapi_font->server_font_data;
285 FT_Face ft_face = face->ft_face;
286 int index = a_char_ref->char_code;
287
288 /* Save a_fapi_font->char_data, which is set to null by FAPI_FF_get_glyph as part of a hack to
289 * make the deprecated Type 2 endchar ('seac') work, so that it can be restored
290 * after the first call to FT_Load_Glyph.
291 */
292 const void *saved_char_data = a_fapi_font->char_data;
293
294 if (!a_char_ref->is_glyph_index)
295 {
296 if (ft_face->num_charmaps)
297 index = FT_Get_Char_Index(ft_face, index);
298 else
299 {
300 /* If there are no character maps and no glyph index, loading the glyph will still work
301 * properly if both glyph data and metrics are supplied by the incremental interface.
302 * In that case we use a dummy glyph index which will be passed
303 * back to FAPI_FF_get_glyph by get_fapi_glyph_data.
304 *
305 * Type 1 fonts don't use the code and can appear to FreeType to have only one glyph,
306 * so we have to set the index to 0.
307 *
308 * For other font types, FAPI_FF_get_glyph requires the character code
309 * when getting data.
310 */
311 if (a_fapi_font->is_type1)
312 index = 0;
313 else
314 index = a_char_ref->char_code;
315 }
316 }
317
318 /* Refresh the pointer to the FAPI_font held by the incremental interface. */
319 if (face->ft_inc_int)
320 face->ft_inc_int->object->fapi_font = a_fapi_font;
321
322 /* Store the overriding metrics if they have been supplied. */
323 if (face->ft_inc_int && a_char_ref->metrics_type != FAPI_METRICS_NOTDEF)
324 {
325 FT_Incremental_MetricsRec *m = &face->ft_inc_int->object->glyph_metrics;
326 m->bearing_x = a_char_ref->sb_x >> 16;
327 m->bearing_y = a_char_ref->sb_y >> 16;
328 m->advance = a_char_ref->aw_x >> 16;
329 face->ft_inc_int->object->glyph_metrics_index = index;
330 face->ft_inc_int->object->metrics_type = a_char_ref->metrics_type;
331 }
332
333 ft_error = FT_Load_Glyph(ft_face, index, FT_LOAD_MONOCHROME | FT_LOAD_NO_SCALE);
334 if (!ft_error && a_metrics)
335 {
336 a_metrics->bbox_x0 = ft_face->glyph->metrics.horiBearingX;
337 a_metrics->bbox_y0 = ft_face->glyph->metrics.horiBearingY - ft_face->glyph->metrics.height;
338 a_metrics->bbox_x1 = a_metrics->bbox_x0 + ft_face->glyph->metrics.width;
339 a_metrics->bbox_y1 = a_metrics->bbox_y0 + ft_face->glyph->metrics.height;
340 a_metrics->escapement = ft_face->glyph->metrics.horiAdvance;
341 a_metrics->v_escapement = ft_face->glyph->metrics.vertAdvance;
342 a_metrics->em_x = ft_face->units_per_EM;
343 a_metrics->em_y = ft_face->units_per_EM;
344 }
345
346 /* We have to load the glyph again, scale it correctly, and render it if we need a bitmap. */
347 if (!ft_error)
348 {
349 a_fapi_font->char_data = saved_char_data;
350 ft_error = FT_Load_Glyph(ft_face, index, a_bitmap ? FT_LOAD_MONOCHROME | FT_LOAD_RENDER: FT_LOAD_MONOCHROME);
351 }
352 if (!ft_error && a_glyph)
353 ft_error = FT_Get_Glyph(ft_face->glyph, a_glyph);
354 if (ft_error == FT_Err_Too_Many_Hints) {
355 eprintf1 ("TrueType glyph %d uses more instructions than the declared maximum in the font. Continuing, ignoring broken glyph\n", a_char_ref->char_code);
356 ft_error = 0;
357 }
358 if (ft_error == FT_Err_Invalid_Argument) {
359 eprintf1 ("TrueType parsing error in glyph %d in the font. Continuing, ignoring broken glyph\n", a_char_ref->char_code);
360 ft_error = 0;
361 }
362 if (ft_error == FT_Err_Too_Many_Function_Defs) {
363 eprintf1 ("TrueType instruction error in glyph %d in the font. Continuing, ignoring broken glyph\n", a_char_ref->char_code);
364 ft_error = 0;
365 }
366 if (ft_error == FT_Err_Invalid_Glyph_Index) {
367 eprintf1 ("FreeType is unable to find the glyph %d in the font. Continuing, ignoring missing glyph\n", a_char_ref->char_code);
368 ft_error = 0;
369 }
370 return ft_to_gs_error(ft_error);
371 }
372
373 /*
374 * Ensure that the rasterizer is open.
375 *
376 * In the case of FreeType this means creating the FreeType library object.
377 */
378 static FAPI_retcode
ensure_open(FAPI_server * a_server,const byte * server_param,int server_param_size)379 ensure_open(FAPI_server *a_server, const byte *server_param, int server_param_size)
380 {
381 FF_server *s = (FF_server*)a_server;
382 if (!s->freetype_library)
383 {
384 FT_Error ft_error = FT_Init_FreeType(&s->freetype_library);
385 if (ft_error)
386 return ft_to_gs_error(ft_error);
387 }
388 return 0;
389 }
390
391 static void
transform_concat(FT_Matrix * a_A,const FT_Matrix * a_B)392 transform_concat(FT_Matrix *a_A, const FT_Matrix *a_B)
393 {
394 FT_Matrix result = *a_B;
395 FT_Matrix_Multiply(a_A, &result);
396 *a_A = result;
397 }
398
399 /* Create a transform representing an angle defined as a vector. */
400 static void
make_rotation(FT_Matrix * a_transform,const FT_Vector * a_vector)401 make_rotation(FT_Matrix *a_transform, const FT_Vector *a_vector)
402 {
403 FT_Fixed length, cos, sin;
404 if (a_vector->x >= 0 && a_vector->y == 0)
405 {
406 a_transform->xx = a_transform->yy = 65536;
407 a_transform->xy = a_transform->yx = 0;
408 return;
409 }
410
411 length = FT_Vector_Length((FT_Vector*)a_vector);
412 cos = FT_DivFix(a_vector->x, length);
413 sin = FT_DivFix(a_vector->y, length);
414 a_transform->xx = a_transform->yy = cos;
415 a_transform->xy = -sin;
416 a_transform->yx = sin;
417 }
418
419 /* Divide a transformation into a scaling part and a rotation-and-shear part.
420 * The scaling part is used for setting the pixel size for hinting.
421 */
422 static void
transform_decompose(FT_Matrix * a_transform,FT_Fixed * a_x_scale,FT_Fixed * a_y_scale)423 transform_decompose(FT_Matrix *a_transform, FT_Fixed *a_x_scale, FT_Fixed *a_y_scale)
424 {
425 float a = a_transform->xx / 65536.0;
426 float b = a_transform->xy / 65536.0;
427 float c = a_transform->yx / 65536.0;
428 float d = a_transform->yy / 65536.0;
429
430 float scale = sqrt(fabs(a * d - b * c));
431
432 a_transform->xx = a / scale * 65536.0;
433 a_transform->xy = b / scale * 65536.0;
434 a_transform->yx = c / scale * 65536.0;
435 a_transform->yy = d / scale * 65536.0;
436
437 *a_x_scale = scale * 65536.0;
438 *a_y_scale = scale * 65536.0;
439 }
440
441 /*
442 * Open a font and set its size.
443 */
444 static FAPI_retcode
get_scaled_font(FAPI_server * a_server,FAPI_font * a_font,const FAPI_font_scale * a_font_scale,const char * a_map,FAPI_descendant_code a_descendant_code)445 get_scaled_font(FAPI_server *a_server, FAPI_font *a_font,
446 const FAPI_font_scale *a_font_scale,
447 const char *a_map,
448 FAPI_descendant_code a_descendant_code)
449 {
450 FF_server *s = (FF_server*)a_server;
451 FF_face *face = (FF_face*)a_font->server_font_data;
452 FT_Error ft_error = 0;
453
454 /* dpf("get_scaled_font enter: is_type1=%d is_cid=%d font_file_path='%s' a_descendant_code=%d\n",
455 a_font->is_type1, a_font->is_cid, a_font->font_file_path ? a_font->font_file_path : "", a_descendant_code); */
456
457 /* If this font is the top level font of an embedded CID type 0 font (font type 9)
458 * do nothing. See the comment in FAPI_prepare_font. The descendant fonts are
459 * passed in individually.
460 */
461 if (a_font->is_cid && a_font->is_type1 && a_font->font_file_path == NULL &&
462 (a_descendant_code == FAPI_TOPLEVEL_BEGIN ||
463 a_descendant_code == FAPI_TOPLEVEL_COMPLETE))
464 {
465 /* dpf("get_scaled_font return 0\n"); */
466 return 0;
467 }
468
469 /* Create the face if it doesn't already exist. */
470 if (!face)
471 {
472 FT_Face ft_face = NULL;
473 FT_Parameter ft_param;
474 FT_Incremental_InterfaceRec *ft_inc_int = NULL;
475 unsigned char *own_font_data = NULL;
476
477 /* dpf("get_scaled_font creating face\n"); */
478
479 /* Load a typeface from a file. */
480 if (a_font->font_file_path)
481 {
482 ft_error = FT_New_Face(s->freetype_library, a_font->font_file_path, a_font->subfont, &ft_face);
483 if (!ft_error && ft_face)
484 ft_error = FT_Select_Charmap(ft_face, ft_encoding_unicode);
485 }
486
487 /* Load a typeface from a representation in GhostScript's memory. */
488 else
489 {
490 FT_Open_Args open_args;
491 open_args.flags = FT_OPEN_MEMORY;
492
493 if (a_font->is_type1)
494 {
495 long length;
496 int type = a_font->get_word(a_font, FAPI_FONT_FEATURE_FontType, 0);
497
498 /* Tell the FAPI interface that we need to decrypt the /Subrs data. */
499 a_font->need_decrypt = true;
500
501 /*
502 Serialise a type 1 font in PostScript source form, or
503 a Type 2 font in binary form, so that FreeType can read it.
504 */
505 if (type == 1)
506 length = FF_serialize_type1_font(a_font, NULL, 0);
507 else
508 length = FF_serialize_type2_font(a_font, NULL, 0);
509 open_args.memory_base = own_font_data = malloc(length);
510 if (!open_args.memory_base)
511 return e_VMerror;
512 if (type == 1)
513 open_args.memory_size = FF_serialize_type1_font(a_font, own_font_data, length);
514 else
515 open_args.memory_size = FF_serialize_type2_font(a_font, own_font_data, length);
516 if (open_args.memory_size != length)
517 return_error(e_unregistered); /* Must not happen. */
518 ft_inc_int = new_inc_int(a_font);
519 if (!ft_inc_int)
520 {
521 free(own_font_data);
522 return e_VMerror;
523 }
524 }
525
526 /* It must be type 42 (see code in FAPI_FF_get_glyph in zfapi.c). */
527 else
528 {
529 /* Get the length of the TrueType data. */
530 open_args.memory_size = a_font->get_long(a_font, FAPI_FONT_FEATURE_TT_size, 0);
531 if (open_args.memory_size == 0)
532 return e_invalidfont;
533
534 /* Load the TrueType data into a single buffer. */
535 open_args.memory_base = own_font_data = malloc(open_args.memory_size);
536 if (!own_font_data)
537 return e_VMerror;
538 if (a_font->serialize_tt_font(a_font, own_font_data, open_args.memory_size))
539 return e_invalidfont;
540
541 /* We always load incrementally. */
542 ft_inc_int = new_inc_int(a_font);
543 if (!ft_inc_int)
544 {
545 free(own_font_data);
546 return e_VMerror;
547 }
548 }
549
550 if (ft_inc_int)
551 {
552 open_args.flags = (FT_UInt)(open_args.flags | FT_OPEN_PARAMS);
553 ft_param.tag = FT_PARAM_TAG_INCREMENTAL;
554 ft_param.data = ft_inc_int;
555 open_args.num_params = 1;
556 open_args.params = &ft_param;
557 }
558 ft_error = FT_Open_Face(s->freetype_library, &open_args, a_font->subfont, &ft_face);
559 }
560
561 if (ft_face)
562 {
563 face = new_face(ft_face, ft_inc_int, own_font_data);
564 if (!face)
565 {
566 free(own_font_data);
567 FT_Done_Face(ft_face);
568 delete_inc_int(ft_inc_int);
569 return e_VMerror;
570 }
571 a_font->server_font_data = face;
572 }
573 else
574 a_font->server_font_data = NULL;
575 }
576
577 /* Set the point size and transformation.
578 * The matrix is scaled by the shift specified in the server, 16,
579 * so we divide by 65536 when converting to a gs_matrix.
580 */
581 if (face)
582 {
583 static const FT_Matrix ft_reflection = { 65536, 0, 0, -65536 };
584 FT_Matrix ft_transform;
585 FT_F26Dot6 width, height;
586
587 /* Convert the GS transform into an FT transform.
588 * Ignore the translation elements because they contain very large values
589 * derived from the current transformation matrix and so are of no use.
590 */
591 ft_transform.xx = a_font_scale->matrix[0];
592 ft_transform.xy = a_font_scale->matrix[2];
593 ft_transform.yx = a_font_scale->matrix[1];
594 ft_transform.yy = a_font_scale->matrix[3];
595
596 /* Split the transform into scale factors and a rotation-and-shear
597 * transform.
598 */
599 transform_decompose(&ft_transform, &width, &height);
600
601 /* Convert width and height to 64ths of pixels and set the FreeType sizes. */
602 width >>= 10;
603 height >>= 10;
604 ft_error = FT_Set_Char_Size(face->ft_face, width, height,
605 a_font_scale->HWResolution[0] >> 16,
606 a_font_scale->HWResolution[1] >> 16);
607 if (ft_error)
608 {
609 delete_face(face);
610 a_font->server_font_data = NULL;
611 return ft_to_gs_error(ft_error);
612 }
613
614 /* Concatenate the transform to a reflection around (y=0) so that it
615 * produces a glyph that is upside down in FreeType terms, with its
616 * first row at the bottom. That is what GhostScript needs.
617 */
618
619 FT_Set_Transform(face->ft_face, &ft_transform, NULL);
620 }
621
622 /* dpf("get_scaled_font return %d\n", a_font->server_font_data ? 0 : -1); */
623 return a_font->server_font_data ? 0 : -1;
624 }
625
626 /*
627 * Return the name of a resource which maps names to character codes. Do this
628 * by setting a_decoding_id to point to a null-terminated string. The resource
629 * is in the 'decoding' directory in the directory named by /GenericResourceDir
630 * in lib/gs_res.ps.
631 */
632 static FAPI_retcode
get_decodingID(FAPI_server * a_server,FAPI_font * a_font,const char ** a_decoding_id)633 get_decodingID(FAPI_server *a_server, FAPI_font *a_font, const char** a_decoding_id)
634 {
635 *a_decoding_id = "Unicode";
636 return 0;
637 }
638
639 /*
640 * Get the font bounding box in font units.
641 */
642 static FAPI_retcode
get_font_bbox(FAPI_server * a_server,FAPI_font * a_font,int a_box[4])643 get_font_bbox(FAPI_server *a_server, FAPI_font *a_font, int a_box[4])
644 {
645 FF_face *face = (FF_face*)a_font->server_font_data;
646 a_box[0] = face->ft_face->bbox.xMin;
647 a_box[1] = face->ft_face->bbox.yMin;
648 a_box[2] = face->ft_face->bbox.xMax;
649 a_box[3] = face->ft_face->bbox.yMax;
650 return 0;
651 }
652
653 /*
654 * Return a boolean value in a_proportional stating whether the font is proportional
655 * or fixed-width.
656 */
657 static FAPI_retcode
get_font_proportional_feature(FAPI_server * a_server,FAPI_font * a_font,bool * a_proportional)658 get_font_proportional_feature(FAPI_server *a_server, FAPI_font *a_font, bool *a_proportional)
659 {
660 *a_proportional = true;
661 return 0;
662 }
663
664 /* Convert the character name in a_char_ref.char_name to a character code or
665 * glyph index and put it in a_char_ref.char_code, setting
666 * a_char_ref.is_glyph_index as appropriate. If this is possible set a_result
667 * to true, otherwise set it to false. The return value is a standard error
668 * return code.
669 */
670 static FAPI_retcode
can_retrieve_char_by_name(FAPI_server * a_server,FAPI_font * a_font,FAPI_char_ref * a_char_ref,bool * a_result)671 can_retrieve_char_by_name(FAPI_server *a_server, FAPI_font *a_font, FAPI_char_ref *a_char_ref, bool *a_result)
672 {
673 FF_face *face = (FF_face*)a_font->server_font_data;
674 char name[128];
675 if (FT_HAS_GLYPH_NAMES(face->ft_face) && a_char_ref->char_name_length < sizeof(name))
676 {
677 memcpy(name, a_char_ref->char_name, a_char_ref->char_name_length);
678 name[a_char_ref->char_name_length] = 0;
679 a_char_ref->char_code = FT_Get_Name_Index(face->ft_face, name);
680 *a_result = a_char_ref->char_code != 0;
681 if (*a_result)
682 a_char_ref->is_glyph_index = true;
683 }
684 else
685 *a_result = false;
686 return 0;
687 }
688
689 /*
690 * Return non-zero if the metrics can be replaced.
691 */
692 static FAPI_retcode
can_replace_metrics(FAPI_server * a_server,FAPI_font * a_font,FAPI_char_ref * a_char_ref,int * a_result)693 can_replace_metrics(FAPI_server *a_server, FAPI_font *a_font, FAPI_char_ref *a_char_ref, int *a_result)
694 {
695 /* Replace metrics only if the metrics are supplied in font units. */
696 *a_result = a_char_ref->metrics_scale == 0;
697 return 0;
698 }
699
700 /*
701 * Retrieve the metrics of a_char_ref and put them in a_metrics.
702 */
703 static FAPI_retcode
get_char_width(FAPI_server * a_server,FAPI_font * a_font,FAPI_char_ref * a_char_ref,FAPI_metrics * a_metrics)704 get_char_width(FAPI_server *a_server, FAPI_font *a_font, FAPI_char_ref *a_char_ref, FAPI_metrics *a_metrics)
705 {
706 return load_glyph(a_font, a_char_ref, a_metrics, NULL, false);
707 }
708
709 /*
710 * Rasterize the character a_char and return its metrics. Do not return the
711 * bitmap but store this. It can be retrieved by a subsequent call to
712 * get_char_raster.
713 */
714 static FAPI_retcode
get_char_raster_metrics(FAPI_server * a_server,FAPI_font * a_font,FAPI_char_ref * a_char_ref,FAPI_metrics * a_metrics)715 get_char_raster_metrics(FAPI_server *a_server, FAPI_font *a_font,
716 FAPI_char_ref *a_char_ref, FAPI_metrics *a_metrics)
717 {
718 FF_server *s = (FF_server*)a_server;
719 FAPI_retcode error = load_glyph(a_font, a_char_ref, a_metrics, (FT_Glyph*)&s->bitmap_glyph, true);
720 return error;
721 }
722
723 /*
724 * Return the bitmap created by the last call to get_char_raster_metrics.
725 */
726 static FAPI_retcode
get_char_raster(FAPI_server * a_server,FAPI_raster * a_raster)727 get_char_raster(FAPI_server *a_server, FAPI_raster *a_raster)
728 {
729 FF_server *s = (FF_server*)a_server;
730 if (!s->bitmap_glyph)
731 return_error(e_unregistered); /* Must not happen. */
732 a_raster->p = s->bitmap_glyph->bitmap.buffer;
733 a_raster->width = s->bitmap_glyph->bitmap.width;
734 a_raster->height = s->bitmap_glyph->bitmap.rows;
735 a_raster->line_step = s->bitmap_glyph->bitmap.pitch;
736 a_raster->orig_x = s->bitmap_glyph->left * 16;
737 a_raster->orig_y = s->bitmap_glyph->top * 16;
738 a_raster->left_indent = a_raster->top_indent = a_raster->black_height = a_raster->black_width = 0;
739 return 0;
740 }
741
742 /*
743 * Create an outline for the character a_char and return its metrics. Do not
744 * return the outline but store this.
745 * It can be retrieved by a subsequent call to get_char_outline.
746 */
747 static FAPI_retcode
get_char_outline_metrics(FAPI_server * a_server,FAPI_font * a_font,FAPI_char_ref * a_char_ref,FAPI_metrics * a_metrics)748 get_char_outline_metrics(FAPI_server *a_server, FAPI_font *a_font,
749 FAPI_char_ref *a_char_ref, FAPI_metrics *a_metrics)
750 {
751 FF_server *s = (FF_server*)a_server;
752 return load_glyph(a_font, a_char_ref, a_metrics, (FT_Glyph*)&s->outline_glyph, false);
753 }
754
755 typedef struct FF_path_info_s
756 {
757 FAPI_path *path;
758 FracInt x;
759 FracInt y;
760 } FF_path_info;
761
move_to(FT_Vector * aTo,void * aObject)762 static int move_to(FT_Vector *aTo, void *aObject)
763 {
764 FF_path_info *p = (FF_path_info*)aObject;
765
766 /* FAPI expects that co-ordinates will be as implied by frac_shift
767 * in our case 16.16 fixed precision. True for 'low level' FT
768 * routines (apparently), it isn't true for these routines where
769 * FT returns a 26.6 format. Rescale to 16.16 so that FAPI will
770 * be able to convert to GS co-ordinates properly.
771 */
772 p->x = aTo->x << 10;
773 p->y = aTo->y << 10;
774
775 return p->path->moveto(p->path, p->x, p->y) ? -1 : 0;
776 }
777
line_to(FT_Vector * aTo,void * aObject)778 static int line_to(FT_Vector *aTo, void *aObject)
779 {
780 FF_path_info *p = (FF_path_info*)aObject;
781
782 /* See move_to() above */
783 p->x = aTo->x << 10;
784 p->y = aTo->y << 10;
785
786 return p->path->lineto(p->path, p->x, p->y) ? -1 : 0;
787 }
788
conic_to(FT_Vector * aControl,FT_Vector * aTo,void * aObject)789 static int conic_to(FT_Vector *aControl, FT_Vector *aTo, void *aObject)
790 {
791 FF_path_info *p = (FF_path_info*)aObject;
792 floatp x, y, Controlx, Controly, Control1x, Control1y, Control2x, Control2y;
793
794 /* More complivated than above, we need to do arithmetic on the
795 * co-ordinates, so we want them as floats and we will convert the
796 * result into 16.16 fixed precision for FAPI
797 *
798 * NB this code is funcitonally the same as the original, but I don't believe
799 * the comment (below) to be what the code is actually doing....
800 *
801 * Convert a quadratic spline to a cubic. Do this by changing the three points
802 * A, B and C to A, 1/3(B,A), 1/3(B,C), C - that is, the two cubic control points are
803 * a third of the way from the single quadratic control point to the end points. This
804 * gives the same curve as the original quadratic.
805 */
806
807 x = aTo->x / 64;
808 p->x = float2fixed(x) << 8;
809 y = aTo->y / 64;
810 p->y = float2fixed(y) << 8;
811 Controlx = aControl->x / 64;
812 Controly = aControl->y / 64;
813
814 Control1x = float2fixed((x + Controlx * 2) / 3) << 8;
815 Control1y = float2fixed((y + Controly * 2) / 3) << 8;
816 Control2x = float2fixed((x + Controlx * 2) / 3) << 8;
817 Control2y = float2fixed((y + Controly * 2) / 3) << 8;
818
819 return p->path->curveto(p->path, Control1x,
820 Control1y,
821 Control2x,
822 Control2y,
823 p->x, p->y) ? -1 : 0;
824 }
825
cubic_to(FT_Vector * aControl1,FT_Vector * aControl2,FT_Vector * aTo,void * aObject)826 static int cubic_to(FT_Vector *aControl1, FT_Vector *aControl2, FT_Vector *aTo, void *aObject)
827 {
828 FF_path_info *p = (FF_path_info*)aObject;
829 unsigned long Control1x, Control1y, Control2x, Control2y;
830
831 /* See move_to() above */
832 p->x = aTo->x << 10;
833 p->y = aTo->y << 10;
834
835 Control1x = aControl1->x << 10;
836 Control1y = aControl1->y << 10;
837 Control2x = aControl2->x << 10;
838 Control2y = aControl2->y << 10;
839 return p->path->curveto(p->path, Control1x, Control1y, Control2x, Control2y, p->x, p->y) ? -1 : 0;
840
841 p->x = aTo->x;
842 p->y = aTo->y;
843 return p->path->curveto(p->path, aControl1->x, aControl1->y, aControl2->x, aControl2->y, aTo->x, aTo->y) ? -1 : 0;
844 }
845
846 static const FT_Outline_Funcs TheFtOutlineFuncs =
847 {
848 move_to,
849 line_to,
850 conic_to,
851 cubic_to,
852 0,
853 0
854 };
855
856 /*
857 * Return the outline created by the last call to get_char_outline_metrics.
858 */
859 static FAPI_retcode
get_char_outline(FAPI_server * a_server,FAPI_path * a_path)860 get_char_outline(FAPI_server *a_server, FAPI_path *a_path)
861 {
862 FF_server *s = (FF_server*)a_server;
863 FF_path_info p;
864 FT_Error ft_error = 0;
865 p.path = a_path;
866 p.x = 0;
867 p.y = 0;
868 ft_error = FT_Outline_Decompose(&s->outline_glyph->outline, &TheFtOutlineFuncs, &p);
869 a_path->closepath(a_path);
870 return ft_to_gs_error(ft_error);
871 }
872
release_char_data(FAPI_server * a_server)873 static FAPI_retcode release_char_data(FAPI_server *a_server)
874 {
875 FF_server *s = (FF_server*)a_server;
876 FT_Done_Glyph(&s->outline_glyph->root);
877 FT_Done_Glyph(&s->bitmap_glyph->root);
878 s->outline_glyph = NULL;
879 s->bitmap_glyph = NULL;
880 return 0;
881 }
882
883 static FAPI_retcode
release_typeface(FAPI_server * a_server,void * a_server_font_data)884 release_typeface(FAPI_server *a_server, void *a_server_font_data)
885 {
886 FF_face *face = (FF_face*)a_server_font_data;
887 delete_face(face);
888 return 0;
889 }
890
891 static FAPI_retcode
check_cmap_for_GID(FAPI_server * server,uint * index)892 check_cmap_for_GID(FAPI_server *server, uint *index)
893 {
894 FF_server *s = (FF_server*)server;
895 FF_face *face = (FF_face*)(server->ff.server_font_data);
896 FT_Face ft_face = face->ft_face;
897
898 *index = FT_Get_Char_Index(ft_face, *index);
899 return 0;
900 }
901
902 static void gs_freetype_destroy(i_plugin_instance *a_instance, i_plugin_client_memory *a_memory);
903
904 static const i_plugin_descriptor TheFreeTypeDescriptor =
905 {
906 "FAPI",
907 "FreeType",
908 gs_freetype_destroy
909 };
910
911 static const FAPI_server TheFreeTypeServer =
912 {
913 { &TheFreeTypeDescriptor },
914 16, /* frac_shift */
915 {gs_no_id},
916 {0},
917 {1, 0, 0, 1, 0, 0},
918 ensure_open,
919 get_scaled_font,
920 get_decodingID,
921 get_font_bbox,
922 get_font_proportional_feature,
923 can_retrieve_char_by_name,
924 can_replace_metrics,
925 get_char_width,
926 get_char_raster_metrics,
927 get_char_raster,
928 get_char_outline_metrics,
929 get_char_outline,
930 release_char_data,
931 release_typeface,
932 check_cmap_for_GID
933 };
934
935 plugin_instantiation_proc(gs_fapi_ft_instantiate);
936
gs_fapi_ft_instantiate(i_plugin_client_memory * a_memory,i_plugin_instance ** a_plugin_instance)937 int gs_fapi_ft_instantiate( i_plugin_client_memory *a_memory, i_plugin_instance **a_plugin_instance)
938 {
939 FF_server *server = (FF_server*) a_memory->alloc(a_memory, sizeof (FF_server), "FF_server");
940 if (!server)
941 return e_VMerror;
942 memset(server, 0, sizeof(*server));
943 server->fapi_server = TheFreeTypeServer;
944 *a_plugin_instance = &server->fapi_server.ig;
945 return 0;
946 }
947
gs_freetype_destroy(i_plugin_instance * a_plugin_instance,i_plugin_client_memory * a_memory)948 static void gs_freetype_destroy(i_plugin_instance *a_plugin_instance, i_plugin_client_memory *a_memory)
949 {
950 FF_server *server = (FF_server *)a_plugin_instance;
951 FT_Done_Glyph(&server->outline_glyph->root);
952 FT_Done_Glyph(&server->bitmap_glyph->root);
953 FT_Done_FreeType(server->freetype_library);
954 a_memory->free(a_memory, server, "FF_server");
955 }
956