along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <assert.h>
#include "../config.h"
#include "gfxdevice.h"
#include "gfxtools.h"
+#include "gfxfont.h"
+#include "ttf.h"
+#include "mem.h"
static int loadfont_scale = 64;
static int full_unicode = 1;
double quality;
} gfxdrawinfo_t;
-static int ft_move_to(FT_Vector* _to, void* user)
+static int ft_move_to(const FT_Vector* _to, void* user)
{
gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
gfxdrawer_t* draw = info->draw;
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)
{
gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
gfxdrawer_t* draw = info->draw;
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)
{
gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
gfxdrawer_t* draw = info->draw;
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)
{
gfxdrawinfo_t* info = (gfxdrawinfo_t*)user;
gfxdrawer_t* draw = info->draw;
{
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;
}
static int errorno = 0;
-gfxfont_t* gfxfont_load(char*id, char*filename, double quality)
+//#define DEBUG 1
+
+gfxfont_t* gfxfont_load(char*id, char*filename, unsigned int flags, double quality)
{
FT_Face face;
FT_Error error;
int t;
int*glyph2glyph = 0;
int*glyph2unicode = 0;
- FT_Size size;
int max_unicode = 0;
int charmap = -1;
int isunicode = 1;
}
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? (error=%02x)\n", filename, error);
return 0;
}
if(face->num_glyphs <= 0) {
- fprintf(stderr, "File %s contains %d glyphs\n", face->num_glyphs);
+ fprintf(stderr, "File %s contains %d glyphs\n", filename, (int)face->num_glyphs);
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->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*));
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 &&
- face->charmaps[charmap+1]->encoding != 0x41444243 /* custom */)
+ 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]);
} 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;
for(t=0; t < face->num_glyphs; t++) {
FT_Glyph glyph;
- FT_BBox bbox;
- FT_Matrix matrix;
char name[128];
gfxdrawer_t draw;
gfxdrawinfo_t info;
- int ret;
char hasname = 0;
int omit = 0;
name[0]=0;
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);
+ fprintf(stderr, "Warning: glyph %d/%d (unicode %d, name %s) has return code %d\n", t, (int)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);
+ fprintf(stderr, "Warning: glyph %d/%d (unicode %d) has return code %d\n", t, (int)face->num_glyphs, glyph2unicode[t], error);
omit = 2;
#if 0
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);
+ fprintf(stderr, "Couldn't get glyph %d/%d, error:%d\n", t, (int)face->num_glyphs, error);
omit = 3;
}
}
FT_Done_Glyph(glyph);
omit = 4;
} else {
- font->glyphs[font->num_glyphs].advance = (glyph->advance.x*20)/65536;
+ 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;
*/
font->glyphs[font->num_glyphs].unicode = 0;
if(font->glyphs[font->num_glyphs].name) {
- free(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);
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);
+ return 0;
}
#endif
if(font->unicode2glyph) {
free(font->unicode2glyph);font->unicode2glyph = 0;
}
+ if(font->id) {
+ free((void*)font->id);font->id=0;
+ }
+ if(font->kerning) {
+ free(font->kerning);font->kerning=0;
+ }
+
free(font);
}
+static inline int invalid_unicode(int u)
+{
+ return (u<32 || (u>=0xe000 && u<0xf900));
+}
+void gfxfont_fix_unicode(gfxfont_t*font)
+{
+ int t;
+
+ /* find the current maximum unicode2glyph */
+ int max = 0;
+ for(t=0;t<font->num_glyphs;t++) {
+ int u = font->glyphs[t].unicode;
+ if(u > max)
+ max = u;
+ }
+ char*used = rfx_calloc(max+1);
+
+ /* now, remap all duplicates (and invalid characters) and
+ calculate the new maximum */
+ int remap_pos=0;
+ max = 0;
+ for(t=0;t<font->num_glyphs;t++) {
+ int u = font->glyphs[t].unicode;
+ if(u>=0) {
+ if(used[u] || invalid_unicode(u)) {
+ u = font->glyphs[t].unicode = 0xe000 + remap_pos++;
+ } else {
+ used[u] = 1;
+ }
+ }
+ if(u > max)
+ max = u;
+ }
+ free(used);
+
+ if(!font->unicode2glyph) {
+ /* (re)generate unicode2glyph-to-glyph mapping table by reverse mapping
+ the glyph unicode2glyph's indexes into the mapping table. For collisions,
+ we prefer the smaller unicode2glyph value.*/
+ font->max_unicode = max+1;
+ font->unicode2glyph = malloc(sizeof(font->unicode2glyph[0])*(font->max_unicode));
+ memset(font->unicode2glyph, -1, sizeof(font->unicode2glyph[0])*(font->max_unicode));
+
+ for(t=0;t<font->num_glyphs;t++) {
+ int u = font->glyphs[t].unicode;
+ if(u>=0) {
+ assert(font->unicode2glyph[u]<0); // we took care of duplicates, right?
+ font->unicode2glyph[u] = t;
+ }
+ }
+ } else {
+ /* add the new glyph indexes (most probably, that's only the remapped values
+ at 0xe000) to the unicode2glyph table. Notice: Unlike glyph2unicode, we don't
+ care about collisions in the unicode2glyph table */
+ int new_max_unicode = max+1;
+ if(font->max_unicode < new_max_unicode) {
+ font->unicode2glyph = rfx_realloc(font->unicode2glyph, sizeof(font->unicode2glyph[0])*(font->max_unicode));
+ memset(font->unicode2glyph+font->max_unicode, -1, sizeof(font->unicode2glyph[0])*(new_max_unicode - font->max_unicode));
+ }
+ for(t=0;t<font->num_glyphs;t++) {
+ int u = font->glyphs[t].unicode;
+ if(u>=0 && font->unicode2glyph[u]<0) {
+ font->unicode2glyph[u] = t;
+ }
+ }
+ font->max_unicode = new_max_unicode;
+ }
+}
+
+ttf_t* gfxfont_to_ttf(gfxfont_t*font)
+{
+ ttf_t*ttf = ttf_new();
+ int num_glyphs = font->num_glyphs;
+ int offset = 0;
+ int t;
+ char has_nondef_glyph =
+ font->num_glyphs && font->glyphs[0].unicode==-1 &&
+ (!font->glyphs[0].line || !font->glyphs[0].line->next);
+
+ if(!has_nondef_glyph) {
+ /* insert a new .nondef glyph at the start of the font */
+ offset++;
+ num_glyphs++;
+ }
+ ttf->num_glyphs = num_glyphs;
+ ttf->glyphs = rfx_calloc(num_glyphs*sizeof(ttfglyph_t));
+ double scale = 1.0;
+ int max_unicode = font->max_unicode;
+ int remap_pos=0;
+ for(t=0;t<font->num_glyphs;t++) {
+ gfxglyph_t*src = &font->glyphs[t];
+ ttfglyph_t*dest = &ttf->glyphs[t+offset];
+ gfxline_t*line = src->line;
+ int count = 0;
+ while(line) {
+ count++;
+ if(line->type == gfx_splineTo)
+ count++;
+ line=line->next;
+ }
+ dest->num_points = count;
+ dest->points = rfx_calloc(count*sizeof(ttfpoint_t));
+ count = 0;
+ line = src->line;
+ while(line) {
+ if(line->type == gfx_splineTo) {
+ dest->points[count].x = line->sx*scale;
+ dest->points[count].y = line->sy*scale;
+ count++;
+ }
+ dest->points[count].x = line->x*scale;
+ dest->points[count].y = line->y*scale;
+ dest->points[count].flags |= GLYPH_ON_CURVE;
+ if(line->type == gfx_moveTo) {
+ dest->points[count].flags |= GLYPH_CONTOUR_START;
+ if(count)
+ dest->points[count-1].flags |= GLYPH_CONTOUR_END;
+ }
+ count++;
+ line=line->next;
+ }
+ if(count)
+ dest->points[count-1].flags |= GLYPH_CONTOUR_END;
+
+ /* compute bounding box */
+ int s;
+ if(count) {
+ dest->xmin = dest->xmax = dest->points[0].x;
+ dest->ymin = dest->ymax = dest->points[0].y;
+ for(s=1;s<count;s++) {
+ if(dest->points[s].x < dest->xmin)
+ dest->xmin = dest->points[s].x;
+ if(dest->points[s].y < dest->ymin)
+ dest->ymin = dest->points[s].y;
+ if(dest->points[s].x > dest->xmax)
+ dest->xmax = dest->points[s].x;
+ if(dest->points[s].y > dest->ymax)
+ dest->ymax = dest->points[s].y;
+ }
+ }
+
+ dest->advance = src->advance*scale;
+
+ int u = font->glyphs[t].unicode;
+ if(invalid_unicode(u)) {
+ u = 0xe000 + remap_pos++;
+ }
+ if(u > max_unicode)
+ max_unicode = u;
+ }
+ ttf->unicode_size = max_unicode+1;
+ ttf->unicode = rfx_calloc(sizeof(unicode_t)*ttf->unicode_size);
+ remap_pos=0;
+ for(t=0;t<font->num_glyphs;t++) {
+ gfxglyph_t*src = &font->glyphs[t];
+ int u = font->glyphs[t].unicode;
+ if(invalid_unicode(u)) {
+ u = 0xe000 + remap_pos++;
+ }
+ if(u>=0 && u<ttf->unicode_size)
+ ttf->unicode[u] = t+offset;
+ }
+ int u;
+ if(font->unicode2glyph) {
+ for(u=0;u<ttf->unicode_size;u++) {
+ int g = font->unicode2glyph[u];
+ if(invalid_unicode(u))
+ continue;
+ if(g>=0 && g<font->num_glyphs && !ttf->unicode[u]) {
+ ttf->unicode[u] = g+offset;
+ }
+ }
+ }
+
+ ttf->ascent = font->ascent;
+ ttf->descent = font->descent;
+ ttf->lineGap = font->ascent - font->descent;
+
+ ttf->full_name = strdup(font->id);
+ ttf->family_name = strdup(font->id);
+ ttf->subfamily_name = strdup(font->id);
+ ttf->postscript_name = strdup(font->id);
+ ttf->version_string = strdup("Version 1.0");
+ ttf->font_uid = strdup(font->id);
+
+ ttf_create_truetype_tables(ttf);
+ return ttf;
+}
+
+void gfxfont_save(gfxfont_t*font, const char*filename)
+{
+ ttf_t*ttf = gfxfont_to_ttf(font);
+ ttf_save(ttf, filename);
+ ttf_destroy(ttf);
+}
+
+void gfxfont_save_eot(gfxfont_t*font, const char*filename)
+{
+ ttf_t*ttf = gfxfont_to_ttf(font);
+ ttf_save_eot(ttf, filename);
+ ttf_destroy(ttf);
+}
+