summaryrefslogtreecommitdiff
path: root/draw/draw_glyph.c
diff options
context:
space:
mode:
Diffstat (limited to 'draw/draw_glyph.c')
-rw-r--r--draw/draw_glyph.c87
1 files changed, 66 insertions, 21 deletions
diff --git a/draw/draw_glyph.c b/draw/draw_glyph.c
index 49f04fe8..00eaf460 100644
--- a/draw/draw_glyph.c
+++ b/draw/draw_glyph.c
@@ -8,6 +8,7 @@ typedef struct fz_glyph_key_s fz_glyph_key;
struct fz_glyph_cache_s
{
+ int refs;
fz_hash_table *hash;
int total;
};
@@ -37,10 +38,12 @@ fz_new_glyph_cache_context(fz_context *ctx)
fz_rethrow(ctx);
}
cache->total = 0;
+ cache->refs = 1;
ctx->glyph_cache = cache;
}
+/* The glyph cache lock is always held when this function is called. */
static void
fz_evict_glyph_cache(fz_context *ctx)
{
@@ -70,10 +73,25 @@ fz_free_glyph_cache_context(fz_context *ctx)
if (!ctx->glyph_cache)
return;
- fz_evict_glyph_cache(ctx);
- fz_free_hash(ctx, ctx->glyph_cache->hash);
- fz_free(ctx, ctx->glyph_cache);
- ctx->glyph_cache = NULL;
+ fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
+ ctx->glyph_cache->refs--;
+ if (ctx->glyph_cache->refs == 0)
+ {
+ fz_evict_glyph_cache(ctx);
+ fz_free_hash(ctx, ctx->glyph_cache->hash);
+ fz_free(ctx, ctx->glyph_cache);
+ ctx->glyph_cache = NULL;
+ }
+ fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
+}
+
+fz_glyph_cache *
+fz_glyph_cache_keep(fz_context *ctx)
+{
+ fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
+ ctx->glyph_cache->refs++;
+ fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
+ return ctx->glyph_cache;
}
fz_pixmap *
@@ -92,8 +110,6 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_color
fz_pixmap *val;
float size = fz_matrix_expansion(ctm);
- if (!ctx->glyph_cache)
- fz_new_glyph_cache_context(ctx);
cache = ctx->glyph_cache;
if (size > MAX_FONT_SIZE)
@@ -113,25 +129,49 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_color
key.e = (ctm.e - floorf(ctm.e)) * 256;
key.f = (ctm.f - floorf(ctm.f)) * 256;
+ fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
val = fz_hash_find(ctx, cache->hash, &key);
if (val)
- return fz_keep_pixmap(ctx, val);
+ {
+ fz_keep_pixmap(ctx, val);
+ fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
+ return val;
+ }
ctm.e = floorf(ctm.e) + key.e / 256.0f;
ctm.f = floorf(ctm.f) + key.f / 256.0f;
- if (font->ft_face)
- {
- val = fz_render_ft_glyph(ctx, font, gid, ctm);
- }
- else if (font->t3procs)
+ fz_try(ctx)
{
- val = fz_render_t3_glyph(ctx, font, gid, ctm, model);
+ if (font->ft_face)
+ {
+ val = fz_render_ft_glyph(ctx, font, gid, ctm);
+ }
+ else if (font->t3procs)
+ {
+ /* We drop the glyphcache here, and execute the t3
+ * glyph code. The danger here is that some other
+ * thread will come along, and want the same glyph
+ * too. If it does, we may both end up rendering
+ * pixmaps. We cope with this later on, by ensuring
+ * that only one gets inserted into the cache. If
+ * we insert ours to find one already there, we
+ * abandon ours, and use the one there already.
+ */
+ fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
+ val = fz_render_t3_glyph(ctx, font, gid, ctm, model);
+ fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
+ }
+ else
+ {
+ fz_warn(ctx, "assert: uninitialized font structure");
+ val = NULL;
+ }
}
- else
+ fz_catch(ctx)
{
- fz_warn(ctx, "assert: uninitialized font structure");
- return NULL;
+ fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
+ fz_rethrow(ctx);
}
if (val)
@@ -142,8 +182,14 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_color
fz_evict_glyph_cache(ctx);
fz_try(ctx)
{
- fz_hash_insert(ctx, cache->hash, &key, val);
- fz_keep_font(ctx, key.font);
+ fz_pixmap *pix = fz_hash_insert(ctx, cache->hash, &key, val);
+ if (pix)
+ {
+ fz_drop_pixmap(ctx, val);
+ val = pix;
+ }
+ else
+ fz_keep_font(ctx, key.font);
val = fz_keep_pixmap(ctx, val);
}
fz_catch(ctx)
@@ -151,10 +197,9 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_color
fz_warn(ctx, "Failed to encache glyph - continuing");
}
cache->total += val->w * val->h;
- return val;
}
- return val;
}
- return NULL;
+ fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
+ return val;
}