[PATCH] win32: Use a font_face hash table provide unique font faces

Adrian Johnson ajohnson at redneon.com
Fri Nov 6 05:07:49 PST 2009


Similar to the freetype and toy font backends, use a hash table
to provide map logfont,hfont to font faces.

Bug 24849 - Inkscape is reembeding the same font.
---
 src/cairo-debug.c              |    4 +
 src/cairo-mutex-list-private.h |    4 +
 src/cairo-win32-font.c         |  163 ++++++++++++++++++++++++++++++++++++++-
 src/cairoint.h                 |    3 +
 4 files changed, 169 insertions(+), 5 deletions(-)

diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index 9160728..0cb416b 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -69,6 +69,10 @@ cairo_debug_reset_static_data (void)
     _cairo_ft_font_reset_static_data ();
 #endif
 
+#if CAIRO_HAS_WIN32_FONT
+    _cairo_win32_font_reset_static_data ();
+#endif
+
     _cairo_intern_string_reset_static_data ();
 
     _cairo_scaled_font_reset_static_data ();
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index 2f48316..3af4d71 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -48,6 +48,10 @@ CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex)
 #endif
 
+#if CAIRO_HAS_WIN32_FONT
+CAIRO_MUTEX_DECLARE (_cairo_win32_font_face_mutex)
+#endif
+
 #if CAIRO_HAS_XLIB_SURFACE
 CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex)
 #endif
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 7a86cc8..c13901d 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -46,6 +46,8 @@
 
 #include "cairo-win32-private.h"
 
+#include <wchar.h>
+
 #ifndef SPI_GETFONTSMOOTHINGTYPE
 #define SPI_GETFONTSMOOTHINGTYPE 0x200a
 #endif
@@ -1903,6 +1905,120 @@ const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
     _cairo_win32_font_face_scaled_font_create
 };
 
