summaryrefslogtreecommitdiff
path: root/world/res_font.c
diff options
context:
space:
mode:
Diffstat (limited to 'world/res_font.c')
-rw-r--r--world/res_font.c442
1 files changed, 276 insertions, 166 deletions
diff --git a/world/res_font.c b/world/res_font.c
index 9d5f29bf..299f0d50 100644
--- a/world/res_font.c
+++ b/world/res_font.c
@@ -1,35 +1,34 @@
#include "fitz-base.h"
#include "fitz-world.h"
+#include "fitz-draw.h" /* for type3 font rendering */
-void
-fz_initfont(fz_font *font, char *name)
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+static fz_font *
+fz_newfont(void)
{
+ fz_font *font;
+
+ font = fz_malloc(sizeof(fz_font));
+ if (!font)
+ return nil;
+
font->refs = 1;
- strlcpy(font->name, name, sizeof font->name);
+ strcpy(font->name, "<unknown>");
+
+ font->ftsubstitute = 0;
+ font->ftface = nil;
- font->wmode = 0;
+ font->t3matrix = fz_identity();
+ font->t3procs = nil;
font->bbox.x0 = 0;
font->bbox.y0 = 0;
font->bbox.x1 = 1000;
font->bbox.y1 = 1000;
- font->hmtxcap = 0;
- font->vmtxcap = 0;
- font->nhmtx = 0;
- font->nvmtx = 0;
- font->hmtx = nil;
- font->vmtx = nil;
-
- font->dhmtx.lo = 0x0000;
- font->dhmtx.hi = 0xFFFF;
- font->dhmtx.w = 0;
-
- font->dvmtx.lo = 0x0000;
- font->dvmtx.hi = 0xFFFF;
- font->dvmtx.x = 0;
- font->dvmtx.y = 880;
- font->dvmtx.w = -1000;
+ return font;
}
fz_font *
@@ -42,23 +41,28 @@ fz_keepfont(fz_font *font)
void
fz_dropfont(fz_font *font)
{
+ int i;
+
if (font && --font->refs == 0)
{
- if (font->drop)
- font->drop(font);
- fz_free(font->hmtx);
- fz_free(font->vmtx);
+ if (font->t3procs)
+ {
+ for (i = 0; i < 256; i++)
+ if (font->t3procs[i])
+ fz_droptree(font->t3procs[i]);
+ fz_free(font->t3procs);
+ }
+
+ if (font->ftface)
+ {
+ FT_Done_Face((FT_Face)font->ftface);
+ }
+
fz_free(font);
}
}
void
-fz_setfontwmode(fz_font *font, int wmode)
-{
- font->wmode = wmode;
-}
-
-void
fz_setfontbbox(fz_font *font, int xmin, int ymin, int xmax, int ymax)
{
font->bbox.x0 = xmin;
@@ -67,204 +71,310 @@ fz_setfontbbox(fz_font *font, int xmin, int ymin, int xmax, int ymax)
font->bbox.y1 = ymax;
}
-void
-fz_setdefaulthmtx(fz_font *font, int w)
+/*
+ * Freetype hooks
+ */
+
+static FT_Library fz_ftlib = nil;
+
+#undef __FTERRORS_H__
+#define FT_ERRORDEF(e, v, s) { (e), (s) },
+#define FT_ERROR_START_LIST
+#define FT_ERROR_END_LIST { 0, NULL }
+
+struct ft_error
{
- font->dhmtx.w = w;
-}
+ int err;
+ char *str;
+};
-void
-fz_setdefaultvmtx(fz_font *font, int y, int w)
+const struct ft_error ft_errors[] =
{
- font->dvmtx.y = y;
- font->dvmtx.w = w;
+#include FT_ERRORS_H
+};
+
+char *ft_errorstring(int err)
+{
+ const struct ft_error *e;
+
+ for (e = ft_errors; e->str != NULL; e++)
+ if (e->err == err)
+ return e->str;
+
+ return "Unknown error";
}
-fz_error *
-fz_addhmtx(fz_font *font, int lo, int hi, int w)
+static fz_error *
+fz_initfreetype(void)
{
- int newcap;
- fz_hmtx *newmtx;
+ int code;
+ int maj, min, pat;
- if (font->nhmtx + 1 >= font->hmtxcap)
- {
- newcap = font->hmtxcap + 16;
- newmtx = fz_realloc(font->hmtx, sizeof(fz_hmtx) * newcap);
- if (!newmtx)
- return fz_outofmem;
- font->hmtxcap = newcap;
- font->hmtx = newmtx;
- }
+ if (fz_ftlib)
+ return fz_okay;
+
+ code = FT_Init_FreeType(&fz_ftlib);
+ if (code)
+ return fz_throw("cannot init freetype: %s", ft_errorstring(code));
- font->hmtx[font->nhmtx].lo = lo;
- font->hmtx[font->nhmtx].hi = hi;
- font->hmtx[font->nhmtx].w = w;
- font->nhmtx++;
+ FT_Library_Version(fz_ftlib, &maj, &min, &pat);
+ if (maj == 2 && min == 1 && pat < 7)
+ return fz_throw("freetype version too old: %d.%d.%d", maj, min, pat);
return fz_okay;
}
fz_error *
-fz_addvmtx(fz_font *font, int lo, int hi, int x, int y, int w)
+fz_newfontfromfile(fz_font **fontp, char *path, int index)
{
- int newcap;
- fz_vmtx *newmtx;
+ fz_error *error;
+ fz_font *font;
+ int code;
- if (font->nvmtx + 1 >= font->vmtxcap)
+ error = fz_initfreetype();
+ if (error)
+ return fz_rethrow(error, "cannot init freetype library");
+
+ font = fz_newfont();
+ if (!font)
+ return fz_throw("outofmem: font struct");
+
+ code = FT_New_Face(fz_ftlib, path, index, (FT_Face*)&font->ftface);
+ if (code)
{
- newcap = font->vmtxcap + 16;
- newmtx = fz_realloc(font->vmtx, sizeof(fz_vmtx) * newcap);
- if (!newmtx)
- return fz_outofmem;
- font->vmtxcap = newcap;
- font->vmtx = newmtx;
+ fz_free(font);
+ return fz_throw("freetype: cannot load font: %s", ft_errorstring(code));
}
- font->vmtx[font->nvmtx].lo = lo;
- font->vmtx[font->nvmtx].hi = hi;
- font->vmtx[font->nvmtx].x = x;
- font->vmtx[font->nvmtx].y = y;
- font->vmtx[font->nvmtx].w = w;
- font->nvmtx++;
-
+ *fontp = font;
return fz_okay;
}
-static int cmph(const void *a0, const void *b0)
-{
- fz_hmtx *a = (fz_hmtx*)a0;
- fz_hmtx *b = (fz_hmtx*)b0;
- return a->lo - b->lo;
-}
-
-static int cmpv(const void *a0, const void *b0)
-{
- fz_vmtx *a = (fz_vmtx*)a0;
- fz_vmtx *b = (fz_vmtx*)b0;
- return a->lo - b->lo;
-}
-
fz_error *
-fz_endhmtx(fz_font *font)
+fz_newfontfrombuffer(fz_font **fontp, unsigned char *data, int len, int index)
{
- fz_hmtx *newmtx;
+ fz_error *error;
+ fz_font *font;
+ int code;
- if (!font->hmtx)
- return fz_okay;
+ error = fz_initfreetype();
+ if (error)
+ return fz_rethrow(error, "cannot init freetype library");
- qsort(font->hmtx, font->nhmtx, sizeof(fz_hmtx), cmph);
+ font = fz_newfont();
+ if (!font)
+ return fz_throw("outofmem: font struct");
- newmtx = fz_realloc(font->hmtx, sizeof(fz_hmtx) * font->nhmtx);
- if (!newmtx)
- return fz_outofmem;
- font->hmtxcap = font->nhmtx;
- font->hmtx = newmtx;
+ code = FT_New_Memory_Face(fz_ftlib, data, len, index, (FT_Face*)&font->ftface);
+ if (code)
+ {
+ fz_free(font);
+ return fz_throw("freetype: cannot load font: %s", ft_errorstring(code));
+ }
+ *fontp = font;
return fz_okay;
}
fz_error *
-fz_endvmtx(fz_font *font)
+fz_renderftglyph(fz_glyph *glyph, fz_font *font, int gid, fz_matrix trm)
{
- fz_vmtx *newmtx;
+ FT_Face face = font->ftface;
+ FT_Matrix m;
+ FT_Vector v;
+ FT_Error fterr;
+ int x, y;
+
+#if 0
+ /* We lost this feature in refactoring.
+ * We can't access pdf_fontdesc metrics from fz_font.
+ * The pdf_fontdesc metrics are character based (cid),
+ * where the glyph being rendered is given by glyph (gid).
+ */
+ if (font->ftsubstitute && font->wmode == 0)
+ {
+ fz_hmtx subw;
+ int realw;
+ float scale;
- if (!font->vmtx)
- return fz_okay;
+ FT_Set_Char_Size(face, 1000, 1000, 72, 72);
- qsort(font->vmtx, font->nvmtx, sizeof(fz_vmtx), cmpv);
+ fterr = FT_Load_Glyph(font->ftface, gid,
+ FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
+ if (fterr)
+ return fz_throw("freetype failed to load glyph: %s", ft_errorstring(fterr));
+
+ realw = ((FT_Face)font->ftface)->glyph->advance.x;
+ subw = fz_gethmtx(font, cid); // <-- this is the offender
+ if (realw)
+ scale = (float) subw.w / realw;
+ else
+ scale = 1.0;
- newmtx = fz_realloc(font->vmtx, sizeof(fz_vmtx) * font->nvmtx);
- if (!newmtx)
- return fz_outofmem;
- font->vmtxcap = font->nvmtx;
- font->vmtx = newmtx;
+ trm = fz_concat(fz_scale(scale, 1.0), trm);
+ }
+#endif
+
+ glyph->w = 0;
+ glyph->h = 0;
+ glyph->x = 0;
+ glyph->y = 0;
+ glyph->samples = nil;
+
+ /* freetype mutilates complex glyphs if they are loaded
+ * with FT_Set_Char_Size 1.0. it rounds the coordinates
+ * before applying transformation. to get more precision in
+ * freetype, we shift part of the scale in the matrix
+ * into FT_Set_Char_Size instead
+ */
+
+ m.xx = trm.a * 64; /* should be 65536 */
+ m.yx = trm.b * 64;
+ m.xy = trm.c * 64;
+ m.yy = trm.d * 64;
+ v.x = trm.e * 64;
+ v.y = trm.f * 64;
+
+ FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */
+ FT_Set_Transform(face, &m, &v);
+
+ fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
+ if (fterr)
+ fz_warn("freetype load glyph: %s", ft_errorstring(fterr));
+ fterr = FT_Render_Glyph(face->glyph, ft_render_mode_normal);
+
+ if (fterr)
+ fz_warn("freetype render glyph: %s", ft_errorstring(fterr));
+
+ glyph->w = face->glyph->bitmap.width;
+ glyph->h = face->glyph->bitmap.rows;
+ glyph->x = face->glyph->bitmap_left;
+ glyph->y = face->glyph->bitmap_top - glyph->h;
+ glyph->samples = face->glyph->bitmap.buffer;
+
+ for (y = 0; y < glyph->h / 2; y++)
+ {
+ for (x = 0; x < glyph->w; x++)
+ {
+ unsigned char a = glyph->samples[y * glyph->w + x ];
+ unsigned char b = glyph->samples[(glyph->h - y - 1) * glyph->w + x];
+ glyph->samples[y * glyph->w + x ] = b;
+ glyph->samples[(glyph->h - y - 1) * glyph->w + x] = a;
+ }
+ }
return fz_okay;
}
-fz_hmtx
-fz_gethmtx(fz_font *font, int cid)
+
+/*
+ * Type 3 fonts...
+ */
+
+fz_error *
+fz_newtype3font(fz_font **fontp, char *name, fz_matrix matrix, void **procs0)
{
- int l = 0;
- int r = font->nhmtx - 1;
- int m;
+ fz_font *font;
+ fz_tree **procs = (fz_tree**)procs0;
+ int i;
- if (!font->hmtx)
- goto notfound;
+ font = fz_newfont();
+ if (!font)
+ return fz_throw("outofmem: font struct");
- while (l <= r)
+ font->t3procs = fz_malloc(sizeof(fz_tree*) * 256);
+ if (!font->t3procs)
{
- m = (l + r) >> 1;
- if (cid < font->hmtx[m].lo)
- r = m - 1;
- else if (cid > font->hmtx[m].hi)
- l = m + 1;
- else
- return font->hmtx[m];
+ fz_free(font);
+ return fz_throw("outofmem: type3 font charproc array");
}
-notfound:
- return font->dhmtx;
+ font->t3matrix = matrix;
+ for (i = 0; i < 256; i++)
+ font->t3procs[i] = procs[i];
+
+ strlcpy(font->name, name, sizeof(font->name));
+
+ *fontp = font;
+ return fz_okay;
}
-fz_vmtx
-fz_getvmtx(fz_font *font, int cid)
+fz_error *
+fz_rendert3glyph(fz_glyph *glyph, fz_font *font, int gid, fz_matrix trm)
{
- fz_hmtx h;
- fz_vmtx v;
- int l = 0;
- int r = font->nvmtx - 1;
- int m;
+ fz_error *error;
+ fz_renderer *gc;
+ fz_tree *tree;
+ fz_matrix ctm;
+ fz_irect bbox;
+
+ /* TODO: make it reentrant */
+ static fz_pixmap *pixmap = nil;
+ if (pixmap)
+ {
+ fz_droppixmap(pixmap);
+ pixmap = nil;
+ }
+
+ if (gid < 0 || gid > 255)
+ return fz_throw("assert: glyph out of range");
+
+ tree = font->t3procs[gid];
+ if (!tree)
+ {
+ glyph->w = 0;
+ glyph->h = 0;
+ return fz_okay;
+ }
- if (!font->vmtx)
- goto notfound;
+ /* XXX UGLY HACK XXX */
+ extern fz_colorspace *pdf_devicegray;
- while (l <= r)
- {
- m = (l + r) >> 1;
- if (cid < font->vmtx[m].lo)
- r = m - 1;
- else if (cid > font->vmtx[m].hi)
- l = m + 1;
- else
- return font->vmtx[m];
- }
+ ctm = fz_concat(font->t3matrix, trm);
+ bbox = fz_roundrect(fz_boundtree(tree, ctm));
+
+ error = fz_newrenderer(&gc, pdf_devicegray, 1, 4096);
+ if (error)
+ return fz_rethrow(error, "cannot create renderer");
+ error = fz_rendertree(&pixmap, gc, tree, ctm, bbox, 0);
+ fz_droprenderer(gc);
+ if (error)
+ return fz_rethrow(error, "cannot render glyph");
-notfound:
- h = fz_gethmtx(font, cid);
- v = font->dvmtx;
- v.x = h.w / 2;
- return v;
+ assert(pixmap->n == 1);
+
+ glyph->x = pixmap->x;
+ glyph->y = pixmap->y;
+ glyph->w = pixmap->w;
+ glyph->h = pixmap->h;
+ glyph->samples = pixmap->samples;
+
+ return fz_okay;
}
void
fz_debugfont(fz_font *font)
{
- int i;
-
printf("font '%s' {\n", font->name);
- printf(" wmode %d\n", font->wmode);
- printf(" bbox [%d %d %d %d]\n",
- font->bbox.x0, font->bbox.y0,
- font->bbox.x1, font->bbox.y1);
- printf(" DW %d\n", font->dhmtx.w);
- printf(" W {\n");
- for (i = 0; i < font->nhmtx; i++)
- printf(" <%04x> <%04x> %d\n",
- font->hmtx[i].lo, font->hmtx[i].hi, font->hmtx[i].w);
- printf(" }\n");
+ if (font->ftface)
+ {
+ printf(" freetype face %p\n", font->ftface);
+ if (font->ftsubstitute)
+ printf(" substitute metrics\n");
+ }
- if (font->wmode)
+ if (font->t3procs)
{
- printf(" DW2 [%d %d]\n", font->dvmtx.y, font->dvmtx.w);
- printf(" W2 {\n");
- for (i = 0; i < font->nvmtx; i++)
- printf(" <%04x> <%04x> %d %d %d\n", font->vmtx[i].lo, font->vmtx[i].hi,
- font->vmtx[i].x, font->vmtx[i].y, font->vmtx[i].w);
- printf(" }\n");
+ printf(" type3 matrix [%g %g %g %g]\n",
+ font->t3matrix.a, font->t3matrix.b,
+ font->t3matrix.c, font->t3matrix.d);
}
+ printf(" bbox [%d %d %d %d]\n",
+ font->bbox.x0, font->bbox.y0,
+ font->bbox.x1, font->bbox.y1);
+
printf("}\n");
}