xref: /plan9/sys/src/cmd/gs/src/fapi_ft.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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