summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2013-08-29 15:53:45 +0100
committerRobin Watts <robin.watts@artifex.com>2013-09-02 11:40:14 +0100
commite53325d2366e313dafcfee8432d12d20f6d0a88f (patch)
tree3b3c39c9c8d83d219c4005be6f46bbe0550a3952
parentda277059b37380d57028ff79a636f4d725c96e8f (diff)
downloadmupdf-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.h5
-rw-r--r--source/fitz/draw-glyph.c127
-rw-r--r--source/fitz/font.c135
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