several small fixes in polygon code
[swftools.git] / lib / gfxfont.c
blobb040a7dc567fe14c9dc40a8f4f77641d5aaf2840
1 /* swffont.c
3 Functions for loading external fonts.
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2003, 2004, 2005 Matthias Kramm
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
24 #include "../config.h"
25 #include "gfxdevice.h"
26 #include "gfxtools.h"
27 #include "gfxfont.h"
29 static int loadfont_scale = 64;
30 static int full_unicode = 1;
32 #ifdef HAVE_FREETYPE
34 #ifdef HAVE_FT2BUILD_H
35 #include <ft2build.h>
36 #include FT_FREETYPE_H
37 #include FT_GLYPH_H
38 #include FT_SIZES_H
39 #include FT_SFNT_NAMES_H
40 #include FT_TRUETYPE_IDS_H
41 #include FT_OUTLINE_H
42 #else
43 #include <freetype/freetype.h>
44 #include <freetype/ftglyph.h>
45 #include <freetype/ftsizes.h>
46 #include <freetype/ftsnames.h>
47 #include <freetype/ttnameid.h>
48 #include <freetype/ftoutln.h>
49 #endif
51 /* Setting subpixels to 64 also means that the "point size" of the
52 font outlines will be 64. So the font, when rendered at original
53 size (i.e., the swf fontsize is 1024) will have the same size as
54 if it was rendered at 64pt */
56 #define FT_SCALE 1
57 #define FT_SUBPIXELS 64
59 typedef struct _gfxdrawinfo_t {
60 gfxdrawer_t* draw;
61 double quality;
62 } gfxdrawinfo_t;
64 static int ft_move_to(const FT_Vector* _to, void* user)
66 gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
67 gfxdrawer_t* draw = info->draw;
68 double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
69 double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
70 draw->moveTo(draw, x,y);
71 return 0;
73 static int ft_line_to(const FT_Vector* _to, void* user)
75 gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
76 gfxdrawer_t* draw = info->draw;
77 double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
78 double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
79 draw->lineTo(draw, x,y);
80 return 0;
82 static int ft_cubic_to(const FT_Vector* _c1, const FT_Vector* _c2, const FT_Vector* _to, void* user)
84 gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
85 gfxdrawer_t* draw = info->draw;
86 double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
87 double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
88 double c1x = _c1->x*FT_SCALE/(float)FT_SUBPIXELS;
89 double c1y = -_c1->y*FT_SCALE/(float)FT_SUBPIXELS;
90 double c2x = _c2->x*FT_SCALE/(float)FT_SUBPIXELS;
91 double c2y = -_c2->y*FT_SCALE/(float)FT_SUBPIXELS;
92 gfxdraw_cubicTo(draw, c1x, c1y, c2x, c2y, tox, toy, info->quality);
93 return 0;
95 static int ft_conic_to(const FT_Vector* _c, const FT_Vector* _to, void* user)
97 gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
98 gfxdrawer_t* draw = info->draw;
99 double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
100 double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
101 double cx = _c->x*FT_SCALE/(float)FT_SUBPIXELS;
102 double cy = -_c->y*FT_SCALE/(float)FT_SUBPIXELS;
103 gfxdraw_conicTo(draw, cx,cy, tox,toy, info->quality);
104 return 0;
106 static FT_Outline_Funcs outline_functions =
108 ft_move_to,
109 ft_line_to,
110 ft_conic_to,
111 ft_cubic_to,
115 static FT_Library ftlibrary = 0;
117 static gfxglyph_t cloneGlyph(gfxglyph_t*src)
119 gfxglyph_t dest;
120 memset(&dest, 0, sizeof(dest));
121 if(src->name)
122 dest.name = strdup(src->name);
123 dest.advance = src->advance;
124 dest.unicode = src->unicode;
125 dest.line = gfxline_clone(src->line);
126 return dest;
129 static void glyph_clear(gfxglyph_t*g)
131 gfxline_t*line;
132 if(g->name) {
133 free((void*)g->name); g->name = 0;
135 gfxline_free(g->line);g->line = 0;
138 static int errorno = 0;
140 //#define DEBUG 1
142 gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality)
144 FT_Face face;
145 FT_Error error;
146 const char* fontname = 0;
147 FT_ULong charcode;
148 FT_UInt gindex;
149 gfxfont_t* font;
150 int t;
151 int*glyph2glyph = 0;
152 int*glyph2unicode = 0;
153 int max_unicode = 0;
154 int charmap = -1;
155 int isunicode = 1;
156 int has_had_errors = 0;
157 int num_names = 0;
159 if(ftlibrary == 0) {
160 if(FT_Init_FreeType(&ftlibrary)) {
161 fprintf(stderr, "Couldn't init freetype library!\n");
162 exit(1);
165 error = FT_New_Face(ftlibrary, filename, 0, &face);
166 FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
167 #ifdef DEBUG
168 printf("gfxfont_load(%s, %s, %f)\n", id, filename, quality);
169 #endif
171 if(error) {
172 fprintf(stderr, "Couldn't load file %s- not a TTF file? (error=%02x)\n", filename, error);
173 return 0;
175 if(face->num_glyphs <= 0) {
176 fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
177 return 0;
180 font = (gfxfont_t*)rfx_calloc(sizeof(gfxfont_t));
181 //font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
182 //font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
183 //font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
184 //font->leading = font->layout->ascent + font->layout->descent;
185 //font->encoding = FONT_ENCODING_UNICODE;
186 font->max_unicode = 0;
187 font->id = strdup(id);
189 font->glyphs = (gfxglyph_t*)rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
190 glyph2unicode = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
191 glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
193 if(FT_HAS_GLYPH_NAMES(face)) {
194 //font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
197 fontname = FT_Get_Postscript_Name(face);
199 #ifdef DEBUG
200 for(t=0;t<face->num_charmaps;t++) {
201 printf("possible encoding: %c%c%c%c (%d of %d)\n",
202 (face->charmaps[t]->encoding >> 24)&255,
203 (face->charmaps[t]->encoding >> 16)&255,
204 (face->charmaps[t]->encoding >> 8)&255,
205 (face->charmaps[t]->encoding >> 0)&255,
206 t+1, face->num_charmaps
209 #endif
211 while(1)
213 charcode = FT_Get_First_Char(face, &gindex);
215 while(gindex != 0)
217 if(gindex >= 0 && gindex<face->num_glyphs) {
218 if(!glyph2unicode[gindex]) {
219 glyph2unicode[gindex] = charcode;
220 if(charcode + 1 > font->max_unicode) {
221 font->max_unicode = charcode + 1;
225 charcode = FT_Get_Next_Char(face, charcode, &gindex);
228 #ifdef DEBUG
229 if(face->charmap) {
230 printf("ENCODING: %c%c%c%c (%d of %d) max_unicode=%d\n",
231 (face->charmap->encoding >> 24)&255,
232 (face->charmap->encoding >> 16)&255,
233 (face->charmap->encoding >> 8)&255,
234 (face->charmap->encoding >> 0)&255,
235 charmap, face->num_charmaps, font->max_unicode
237 } else {
238 printf("ENCODING: NONE (%d of %d) max_unicode=%d\n",
239 charmap, face->num_charmaps, font->max_unicode
242 #endif
244 /* if we didn't find a single encoding character, try
245 the font's charmaps instead. That usually means that
246 the encoding is no longer unicode.
247 TODO: find a way to convert the encoding to unicode
249 if(font->max_unicode == 0 && charmap < face->num_charmaps-1
250 && face->charmaps[charmap+1]->encoding != 0x41444243 /* adbc, custom */
251 && face->charmaps[charmap+1]->encoding != 0x61726d6e /* armn */
254 charmap++;
255 FT_Set_Charmap(face, face->charmaps[charmap]);
256 isunicode = 0;
257 } else
258 break;
260 /* TODO: if isunicode is 1, we now need to permutate the character
261 order so that each character is at it's encoding position */
263 if(full_unicode)
264 font->max_unicode = 65535;
266 font->unicode2glyph = (int*)rfx_calloc(font->max_unicode*sizeof(int));
268 for(t=0;t<font->max_unicode;t++) {
269 int g = FT_Get_Char_Index(face, t);
270 if(!g || g>=face->num_glyphs)
271 g = -1;
272 font->unicode2glyph[t] = g;
273 if(g>=0) {
274 #ifdef DEBUG
275 printf("u%d ->%d\n", t, g);
276 #endif
277 max_unicode = t+1;
278 if(!glyph2unicode[g]) {
279 glyph2unicode[g] = t;
283 font->max_unicode = max_unicode;
285 font->num_glyphs = 0;
288 for(t=0; t < face->num_glyphs; t++) {
289 if(FT_HAS_GLYPH_NAMES(face)) {
290 char name[128];
291 error = FT_Get_Glyph_Name(face, t, name, 127);
292 if(!error && name[0] && !strstr(name, "notdef")) {
293 num_names++;
299 for(t=0; t < face->num_glyphs; t++) {
300 FT_Glyph glyph;
301 char name[128];
302 gfxdrawer_t draw;
303 gfxdrawinfo_t info;
304 char hasname = 0;
305 int omit = 0;
306 name[0]=0;
308 font->glyphs[font->num_glyphs].advance = 0;
309 font->glyphs[font->num_glyphs].line = 0;
310 font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
311 font->glyphs[font->num_glyphs].name = 0;
313 if(FT_HAS_GLYPH_NAMES(face) && (num_names >= face->num_glyphs/10 || num_names > 2)) {
314 name[0] = 0;
315 error = FT_Get_Glyph_Name(face, t, name, 127);
316 if(!error && name[0] && !strstr(name, "notdef")) {
317 font->glyphs[font->num_glyphs].name = strdup(name);
318 hasname = 1;
322 #if 0 // some cantonese pdfs fail to work if this is activated
324 if(has_had_errors && (isunicode && !glyph2unicode[t]) && !hasname && t>=256) {
325 /* some freetype versions crash or corrupt memory if we try to load
326 characters (without unicode index or name) above 256 for some fonts.
327 So skip those characters once the first error occured */
328 omit = 1;
330 #endif
332 if(!omit) {
333 error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
334 if(error) {
335 if(hasname)
336 fprintf(stderr, "Warning: glyph %d/%d (unicode %d, name %s) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], name, error);
337 else
338 fprintf(stderr, "Warning: glyph %d/%d (unicode %d) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], error);
339 omit = 2;
341 #if 0
342 if(!has_had_errors) {
343 char buf[256];
344 if(fontname && *fontname) {
345 fprintf(stderr, "font has been copied to %s.ttf\n", fontname);
346 sprintf(buf, "cp %s %s.ttf", filename, fontname);
347 } else {
348 fprintf(stderr, "font has been copied to badfont%d.ttf\n", errorno);
349 sprintf(buf, "cp %s badfont%d.ttf", filename, errorno);
350 errorno++;
352 system(buf);
354 #endif
355 has_had_errors = 1;
358 if(!omit) {
359 error = FT_Get_Glyph(face->glyph, &glyph);
360 if(error) {
361 fprintf(stderr, "Couldn't get glyph %d/%d, error:%d\n", t, face->num_glyphs, error);
362 omit = 3;
366 if(!omit) {
367 gfxline_t*l;
368 int ok=0;
369 gfxdrawer_target_gfxline(&draw);
370 info.draw = &draw;
371 info.quality = quality;
373 //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
374 error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
376 if(error) {
377 fprintf(stderr, "Couldn't decompose glyph %d\n", t);
378 gfxline_free((gfxline_t*)draw.result(&draw));
379 FT_Done_Glyph(glyph);
380 omit = 4;
381 } else {
382 font->glyphs[font->num_glyphs].advance = glyph->advance.x/65536;
383 font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
385 l = font->glyphs[font->num_glyphs].line;
386 while(l) {
387 if(l->type != gfx_moveTo) {
388 ok = 1;
390 l = l->next;
392 if(!ok && !name) {
393 gfxline_free(font->glyphs[font->num_glyphs].line);
394 font->glyphs[font->num_glyphs].line = 0;
395 font->glyphs[font->num_glyphs].advance = 0;
397 /* Some PDFs created e.g. by InDesign tend to create
398 fonts with reduced (empty) characters, which still
399 have unicode indices attached to them.
400 Remove that information, in order to not confuse
401 any converter applications.
403 font->glyphs[font->num_glyphs].unicode = 0;
404 if(font->glyphs[font->num_glyphs].name) {
405 free((void*)font->glyphs[font->num_glyphs].name);
406 font->glyphs[font->num_glyphs].name = 0;
408 FT_Done_Glyph(glyph);
409 omit = 5;
413 if(!omit) {
414 FT_Done_Glyph(glyph);
415 font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
418 glyph2glyph[t] = font->num_glyphs;
419 font->num_glyphs++;
422 /* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will
423 have more memory allocated than just font->num_glyphs, but only the first font->numchars
424 are used/valid */
426 for(t=0;t<font->max_unicode;t++) {
427 if(font->unicode2glyph[t]>=0) {
428 font->unicode2glyph[t] = glyph2glyph[font->unicode2glyph[t]];
431 rfx_free(glyph2glyph);
432 rfx_free(glyph2unicode);
434 FT_Done_Face(face);
435 FT_Done_FreeType(ftlibrary);ftlibrary=0;
437 if(!isunicode && font->num_glyphs>0 && font->max_unicode) {
438 /* if the encoding isn't unicode, remap the font
439 so that the encoding equals the char position, and
440 remove the unicode table */
441 int t;
442 gfxglyph_t*newglyphs = (gfxglyph_t*)rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
444 for(t=0;t<max_unicode;t++) {
445 int c = font->unicode2glyph[t];
446 if(c>=font->num_glyphs || c<0)
447 c = 0;
448 newglyphs[t] = cloneGlyph(&font->glyphs[c]);
449 newglyphs[t].unicode = -1;
451 for(t=0;t<font->num_glyphs;t++) {
452 glyph_clear(&font->glyphs[t]);
454 free(font->glyphs);
455 font->glyphs = newglyphs;
456 font->num_glyphs = font->max_unicode;
458 free(font->unicode2glyph);font->unicode2glyph = 0;
459 font->max_unicode = 0;
462 if(font->unicode2glyph) {
463 int t;
464 int bad = 0;
465 /* check whether the Unicode indices look o.k.
466 If they don't, disable the unicode lookup by setting
467 the unicode map to -1 everywhere */
468 for(t=0;t<font->num_glyphs;t++) {
469 int c = font->glyphs[t].unicode;
470 gfxline_t* line = font->glyphs[t].line;
471 if(c && c < 32 && (line && line->next && line->next->next)) {
472 // the character maps into the unicode control character range
473 // between 0001-001f. Yet it is not empty. Treat the one
474 // mapping as broken, and look how many of those we find.
475 bad ++;
478 if(bad>5) {
479 free(font->unicode2glyph);font->unicode2glyph = 0;
480 font->max_unicode = 0;
481 for(t=0;t<font->num_glyphs;t++) {
482 font->glyphs[t].unicode = -1;
487 return font;
489 #else
491 gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality)
493 fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);
496 #endif
498 void gfxfont_free(gfxfont_t*font)
500 int t;
501 for(t=0;t<font->num_glyphs;t++) {
502 glyph_clear(&font->glyphs[t]);
504 if(font->glyphs) {
505 free(font->glyphs);font->glyphs = 0;
507 font->num_glyphs = 0;
508 if(font->unicode2glyph) {
509 free(font->unicode2glyph);font->unicode2glyph = 0;
511 if(font->id) {
512 free((void*)font->id);font->id=0;
515 free(font);