From 4091b7a357728aed033216baafed540b795bcf9e Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 17 Jul 2012 18:05:05 +0200 Subject: Handle glyphs that are too large to render as pixmaps. --- fitz/fitz-internal.h | 9 ++- fitz/res_font.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++-- fitz/res_path.c | 34 ++++++++++++ 3 files changed, 190 insertions(+), 7 deletions(-) (limited to 'fitz') diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h index d352a94b..2670a335 100644 --- a/fitz/fitz-internal.h +++ b/fitz/fitz-internal.h @@ -810,6 +810,7 @@ struct fz_stroke_state_s }; fz_path *fz_new_path(fz_context *ctx); +fz_point fz_currentpoint(fz_context *ctx, fz_path *path); void fz_moveto(fz_context*, fz_path*, float x, float y); void fz_lineto(fz_context*, fz_path*, float x, float y); void fz_curveto(fz_context*,fz_path*, float, float, float, float, float, float); @@ -845,11 +846,13 @@ fz_glyph_cache *fz_keep_glyph_cache(fz_context *ctx); void fz_drop_glyph_cache_context(fz_context *ctx); void fz_purge_glyph_cache(fz_context *ctx); +fz_path *fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm); +fz_path *fz_outline_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm); fz_pixmap *fz_render_ft_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, int aa); -fz_pixmap *fz_render_t3_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, fz_colorspace *model); +fz_pixmap *fz_render_t3_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, fz_colorspace *model, fz_bbox scissor); fz_pixmap *fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_stroke_state *state); -fz_pixmap *fz_render_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_colorspace *model); -fz_pixmap *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_matrix, fz_stroke_state *stroke); +fz_pixmap *fz_render_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_colorspace *model, fz_bbox scissor); +fz_pixmap *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_matrix, fz_stroke_state *stroke, fz_bbox scissor); void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, fz_matrix trm, void *gstate); /* diff --git a/fitz/res_font.c b/fitz/res_font.c index e8af6643..568308be 100644 --- a/fitz/res_font.c +++ b/fitz/res_font.c @@ -380,7 +380,7 @@ fz_copy_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap) for (y = 0; y < pixmap->h; y++) { memcpy(pixmap->samples + (unsigned int)(y * pixmap->w), - bitmap->buffer + (unsigned int)((pixmap->h - y - 1) * bitmap->pitch), + bitmap->buffer + (unsigned int)((pixmap->h - y - 1) * bitmap->pitch), pixmap->w); } } @@ -398,6 +398,8 @@ fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, int a FT_Error fterr; fz_pixmap *result; + float strength = fz_matrix_expansion(trm) * 0.02f; + trm = fz_adjust_ft_glyph_width(ctx, font, gid, trm); if (font->ft_italic) @@ -474,7 +476,6 @@ retry_unhinted: if (font->ft_bold) { - float strength = fz_matrix_expansion(trm) * 0.02f; FT_Outline_Embolden(&face->glyph->outline, strength * 64); FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); } @@ -614,6 +615,8 @@ fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) // TODO: refactor loading into fz_load_ft_glyph // TODO: cache results + float strength = fz_matrix_expansion(trm) * 0.02f; + trm = fz_adjust_ft_glyph_width(ctx, font, gid, trm); if (font->ft_italic) @@ -644,7 +647,6 @@ fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) if (font->ft_bold) { - float strength = fz_matrix_expansion(trm) * 0.04f; FT_Outline_Embolden(&face->glyph->outline, strength * 64); FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); } @@ -665,6 +667,136 @@ fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) return bounds; } +/* Turn FT_Outline into a fz_path */ + +struct closure { + fz_context *ctx; + fz_path *path; + float x, y; +}; + +static int move_to(const FT_Vector *p, void *cc) +{ + fz_context *ctx = ((struct closure *)cc)->ctx; + fz_path *path = ((struct closure *)cc)->path; + float tx = ((struct closure *)cc)->x; + float ty = ((struct closure *)cc)->y; + fz_moveto(ctx, path, tx + p->x / 64.0f, ty + p->y / 64.0f); + return 0; +} + +static int line_to(const FT_Vector *p, void *cc) +{ + fz_context *ctx = ((struct closure *)cc)->ctx; + fz_path *path = ((struct closure *)cc)->path; + float tx = ((struct closure *)cc)->x; + float ty = ((struct closure *)cc)->y; + fz_lineto(ctx, path, tx + p->x / 64.0f, ty + p->y / 64.0f); + return 0; +} + +static int conic_to(const FT_Vector *c, const FT_Vector *p, void *cc) +{ + fz_context *ctx = ((struct closure *)cc)->ctx; + fz_path *path = ((struct closure *)cc)->path; + float tx = ((struct closure *)cc)->x; + float ty = ((struct closure *)cc)->y; + fz_point s, c1, c2; + float cx = tx + c->x / 64.0f, cy = ty + c->y / 64.0f; + float px = tx + p->x / 64.0f, py = ty + p->y / 64.0f; + s = fz_currentpoint(ctx, path); + c1.x = (s.x + cx * 2) / 3; + c1.y = (s.y + cy * 2) / 3; + c2.x = (px + cx * 2) / 3; + c2.y = (py + cy * 2) / 3; + fz_curveto(ctx, path, c1.x, c1.y, c2.x, c2.y, px, py); + return 0; +} + +static int cubic_to(const FT_Vector *c1, const FT_Vector *c2, const FT_Vector *p, void *cc) +{ + fz_context *ctx = ((struct closure *)cc)->ctx; + fz_path *path = ((struct closure *)cc)->path; + float tx = ((struct closure *)cc)->x; + float ty = ((struct closure *)cc)->y; + fz_curveto(ctx, path, + tx + c1->x/64.0f, ty + c1->y/64.0f, + tx + c2->x/64.0f, ty + c2->y/64.0f, + tx + p->x/64.0f, ty + p->y/64.0f); + return 0; +} + +static const FT_Outline_Funcs outline_funcs = { + move_to, line_to, conic_to, cubic_to, 0, 0 +}; + +fz_path * +fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) +{ + struct closure cc; + FT_Face face = font->ft_face; + FT_Matrix m; + FT_Vector v; + int fterr; + + float strength = fz_matrix_expansion(trm) * 0.02f; + + trm = fz_adjust_ft_glyph_width(ctx, font, gid, trm); + + if (font->ft_italic) + trm = fz_concat(fz_shear(SHEAR, 0), trm); + + 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 = 0; + v.y = 0; + + fz_lock(ctx, FZ_LOCK_FREETYPE); + + fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ + if (fterr) + fz_warn(ctx, "freetype setting character size: %s", ft_error_string(fterr)); + FT_Set_Transform(face, &m, &v); + + fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); + if (fterr) + { + fz_warn(ctx, "freetype load glyph (gid %d): %s", gid, ft_error_string(fterr)); + fz_unlock(ctx, FZ_LOCK_FREETYPE); + return NULL; + } + + if (font->ft_bold) + { + FT_Outline_Embolden(&face->glyph->outline, strength * 64); + FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); + } + + fz_try(ctx) + { + cc.ctx = ctx; + cc.path = fz_new_path(ctx); + cc.x = trm.e; + cc.y = trm.f; + fz_moveto(ctx, cc.path, cc.x, cc.y); + FT_Outline_Decompose(&face->glyph->outline, &outline_funcs, &cc); + fz_closepath(ctx, cc.path); + } + fz_catch(ctx) + { + fz_warn(ctx, "freetype cannot decompose outline"); + fz_free(ctx, cc.path); + fz_unlock(ctx, FZ_LOCK_FREETYPE); + return NULL; + } + + fz_unlock(ctx, FZ_LOCK_FREETYPE); + + return cc.path; +} + /* * Type 3 fonts... */ @@ -726,7 +858,7 @@ fz_bound_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) } fz_pixmap * -fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_colorspace *model) +fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_colorspace *model, fz_bbox scissor) { fz_matrix ctm; void *contents; @@ -765,6 +897,8 @@ fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_co bbox.x1++; bbox.y1++; + bbox = fz_intersect_bbox(bbox, scissor); + glyph = fz_new_pixmap_with_bbox(ctx, model ? model : fz_device_gray, bbox); fz_clear_pixmap(ctx, glyph); @@ -865,6 +999,18 @@ fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) return fz_transform_rect(trm, font->bbox); } +fz_path * +fz_outline_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm) +{ + if (!font->ft_face) + { + fz_warn(ctx, "cannot convert type3 glyph to path"); + return NULL; + } + + return fz_outline_ft_glyph(ctx, font, gid, ctm); +} + int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid) { if (!font->t3procs || !font->t3flags || gid < 0 || gid >= font->bbox_count) diff --git a/fitz/res_path.c b/fitz/res_path.c index 7b429c43..d02ea560 100644 --- a/fitz/res_path.c +++ b/fitz/res_path.c @@ -63,6 +63,40 @@ grow_path(fz_context *ctx, fz_path *path, int n) path->last = path->len; } +fz_point +fz_currentpoint(fz_context *ctx, fz_path *path) +{ + fz_point c, m; + int i; + + c.x = c.y = m.x = m.y = 0; + i = 0; + + while (i < path->len) + { + switch (path->items[i++].k) + { + case FZ_MOVETO: + m.x = c.x = path->items[i++].v; + m.y = c.y = path->items[i++].v; + break; + case FZ_LINETO: + c.x = path->items[i++].v; + c.y = path->items[i++].v; + break; + case FZ_CURVETO: + i += 4; + c.x = path->items[i++].v; + c.y = path->items[i++].v; + break; + case FZ_CLOSE_PATH: + c = m; + } + } + + return c; +} + void fz_moveto(fz_context *ctx, fz_path *path, float x, float y) { -- cgit v1.2.3