diff options
author | Robin Watts <robin.watts@artifex.com> | 2013-08-29 15:53:45 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2013-09-02 11:40:14 +0100 |
commit | e53325d2366e313dafcfee8432d12d20f6d0a88f (patch) | |
tree | 3b3c39c9c8d83d219c4005be6f46bbe0550a3952 | |
parent | da277059b37380d57028ff79a636f4d725c96e8f (diff) | |
download | mupdf-e53325d2366e313dafcfee8432d12d20f6d0a88f.tar.xz |
Add glyph rendering routines that return fz_pixmaps rather than fz_glyphs.
These do no caching, and are intended to be useful for the opengl device.
-rw-r--r-- | include/mupdf/fitz/glyph-cache.h | 5 | ||||
-rw-r--r-- | source/fitz/draw-glyph.c | 127 | ||||
-rw-r--r-- | source/fitz/font.c | 135 |
3 files changed, 237 insertions, 30 deletions
diff --git a/include/mupdf/fitz/glyph-cache.h b/include/mupdf/fitz/glyph-cache.h index b9498cd8..fe8e272f 100644 --- a/include/mupdf/fitz/glyph-cache.h +++ b/include/mupdf/fitz/glyph-cache.h @@ -21,10 +21,15 @@ void fz_purge_glyph_cache(fz_context *ctx); fz_path *fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm); fz_path *fz_outline_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *ctm); fz_glyph *fz_render_ft_glyph(fz_context *ctx, fz_font *font, int cid, const fz_matrix *trm, int aa); +fz_pixmap *fz_render_ft_glyph_pixmap(fz_context *ctx, fz_font *font, int cid, const fz_matrix *trm, int aa); fz_glyph *fz_render_t3_glyph(fz_context *ctx, fz_font *font, int cid, const fz_matrix *trm, fz_colorspace *model, const fz_irect *scissor); +fz_pixmap *fz_render_t3_glyph_pixmap(fz_context *ctx, fz_font *font, int cid, const fz_matrix *trm, fz_colorspace *model, const fz_irect *scissor); fz_glyph *fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *state); +fz_pixmap *fz_render_ft_stroked_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *state); fz_glyph *fz_render_glyph(fz_context *ctx, fz_font*, int, fz_matrix *, fz_colorspace *model, const fz_irect *scissor); +fz_pixmap *fz_render_glyph_pixmap(fz_context *ctx, fz_font*, int, fz_matrix *, fz_colorspace *model, const fz_irect *scissor); fz_glyph *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, fz_matrix *, const fz_matrix *, fz_stroke_state *stroke, const fz_irect *scissor); +fz_pixmap *fz_render_stroked_glyph_pixmap(fz_context *ctx, fz_font*, int, fz_matrix *, const fz_matrix *, fz_stroke_state *stroke, const fz_irect *scissor); void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, const fz_matrix *trm, void *gstate, int nestedDepth); void fz_prepare_t3_glyph(fz_context *ctx, fz_font *font, int gid, int nestedDepth); void fz_dump_glyph_cache_stats(fz_context *ctx); diff --git a/source/fitz/draw-glyph.c b/source/fitz/draw-glyph.c index 3609cc8b..191f098b 100644 --- a/source/fitz/draw-glyph.c +++ b/source/fitz/draw-glyph.c @@ -176,6 +176,52 @@ fz_render_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix *trm, return fz_render_glyph(ctx, font, gid, trm, NULL, scissor); } +fz_pixmap * +fz_render_stroked_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *stroke, const fz_irect *scissor) +{ + if (font->ft_face) + { + float size = fz_matrix_expansion(trm); + fz_matrix subpix_trm = *trm; + unsigned char qe, qf; + int q; + float pix_e, pix_f, r; + + /* Quantise the subpixel positions. */ + /* We never need more than 4 subpixel positions for glyphs - arguably + * even that is too much. */ + if (size >= 48) + q = 0, r = 0.5f; + else if (size >= 24) + q = 128, r = 0.25f; + else + q = 192, r = 0.125f; + + /* Split translation into pixel and subpixel parts */ + subpix_trm.e += r; + pix_e = floorf(subpix_trm.e); + subpix_trm.e -= pix_e; + subpix_trm.f += r; + pix_f = floorf(subpix_trm.f); + subpix_trm.f -= pix_f; + + /* Quantise the subpixel part */ + qe = (int)(subpix_trm.e * 256) & q; + qf = (int)(subpix_trm.f * 256) & q; + subpix_trm.e = qe / 256.0f; + subpix_trm.f = qf / 256.0f; + + /* Reassemble the complete translation */ + trm->e = subpix_trm.e + pix_e; + trm->f = subpix_trm.f + pix_f; + + if (stroke->dash_len > 0) + return NULL; + return fz_render_ft_stroked_glyph_pixmap(ctx, font, gid, &subpix_trm, ctm, stroke); + } + return fz_render_glyph_pixmap(ctx, font, gid, trm, NULL, scissor); +} + static unsigned do_hash(unsigned char *s, int len) { unsigned val = 0; @@ -212,15 +258,6 @@ move_to_front(fz_glyph_cache *cache, fz_glyph_cache_entry *entry) entry->lru_prev = NULL; } -/* - Render a glyph and return a bitmap. - If the glyph is too large to fit the cache we have two choices: - 1) Return NULL so the caller can draw the glyph using an outline. - Only supported for freetype fonts. - 2) Render a clipped glyph by using the scissor rectangle. - Only supported for type 3 fonts. - This must not be inserted into the cache. - */ fz_glyph * fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix *ctm, fz_colorspace *model, const fz_irect *scissor) { @@ -407,6 +444,78 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix *ctm, fz_colo return val; } +fz_pixmap * +fz_render_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, fz_matrix *ctm, fz_colorspace *model, const fz_irect *scissor) +{ + fz_pixmap *val; + float size = fz_matrix_expansion(ctm); + fz_matrix subpix_ctm = *ctm; + int q; + float pix_e, pix_f, r; + unsigned char qe, qf; + + if (size <= MAX_GLYPH_SIZE) + { + scissor = &fz_infinite_irect; + } + else + { + if (font->ft_face) + return NULL; + } + + /* Quantise the subpixel positions. */ + /* We never need more than 4 subpixel positions for glyphs - arguably + * even that is too much. */ + if (size >= 48) + q = 0, r = 0.5f; + else if (size >= 24) + q = 128, r = 0.25f; + else + q = 192, r = 0.125f; + + /* Split translation into pixel and subpixel parts */ + subpix_ctm.e += r; + pix_e = floorf(subpix_ctm.e); + subpix_ctm.e -= pix_e; + subpix_ctm.f += r; + pix_f = floorf(subpix_ctm.f); + subpix_ctm.f -= pix_f; + + /* Quantise the subpixel part */ + qe = (int)(subpix_ctm.e * 256) & q; + qf = (int)(subpix_ctm.f * 256) & q; + subpix_ctm.e = qe / 256.0f; + subpix_ctm.f = qf / 256.0f; + + /* Reassemble the complete translation */ + ctm->e = subpix_ctm.e + pix_e; + ctm->f = subpix_ctm.f + pix_f; + + fz_try(ctx) + { + if (font->ft_face) + { + val = fz_render_ft_glyph_pixmap(ctx, font, gid, &subpix_ctm, fz_aa_level(ctx)); + } + else if (font->t3procs) + { + val = fz_render_t3_glyph_pixmap(ctx, font, gid, &subpix_ctm, model, scissor); + } + else + { + fz_warn(ctx, "assert: uninitialized font structure"); + val = NULL; + } + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + + return val; +} + void fz_dump_glyph_cache_stats(fz_context *ctx) { diff --git a/source/fitz/font.c b/source/fitz/font.c index 1aeab3a6..165b6880 100644 --- a/source/fitz/font.c +++ b/source/fitz/font.c @@ -402,7 +402,7 @@ fz_adjust_ft_glyph_width(fz_context *ctx, fz_font *font, int gid, fz_matrix *trm } static fz_glyph * -fz_copy_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap) +glyph_from_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap) { if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) return fz_new_glyph_from_1bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch); @@ -410,15 +410,23 @@ fz_copy_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap) return fz_new_glyph_from_8bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch); } -/* The glyph cache lock is always taken when this is called. */ -fz_glyph * -fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, int aa) +static fz_pixmap * +pixmap_from_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap) +{ + if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) + return fz_new_pixmap_from_1bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch); + else + return fz_new_pixmap_from_8bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch); +} + +/* Takes the freetype lock, and returns with it held */ +static FT_GlyphSlot +do_ft_render_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, int aa) { FT_Face face = font->ft_face; FT_Matrix m; FT_Vector v; FT_Error fterr; - fz_glyph *result; fz_matrix local_trm = *trm; float strength = fz_matrix_expansion(trm) * 0.02f; @@ -492,7 +500,6 @@ retry_unhinted: if (fterr) { fz_warn(ctx, "freetype load glyph (gid %d): %s", gid, ft_error_string(fterr)); - fz_unlock(ctx, FZ_LOCK_FREETYPE); return NULL; } } @@ -507,13 +514,26 @@ retry_unhinted: if (fterr) { fz_warn(ctx, "freetype render glyph (gid %d): %s", gid, ft_error_string(fterr)); + return NULL; + } + return face->glyph; +} + +fz_pixmap * +fz_render_ft_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, int aa) +{ + FT_GlyphSlot slot = do_ft_render_glyph(ctx, font, gid, trm, aa); + fz_pixmap *pixmap; + + if (slot == NULL) + { fz_unlock(ctx, FZ_LOCK_FREETYPE); return NULL; } fz_try(ctx) { - result = fz_copy_ft_bitmap(ctx, face->glyph->bitmap_left, face->glyph->bitmap_top, &face->glyph->bitmap); + pixmap = pixmap_from_ft_bitmap(ctx, slot->bitmap_left, slot->bitmap_top, &slot->bitmap); } fz_always(ctx) { @@ -524,11 +544,41 @@ retry_unhinted: fz_rethrow(ctx); } - return result; + return pixmap; } +/* The glyph cache lock is always taken when this is called. */ fz_glyph * -fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *state) +fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, int aa) +{ + FT_GlyphSlot slot = do_ft_render_glyph(ctx, font, gid, trm, aa); + fz_glyph *glyph; + + if (slot == NULL) + { + fz_unlock(ctx, FZ_LOCK_FREETYPE); + return NULL; + } + + fz_try(ctx) + { + glyph = glyph_from_ft_bitmap(ctx, slot->bitmap_left, slot->bitmap_top, &slot->bitmap); + } + fz_always(ctx) + { + fz_unlock(ctx, FZ_LOCK_FREETYPE); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + + return glyph; +} + +/* Takes the freetype lock, and returns with it held */ +static FT_Glyph +do_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *state) { FT_Face face = font->ft_face; float expansion = fz_matrix_expansion(ctm); @@ -538,8 +588,6 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_mat FT_Error fterr; FT_Stroker stroker; FT_Glyph glyph; - FT_BitmapGlyph bitmap; - fz_glyph *result; FT_Stroker_LineJoin line_join; fz_matrix local_trm = *trm; @@ -560,7 +608,6 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_mat if (fterr) { fz_warn(ctx, "FT_Set_Char_Size: %s", ft_error_string(fterr)); - fz_unlock(ctx, FZ_LOCK_FREETYPE); return NULL; } @@ -570,7 +617,6 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_mat if (fterr) { fz_warn(ctx, "FT_Load_Glyph(gid %d): %s", gid, ft_error_string(fterr)); - fz_unlock(ctx, FZ_LOCK_FREETYPE); return NULL; } @@ -578,7 +624,6 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_mat if (fterr) { fz_warn(ctx, "FT_Stroker_New: %s", ft_error_string(fterr)); - fz_unlock(ctx, FZ_LOCK_FREETYPE); return NULL; } @@ -604,7 +649,6 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_mat { fz_warn(ctx, "FT_Get_Glyph: %s", ft_error_string(fterr)); FT_Stroker_Done(stroker); - fz_unlock(ctx, FZ_LOCK_FREETYPE); return NULL; } @@ -614,7 +658,6 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_mat fz_warn(ctx, "FT_Glyph_Stroke: %s", ft_error_string(fterr)); FT_Done_Glyph(glyph); FT_Stroker_Done(stroker); - fz_unlock(ctx, FZ_LOCK_FREETYPE); return NULL; } @@ -625,14 +668,57 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_mat { fz_warn(ctx, "FT_Glyph_To_Bitmap: %s", ft_error_string(fterr)); FT_Done_Glyph(glyph); + return NULL; + } + return glyph; +} + +fz_pixmap * +fz_render_ft_stroked_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *state) +{ + FT_Glyph glyph = do_render_ft_stroked_glyph(ctx, font, gid, trm, ctm, state); + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; + fz_pixmap *pixmap; + + if (bitmap == NULL) + { fz_unlock(ctx, FZ_LOCK_FREETYPE); return NULL; } - bitmap = (FT_BitmapGlyph)glyph; fz_try(ctx) { - result = fz_copy_ft_bitmap(ctx, bitmap->left, bitmap->top, &bitmap->bitmap); + pixmap = pixmap_from_ft_bitmap(ctx, bitmap->left, bitmap->top, &bitmap->bitmap); + } + fz_always(ctx) + { + FT_Done_Glyph(glyph); + fz_unlock(ctx, FZ_LOCK_FREETYPE); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + + return pixmap; +} + +fz_glyph * +fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, const fz_matrix *ctm, fz_stroke_state *state) +{ + FT_Glyph glyph = do_render_ft_stroked_glyph(ctx, font, gid, trm, ctm, state); + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; + fz_glyph *result; + + if (bitmap == NULL) + { + fz_unlock(ctx, FZ_LOCK_FREETYPE); + return NULL; + } + + fz_try(ctx) + { + result = glyph_from_ft_bitmap(ctx, bitmap->left, bitmap->top, &bitmap->bitmap); } fz_always(ctx) { @@ -933,8 +1019,8 @@ fz_bound_t3_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, return bounds; } -fz_glyph * -fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, fz_colorspace *model, const fz_irect *scissor) +fz_pixmap * +fz_render_t3_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, fz_colorspace *model, const fz_irect *scissor) { fz_display_list *list; fz_matrix ctm; @@ -998,7 +1084,14 @@ fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm else result = glyph; - return fz_new_glyph_from_pixmap(ctx, result); + return result; +} + +fz_glyph * +fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, fz_colorspace *model, const fz_irect *scissor) +{ + fz_pixmap *pixmap = fz_render_t3_glyph_pixmap(ctx, font, gid, trm, model, scissor); + return fz_new_glyph_from_pixmap(ctx, pixmap); } void |