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