diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-02-28 14:50:16 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-02-28 14:50:16 +0000 |
commit | da381da7f324497132ca547246c5299708fb968e (patch) | |
tree | eac4d5efcb00934dfde56c76dc7f13f9dfeaade8 /src/cairo-scaled-font.c | |
parent | 1cfd27851e4700270204bb39d48827eaa33b849d (diff) |
scaled-font: Key the cache on the original font face
Complete the task started in cd4b2d843b2a8c06ba78c15ff65763b5bdf54dc6 by
remembering to compute the insertion hash on the original font face as
well as the lookup hashes. Also take advantage by deferring resolution
of the implementation for the font face until after we fail to find an
already constructed scaled font.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/cairo-scaled-font.c')
-rw-r--r-- | src/cairo-scaled-font.c | 181 |
1 files changed, 94 insertions, 87 deletions
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index be612a9b9..e70c17858 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -689,8 +689,16 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, if (unlikely (status)) return status; - _cairo_scaled_font_init_key (scaled_font, font_face, - font_matrix, ctm, options); + scaled_font->status = CAIRO_STATUS_SUCCESS; + scaled_font->placeholder = FALSE; + scaled_font->font_face = font_face; + scaled_font->original_font_face = font_face; + scaled_font->font_matrix = *font_matrix; + scaled_font->ctm = *ctm; + /* ignore translation values in the ctm */ + scaled_font->ctm.x0 = 0.; + scaled_font->ctm.y0 = 0.; + _cairo_font_options_init_copy (&scaled_font->options, options); cairo_matrix_multiply (&scaled_font->scale, &scaled_font->font_matrix, @@ -996,106 +1004,88 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, scaled_font->hash_entry.hash = ZOMBIE; dead = scaled_font; font_map->mru_scaled_font = NULL; - - if (font_face->backend->get_implementation != NULL) { - font_face = font_face->backend->get_implementation (font_face, - font_matrix, - ctm, - options); - if (unlikely (font_face->status)) { - _cairo_scaled_font_map_unlock (); - cairo_scaled_font_destroy (scaled_font); - return _cairo_scaled_font_create_in_error (font_face->status); - } - } - - _cairo_scaled_font_init_key (&key, original_font_face, - font_matrix, ctm, options); } - else - { - if (font_face->backend->get_implementation != NULL) { - font_face = font_face->backend->get_implementation (font_face, - font_matrix, - ctm, - options); - if (unlikely (font_face->status)) { - _cairo_scaled_font_map_unlock (); - return _cairo_scaled_font_create_in_error (font_face->status); - } - } - _cairo_scaled_font_init_key (&key, original_font_face, - font_matrix, ctm, options); + _cairo_scaled_font_init_key (&key, font_face, font_matrix, ctm, options); - while ((scaled_font = _cairo_hash_table_lookup (font_map->hash_table, - &key.hash_entry))) - { - if (! scaled_font->placeholder) - break; + while ((scaled_font = _cairo_hash_table_lookup (font_map->hash_table, + &key.hash_entry))) + { + if (! scaled_font->placeholder) + break; - /* If the scaled font is being created (happens for user-font), - * just wait until it's done, then retry */ - _cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font); - } + /* If the scaled font is being created (happens for user-font), + * just wait until it's done, then retry */ + _cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font); + } - /* Return existing scaled_font if it exists in the hash table. */ - if (scaled_font != NULL) { - /* If the original reference count is 0, then this font must have - * been found in font_map->holdovers, (which means this caching is - * actually working). So now we remove it from the holdovers - * array, unless we caught the font in the middle of destruction. - */ - if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) { - if (scaled_font->holdover) { - int i; - - for (i = 0; i < font_map->num_holdovers; i++) { - if (font_map->holdovers[i] == scaled_font) { - font_map->num_holdovers--; - memmove (&font_map->holdovers[i], - &font_map->holdovers[i+1], - (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*)); - break; - } + if (scaled_font != NULL) { + /* If the original reference count is 0, then this font must have + * been found in font_map->holdovers, (which means this caching is + * actually working). So now we remove it from the holdovers + * array, unless we caught the font in the middle of destruction. + */ + if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) { + if (scaled_font->holdover) { + int i; + + for (i = 0; i < font_map->num_holdovers; i++) { + if (font_map->holdovers[i] == scaled_font) { + font_map->num_holdovers--; + memmove (&font_map->holdovers[i], + &font_map->holdovers[i+1], + (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*)); + break; } - - scaled_font->holdover = FALSE; } - /* reset any error status */ - scaled_font->status = CAIRO_STATUS_SUCCESS; + scaled_font->holdover = FALSE; } - if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) { - /* We increment the reference count manually here, (rather - * than calling into cairo_scaled_font_reference), since we - * must modify the reference count while our lock is still - * held. */ - - old = font_map->mru_scaled_font; - font_map->mru_scaled_font = scaled_font; - /* increment reference count for the mru cache */ - _cairo_reference_count_inc (&scaled_font->ref_count); - /* and increment for the returned reference */ - _cairo_reference_count_inc (&scaled_font->ref_count); - _cairo_scaled_font_map_unlock (); - - cairo_scaled_font_destroy (old); - if (font_face != original_font_face) - cairo_font_face_destroy (font_face); - - return scaled_font; - } + /* reset any error status */ + scaled_font->status = CAIRO_STATUS_SUCCESS; + } - /* the font has been put into an error status - abandon the cache */ - _cairo_hash_table_remove (font_map->hash_table, - &scaled_font->hash_entry); - scaled_font->hash_entry.hash = ZOMBIE; + if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) { + /* We increment the reference count manually here, (rather + * than calling into cairo_scaled_font_reference), since we + * must modify the reference count while our lock is still + * held. */ + + old = font_map->mru_scaled_font; + font_map->mru_scaled_font = scaled_font; + /* increment reference count for the mru cache */ + _cairo_reference_count_inc (&scaled_font->ref_count); + /* and increment for the returned reference */ + _cairo_reference_count_inc (&scaled_font->ref_count); + _cairo_scaled_font_map_unlock (); + + cairo_scaled_font_destroy (old); + if (font_face != original_font_face) + cairo_font_face_destroy (font_face); + + return scaled_font; } + + /* the font has been put into an error status - abandon the cache */ + _cairo_hash_table_remove (font_map->hash_table, + &scaled_font->hash_entry); + scaled_font->hash_entry.hash = ZOMBIE; } + /* Otherwise create it and insert it into the hash table. */ + if (font_face->backend->get_implementation != NULL) { + font_face = font_face->backend->get_implementation (font_face, + font_matrix, + ctm, + options); + if (unlikely (font_face->status)) { + _cairo_scaled_font_map_unlock (); + return _cairo_scaled_font_create_in_error (font_face->status); + } + } + status = font_face->backend->scaled_font_create (font_face, font_matrix, ctm, options, &scaled_font); /* Did we leave the backend in an error state? */ @@ -1131,6 +1121,23 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, scaled_font->original_font_face = cairo_font_face_reference (original_font_face); + { + uint32_t hash = FNV1_32_INIT; + + /* We do a bytewise hash on the font matrices */ + hash = _hash_matrix_fnv (&scaled_font->font_matrix, hash); + hash = _hash_matrix_fnv (&scaled_font->ctm, hash); + hash = _hash_mix_bits (hash); + + hash ^= (unsigned long) scaled_font->original_font_face; + hash ^= cairo_font_options_hash (&scaled_font->options); + + /* final mixing of bits */ + hash = _hash_mix_bits (hash); + assert (hash != ZOMBIE); + scaled_font->hash_entry.hash = hash; + } + status = _cairo_hash_table_insert (font_map->hash_table, &scaled_font->hash_entry); if (likely (status == CAIRO_STATUS_SUCCESS)) { |