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