along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "../config.h"
#include "gfxdevice.h"
#include "gfxtools.h"
+#include "gfxfont.h"
static int loadfont_scale = 64;
-static int skip_unused = 0;
static int full_unicode = 1;
#ifdef HAVE_FREETYPE
#define FT_SCALE 1
#define FT_SUBPIXELS 64
-static int ft_move_to(FT_Vector* _to, void* user)
+typedef struct _gfxdrawinfo_t {
+ gfxdrawer_t* draw;
+ double quality;
+} gfxdrawinfo_t;
+
+static int ft_move_to(const FT_Vector* _to, void* user)
{
- gfxdrawer_t* draw = (gfxdrawer_t*)user;
+ gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
+ gfxdrawer_t* draw = info->draw;
double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
draw->moveTo(draw, x,y);
return 0;
}
-static int ft_line_to(FT_Vector* _to, void* user)
+static int ft_line_to(const FT_Vector* _to, void* user)
{
- gfxdrawer_t* draw = (gfxdrawer_t*)user;
+ gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
+ gfxdrawer_t* draw = info->draw;
double x = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
double y = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
draw->lineTo(draw, x,y);
return 0;
}
-static int ft_cubic_to(FT_Vector* _c1, FT_Vector* _c2, FT_Vector* _to, void* user)
+static int ft_cubic_to(const FT_Vector* _c1, const FT_Vector* _c2, const FT_Vector* _to, void* user)
{
- gfxdrawer_t* draw = (gfxdrawer_t*)user;
+ gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
+ gfxdrawer_t* draw = info->draw;
double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
double c1x = _c1->x*FT_SCALE/(float)FT_SUBPIXELS;
double c1y = -_c1->y*FT_SCALE/(float)FT_SUBPIXELS;
double c2x = _c2->x*FT_SCALE/(float)FT_SUBPIXELS;
double c2y = -_c2->y*FT_SCALE/(float)FT_SUBPIXELS;
- gfxdraw_cubicTo(draw, c1x, c1y, c2x, c2y, tox, toy);
+ gfxdraw_cubicTo(draw, c1x, c1y, c2x, c2y, tox, toy, info->quality);
return 0;
}
-static int ft_conic_to(FT_Vector* _c, FT_Vector* _to, void* user)
+static int ft_conic_to(const FT_Vector* _c, const FT_Vector* _to, void* user)
{
- gfxdrawer_t* draw = (gfxdrawer_t*)user;
+ gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
+ gfxdrawer_t* draw = info->draw;
double tox = _to->x*FT_SCALE/(float)FT_SUBPIXELS;
double toy = -_to->y*FT_SCALE/(float)FT_SUBPIXELS;
double cx = _c->x*FT_SCALE/(float)FT_SUBPIXELS;
double cy = -_c->y*FT_SCALE/(float)FT_SUBPIXELS;
- gfxdraw_conicTo(draw, cx,cy, tox,toy);
+ gfxdraw_conicTo(draw, cx,cy, tox,toy, info->quality);
return 0;
}
static FT_Outline_Funcs outline_functions =
{
gfxline_t*line;
if(g->name) {
- free(g->name); g->name = 0;
+ free((void*)g->name); g->name = 0;
}
gfxline_free(g->line);g->line = 0;
}
-void gfxfont_free(gfxfont_t*font)
-{
- int t;
- for(t=0;t<font->num_glyphs;t++) {
- glyph_clear(&font->glyphs[t]);
- }
- if(font->glyphs) {
- free(font->glyphs);font->glyphs = 0;
- }
- font->num_glyphs = 0;
- if(font->unicode2glyph) {
- free(font->unicode2glyph);font->unicode2glyph = 0;
- }
- free(font);
-}
+static int errorno = 0;
+
+//#define DEBUG 1
-gfxfont_t* gfxfont_load(char*filename)
+gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality)
{
FT_Face face;
FT_Error error;
- const char* name = 0;
+ const char* fontname = 0;
FT_ULong charcode;
FT_UInt gindex;
gfxfont_t* font;
int t;
int*glyph2glyph = 0;
int*glyph2unicode = 0;
- FT_Size size;
int max_unicode = 0;
int charmap = -1;
int isunicode = 1;
-
+ int has_had_errors = 0;
+ int num_names = 0;
+
if(ftlibrary == 0) {
if(FT_Init_FreeType(&ftlibrary)) {
fprintf(stderr, "Couldn't init freetype library!\n");
}
error = FT_New_Face(ftlibrary, filename, 0, &face);
FT_Set_Pixel_Sizes (face, 16*loadfont_scale, 16*loadfont_scale);
+#ifdef DEBUG
+ printf("gfxfont_load(%s, %s, %f)\n", id, filename, quality);
+#endif
if(error) {
- fprintf(stderr, "Couldn't load file %s- not a TTF file?\n", filename);
+ fprintf(stderr, "Couldn't load file %s- not a TTF file? (error=%02x)\n", filename, error);
return 0;
}
if(face->num_glyphs <= 0) {
return 0;
}
- font = rfx_calloc(sizeof(gfxfont_t));
+ font = (gfxfont_t*)rfx_calloc(sizeof(gfxfont_t));
//font->style = ((face->style_flags&FT_STYLE_FLAG_ITALIC)?FONT_STYLE_ITALIC:0) |((face->style_flags&FT_STYLE_FLAG_BOLD)?FONT_STYLE_BOLD:0);
//font->ascent = abs(face->ascender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMin;
//font->descent = abs(face->descender)*FT_SCALE*loadfont_scale*20/FT_SUBPIXELS/2; //face->bbox.xMax;
//font->leading = font->layout->ascent + font->layout->descent;
//font->encoding = FONT_ENCODING_UNICODE;
font->max_unicode = 0;
+ font->id = strdup(id);
- font->glyphs = rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
- glyph2unicode = rfx_calloc(face->num_glyphs*sizeof(int));
- glyph2glyph = rfx_calloc(face->num_glyphs*sizeof(int));
+ font->glyphs = (gfxglyph_t*)rfx_calloc(face->num_glyphs*sizeof(gfxglyph_t));
+ glyph2unicode = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
+ glyph2glyph = (int*)rfx_calloc(face->num_glyphs*sizeof(int));
if(FT_HAS_GLYPH_NAMES(face)) {
//font->glyphnames = rfx_calloc(face->num_glyphs*sizeof(char*));
}
- /*name = FT_Get_Postscript_Name(face);
- if(name && *name)
- font->name = strdup(name);*/
+ fontname = FT_Get_Postscript_Name(face);
+
+#ifdef DEBUG
+ for(t=0;t<face->num_charmaps;t++) {
+ printf("possible encoding: %c%c%c%c (%d of %d)\n",
+ (face->charmaps[t]->encoding >> 24)&255,
+ (face->charmaps[t]->encoding >> 16)&255,
+ (face->charmaps[t]->encoding >> 8)&255,
+ (face->charmaps[t]->encoding >> 0)&255,
+ t+1, face->num_charmaps
+ );
+ }
+#endif
while(1)
{
charcode = FT_Get_First_Char(face, &gindex);
+
while(gindex != 0)
{
if(gindex >= 0 && gindex<face->num_glyphs) {
charcode = FT_Get_Next_Char(face, charcode, &gindex);
}
+#ifdef DEBUG
+ if(face->charmap) {
+ printf("ENCODING: %c%c%c%c (%d of %d) max_unicode=%d\n",
+ (face->charmap->encoding >> 24)&255,
+ (face->charmap->encoding >> 16)&255,
+ (face->charmap->encoding >> 8)&255,
+ (face->charmap->encoding >> 0)&255,
+ charmap, face->num_charmaps, font->max_unicode
+ );
+ } else {
+ printf("ENCODING: NONE (%d of %d) max_unicode=%d\n",
+ charmap, face->num_charmaps, font->max_unicode
+ );
+ }
+#endif
+
/* if we didn't find a single encoding character, try
the font's charmaps instead. That usually means that
the encoding is no longer unicode.
TODO: find a way to convert the encoding to unicode
*/
- if(font->max_unicode == 0 && charmap < face->num_charmaps - 1) {
+ if(font->max_unicode == 0 && charmap < face->num_charmaps-1
+ && face->charmaps[charmap+1]->encoding != 0x41444243 /* adbc, custom */
+ && face->charmaps[charmap+1]->encoding != 0x61726d6e /* armn */
+ )
+ {
charmap++;
FT_Set_Charmap(face, face->charmaps[charmap]);
- //font->encoding = 0;//anything but unicode FIXME
isunicode = 0;
- } else
+ } else
break;
}
-
/* TODO: if isunicode is 1, we now need to permutate the character
order so that each character is at it's encoding position */
if(full_unicode)
font->max_unicode = 65535;
- font->unicode2glyph = rfx_calloc(font->max_unicode*sizeof(int));
+ font->unicode2glyph = (int*)rfx_calloc(font->max_unicode*sizeof(int));
for(t=0;t<font->max_unicode;t++) {
int g = FT_Get_Char_Index(face, t);
g = -1;
font->unicode2glyph[t] = g;
if(g>=0) {
+#ifdef DEBUG
+ printf("u%d ->%d\n", t, g);
+#endif
max_unicode = t+1;
if(!glyph2unicode[g]) {
glyph2unicode[g] = t;
font->num_glyphs = 0;
+
+ for(t=0; t < face->num_glyphs; t++) {
+ if(FT_HAS_GLYPH_NAMES(face)) {
+ char name[128];
+ error = FT_Get_Glyph_Name(face, t, name, 127);
+ if(!error && name[0] && !strstr(name, "notdef")) {
+ num_names++;
+ }
+ }
+ }
+
+
for(t=0; t < face->num_glyphs; t++) {
FT_Glyph glyph;
- FT_BBox bbox;
- FT_Matrix matrix;
char name[128];
gfxdrawer_t draw;
- int ret;
+ gfxdrawinfo_t info;
char hasname = 0;
+ int omit = 0;
name[0]=0;
- if(FT_HAS_GLYPH_NAMES(face)) {
+
+ font->glyphs[font->num_glyphs].advance = 0;
+ font->glyphs[font->num_glyphs].line = 0;
+ font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
+ font->glyphs[font->num_glyphs].name = 0;
+
+ if(FT_HAS_GLYPH_NAMES(face) && (num_names >= face->num_glyphs/10 || num_names > 2)) {
+ name[0] = 0;
error = FT_Get_Glyph_Name(face, t, name, 127);
if(!error && name[0] && !strstr(name, "notdef")) {
font->glyphs[font->num_glyphs].name = strdup(name);
hasname = 1;
}
}
- if(!glyph2unicode[t] && !hasname && skip_unused) {
- continue;
- }
- error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
- if(error) {
- fprintf(stderr, "Couldn't load glyph %d, error:%d\n", t, error);
- continue;
- }
- error = FT_Get_Glyph(face->glyph, &glyph);
- if(error) {
- fprintf(stderr, "Couldn't get glyph %d, error:%d\n", t, error);
- continue;
+
+#if 0 // some cantonese pdfs fail to work if this is activated
+
+ if(has_had_errors && (isunicode && !glyph2unicode[t]) && !hasname && t>=256) {
+ /* some freetype versions crash or corrupt memory if we try to load
+ characters (without unicode index or name) above 256 for some fonts.
+ So skip those characters once the first error occured */
+ omit = 1;
}
+#endif
- FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
- bbox.yMin = -bbox.yMin;
- bbox.yMax = -bbox.yMax;
- if(bbox.xMax < bbox.xMin) {
- // swap
- bbox.xMax ^= bbox.xMin;
- bbox.xMin ^= bbox.xMax;
- bbox.xMax ^= bbox.xMin;
+ if(!omit) {
+ error = FT_Load_Glyph(face, t, FT_LOAD_NO_BITMAP);
+ if(error) {
+ if(hasname)
+ fprintf(stderr, "Warning: glyph %d/%d (unicode %d, name %s) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], name, error);
+ else
+ fprintf(stderr, "Warning: glyph %d/%d (unicode %d) has return code %d\n", t, face->num_glyphs, glyph2unicode[t], error);
+ omit = 2;
+
+#if 0
+ if(!has_had_errors) {
+ char buf[256];
+ if(fontname && *fontname) {
+ fprintf(stderr, "font has been copied to %s.ttf\n", fontname);
+ sprintf(buf, "cp %s %s.ttf", filename, fontname);
+ } else {
+ fprintf(stderr, "font has been copied to badfont%d.ttf\n", errorno);
+ sprintf(buf, "cp %s badfont%d.ttf", filename, errorno);
+ errorno++;
+ }
+ system(buf);
+ }
+#endif
+ has_had_errors = 1;
+ }
}
- if(bbox.yMax < bbox.yMin) {
- // swap
- bbox.yMax ^= bbox.yMin;
- bbox.yMin ^= bbox.yMax;
- bbox.yMax ^= bbox.yMin;
+ if(!omit) {
+ error = FT_Get_Glyph(face->glyph, &glyph);
+ if(error) {
+ fprintf(stderr, "Couldn't get glyph %d/%d, error:%d\n", t, face->num_glyphs, error);
+ omit = 3;
+ }
}
- gfxdrawer_target_gfxline(&draw);
-
- //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
- error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &draw);
-
- if(error) {
- fprintf(stderr, "Couldn't decompose glyph %d\n", t);
- gfxline_free((gfxline_t*)draw.result(&draw));
- continue;
+ if(!omit) {
+ gfxline_t*l;
+ int ok=0;
+ gfxdrawer_target_gfxline(&draw);
+ info.draw = &draw;
+ info.quality = quality;
+
+ //error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
+ error = FT_Outline_Decompose(&face->glyph->outline, &outline_functions, &info);
+
+ if(error) {
+ fprintf(stderr, "Couldn't decompose glyph %d\n", t);
+ gfxline_free((gfxline_t*)draw.result(&draw));
+ FT_Done_Glyph(glyph);
+ omit = 4;
+ } else {
+ font->glyphs[font->num_glyphs].advance = glyph->advance.x/65536;
+ font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
+ }
+ l = font->glyphs[font->num_glyphs].line;
+ while(l) {
+ if(l->type != gfx_moveTo) {
+ ok = 1;
+ }
+ l = l->next;
+ }
+ if(!ok && !name) {
+ gfxline_free(font->glyphs[font->num_glyphs].line);
+ font->glyphs[font->num_glyphs].line = 0;
+ font->glyphs[font->num_glyphs].advance = 0;
+
+ /* Some PDFs created e.g. by InDesign tend to create
+ fonts with reduced (empty) characters, which still
+ have unicode indices attached to them.
+ Remove that information, in order to not confuse
+ any converter applications.
+ */
+ font->glyphs[font->num_glyphs].unicode = 0;
+ if(font->glyphs[font->num_glyphs].name) {
+ free((void*)font->glyphs[font->num_glyphs].name);
+ font->glyphs[font->num_glyphs].name = 0;
+ }
+ FT_Done_Glyph(glyph);
+ omit = 5;
+ }
}
-#if 0
- if(bbox.xMin > 0) {
- font->glyph[font->num_glyphs].advance = (bbox.xMax*20*FT_SCALE)/FT_SUBPIXELS;
- } else {
- font->glyph[font->num_glyphs].advance = ((bbox.xMax - bbox.xMin)*20*FT_SCALE)/FT_SUBPIXELS;
+ if(!omit) {
+ FT_Done_Glyph(glyph);
+ font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
}
-#else
- font->glyphs[font->num_glyphs].advance = glyph->advance.x*20/65536;
-#endif
-
- font->glyphs[font->num_glyphs].line = (gfxline_t*)draw.result(&draw);
-
- /*font->glyphs[font->num_glyphs].bbox.xmin = (bbox.xMin*FT_SCALE*20)/FT_SUBPIXELS;
- font->glyphs[font->num_glyphs].bbox.ymin = (bbox.yMin*FT_SCALE*20)/FT_SUBPIXELS;
- font->glyphs[font->num_glyphs].bbox.xmax = (bbox.xMax*FT_SCALE*20)/FT_SUBPIXELS;
- font->glyphs[font->num_glyphs].bbox.ymax = (bbox.yMax*FT_SCALE*20)/FT_SUBPIXELS;*/
- FT_Done_Glyph(glyph);
- font->glyphs[font->num_glyphs].unicode = glyph2unicode[t];
glyph2glyph[t] = font->num_glyphs;
font->num_glyphs++;
}
+
/* notice: if skip_unused is true, font->glyph2unicode, font->glyphnames and font->layout->bounds will
have more memory allocated than just font->num_glyphs, but only the first font->numchars
are used/valid */
FT_Done_Face(face);
FT_Done_FreeType(ftlibrary);ftlibrary=0;
-
- if(!isunicode && font->num_glyphs>0) {
+
+ if(!isunicode && font->num_glyphs>0 && font->max_unicode) {
/* if the encoding isn't unicode, remap the font
so that the encoding equals the char position, and
remove the unicode table */
int t;
- gfxglyph_t*newglyphs = rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
+ gfxglyph_t*newglyphs = (gfxglyph_t*)rfx_calloc(font->max_unicode*sizeof(gfxglyph_t));
for(t=0;t<max_unicode;t++) {
int c = font->unicode2glyph[t];
}
#else
-gfxfont_t* gfxfont_load(char*filename)
+gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality)
{
fprintf(stderr, "No freetype support compiled in! Not able to load %s\n", filename);
}
#endif
+void gfxfont_free(gfxfont_t*font)
+{
+ int t;
+ for(t=0;t<font->num_glyphs;t++) {
+ glyph_clear(&font->glyphs[t]);
+ }
+ if(font->glyphs) {
+ free(font->glyphs);font->glyphs = 0;
+ }
+ font->num_glyphs = 0;
+ if(font->unicode2glyph) {
+ free(font->unicode2glyph);font->unicode2glyph = 0;
+ }
+ if(font->id) {
+ free((void*)font->id);font->id=0;
+ }
+
+ free(font);
+}
+