michael@0: # HG changeset patch michael@0: # User Andrea Canciani , Adrian Johnson michael@0: # Date 1354838294 -46800 michael@0: # Node ID 390df735b9d5c5ba07a4d3fe9ca2ebc9e7626a78 michael@0: # Parent e30a5b6a5a003b85fc1ca8b76719a56ef59d976e michael@0: Bug 717178. Part 2: Import changesets eb29a25d, 6e3e3291 and 101fab7c from upstream. michael@0: ====== michael@0: michael@0: From 101fab7cd8a90f7cf3d8113c792b3f8c2a9afb7d Mon Sep 17 00:00:00 2001 michael@0: From: Andrea Canciani michael@0: Date: Wed, 15 Jun 2011 09:37:36 +0000 michael@0: Subject: win32-font: Improve static data reset function michael@0: michael@0: The hashtable is guaranteed to only contain font faces which are michael@0: currently referenced, hence there is no need to remove any font face michael@0: when it is reset (just like for toy-font). michael@0: michael@0: This makes the function simpler and fixes the assertion michael@0: michael@0: Assertion failed: predicate != NULL, file cairo-hash.c, line 373 michael@0: michael@0: hit by multiple tests (the first one being "clear"). michael@0: michael@0: See https://bugs.freedesktop.org/show_bug.cgi?id=38049 michael@0: michael@0: ====== michael@0: michael@0: From eb29a25dd6dddc511388bf883c9b95843ecdb823 Mon Sep 17 00:00:00 2001 michael@0: From: Adrian Johnson michael@0: Date: Tue, 16 Nov 2010 13:18:39 +0000 michael@0: Subject: win32: Use a font_face hash table to provide unique font faces michael@0: michael@0: Similar to the freetype and toy font backends, use a hash table michael@0: to map logfont,hfont to font faces. michael@0: michael@0: This fixes the multiple embedding of the same font in PDF. michael@0: michael@0: https://bugs.freedesktop.org/show_bug.cgi?id=24849 michael@0: michael@0: ====== michael@0: michael@0: From 6e3e329170ab4b96bc0d587c8071e869e228e758 Mon Sep 17 00:00:00 2001 michael@0: From: Adrian Johnson michael@0: Date: Thu, 18 Nov 2010 12:37:45 +0000 michael@0: Subject: win32: fix font_face hashing michael@0: michael@0: some bugs were discovered while testing with firefox michael@0: michael@0: ====== michael@0: michael@0: diff --git a/gfx/cairo/cairo/src/cairo-debug.c b/gfx/cairo/cairo/src/cairo-debug.c michael@0: --- a/gfx/cairo/cairo/src/cairo-debug.c michael@0: +++ b/gfx/cairo/cairo/src/cairo-debug.c michael@0: @@ -64,16 +64,20 @@ cairo_debug_reset_static_data (void) michael@0: _cairo_scaled_font_map_destroy (); michael@0: michael@0: _cairo_toy_font_face_reset_static_data (); michael@0: michael@0: #if CAIRO_HAS_FT_FONT michael@0: _cairo_ft_font_reset_static_data (); michael@0: #endif michael@0: michael@0: +#if CAIRO_HAS_WIN32_FONT michael@0: + _cairo_win32_font_reset_static_data (); michael@0: +#endif michael@0: + michael@0: _cairo_intern_string_reset_static_data (); michael@0: michael@0: _cairo_scaled_font_reset_static_data (); michael@0: michael@0: _cairo_pattern_reset_static_data (); michael@0: michael@0: _cairo_clip_reset_static_data (); michael@0: michael@0: diff --git a/gfx/cairo/cairo/src/cairo-mutex-list-private.h b/gfx/cairo/cairo/src/cairo-mutex-list-private.h michael@0: --- a/gfx/cairo/cairo/src/cairo-mutex-list-private.h michael@0: +++ b/gfx/cairo/cairo/src/cairo-mutex-list-private.h michael@0: @@ -46,16 +46,20 @@ CAIRO_MUTEX_DECLARE (_cairo_intern_strin michael@0: CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex) michael@0: CAIRO_MUTEX_DECLARE (_cairo_scaled_glyph_page_cache_mutex) michael@0: CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex) michael@0: michael@0: #if CAIRO_HAS_FT_FONT michael@0: CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex) michael@0: #endif michael@0: michael@0: +#if CAIRO_HAS_WIN32_FONT michael@0: +CAIRO_MUTEX_DECLARE (_cairo_win32_font_face_mutex) michael@0: +#endif michael@0: + michael@0: #if CAIRO_HAS_XLIB_SURFACE michael@0: CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex) michael@0: #endif michael@0: michael@0: #if CAIRO_HAS_XCB_SURFACE michael@0: CAIRO_MUTEX_DECLARE (_cairo_xcb_connections_mutex) michael@0: #endif michael@0: michael@0: diff --git a/gfx/cairo/cairo/src/cairo-win32-font.c b/gfx/cairo/cairo/src/cairo-win32-font.c michael@0: --- a/gfx/cairo/cairo/src/cairo-win32-font.c michael@0: +++ b/gfx/cairo/cairo/src/cairo-win32-font.c michael@0: @@ -42,16 +42,18 @@ michael@0: # define _WIN32_WINNT 0x0500 michael@0: #endif michael@0: michael@0: #include "cairoint.h" michael@0: michael@0: #include "cairo-win32-private.h" michael@0: #include "cairo-error-private.h" michael@0: michael@0: +#include michael@0: + michael@0: #ifndef SPI_GETFONTSMOOTHINGTYPE michael@0: #define SPI_GETFONTSMOOTHINGTYPE 0x200a michael@0: #endif michael@0: #ifndef FE_FONTSMOOTHINGCLEARTYPE michael@0: #define FE_FONTSMOOTHINGCLEARTYPE 2 michael@0: #endif michael@0: #ifndef CLEARTYPE_QUALITY michael@0: #define CLEARTYPE_QUALITY 5 michael@0: @@ -1887,19 +1889,17 @@ struct _cairo_win32_font_face { michael@0: cairo_font_face_t base; michael@0: LOGFONTW logfont; michael@0: HFONT hfont; michael@0: }; michael@0: michael@0: /* implement the platform-specific interface */ michael@0: michael@0: static void michael@0: -_cairo_win32_font_face_destroy (void *abstract_face) michael@0: -{ michael@0: -} michael@0: +_cairo_win32_font_face_destroy (void *abstract_face); michael@0: michael@0: static cairo_bool_t michael@0: _is_scale (const cairo_matrix_t *matrix, double scale) michael@0: { michael@0: return matrix->xx == scale && matrix->yy == scale && michael@0: matrix->xy == 0. && matrix->yx == 0. && michael@0: matrix->x0 == 0. && matrix->y0 == 0.; michael@0: } michael@0: @@ -1932,16 +1932,128 @@ static cairo_status_t michael@0: michael@0: const cairo_font_face_backend_t _cairo_win32_font_face_backend = { michael@0: CAIRO_FONT_TYPE_WIN32, michael@0: _cairo_win32_font_face_create_for_toy, michael@0: _cairo_win32_font_face_destroy, michael@0: _cairo_win32_font_face_scaled_font_create michael@0: }; michael@0: michael@0: +/* We maintain a hash table from LOGFONT,HFONT => #cairo_font_face_t. michael@0: + * The primary purpose of this mapping is to provide unique michael@0: + * #cairo_font_face_t values so that our cache and mapping from michael@0: + * #cairo_font_face_t => #cairo_scaled_font_t works. Once the michael@0: + * corresponding #cairo_font_face_t objects fall out of downstream michael@0: + * caches, we don't need them in this hash table anymore. michael@0: + * michael@0: + * Modifications to this hash table are protected by michael@0: + * _cairo_win32_font_face_mutex. michael@0: + */ michael@0: + michael@0: +static cairo_hash_table_t *cairo_win32_font_face_hash_table = NULL; michael@0: + michael@0: +static int michael@0: +_cairo_win32_font_face_keys_equal (const void *key_a, michael@0: + const void *key_b); michael@0: + michael@0: +static void michael@0: +_cairo_win32_font_face_hash_table_destroy (void) michael@0: +{ michael@0: + cairo_hash_table_t *hash_table; michael@0: + michael@0: + /* We manually acquire the lock rather than calling michael@0: + * _cairo_win32_font_face_hash_table_lock simply to avoid creating michael@0: + * the table only to destroy it again. */ michael@0: + CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex); michael@0: + hash_table = cairo_win32_font_face_hash_table; michael@0: + cairo_win32_font_face_hash_table = NULL; michael@0: + CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); michael@0: + michael@0: + if (hash_table != NULL) michael@0: + _cairo_hash_table_destroy (hash_table); michael@0: +} michael@0: + michael@0: +static cairo_hash_table_t * michael@0: +_cairo_win32_font_face_hash_table_lock (void) michael@0: +{ michael@0: + CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex); michael@0: + michael@0: + if (unlikely (cairo_win32_font_face_hash_table == NULL)) michael@0: + { michael@0: + cairo_win32_font_face_hash_table = michael@0: + _cairo_hash_table_create (_cairo_win32_font_face_keys_equal); michael@0: + michael@0: + if (unlikely (cairo_win32_font_face_hash_table == NULL)) { michael@0: + CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); michael@0: + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); michael@0: + return NULL; michael@0: + } michael@0: + } michael@0: + michael@0: + return cairo_win32_font_face_hash_table; michael@0: +} michael@0: + michael@0: +static void michael@0: +_cairo_win32_font_face_hash_table_unlock (void) michael@0: +{ michael@0: + CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); michael@0: +} michael@0: + michael@0: +static void michael@0: +_cairo_win32_font_face_init_key (cairo_win32_font_face_t *key, michael@0: + LOGFONTW *logfont, michael@0: + HFONT font) michael@0: +{ michael@0: + unsigned long hash = _CAIRO_HASH_INIT_VALUE; michael@0: + michael@0: + key->logfont = *logfont; michael@0: + key->hfont = font; michael@0: + michael@0: + hash = _cairo_hash_bytes (0, logfont->lfFaceName, 2*wcslen(logfont->lfFaceName)); michael@0: + hash = _cairo_hash_bytes (hash, &logfont->lfWeight, sizeof(logfont->lfWeight)); michael@0: + hash = _cairo_hash_bytes (hash, &logfont->lfItalic, sizeof(logfont->lfItalic)); michael@0: + michael@0: + key->base.hash_entry.hash = hash; michael@0: +} michael@0: + michael@0: +static int michael@0: +_cairo_win32_font_face_keys_equal (const void *key_a, michael@0: + const void *key_b) michael@0: +{ michael@0: + const cairo_win32_font_face_t *face_a = key_a; michael@0: + const cairo_win32_font_face_t *face_b = key_b; michael@0: + michael@0: + if (face_a->logfont.lfWeight == face_b->logfont.lfWeight && michael@0: + face_a->logfont.lfItalic == face_b->logfont.lfItalic && michael@0: + face_a->logfont.lfUnderline == face_b->logfont.lfUnderline && michael@0: + face_a->logfont.lfStrikeOut == face_b->logfont.lfStrikeOut && michael@0: + face_a->logfont.lfCharSet == face_b->logfont.lfCharSet && michael@0: + face_a->logfont.lfOutPrecision == face_b->logfont.lfOutPrecision && michael@0: + face_a->logfont.lfClipPrecision == face_b->logfont.lfClipPrecision && michael@0: + face_a->logfont.lfPitchAndFamily == face_b->logfont.lfPitchAndFamily && michael@0: + (wcscmp (face_a->logfont.lfFaceName, face_b->logfont.lfFaceName) == 0)) michael@0: + return TRUE; michael@0: + else michael@0: + return FALSE; michael@0: +} michael@0: + michael@0: +static void michael@0: +_cairo_win32_font_face_destroy (void *abstract_face) michael@0: +{ michael@0: + cairo_hash_table_t *hash_table; michael@0: + cairo_win32_font_face_t *font_face = abstract_face; michael@0: + michael@0: + hash_table = _cairo_win32_font_face_hash_table_lock (); michael@0: + if (unlikely (hash_table == NULL)) { michael@0: + return; michael@0: + } michael@0: + _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); michael@0: + _cairo_win32_font_face_hash_table_unlock (); michael@0: +} michael@0: + michael@0: /** michael@0: * cairo_win32_font_face_create_for_logfontw_hfont: michael@0: * @logfont: A #LOGFONTW structure specifying the font to use. michael@0: * If @font is %NULL then the lfHeight, lfWidth, lfOrientation and lfEscapement michael@0: * fields of this structure are ignored. Otherwise lfWidth, lfOrientation and michael@0: * lfEscapement must be zero. michael@0: * @font: An #HFONT that can be used when the font matrix is a scale by michael@0: * -lfHeight and the CTM is identity. michael@0: @@ -1954,30 +2066,61 @@ const cairo_font_face_backend_t _cairo_w michael@0: * and can be used with functions such as cairo_win32_scaled_font_select_font(). michael@0: * michael@0: * Return value: a newly created #cairo_font_face_t. Free with michael@0: * cairo_font_face_destroy() when you are done using it. michael@0: **/ michael@0: cairo_font_face_t * michael@0: cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font) michael@0: { michael@0: - cairo_win32_font_face_t *font_face; michael@0: + cairo_win32_font_face_t *font_face, key; michael@0: + cairo_hash_table_t *hash_table; michael@0: + cairo_status_t status; michael@0: michael@0: + hash_table = _cairo_win32_font_face_hash_table_lock (); michael@0: + if (unlikely (hash_table == NULL)) { michael@0: + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); michael@0: + return (cairo_font_face_t *)&_cairo_font_face_nil; michael@0: + } michael@0: + michael@0: + _cairo_win32_font_face_init_key (&key, logfont, font); michael@0: + michael@0: + /* Return existing unscaled font if it exists in the hash table. */ michael@0: + font_face = _cairo_hash_table_lookup (hash_table, michael@0: + &key.base.hash_entry); michael@0: + if (font_face != NULL) { michael@0: + cairo_font_face_reference (&font_face->base); michael@0: + goto DONE; michael@0: + } michael@0: + michael@0: + /* Otherwise create it and insert into hash table. */ michael@0: font_face = malloc (sizeof (cairo_win32_font_face_t)); michael@0: if (!font_face) { michael@0: _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); michael@0: - return (cairo_font_face_t *)&_cairo_font_face_nil; michael@0: + goto FAIL; michael@0: } michael@0: michael@0: - font_face->logfont = *logfont; michael@0: - font_face->hfont = font; michael@0: - michael@0: + _cairo_win32_font_face_init_key (font_face, logfont, font); michael@0: _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend); michael@0: michael@0: + assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash); michael@0: + status = _cairo_hash_table_insert (hash_table, michael@0: + &font_face->base.hash_entry); michael@0: + if (unlikely (status)) michael@0: + goto FAIL; michael@0: + michael@0: +DONE: michael@0: + _cairo_win32_font_face_hash_table_unlock (); michael@0: + michael@0: return &font_face->base; michael@0: + michael@0: +FAIL: michael@0: + _cairo_win32_font_face_hash_table_unlock (); michael@0: + michael@0: + return (cairo_font_face_t *)&_cairo_font_face_nil; michael@0: } michael@0: michael@0: /** michael@0: * cairo_win32_font_face_create_for_logfontw: michael@0: * @logfont: A #LOGFONTW structure specifying the font to use. michael@0: * The lfHeight, lfWidth, lfOrientation and lfEscapement michael@0: * fields of this structure are ignored. michael@0: * michael@0: @@ -2176,8 +2319,14 @@ cairo_win32_scaled_font_get_device_to_lo michael@0: cairo_win32_scaled_font_t *win_font = (cairo_win32_scaled_font_t *)scaled_font; michael@0: if (! _cairo_scaled_font_is_win32 (scaled_font)) { michael@0: _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH); michael@0: cairo_matrix_init_identity (device_to_logical); michael@0: return; michael@0: } michael@0: *device_to_logical = win_font->device_to_logical; michael@0: } michael@0: + michael@0: +void michael@0: +_cairo_win32_font_reset_static_data (void) michael@0: +{ michael@0: + _cairo_win32_font_face_hash_table_destroy (); michael@0: +} michael@0: diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h michael@0: --- a/gfx/cairo/cairo/src/cairoint.h michael@0: +++ b/gfx/cairo/cairo/src/cairoint.h michael@0: @@ -403,16 +403,19 @@ cairo_private void michael@0: _cairo_reset_static_data (void); michael@0: michael@0: cairo_private void michael@0: _cairo_toy_font_face_reset_static_data (void); michael@0: michael@0: cairo_private void michael@0: _cairo_ft_font_reset_static_data (void); michael@0: michael@0: +cairo_private void michael@0: +_cairo_win32_font_reset_static_data (void); michael@0: + michael@0: /* the font backend interface */ michael@0: michael@0: struct _cairo_unscaled_font_backend { michael@0: void (*destroy) (void *unscaled_font); michael@0: }; michael@0: michael@0: /* #cairo_toy_font_face_t - simple family/slant/weight font faces used for michael@0: * the built-in font API