|
View:
New views
2 Messages
—
Rating Filter:
Alert me
|
|
|
win32 font facesBug 24849 reports that Inkscape on win32 is creating PDFs with the same
font embedded multiple times. This is because the win32 font backend is not using a hash table of font faces to return an existing face when the same font is used. Attached is a patch that to fix this. The patch doesn't completely solve the problem of ensuring each win32 font used is embedded only once. The function cairo_win32_font_face_create_for_logfontw_hfont ((LOGFONTW *logfont, HFONT font);) which can specify a HFONT object to use. My patch uses both LOGFONT and HFONT as the hash table key so creating fonts with the same LOGFONT but different HFONT objects will return different font faces. For Inkscape the patch fixes the problem as Inkscape only uses cairo_win32_font_face_create_for_logfontw (). Would it be better to filter out duplicate LOGFONTS in cairo-scaled-font-subsets.c instead to guarantee fonts will only be embedded once? From 668fb31a2bbf8cc01baaa6c786b7757066edb4df Mon Sep 17 00:00:00 2001 From: Adrian Johnson <ajohnson@...> Date: Fri, 6 Nov 2009 23:37:49 +1030 Subject: [PATCH] win32: Use a font_face hash table provide unique font faces 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 _______________________________________________ cairo mailing list cairo@... http://lists.cairographics.org/mailman/listinfo/cairo |
|
|
Re: win32 font facesAdrian Johnson wrote:
> Bug 24849 reports that Inkscape on win32 is creating PDFs with the same > font embedded multiple times. FYI - I encountered a similar problem with custom/user fonts being embedded multiple times in PDFs. (Or was it with FT fonts? Or was it both? I don't recall at the moment.) However, I had to end up filtering out duplicates myself... [ snip ] > Would it be better to filter out duplicate LOGFONTS in > cairo-scaled-font-subsets.c instead to guarantee fonts will only be > embedded once? Would this alternate fix be limited to just win32/LOGFONTS, or would it filter out any/all duplicates (Including user fonts)? I don't particularly _need_ it, since my code is in place, and I have to do some caching anyways to prevent dangling pointers, but if this affected my case, I'd probably review/revise my code accordingly. Ian _______________________________________________ cairo mailing list cairo@... http://lists.cairographics.org/mailman/listinfo/cairo |
| Free embeddable forum powered by Nabble | Forum Help |