+/* We maintain a hash table from LOGFONT,HFONT => #cairo_font_face_t.
+ * The primary purpose of this mapping is to provide unique
+ * #cairo_font_face_t values so that our cache and mapping from
+ * #cairo_font_face_t => #cairo_scaled_font_t works. Once the
+ * corresponding #cairo_font_face_t objects fall out of downstream
+ * caches, we don't need them in this hash table anymore.
+ *
+ * Modifications to this hash table are protected by
+ * _cairo_win32_font_face_mutex.
+ */
+
+static cairo_hash_table_t *cairo_win32_font_face_hash_table = NULL;
+
+static int
+_cairo_win32_font_face_keys_equal (const void *key_a,
+				   const void *key_b);
+
+static void
+_cairo_win32_font_face_hash_table_destroy (void)
+{
+    cairo_win32_font_face_t *font_face;
+
+    CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex);
+
+    if (cairo_win32_font_face_hash_table) {
+	/* This is rather inefficient, but destroying the hash table
+	 * is something we only do during debugging, (during
+	 * cairo_debug_reset_static_data), when efficiency is not
+	 * relevant. */
+        while (1) {
+	    font_face= _cairo_hash_table_random_entry (cairo_win32_font_face_hash_table,
+						       NULL);
+	    if (font_face == NULL)
+		break;
+	    _cairo_hash_table_remove (cairo_win32_font_face_hash_table,
+				      &font_face->base.hash_entry);
+
+	    cairo_font_face_destroy (&font_face->base);
+	}
+
+	_cairo_hash_table_destroy (cairo_win32_font_face_hash_table);
+
+	cairo_win32_font_face_hash_table = NULL;
+    }
+
+    CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex);
+}
+
+static cairo_hash_table_t *
+_cairo_win32_font_face_hash_table_lock (void)
+{
+    CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex);
+
+    if (cairo_win32_font_face_hash_table == NULL)
+    {
+	cairo_win32_font_face_hash_table =
+	_cairo_hash_table_create (_cairo_win32_font_face_keys_equal);
+
+	if (cairo_win32_font_face_hash_table == NULL) {
+	    CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex);
+	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	    return NULL;
+	}
+    }
+
+    return cairo_win32_font_face_hash_table;
+}
+
+static void
+_cairo_win32_font_face_hash_table_unlock (void)
+{
+    CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex);
+}
+
+static void
+_cairo_win32_font_face_init_key (cairo_win32_font_face_t *key,
+				 LOGFONTW                *logfont,
+				 HFONT                    font)
+{
+    unsigned long hash = _CAIRO_HASH_INIT_VALUE;
+
+    key->logfont = *logfont;
+    key->hfont = font;
+
+    hash = _cairo_hash_bytes (0, logfont->lfFaceName, wcslen(logfont->lfFaceName));
+    hash = _cairo_hash_bytes (hash, &logfont->lfWeight, sizeof(logfont->lfWeight));
+    hash = _cairo_hash_bytes (hash, &logfont->lfItalic, sizeof(logfont->lfItalic));
+    hash = _cairo_hash_bytes (hash, &font, sizeof(font));
+
+    key->base.hash_entry.hash = hash;
+}
+
+static int
+_cairo_win32_font_face_keys_equal (const void *key_a,
+				   const void *key_b)
+{
+    const cairo_win32_font_face_t *face_a = key_a;
+    const cairo_win32_font_face_t *face_b = key_b;
+
+    if (face_a->logfont.lfWeight         == face_b->logfont.lfWeight &&
+	face_a->logfont.lfItalic         == face_b->logfont.lfItalic &&
+	face_a->logfont.lfUnderline      == face_b->logfont.lfUnderline &&
+	face_a->logfont.lfStrikeOut      == face_b->logfont.lfStrikeOut &&
+	face_a->logfont.lfCharSet        == face_b->logfont.lfCharSet &&
+	face_a->logfont.lfOutPrecision   == face_b->logfont.lfOutPrecision &&
+	face_a->logfont.lfClipPrecision  == face_b->logfont.lfClipPrecision &&
+	face_a->logfont.lfPitchAndFamily == face_b->logfont.lfPitchAndFamily &&
+	wcscmp (face_a->logfont.lfFaceName, face_a->logfont.lfFaceName) == 0 &&
+	face_a->hfont                    == face_b->hfont)
+	return TRUE;
+    else
+	return FALSE;
+}
+
 /**
  * cairo_win32_font_face_create_for_logfontw_hfont:
  * @logfont: A #LOGFONTW structure specifying the font to use.
@@ -1925,20 +2041,51 @@ const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
 cairo_font_face_t *
 cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font)
 {
-    cairo_win32_font_face_t *font_face;
+    cairo_win32_font_face_t *font_face, key;
+    cairo_hash_table_t *hash_table;
+    cairo_status_t status;
+
+    hash_table = _cairo_win32_font_face_hash_table_lock ();
+    if (unlikely (hash_table == NULL)) {
+        _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_font_face_t *)&_cairo_font_face_nil;
+    }
+
+    _cairo_win32_font_face_init_key (&key, logfont, font);
+
+    /* Return existing unscaled font if it exists in the hash table. */
+    font_face = _cairo_hash_table_lookup (hash_table,
+					 &key.base.hash_entry);
+    if (font_face != NULL) {
+	cairo_font_face_reference (&font_face->base);
+	goto DONE;
+    }
 
+    /* Otherwise create it and insert into hash table. */
     font_face = malloc (sizeof (cairo_win32_font_face_t));
     if (!font_face) {
         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
-        return (cairo_font_face_t *)&_cairo_font_face_nil;
+	goto FAIL;
     }
 
-    font_face->logfont = *logfont;
-    font_face->hfont = font;
-
+    _cairo_win32_font_face_init_key (font_face, logfont, font);
     _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend);
 
+    assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash);
+    status = _cairo_hash_table_insert (hash_table,
+				       &font_face->base.hash_entry);
+    if (unlikely (status))
+	goto FAIL;
+
+DONE:
+    _cairo_win32_font_face_hash_table_unlock ();
+
     return &font_face->base;
+
+FAIL:
+    _cairo_win32_font_face_hash_table_unlock ();
+
+    return (cairo_font_face_t *)&_cairo_font_face_nil;
 }
 
 /**
@@ -2147,3 +2294,9 @@ cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font,
     }
     *device_to_logical = win_font->device_to_logical;
 }
+
+void
+_cairo_win32_font_reset_static_data (void)
+{
+    _cairo_win32_font_face_hash_table_destroy ();
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 5912173..90059a1 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -433,6 +433,9 @@ _cairo_toy_font_face_reset_static_data (void);
 cairo_private void
 _cairo_ft_font_reset_static_data (void);
 
+cairo_private void
+_cairo_win32_font_reset_static_data (void);
+
 /* the font backend interface */
 
 struct _cairo_unscaled_font_backend {
-- 
1.6.4.2


--------------060809000902000101060603--


More information about the cairo mailing list