1 /****************************************************************************
2  *
3  *  Copyright (C) 2005-2006 "Stuart R. Anderson" <anderson@netsweng.com>
4  *  Copyright (C) 2007 Klaus Rechert
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  ****************************************************************************/
21 #include "ming_config.h"
22 #if USE_FREETYPE
23 #include <assert.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <sys/types.h>
29 
30 #include <ft2build.h>
31 #include FT_FREETYPE_H
32 #include FT_GLYPH_H
33 #include FT_SFNT_NAMES_H
34 #include FT_TRUETYPE_IDS_H
35 #include FT_OUTLINE_H
36 
37 // Methods of FT_Outline_Funcs take a 'const FT_Vector*' in 2.2
38 // and a non-const one in 2.1, so we use an FT_CONST macro to
39 // support both
40 #if FREETYPE_MAJOR == 2 && FREETYPE_MINOR < 2
41 #define FT_CONST
42 #else
43 #define FT_CONST const
44 #endif
45 
46 #include "shape.h"
47 #include "font.h"
48 
49 struct outl_data
50 {
51 	SWFShape shape;
52 	double ratio_EM;
53 };
54 
55 static int
outl_moveto(FT_CONST FT_Vector * to,void * user)56 outl_moveto(FT_CONST FT_Vector *to, void *user)
57 {
58 	struct outl_data *data = (struct outl_data *)user;
59 	SWFShape shape = data->shape;
60 	double ratio_EM = data->ratio_EM;
61 
62 	int dx = (int)(to->x*ratio_EM);
63 	int dy = -(int)(to->y*ratio_EM);
64 
65 	SWFShape_moveScaledPenTo(shape, dx, dy);
66 
67 	return 0;
68 }
69 
70 static int
outl_lineto(FT_CONST FT_Vector * to,void * user)71 outl_lineto(FT_CONST FT_Vector *to, void *user)
72 {
73 	struct outl_data *data = (struct outl_data *)user;
74 	SWFShape shape = data->shape;
75 	double ratio_EM = data->ratio_EM;
76 
77 	int x = (int)(to->x*ratio_EM);
78 	int y = -(int)(to->y*ratio_EM);
79 
80 	SWFShape_drawScaledLineTo(shape, x, y);
81 	return 0;
82 }
83 
84 static int
outl_conicto(FT_CONST FT_Vector * ctl,FT_CONST FT_Vector * to,void * user)85 outl_conicto(FT_CONST FT_Vector *ctl, FT_CONST FT_Vector *to, void *user)
86 {
87 	struct outl_data *data = (struct outl_data *)user;
88 	SWFShape shape = data->shape;
89 	double ratio_EM = data->ratio_EM;
90 
91 	int cx = (int)(ctl->x*ratio_EM);
92 	int cy = -(int)(ctl->y*ratio_EM);
93 	int ax = (int)(to->x*ratio_EM);
94 	int ay = -(int)(to->y*ratio_EM);
95 
96 	SWFShape_drawScaledCurveTo(shape, cx, cy, ax, ay);
97 
98 	return 0;
99 }
100 
101 static int
outl_cubicto(FT_CONST FT_Vector * ctl1,FT_CONST FT_Vector * ctl2,FT_CONST FT_Vector * to,void * user)102 outl_cubicto(FT_CONST FT_Vector *ctl1, FT_CONST FT_Vector *ctl2,
103              FT_CONST FT_Vector *to, void *user)
104 {
105 	FT_Vector midpnt;
106 	int cx, cy, ax, ay;
107 	struct outl_data *data = (struct outl_data *)user;
108 	SWFShape shape = data->shape;
109 	double ratio_EM = data->ratio_EM;
110 
111 	/* This is handled by breaking the cubic into 2 conic segments */
112 	midpnt.x=(ctl1->x+ctl2->x)/2;
113 	midpnt.y=(ctl1->y+ctl2->y)/2;
114 
115 	/* First half */
116 	cx = (int)(ctl1->x*ratio_EM);
117 	cy = -(int)(ctl1->y*ratio_EM);
118 	ax = (int)(midpnt.x*ratio_EM);
119 	ay = -(int)(midpnt.y*ratio_EM);
120 	SWFShape_drawScaledCurveTo(shape, cx, cy, ax, ay);
121 
122 	/* Second half */
123 	cx = (int)(ctl2->x*ratio_EM);
124 	cy = -(int)(ctl2->y*ratio_EM);
125 	ax = (int)(to->x*ratio_EM);
126 	ay = -(int)(to->y*ratio_EM);
127 	SWFShape_drawScaledCurveTo(shape, cx, cy, ax, ay);
128 	return 0;
129 }
130 
131 static FT_Outline_Funcs ft_outl_funcs = {
132 	outl_moveto,
133 	outl_lineto,
134 	outl_conicto,
135 	outl_cubicto,
136 	0,
137 	0
138 };
139 
140 
readGlyphs(SWFFont font,FT_Face face)141 static void readGlyphs(SWFFont font, FT_Face face)
142 {
143 	int glyphCount = 0;
144 	FT_UInt gindex;
145 	FT_ULong charcode;
146 	double ratio_EM = 1024.0 / face->units_per_EM;
147 
148 	int msize = face->num_glyphs + 20; /* +20 to avoid realloc in most cases */
149 	font->shapes = (SWFShape *)malloc(sizeof(SWFShape) * msize);
150 	font->advances = (short *)malloc(sizeof(short) * msize);
151 	font->glyphToCode = (unsigned short *)malloc(sizeof(unsigned short) * msize);
152 
153 	charcode = FT_Get_First_Char(face, &gindex );
154 	while ( gindex != 0 )
155 	{
156 		struct outl_data data;
157 		if( FT_Load_Glyph(face, gindex, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE))
158 		{
159 			SWF_warn("readGlyphsTTF: Can't load glyph %d, skipped\n", gindex);
160 			charcode = FT_Get_Next_Char(face, charcode, &gindex);
161 			continue;
162 		}
163 
164 		data.shape = newSWFGlyphShape();
165 		data.ratio_EM = ratio_EM;
166 		if(FT_Outline_Decompose(&(face->glyph->outline),
167 			&ft_outl_funcs, &data))
168 		{
169 			SWF_warn("readGlyphsTTF: Can't decompose outline for glyph %d\n", gindex);
170 			destroySWFShape(data.shape);
171 			charcode = FT_Get_Next_Char(face, charcode, &gindex);
172 			continue;
173 		}
174 
175 		/*
176 		 * reallocate the arrays to make space for reused glyphs
177 		 * TODO: avoid the duplication of glyphs instead!
178 		 */
179 		if ( glyphCount >= msize )
180 		{
181 			msize += 128;
182 			font->shapes = (SWFShape *)realloc(font->shapes, sizeof(SWFShape) * msize);
183 			font->advances = (short *)realloc(font->advances, sizeof(short) * msize);
184 			font->glyphToCode = (unsigned short *)realloc(font->glyphToCode,
185 				sizeof(unsigned short) * msize);
186 		}
187 		font->shapes[glyphCount] = data.shape;
188 		font->glyphToCode[glyphCount] = charcode;
189 		font->advances[glyphCount] = (short)(face->glyph->advance.x * ratio_EM);
190 		if(charcode > 255)
191 			font->flags |= SWF_FONT_WIDECODES;
192 		charcode = FT_Get_Next_Char(face, charcode, &gindex);
193 		glyphCount++;
194 	}
195 	font->nGlyphs = glyphCount;
196 
197 	if(font->nGlyphs > 255) // XXX: very simple estimation right now
198 		font->flags |=  SWF_FONT_WIDEOFFSETS;
199 }
200 
loadFontFromFace(FT_Face face)201 static SWFFont loadFontFromFace(FT_Face face)
202 {
203 	// FT_CharMap charmap = NULL;
204 	SWFFont font;
205 	double ratio_EM;
206 
207 	/*
208 	for(i=0; i < face->num_charmaps; i++)
209 	{
210 		printf("map %d encoding pid=%d eid=%d\n", i,
211 			face->charmaps[i]->platform_id,
212 			face->charmaps[i]->encoding_id);
213 		if( face->charmaps[i]->platform_id == TT_PLATFORM_MACINTOSH &&
214 			face->charmaps[i]->encoding_id == TT_MAC_ID_ROMAN )
215 		{
216 			charmap = face->charmaps[i];
217 			break;
218 		}
219 	}
220 
221 	if( charmap == NULL )
222 	{
223 		SWF_warn("loadSWFFontTTF: Unable to find an ANSI charactermap.");
224 		goto error_face;
225 	}
226 	FT_Set_Charmap(face, charmap);
227 	*/
228 
229 	font = newSWFFont();
230 	font->flags = SWF_FONT_WIDECODES | SWF_FONT_HASLAYOUT;
231 	font->name = strdup(face->family_name);
232 	font->langCode = 0;
233 
234 	if( face->style_flags & FT_STYLE_FLAG_BOLD)
235 		font->flags |= SWF_FONT_ISBOLD ;
236 
237 	if( face->style_flags & FT_STYLE_FLAG_ITALIC )
238 		font->flags |= SWF_FONT_ISITALIC;
239 
240 	readGlyphs(font, face);
241 
242 	ratio_EM = 1024.0 / face->units_per_EM;
243 	font->ascent = (short)(face->ascender * ratio_EM);
244 	font->descent = (short)(face->descender * -ratio_EM);
245 	font->leading = ((face->height-face->ascender + face->descender) * ratio_EM);
246 
247 	SWFFont_buildReverseMapping(font);
248 	return font;
249 }
250 
loadTTFCollection(const char * filename)251 SWFFontCollection loadTTFCollection(const char *filename)
252 {
253 	FT_Error error;
254 	FT_Library library;
255 	FT_Face face;
256 	int numFaces, i;
257 	SWFFontCollection collection;
258 	SWFFont font;
259 
260 	if( FT_Init_FreeType( &library ) ) {
261 		SWF_warn("loadSWFFontTTF: FreeType initialization failed\n");
262 		return NULL;
263 	}
264 
265 	if( (error = FT_New_Face(library, filename, 0, &face )) )
266 	{
267 		if ( error == FT_Err_Unknown_File_Format )
268 			SWF_warn("loadTTFCollection: %s has format unknown to FreeType\n",
269 				filename);
270 		else
271 			SWF_warn("loadTTFCollection: Cannot access %s ****\n", filename);
272 		goto error_ft;
273 	}
274 	numFaces = face->num_faces;
275 	collection = newSWFFontCollection();
276 
277 	font = loadFontFromFace(face);
278 	SWFFontCollection_addFont(collection, font);
279 
280 	for(i = 1; i < numFaces; i++)
281 	{
282 		if((error = FT_New_Face(library, filename, i, &face )))
283 			goto error_ft;
284 		font = loadFontFromFace(face);
285 		SWFFontCollection_addFont(collection, font);
286 	}
287 	return collection;
288 
289 error_ft:
290 	FT_Done_FreeType(library);
291 	return NULL;
292 }
293 
loadSWFFontTTF(const char * filename)294 SWFFont loadSWFFontTTF(const char *filename)
295 {
296 	FT_Error error;
297 	FT_Library library;
298 	FT_Face face;
299 	SWFFont font;
300 
301 	if( FT_Init_FreeType( &library ) ) {
302 		SWF_warn("loadSWFFontTTF: FreeType initialization failed\n");
303 		return NULL;
304 	}
305 
306 	if( (error = FT_New_Face( library, filename, 0, &face )) )
307 	{
308 		if ( error == FT_Err_Unknown_File_Format )
309 			SWF_warn("loadSWFFontTTF: %s has format unknown to FreeType\n",
310 				filename);
311 		else
312 			SWF_warn("loadSWFFontTTF: Cannot access %s ****\n", filename);
313 		goto error_ft;
314 	}
315 
316 	font = loadFontFromFace(face);
317 	FT_Done_Face(face);
318 	FT_Done_FreeType(library);
319 	return font;
320 
321 error_ft:
322 	FT_Done_FreeType(library);
323 	return NULL;
324 }
325 #endif // USE_FREETYPE
326