1 /* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: fapi_ft.c,v 1.14 2004/12/08 21:35:13 stefan Exp $ */
18
19 /*
20 GhostScript Font API plug-in that allows fonts to be rendered by FreeType.
21 Started by Graham Asher, 6th June 2002.
22 */
23
24 /* GhostScript headers. */
25 #include "stdio_.h"
26 #include "ierrors.h"
27 #include "ifapi.h"
28 #include "write_t1.h"
29 #include "write_t2.h"
30 #include "math_.h"
31
32 /* FreeType headers */
33 #include "freetype/freetype.h"
34 #include "freetype/ftincrem.h"
35 #include "freetype/ftglyph.h"
36 #include "freetype/ftoutln.h"
37 #include "freetype/fttrigon.h"
38
39 #include <assert.h>
40
41 /* Note: structure definitions here start with FF_, which stands for 'FAPI FreeType". */
42
43 typedef struct FF_server_
44 {
45 FAPI_server m_fapi_server;
46 FT_Library m_freetype_library;
47 FT_OutlineGlyph m_outline_glyph;
48 FT_BitmapGlyph m_bitmap_glyph;
49 } FF_server;
50
51 typedef struct FF_face_
52 {
53 FT_Face m_ft_face; /* The FreeType typeface object. */
54 FT_Incremental_InterfaceRec* m_ft_inc_int; /* If non-null, the incremental interface object passed to FreeType. */
55 unsigned char* m_font_data; /* Non-null if font data is owned by this object. */
56 } FF_face;
57
58 /*
59 This structure has to have the tag FT_IncrementalRec to be compatible with
60 the functions defined in FT_Incremental_FuncsRec.
61 */
62 typedef struct FT_IncrementalRec_
63 {
64 FAPI_font* m_fapi_font; /* The font. */
65 unsigned char* m_glyph_data; /* A one-shot buffer for glyph data. */
66 /* If it is already in use glyph data is allocated on the heap. */
67 size_t m_glyph_data_length; /* Length in bytes of m_glyph_data. */
68 bool m_glyph_data_in_use; /* True if m_glyph_data is already in use. */
69 FT_Incremental_MetricsRec m_glyph_metrics; /* Incremental glyph metrics supplied by GhostScript. */
70 unsigned long m_glyph_metrics_index; /* m_glyph_metrics contains data for this glyph index unless it is 0xFFFFFFFF. */
71 FAPI_metrics_type m_metrics_type; /* The metrics type determines whether metrics are replaced, added, etc. */
72 } FT_IncrementalRec;
73
new_face(FT_Face a_ft_face,FT_Incremental_InterfaceRec * a_ft_inc_int,unsigned char * a_font_data)74 static FF_face* new_face(FT_Face a_ft_face,FT_Incremental_InterfaceRec* a_ft_inc_int,
75 unsigned char* a_font_data)
76 {
77 FF_face* face = (FF_face *)malloc(sizeof(FF_face));
78 if (face)
79 {
80 face->m_ft_face = a_ft_face;
81 face->m_ft_inc_int = a_ft_inc_int;
82 face->m_font_data = a_font_data;
83 }
84 return face;
85 }
86
delete_face(FF_face * a_face)87 static void delete_face(FF_face* a_face)
88 {
89 if (a_face)
90 {
91 FT_Done_Face(a_face->m_ft_face);
92 free(a_face->m_ft_inc_int);
93 free(a_face->m_font_data);
94 free(a_face);
95 }
96 }
97
new_inc_int_info(FAPI_font * a_fapi_font)98 static FT_IncrementalRec* new_inc_int_info(FAPI_font* a_fapi_font)
99 {
100 FT_IncrementalRec* info = (FT_IncrementalRec*)malloc(sizeof(FT_IncrementalRec));
101 if (info)
102 {
103 info->m_fapi_font = a_fapi_font;
104 info->m_glyph_data = NULL;
105 info->m_glyph_data_length = 0;
106 info->m_glyph_data_in_use = false;
107 info->m_glyph_metrics_index = 0xFFFFFFFF;
108 info->m_metrics_type = FAPI_METRICS_NOTDEF;
109 }
110 return info;
111 }
112
delete_inc_int_info(FT_IncrementalRec * a_inc_int_info)113 static void delete_inc_int_info(FT_IncrementalRec* a_inc_int_info)
114 {
115 if (a_inc_int_info)
116 {
117 free(a_inc_int_info->m_glyph_data);
118 free(a_inc_int_info);
119 }
120 }
121
get_fapi_glyph_data(FT_Incremental a_info,FT_UInt a_index,FT_Data * a_data)122 static FT_Error get_fapi_glyph_data(FT_Incremental a_info,FT_UInt a_index,FT_Data* a_data)
123 {
124 FAPI_font* ff = a_info->m_fapi_font;
125 ushort length = 0;
126
127 /* Tell the FAPI interface that we need to decrypt the glyph data. */
128 ff->need_decrypt = true;
129
130 /* If m_glyph_data is already in use (as will happen for composite glyphs) create a new buffer on the heap. */
131 if (a_info->m_glyph_data_in_use)
132 {
133 unsigned char* buffer = NULL;
134 length = ff->get_glyph(ff,a_index,NULL,0);
135 buffer = malloc(length);
136 if (!buffer)
137 return FT_Err_Out_Of_Memory;
138 ff->get_glyph(ff,a_index,buffer,length);
139 a_data->pointer = buffer;
140 }
141 else
142 {
143 /*
144 Save ff->char_data, which is set to null by FAPI_FF_get_glyph as part of a hack to
145 make the deprecated Type 2 endchar ('seac') work, so that it can be restored
146 if we need to try again with a longer buffer.
147 */
148 const void* saved_char_data = ff->char_data;
149
150 /* Get as much of the glyph data as possible into the buffer */
151 length = ff->get_glyph(ff,a_index,a_info->m_glyph_data,(ushort)a_info->m_glyph_data_length);
152
153 /* If the buffer was too small enlarge it and try again. */
154 if (length > a_info->m_glyph_data_length)
155 {
156 a_info->m_glyph_data = realloc(a_info->m_glyph_data,length);
157 if (!a_info->m_glyph_data)
158 {
159 a_info->m_glyph_data_length = 0;
160 return FT_Err_Out_Of_Memory;
161 }
162 a_info->m_glyph_data_length = length;
163 ff->char_data = saved_char_data;
164 ff->get_glyph(ff,a_index,a_info->m_glyph_data,length);
165 }
166
167 /* Set the returned pointer and length. */
168 a_data->pointer = a_info->m_glyph_data;
169
170 a_info->m_glyph_data_in_use = true;
171 }
172
173 a_data->length = length;
174 return 0;
175 }
176
free_fapi_glyph_data(FT_Incremental a_info,FT_Data * a_data)177 static void free_fapi_glyph_data(FT_Incremental a_info,FT_Data* a_data)
178 {
179 if (a_data->pointer == (const FT_Byte*)a_info->m_glyph_data)
180 a_info->m_glyph_data_in_use = false;
181 else
182 free((FT_Byte*)a_data->pointer);
183 }
184
get_fapi_glyph_metrics(FT_Incremental a_info,FT_UInt a_glyph_index,FT_Bool a_vertical,FT_Incremental_MetricsRec * a_metrics)185 static FT_Error get_fapi_glyph_metrics(FT_Incremental a_info,FT_UInt a_glyph_index,
186 FT_Bool a_vertical,FT_Incremental_MetricsRec* a_metrics)
187 {
188 if (a_info->m_glyph_metrics_index == a_glyph_index)
189 {
190 switch (a_info->m_metrics_type)
191 {
192 case FAPI_METRICS_ADD:
193 a_metrics->advance += a_info->m_glyph_metrics.advance;
194 break;
195 case FAPI_METRICS_REPLACE_WIDTH:
196 a_metrics->advance = a_info->m_glyph_metrics.advance;
197 break;
198 case FAPI_METRICS_REPLACE:
199 *a_metrics = a_info->m_glyph_metrics;
200 break;
201 default:
202 assert(false); /* This can't happen. */
203 break;
204 }
205 }
206 return 0;
207 }
208
209 static const FT_Incremental_FuncsRec TheFAPIIncrementalInterfaceFuncs =
210 {
211 get_fapi_glyph_data,
212 free_fapi_glyph_data,
213 get_fapi_glyph_metrics
214 };
215
new_inc_int(FAPI_font * a_fapi_font)216 static FT_Incremental_InterfaceRec* new_inc_int(FAPI_font* a_fapi_font)
217 {
218 FT_Incremental_InterfaceRec* i = (FT_Incremental_InterfaceRec*)malloc(sizeof(FT_Incremental_InterfaceRec));
219 if (i)
220 {
221 i->object = (FT_Incremental)new_inc_int_info(a_fapi_font);
222 i->funcs = &TheFAPIIncrementalInterfaceFuncs;
223 }
224 if (!i->object)
225 {
226 free(i);
227 i = NULL;
228 }
229 return i;
230 }
231
delete_inc_int(FT_Incremental_InterfaceRec * a_inc_int)232 static void delete_inc_int(FT_Incremental_InterfaceRec* a_inc_int)
233 {
234 if (a_inc_int)
235 {
236 delete_inc_int_info(a_inc_int->object);
237 free(a_inc_int);
238 }
239 }
240
241 /*
242 Convert FreeType error codes to GhostScript ones.
243 Very rudimentary because most don't correspond.
244 */
ft_to_gs_error(FT_Error a_error)245 static int ft_to_gs_error(FT_Error a_error)
246 {
247 if (a_error)
248 {
249 if (a_error == FT_Err_Out_Of_Memory)
250 return e_VMerror;
251 else
252 return e_unknownerror;
253 }
254 return 0;
255 }
256
257 /*
258 Load a glyph and optionally rasterize it. Return its metrics in a_metrics.
259 If a_bitmap is true convert the glyph to a bitmap.
260 */
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)261 static FAPI_retcode load_glyph(FAPI_font* a_fapi_font,const FAPI_char_ref *a_char_ref,
262 FAPI_metrics* a_metrics,FT_Glyph* a_glyph,bool a_bitmap)
263 {
264 FT_Error ft_error = 0;
265 FF_face* face = (FF_face*)a_fapi_font->server_font_data;
266 FT_Face ft_face = face->m_ft_face;
267 int index = a_char_ref->char_code;
268
269 /*
270 Save a_fapi_font->char_data, which is set to null by FAPI_FF_get_glyph as part of a hack to
271 make the deprecated Type 2 endchar ('seac') work, so that it can be restored
272 after the first call to FT_Load_Glyph.
273 */
274 const void* saved_char_data = a_fapi_font->char_data;
275
276 if (!a_char_ref->is_glyph_index)
277 {
278 if (ft_face->num_charmaps)
279 index = FT_Get_Char_Index(ft_face,index);
280 else
281 /*
282 If there are no character maps and no glyph index, loading the glyph will still work
283 properly if both glyph data and metrics are supplied by the incremental interface.
284 In that case we use a dummy glyph index which will be passed
285 back to FAPI_FF_get_glyph by get_fapi_glyph_data.
286
287 */
288 {
289 /*
290 Type 1 fonts don't use the code and can appear to FreeType to have only one glyph,
291 so we have to set the index to 0.
292 */
293 if (a_fapi_font->is_type1)
294 index = 0;
295 /*
296 For other font types, FAPI_FF_get_glyph requires the character code when getting
297 data.
298 */
299 else
300 index = a_char_ref->char_code;
301 }
302 }
303
304 /* Refresh the pointer to the FAPI_font held by the incremental interface. */
305 if (face->m_ft_inc_int)
306 face->m_ft_inc_int->object->m_fapi_font = a_fapi_font;
307
308 /* Store the overriding metrics if they have been supplied. */
309 if (face->m_ft_inc_int && a_char_ref->metrics_type != FAPI_METRICS_NOTDEF)
310 {
311 FT_Incremental_MetricsRec* m = &face->m_ft_inc_int->object->m_glyph_metrics;
312 m->bearing_x = a_char_ref->sb_x >> 16;
313 m->bearing_y = a_char_ref->sb_y >> 16;
314 m->advance = a_char_ref->aw_x >> 16;
315 face->m_ft_inc_int->object->m_glyph_metrics_index = index;
316 face->m_ft_inc_int->object->m_metrics_type = a_char_ref->metrics_type;
317 }
318
319 ft_error = FT_Load_Glyph(ft_face,index,FT_LOAD_MONOCHROME | FT_LOAD_NO_SCALE);
320 if (!ft_error && a_metrics)
321 {
322 a_metrics->bbox_x0 = ft_face->glyph->metrics.horiBearingX;
323 a_metrics->bbox_y0 = ft_face->glyph->metrics.horiBearingY - ft_face->glyph->metrics.height;
324 a_metrics->bbox_x1 = a_metrics->bbox_x0 + ft_face->glyph->metrics.width;
325 a_metrics->bbox_y1 = a_metrics->bbox_y0 + ft_face->glyph->metrics.height;
326 a_metrics->escapement = ft_face->glyph->metrics.horiAdvance;
327 a_metrics->em_x = ft_face->units_per_EM;
328 a_metrics->em_y = ft_face->units_per_EM;
329 }
330
331 /* We have to load the glyph again, scale it correctly, and render it if we need a bitmap. */
332 if (!ft_error)
333 {
334 a_fapi_font->char_data = saved_char_data;
335 ft_error = FT_Load_Glyph(ft_face,index,a_bitmap ? FT_LOAD_MONOCHROME | FT_LOAD_RENDER: FT_LOAD_MONOCHROME);
336 }
337 if (!ft_error && a_glyph)
338 ft_error = FT_Get_Glyph(ft_face->glyph,a_glyph);
339 return ft_to_gs_error(ft_error);
340 }
341
342 /**
343 Ensure that the rasterizer is open.
344
345 In the case of FreeType this means creating the FreeType library object.
346 */
ensure_open(FAPI_server * a_server)347 static FAPI_retcode ensure_open(FAPI_server* a_server)
348 {
349 FF_server* s = (FF_server*)a_server;
350 if (!s->m_freetype_library)
351 {
352 FT_Error ft_error = FT_Init_FreeType(&s->m_freetype_library);
353 if (ft_error)
354 return ft_to_gs_error(ft_error);
355 }
356 return 0;
357 }
358
transform_concat(FT_Matrix * a_A,const FT_Matrix * a_B)359 static void transform_concat(FT_Matrix* a_A,const FT_Matrix* a_B)
360 {
361 FT_Matrix result = *a_B;
362 FT_Matrix_Multiply(a_A,&result);
363 *a_A = result;
364 }
365
366 /** Create a transform representing an angle defined as a vector. */
make_rotation(FT_Matrix * a_transform,const FT_Vector * a_vector)367 static void make_rotation(FT_Matrix* a_transform,const FT_Vector* a_vector)
368 {
369 FT_Fixed length, cos, sin;
370 if (a_vector->x >= 0 && a_vector->y == 0)
371 {
372 a_transform->xx = a_transform->yy = 65536;
373 a_transform->xy = a_transform->yx = 0;
374 return;
375 }
376
377 length = FT_Vector_Length((FT_Vector*)a_vector);
378 cos = FT_DivFix(a_vector->x,length);
379 sin = FT_DivFix(a_vector->y,length);
380 a_transform->xx = a_transform->yy = cos;
381 a_transform->xy = -sin;
382 a_transform->yx = sin;
383 }
384
385 /**
386 Divide a transformation into a scaling part and a rotation-and-shear part.
387 The scaling part is used for setting the pixel size for hinting.
388 */
transform_decompose(FT_Matrix * a_transform,FT_Fixed * a_x_scale,FT_Fixed * a_y_scale)389 static void transform_decompose(FT_Matrix* a_transform,
390 FT_Fixed* a_x_scale,FT_Fixed* a_y_scale)
391 {
392 FT_Matrix rotation;
393 bool have_rotation = false;
394 FT_Vector v;
395
396 /*
397 Set v to the result of applying the matrix to the (1,0) vector
398 and reverse the direction of rotation by negating the y coordinate.
399 */
400 v.x = a_transform->xx;
401 v.y = -a_transform->yx;
402 if (v.y || v.x < 0)
403 {
404 have_rotation = true;
405
406 /* Get the inverse of the rotation. */
407 make_rotation(&rotation,&v);
408
409 /* Remove the rotation. */
410 transform_concat(a_transform,&rotation);
411 }
412
413 /* Separate the scales from the transform. */
414 *a_x_scale = a_transform->xx;
415 if (*a_x_scale < 0)
416 {
417 *a_x_scale = -*a_x_scale;
418 a_transform->xx = -65536;
419 }
420 else
421 a_transform->xx = 65536;
422 *a_y_scale = a_transform->yy;
423 if (*a_y_scale < 0)
424 {
425 *a_y_scale = -*a_y_scale;
426 a_transform->yy = -65536;
427 }
428 else
429 a_transform->yy = 65536;
430 a_transform->yx = FT_DivFix(a_transform->yx,*a_x_scale);
431 a_transform->xy = FT_DivFix(a_transform->xy,*a_y_scale);
432
433 if (have_rotation)
434 {
435 /* Add back the rotation. */
436 rotation.xy = -rotation.xy;
437 rotation.yx = -rotation.yx;
438 transform_concat(a_transform,&rotation);
439 }
440 }
441
442 /**
443 Open a font and set its size.
444 */
get_scaled_font(FAPI_server * a_server,FAPI_font * a_font,int a_subfont,const FAPI_font_scale * a_font_scale,const char * a_map,bool a_vertical,FAPI_descendant_code a_descendant_code)445 static FAPI_retcode get_scaled_font(FAPI_server* a_server,FAPI_font* a_font,int a_subfont,
446 const FAPI_font_scale* a_font_scale,
447 const char* a_map,bool a_vertical,
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_subfont=%d 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_subfont,a_descendant_code); */
456
457 /*
458 If this font is the top level font of an embedded CID type 0 font (font type 9)
459 do nothing. See the comment in FAPI_prepare_font. The descendant fonts are
460 passed in individually.
461 */
462 if (a_font->is_cid && a_font->is_type1 && a_font->font_file_path == NULL &&
463 (a_descendant_code == FAPI_TOPLEVEL_BEGIN ||
464 a_descendant_code == FAPI_TOPLEVEL_COMPLETE))
465 {
466 /* dpf("get_scaled_font return 0\n"); */
467 return 0;
468 }
469
470 /* Create the face if it doesn't already exist. */
471 if (!face)
472 {
473 FT_Face ft_face = NULL;
474 FT_Parameter ft_param;
475 FT_Incremental_InterfaceRec* ft_inc_int = NULL;
476 unsigned char* own_font_data = NULL;
477
478 /* dpf("get_scaled_font creating face\n"); */
479
480 /* Load a typeface from a file. */
481 if (a_font->font_file_path)
482 {
483 ft_error = FT_New_Face(s->m_freetype_library,a_font->font_file_path,a_subfont,&ft_face);
484 if (!ft_error && ft_face)
485 ft_error = FT_Select_Charmap(ft_face,ft_encoding_unicode);
486 }
487
488 /* Load a typeface from a representation in GhostScript's memory. */
489 else
490 {
491 FT_Open_Args open_args;
492 open_args.flags = FT_OPEN_MEMORY;
493
494 if (a_font->is_type1)
495 {
496 long length;
497 int type = a_font->get_word(a_font,FAPI_FONT_FEATURE_FontType,0);
498
499 /* Tell the FAPI interface that we need to decrypt the /Subrs data. */
500 a_font->need_decrypt = true;
501
502 /*
503 Serialise a type 1 font in PostScript source form, or
504 a Type 2 font in binary form, so that FreeType can read it.
505 */
506 if (type == 1)
507 length = FF_serialize_type1_font(a_font,NULL,0);
508 else
509 length = FF_serialize_type2_font(a_font,NULL,0);
510 open_args.memory_base = own_font_data = malloc(length);
511 if (!open_args.memory_base)
512 return e_VMerror;
513 if (type == 1)
514 open_args.memory_size = FF_serialize_type1_font(a_font,own_font_data,length);
515 else
516 open_args.memory_size = FF_serialize_type2_font(a_font,own_font_data,length);
517 assert(open_args.memory_size == length);
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->m_freetype_library,&open_args,a_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 /*
578 Set the point size and transformation.
579 The matrix is scaled by the shift specified in the server, 16,
580 so we divide by 65536 when converting to a gs_matrix.
581 */
582 if (face)
583 {
584 static const FT_Matrix ft_reflection = { 65536, 0, 0, -65536 };
585 FT_Matrix ft_transform;
586 FT_F26Dot6 width, height;
587
588 /*
589 Convert the GS transform into an FT transform.
590 Ignore the translation elements because they contain very large values
591 derived from the current transformation matrix and so are of no use.
592 */
593 ft_transform.xx = a_font_scale->matrix[0];
594 ft_transform.xy = a_font_scale->matrix[1];
595 ft_transform.yx = -a_font_scale->matrix[2];
596 ft_transform.yy = -a_font_scale->matrix[3];
597
598 /*
599 Split the transform into scale factors and a rotation-and-shear
600 transform.
601 */
602 transform_decompose(&ft_transform,&width,&height);
603
604 /* Convert width and height to 64ths of pixels and set the FreeType sizes. */
605 width >>= 10;
606 height >>= 10;
607 ft_error = FT_Set_Char_Size(face->m_ft_face,width,height,
608 a_font_scale->HWResolution[0] >> 16,
609 a_font_scale->HWResolution[1] >> 16);
610 if (ft_error)
611 {
612 delete_face(face);
613 a_font->server_font_data = NULL;
614 return ft_to_gs_error(ft_error);
615 }
616
617 /*
618 Concatenate the transform to a reflection around (y=0) so that it
619 produces a glyph that is upside down in FreeType terms, with its
620 first row at the bottom. That is what GhostScript needs.
621 */
622 FT_Matrix_Multiply(&ft_reflection,&ft_transform);
623
624 FT_Set_Transform(face->m_ft_face,&ft_transform,NULL);
625 }
626
627 /* dpf("get_scaled_font return %d\n",a_font->server_font_data ? 0 : -1); */
628 return a_font->server_font_data ? 0 : -1;
629 }
630
631 /**
632 Return the name of a resource which maps names to character codes. Do this by setting a_decoding_id
633 to point to a null-terminated string. The resource is in the 'decoding' directory in the directory named by
634 /GenericResourceDir in \lib\gs_res.ps.
635 */
get_decodingID(FAPI_server * a_server,FAPI_font * a_font,const char ** a_decoding_id)636 static FAPI_retcode get_decodingID(FAPI_server* a_server,FAPI_font* a_font,const char** a_decoding_id)
637 {
638 *a_decoding_id = "Unicode";
639 return 0;
640 }
641
642 /**
643 Get the font bounding box in font units.
644 */
get_font_bbox(FAPI_server * a_server,FAPI_font * a_font,int a_box[4])645 static FAPI_retcode get_font_bbox(FAPI_server* a_server,FAPI_font* a_font,int a_box[4])
646 {
647 FF_face* face = (FF_face*)a_font->server_font_data;
648 a_box[0] = face->m_ft_face->bbox.xMin;
649 a_box[1] = face->m_ft_face->bbox.yMin;
650 a_box[2] = face->m_ft_face->bbox.xMax;
651 a_box[3] = face->m_ft_face->bbox.yMax;
652 return 0;
653 }
654
655 /**
656 Return a boolean value in a_proportional stating whether the font is proportional
657 or fixed-width.
658 */
get_font_proportional_feature(FAPI_server * a_server,FAPI_font * a_font,int a_subfont,bool * a_proportional)659 static FAPI_retcode get_font_proportional_feature(FAPI_server* a_server,FAPI_font* a_font,int a_subfont,
660 bool* a_proportional)
661 {
662 *a_proportional = true;
663 return 0;
664 }
665
666 /**
667 Convert the character name in a_char_ref.char_name to a character code or glyph index and put it in a_char_ref.char_code,
668 setting a_char_ref.is_glyph_index as appropriate. If this is possible set a_result to true, otherwise set it to false.
669 The return value is a standard error return code.
670 */
can_retrieve_char_by_name(FAPI_server * a_server,FAPI_font * a_font,FAPI_char_ref * a_char_ref,bool * a_result)671 static FAPI_retcode can_retrieve_char_by_name(FAPI_server* a_server,FAPI_font* a_font,FAPI_char_ref* a_char_ref,
672 bool* a_result)
673 {
674 FF_face* face = (FF_face*)a_font->server_font_data;
675 char name[128];
676 if (FT_HAS_GLYPH_NAMES(face->m_ft_face) && a_char_ref->char_name_length < sizeof(name))
677 {
678 memcpy(name,a_char_ref->char_name,a_char_ref->char_name_length);
679 name[a_char_ref->char_name_length] = 0;
680 a_char_ref->char_code = FT_Get_Name_Index(face->m_ft_face,name);
681 *a_result = a_char_ref->char_code != 0;
682 if (*a_result)
683 a_char_ref->is_glyph_index = true;
684 }
685 else
686 *a_result = false;
687 return 0;
688 }
689
690 /**
691 Return non-zero if the metrics can be replaced.
692 */
can_replace_metrics(FAPI_server * a_server,FAPI_font * a_font,FAPI_char_ref * a_char_ref,int * a_result)693 static FAPI_retcode 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 */
get_char_width(FAPI_server * a_server,FAPI_font * a_font,FAPI_char_ref * a_char_ref,FAPI_metrics * a_metrics)703 static FAPI_retcode get_char_width(FAPI_server *a_server,FAPI_font *a_font,FAPI_char_ref *a_char_ref,
704 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 bitmap but store this. It can be retrieved by
711 a subsequent call to get_char_raster.
712 */
get_char_raster_metrics(FAPI_server * a_server,FAPI_font * a_font,FAPI_char_ref * a_char_ref,FAPI_metrics * a_metrics)713 static FAPI_retcode get_char_raster_metrics(FAPI_server* a_server,FAPI_font* a_font,FAPI_char_ref* a_char_ref,
714 FAPI_metrics* a_metrics)
715 {
716 FF_server* s = (FF_server*)a_server;
717 FAPI_retcode error = load_glyph(a_font,a_char_ref,a_metrics,(FT_Glyph*)&s->m_bitmap_glyph,true);
718 return error;
719 }
720
721 /**
722 Return the bitmap created by the last call to get_char_raster_metrics.
723 */
get_char_raster(FAPI_server * a_server,FAPI_raster * a_raster)724 static FAPI_retcode get_char_raster(FAPI_server *a_server,FAPI_raster *a_raster)
725 {
726 FF_server* s = (FF_server*)a_server;
727 assert(s->m_bitmap_glyph);
728 a_raster->p = s->m_bitmap_glyph->bitmap.buffer;
729 a_raster->width = s->m_bitmap_glyph->bitmap.width;
730 a_raster->height = s->m_bitmap_glyph->bitmap.rows;
731 a_raster->line_step = s->m_bitmap_glyph->bitmap.pitch;
732 a_raster->orig_x = s->m_bitmap_glyph->left * 16;
733 a_raster->orig_y = s->m_bitmap_glyph->top * 16;
734 return 0;
735 }
736
737 /**
738 Create an outline for the character a_char and return its metrics. Do not return the outline but store this.
739 It can be retrieved by a subsequent call to get_char_outline.
740 */
get_char_outline_metrics(FAPI_server * a_server,FAPI_font * a_font,FAPI_char_ref * a_char_ref,FAPI_metrics * a_metrics)741 static FAPI_retcode get_char_outline_metrics(FAPI_server *a_server,FAPI_font *a_font,FAPI_char_ref *a_char_ref,
742 FAPI_metrics *a_metrics)
743 {
744 FF_server* s = (FF_server*)a_server;
745 return load_glyph(a_font,a_char_ref,a_metrics,(FT_Glyph*)&s->m_outline_glyph,false);
746 }
747
748 typedef struct FF_path_info_
749 {
750 FAPI_path* m_path;
751 FracInt m_x;
752 FracInt m_y;
753 } FF_path_info;
754
move_to(FT_Vector * aTo,void * aObject)755 static int move_to(FT_Vector* aTo,void* aObject)
756 {
757 FF_path_info* p = (FF_path_info*)aObject;
758 p->m_x = aTo->x;
759 p->m_y = aTo->y;
760 return p->m_path->moveto(p->m_path,aTo->x,aTo->y) ? -1 : 0;
761 }
762
line_to(FT_Vector * aTo,void * aObject)763 static int line_to(FT_Vector* aTo,void* aObject)
764 {
765 FF_path_info* p = (FF_path_info*)aObject;
766 p->m_x = aTo->x;
767 p->m_y = aTo->y;
768 return p->m_path->lineto(p->m_path,aTo->x,aTo->y) ? -1 : 0;
769 }
770
conic_to(FT_Vector * aControl,FT_Vector * aTo,void * aObject)771 static int conic_to(FT_Vector* aControl,FT_Vector* aTo,void* aObject)
772 {
773 FF_path_info* p = (FF_path_info*)aObject;
774 p->m_x = aTo->x;
775 p->m_y = aTo->y;
776 /*
777 Convert a quadratic spline to a cubic. Do this by changing the three points
778 A, B and C to A, 1/3(B,A), 1/3(B,C), C - that is, the two cubic control points are
779 a third of the way from the single quadratic control point to the end points. This
780 gives the same curve as the original quadratic.
781 */
782 return p->m_path->curveto(p->m_path,(p->m_x + aControl->x * 2) / 3,
783 (p->m_y + aControl->y * 2) / 3,
784 (aTo->x + aControl->x * 2) / 3,
785 (aTo->y + aControl->y * 2) / 3,
786 aTo->x,aTo->y) ? -1 : 0;
787 }
788
cubic_to(FT_Vector * aControl1,FT_Vector * aControl2,FT_Vector * aTo,void * aObject)789 static int cubic_to(FT_Vector* aControl1,FT_Vector* aControl2,FT_Vector* aTo,void* aObject)
790 {
791 FF_path_info* p = (FF_path_info*)aObject;
792 p->m_x = aTo->x;
793 p->m_y = aTo->y;
794 return p->m_path->curveto(p->m_path,aControl1->x,aControl1->y,aControl2->x,aControl2->y,aTo->x,aTo->y) ? -1 : 0;
795 }
796
797 static const FT_Outline_Funcs TheFtOutlineFuncs =
798 {
799 move_to,
800 line_to,
801 conic_to,
802 cubic_to,
803 0,
804 0
805 };
806
807 /**
808 Return the outline created by the last call to get_char_outline_metrics.
809 */
get_char_outline(FAPI_server * a_server,FAPI_path * a_path)810 static FAPI_retcode get_char_outline(FAPI_server *a_server,FAPI_path *a_path)
811 {
812 FF_server* s = (FF_server*)a_server;
813 FF_path_info p;
814 FT_Error ft_error = 0;
815 p.m_path = a_path;
816 p.m_x = 0;
817 p.m_y = 0;
818 ft_error = FT_Outline_Decompose(&s->m_outline_glyph->outline,&TheFtOutlineFuncs,&p);
819 a_path->closepath(a_path);
820 return ft_to_gs_error(ft_error);
821 }
822
release_char_data(FAPI_server * a_server)823 static FAPI_retcode release_char_data(FAPI_server *a_server)
824 {
825 FF_server* s = (FF_server*)a_server;
826 FT_Done_Glyph(&s->m_outline_glyph->root);
827 FT_Done_Glyph(&s->m_bitmap_glyph->root);
828 s->m_outline_glyph = NULL;
829 s->m_bitmap_glyph = NULL;
830 return 0;
831 }
832
release_typeface(FAPI_server * a_server,void * a_server_font_data)833 static FAPI_retcode release_typeface(FAPI_server* a_server,void* a_server_font_data)
834 {
835 FF_face* face = (FF_face*)a_server_font_data;
836 delete_face(face);
837 return 0;
838 }
839
840 static void gs_freetype_destroy(i_plugin_instance* a_instance,i_plugin_client_memory* a_memory);
841
842 static const i_plugin_descriptor TheFreeTypeDescriptor =
843 {
844 "FAPI",
845 "FreeType",
846 gs_freetype_destroy
847 };
848
849 static const FAPI_server TheFreeTypeServer =
850 {
851 { &TheFreeTypeDescriptor },
852 16, /* frac_shift */
853 ensure_open,
854 get_scaled_font,
855 get_decodingID,
856 get_font_bbox,
857 get_font_proportional_feature,
858 can_retrieve_char_by_name,
859 can_replace_metrics,
860 get_char_width,
861 get_char_raster_metrics,
862 get_char_raster,
863 get_char_outline_metrics,
864 get_char_outline,
865 release_char_data,
866 release_typeface
867 };
868
869 plugin_instantiation_proc(gs_fapi_ft_instantiate);
870
gs_fapi_ft_instantiate(i_ctx_t * a_context,i_plugin_client_memory * a_memory,i_plugin_instance ** a_plugin_instance)871 int gs_fapi_ft_instantiate(i_ctx_t *a_context,
872 i_plugin_client_memory *a_memory,
873 i_plugin_instance **a_plugin_instance)
874 {
875 FF_server *server = (FF_server *)a_memory->alloc(a_memory,
876 sizeof(FF_server),"FF_server");
877 if (!server)
878 return e_VMerror;
879 memset(server,0,sizeof(*server));
880 server->m_fapi_server = TheFreeTypeServer;
881 *a_plugin_instance = &server->m_fapi_server.ig;
882 return 0;
883 }
884
gs_freetype_destroy(i_plugin_instance * a_plugin_instance,i_plugin_client_memory * a_memory)885 static void gs_freetype_destroy(i_plugin_instance *a_plugin_instance,i_plugin_client_memory *a_memory)
886 {
887 FF_server *server = (FF_server *)a_plugin_instance;
888 assert(server->m_fapi_server.ig.d == &TheFreeTypeDescriptor);
889 FT_Done_Glyph(&server->m_outline_glyph->root);
890 FT_Done_Glyph(&server->m_bitmap_glyph->root);
891 FT_Done_FreeType(server->m_freetype_library);
892 a_memory->free(a_memory,server,"FF_server");
893 }
894