40,7 → 40,11 |
|
#include "cairoint.h" |
#include "cairo-error-private.h" |
#include "cairo-image-surface-private.h" |
#include "cairo-list-inline.h" |
#include "cairo-pattern-private.h" |
#include "cairo-scaled-font-private.h" |
#include "cairo-surface-backend-private.h" |
|
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE) |
#define ISFINITE(x) isfinite (x) |
56,8 → 60,11 |
* |
* #cairo_scaled_font_t represents a realization of a font face at a particular |
* size and transformation and a certain set of font options. |
*/ |
**/ |
|
static uint32_t |
_cairo_scaled_font_compute_hash (cairo_scaled_font_t *scaled_font); |
|
/* Global Glyph Cache |
* |
* We maintain a global pool of glyphs split between all active fonts. This |
197,10 → 204,15 |
_cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font, |
cairo_scaled_glyph_t *scaled_glyph) |
{ |
const cairo_surface_backend_t *surface_backend = scaled_font->surface_backend; |
while (! cairo_list_is_empty (&scaled_glyph->dev_privates)) { |
cairo_scaled_glyph_private_t *private = |
cairo_list_first_entry (&scaled_glyph->dev_privates, |
cairo_scaled_glyph_private_t, |
link); |
private->destroy (private, scaled_glyph, scaled_font); |
} |
|
if (surface_backend != NULL && surface_backend->scaled_glyph_fini != NULL) |
surface_backend->scaled_glyph_fini (scaled_glyph, scaled_font); |
_cairo_image_scaled_glyph_fini (scaled_font, scaled_glyph); |
|
if (scaled_glyph->surface != NULL) |
cairo_surface_destroy (&scaled_glyph->surface->base); |
241,8 → 253,7 |
{ NULL, NULL }, /* pages */ |
FALSE, /* cache_frozen */ |
FALSE, /* global_cache_frozen */ |
NULL, /* surface_backend */ |
NULL, /* surface_private */ |
{ NULL, NULL }, /* privates */ |
NULL /* backend */ |
}; |
|
309,6 → 320,8 |
* |
* Return value: %CAIRO_STATUS_SUCCESS or another error such as |
* %CAIRO_STATUS_NO_MEMORY. |
* |
* Since: 1.0 |
**/ |
cairo_status_t |
cairo_scaled_font_status (cairo_scaled_font_t *scaled_font) |
436,14 → 449,16 |
CLEANUP_MUTEX_LOCK: |
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); |
} |
|
static void |
_cairo_scaled_glyph_page_destroy (void *closure) |
_cairo_scaled_glyph_page_destroy (cairo_scaled_font_t *scaled_font, |
cairo_scaled_glyph_page_t *page) |
{ |
cairo_scaled_glyph_page_t *page = closure; |
cairo_scaled_font_t *scaled_font; |
unsigned int n; |
|
scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash; |
assert (!scaled_font->cache_frozen); |
assert (!scaled_font->global_cache_frozen); |
|
for (n = 0; n < page->num_glyphs; n++) { |
_cairo_hash_table_remove (scaled_font->glyphs, |
&page->glyphs[n].hash_entry); |
451,10 → 466,24 |
} |
|
cairo_list_del (&page->link); |
|
free (page); |
} |
|
static void |
_cairo_scaled_glyph_page_pluck (void *closure) |
{ |
cairo_scaled_glyph_page_t *page = closure; |
cairo_scaled_font_t *scaled_font; |
|
assert (! cairo_list_is_empty (&page->link)); |
|
scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash; |
|
CAIRO_MUTEX_LOCK (scaled_font->mutex); |
_cairo_scaled_glyph_page_destroy (scaled_font, page); |
CAIRO_MUTEX_UNLOCK (scaled_font->mutex); |
} |
|
/* If a scaled font wants to unlock the font map while still being |
* created (needed for user-fonts), we need to take extra care not |
* ending up with multiple identical scaled fonts being created. |
499,6 → 528,8 |
|
placeholder_scaled_font->placeholder = TRUE; |
|
placeholder_scaled_font->hash_entry.hash |
= _cairo_scaled_font_compute_hash (placeholder_scaled_font); |
status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table, |
&placeholder_scaled_font->hash_entry); |
if (unlikely (status)) |
524,6 → 555,9 |
|
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); |
|
/* temporary hash value to match the placeholder */ |
scaled_font->hash_entry.hash |
= _cairo_scaled_font_compute_hash (scaled_font); |
placeholder_scaled_font = |
_cairo_hash_table_lookup (cairo_scaled_font_map->hash_table, |
&scaled_font->hash_entry); |
595,6 → 629,26 |
return hash; |
} |
|
static uint32_t |
_cairo_scaled_font_compute_hash (cairo_scaled_font_t *scaled_font) |
{ |
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); |
|
return hash; |
} |
|
static void |
_cairo_scaled_font_init_key (cairo_scaled_font_t *scaled_font, |
cairo_font_face_t *font_face, |
602,11 → 656,10 |
const cairo_matrix_t *ctm, |
const cairo_font_options_t *options) |
{ |
uint32_t hash = FNV1_32_INIT; |
|
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 */ |
614,19 → 667,8 |
scaled_font->ctm.y0 = 0.; |
_cairo_font_options_init_copy (&scaled_font->options, options); |
|
/* 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->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; |
scaled_font->hash_entry.hash = |
_cairo_scaled_font_compute_hash (scaled_font); |
} |
|
static cairo_bool_t |
636,10 → 678,7 |
const cairo_scaled_font_t *key_a = abstract_key_a; |
const cairo_scaled_font_t *key_b = abstract_key_b; |
|
if (key_a->hash_entry.hash != key_b->hash_entry.hash) |
return FALSE; |
|
return key_a->font_face == key_b->font_face && |
return key_a->original_font_face == key_b->original_font_face && |
memcmp ((unsigned char *)(&key_a->font_matrix.xx), |
(unsigned char *)(&key_b->font_matrix.xx), |
sizeof(cairo_matrix_t)) == 0 && |
666,15 → 705,6 |
cairo_font_options_equal (&scaled_font->options, options); |
} |
|
static cairo_bool_t |
_cairo_scaled_glyphs_equal (const void *abstract_a, const void *abstract_b) |
{ |
const cairo_scaled_glyph_t *a = abstract_a; |
const cairo_scaled_glyph_t *b = abstract_b; |
|
return a->hash_entry.hash == b->hash_entry.hash; |
} |
|
/* |
* Basic #cairo_scaled_font_t object management |
*/ |
693,8 → 723,16 |
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, |
723,7 → 761,7 |
return status; |
} |
|
scaled_font->glyphs = _cairo_hash_table_create (_cairo_scaled_glyphs_equal); |
scaled_font->glyphs = _cairo_hash_table_create (NULL); |
if (unlikely (scaled_font->glyphs == NULL)) |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
743,8 → 781,7 |
|
CAIRO_MUTEX_INIT (scaled_font->mutex); |
|
scaled_font->surface_backend = NULL; |
scaled_font->surface_private = NULL; |
cairo_list_init (&scaled_font->dev_privates); |
|
scaled_font->backend = backend; |
cairo_list_init (&scaled_font->link); |
765,16 → 802,16 |
void |
_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font) |
{ |
scaled_font->cache_frozen = FALSE; |
assert (scaled_font->cache_frozen); |
|
if (scaled_font->global_cache_frozen) { |
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex); |
_cairo_cache_thaw (&cairo_scaled_glyph_page_cache); |
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); |
|
scaled_font->global_cache_frozen = FALSE; |
} |
|
scaled_font->cache_frozen = FALSE; |
CAIRO_MUTEX_UNLOCK (scaled_font->mutex); |
} |
|
781,16 → 818,24 |
void |
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font) |
{ |
CAIRO_MUTEX_LOCK (scaled_font->mutex); |
assert (! scaled_font->cache_frozen); |
|
assert (! scaled_font->global_cache_frozen); |
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex); |
while (! cairo_list_is_empty (&scaled_font->glyph_pages)) { |
_cairo_cache_remove (&cairo_scaled_glyph_page_cache, |
&cairo_list_first_entry (&scaled_font->glyph_pages, |
cairo_scaled_glyph_page_t *page = |
cairo_list_first_entry (&scaled_font->glyph_pages, |
cairo_scaled_glyph_page_t, |
link)->cache_entry); |
link); |
|
cairo_scaled_glyph_page_cache.size -= page->cache_entry.size; |
_cairo_hash_table_remove (cairo_scaled_glyph_page_cache.hash_table, |
(cairo_hash_entry_t *) &page->cache_entry); |
|
_cairo_scaled_glyph_page_destroy (scaled_font, page); |
} |
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); |
CAIRO_MUTEX_UNLOCK (scaled_font->mutex); |
} |
|
cairo_status_t |
825,6 → 870,8 |
static void |
_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font) |
{ |
assert (! scaled_font->cache_frozen); |
assert (! scaled_font->global_cache_frozen); |
scaled_font->finished = TRUE; |
|
_cairo_scaled_font_reset_cache (scaled_font); |
835,9 → 882,13 |
|
CAIRO_MUTEX_FINI (scaled_font->mutex); |
|
if (scaled_font->surface_backend != NULL && |
scaled_font->surface_backend->scaled_font_fini != NULL) |
scaled_font->surface_backend->scaled_font_fini (scaled_font); |
while (! cairo_list_is_empty (&scaled_font->dev_privates)) { |
cairo_scaled_font_private_t *private = |
cairo_list_first_entry (&scaled_font->dev_privates, |
cairo_scaled_font_private_t, |
link); |
private->destroy (private, scaled_font); |
} |
|
if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL) |
scaled_font->backend->fini (scaled_font); |
845,32 → 896,79 |
_cairo_user_data_array_fini (&scaled_font->user_data); |
} |
|
/* XXX: allow multiple backends to share the font */ |
void |
_cairo_scaled_font_revoke_ownership (cairo_scaled_font_t *scaled_font) |
_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font) |
{ |
if (scaled_font->surface_backend == NULL) |
return; |
/* Release the lock to avoid the possibility of a recursive |
* deadlock when the scaled font destroy closure gets called. */ |
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); |
_cairo_scaled_font_fini_internal (scaled_font); |
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); |
} |
|
_cairo_scaled_font_reset_cache (scaled_font); |
void |
_cairo_scaled_font_attach_private (cairo_scaled_font_t *scaled_font, |
cairo_scaled_font_private_t *private, |
const void *key, |
void (*destroy) (cairo_scaled_font_private_t *, |
cairo_scaled_font_t *)) |
{ |
private->key = key; |
private->destroy = destroy; |
cairo_list_add (&private->link, &scaled_font->dev_privates); |
} |
|
if (scaled_font->surface_backend->scaled_font_fini != NULL) |
scaled_font->surface_backend->scaled_font_fini (scaled_font); |
cairo_scaled_font_private_t * |
_cairo_scaled_font_find_private (cairo_scaled_font_t *scaled_font, |
const void *key) |
{ |
cairo_scaled_font_private_t *priv; |
|
scaled_font->surface_backend = NULL; |
scaled_font->surface_private = NULL; |
cairo_list_foreach_entry (priv, cairo_scaled_font_private_t, |
&scaled_font->dev_privates, link) |
{ |
if (priv->key == key) { |
if (priv->link.prev != &scaled_font->dev_privates) |
cairo_list_move (&priv->link, &scaled_font->dev_privates); |
return priv; |
} |
} |
|
return NULL; |
} |
|
void |
_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font) |
_cairo_scaled_glyph_attach_private (cairo_scaled_glyph_t *scaled_glyph, |
cairo_scaled_glyph_private_t *private, |
const void *key, |
void (*destroy) (cairo_scaled_glyph_private_t *, |
cairo_scaled_glyph_t *, |
cairo_scaled_font_t *)) |
{ |
/* Release the lock to avoid the possibility of a recursive |
* deadlock when the scaled font destroy closure gets called. */ |
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); |
_cairo_scaled_font_fini_internal (scaled_font); |
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); |
private->key = key; |
private->destroy = destroy; |
cairo_list_add (&private->link, &scaled_glyph->dev_privates); |
} |
|
cairo_scaled_glyph_private_t * |
_cairo_scaled_glyph_find_private (cairo_scaled_glyph_t *scaled_glyph, |
const void *key) |
{ |
cairo_scaled_glyph_private_t *priv; |
|
cairo_list_foreach_entry (priv, cairo_scaled_glyph_private_t, |
&scaled_glyph->dev_privates, link) |
{ |
if (priv->key == key) { |
if (priv->link.prev != &scaled_glyph->dev_privates) |
cairo_list_move (&priv->link, &scaled_glyph->dev_privates); |
return priv; |
} |
} |
|
return NULL; |
} |
|
/** |
* cairo_scaled_font_create: |
* @font_face: a #cairo_font_face_t |
890,6 → 988,8 |
* |
* Return value: a newly created #cairo_scaled_font_t. Destroy with |
* cairo_scaled_font_destroy() |
* |
* Since: 1.0 |
**/ |
cairo_scaled_font_t * |
cairo_scaled_font_create (cairo_font_face_t *font_face, |
950,38 → 1050,10 |
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, 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, 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))) |
{ |
993,7 → 1065,6 |
_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 |
1047,9 → 1118,20 |
&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); |
} |
} |
|
/* Otherwise create it and insert it into the hash table. */ |
status = font_face->backend->scaled_font_create (font_face, font_matrix, |
ctm, options, &scaled_font); |
/* Did we leave the backend in an error state? */ |
1081,10 → 1163,14 |
* ft-font-faces |
*/ |
assert (scaled_font->font_face == font_face); |
assert (! scaled_font->cache_frozen); |
assert (! scaled_font->global_cache_frozen); |
|
scaled_font->original_font_face = |
cairo_font_face_reference (original_font_face); |
|
scaled_font->hash_entry.hash = _cairo_scaled_font_compute_hash(scaled_font); |
|
status = _cairo_hash_table_insert (font_map->hash_table, |
&scaled_font->hash_entry); |
if (likely (status == CAIRO_STATUS_SUCCESS)) { |
1157,11 → 1243,9 |
status <= CAIRO_STATUS_LAST_STATUS; |
status++) |
{ |
if (_cairo_scaled_font_nil_objects[status] != NULL) { |
free (_cairo_scaled_font_nil_objects[status]); |
_cairo_scaled_font_nil_objects[status] = NULL; |
} |
} |
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex); |
|
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex); |
1185,6 → 1269,8 |
* cairo_scaled_font_get_reference_count(). |
* |
* Returns: the referenced #cairo_scaled_font_t |
* |
* Since: 1.0 |
**/ |
cairo_scaled_font_t * |
cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font) |
1208,6 → 1294,8 |
* Decreases the reference count on @font by one. If the result |
* is zero, then @font and all associated resources are freed. |
* See cairo_scaled_font_reference(). |
* |
* Since: 1.0 |
**/ |
void |
cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) |
1226,6 → 1314,9 |
if (! _cairo_reference_count_dec_and_test (&scaled_font->ref_count)) |
return; |
|
assert (! scaled_font->cache_frozen); |
assert (! scaled_font->global_cache_frozen); |
|
font_map = _cairo_scaled_font_map_lock (); |
assert (font_map != NULL); |
|
1364,6 → 1455,8 |
* @extents: a #cairo_font_extents_t which to store the retrieved extents. |
* |
* Gets the metrics for a #cairo_scaled_font_t. |
* |
* Since: 1.0 |
**/ |
void |
cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font, |
1461,6 → 1554,8 |
* |
* Note that whitespace glyphs do not contribute to the size of the |
* rectangle (extents.width and extents.height). |
* |
* Since: 1.0 |
**/ |
void |
cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, |
1856,7 → 1951,7 |
cairo_text_cluster_flags_t *cluster_flags) |
{ |
int num_chars = 0; |
cairo_status_t status; |
cairo_int_status_t status; |
cairo_glyph_t *orig_glyphs; |
cairo_text_cluster_t *orig_clusters; |
|
1939,7 → 2034,7 |
clusters, num_clusters, |
cluster_flags); |
if (status != CAIRO_INT_STATUS_UNSUPPORTED) { |
if (status == CAIRO_STATUS_SUCCESS) { |
if (status == CAIRO_INT_STATUS_SUCCESS) { |
/* The checks here are crude; we only should do them in |
* user-font backend, but they don't hurt here. This stuff |
* can be hard to get right. */ |
2051,6 → 2146,9 |
cairo_fixed_t right, |
cairo_fixed_t bottom) |
{ |
if (left == right || top == bottom) |
return FALSE; |
|
return right > extents->p1.x && |
left < extents->p2.x && |
bottom > extents->p1.y && |
2057,6 → 2155,44 |
top < extents->p2.y; |
} |
|
static cairo_status_t |
_cairo_scaled_font_single_glyph_device_extents (cairo_scaled_font_t *scaled_font, |
const cairo_glyph_t *glyph, |
cairo_rectangle_int_t *extents) |
{ |
cairo_scaled_glyph_t *scaled_glyph; |
cairo_status_t status; |
|
_cairo_scaled_font_freeze_cache (scaled_font); |
status = _cairo_scaled_glyph_lookup (scaled_font, |
glyph->index, |
CAIRO_SCALED_GLYPH_INFO_METRICS, |
&scaled_glyph); |
if (likely (status == CAIRO_STATUS_SUCCESS)) { |
cairo_bool_t round_xy = _cairo_font_options_get_round_glyph_positions (&scaled_font->options) == CAIRO_ROUND_GLYPH_POS_ON; |
cairo_box_t box; |
cairo_fixed_t v; |
|
if (round_xy) |
v = _cairo_fixed_from_int (_cairo_lround (glyph->x)); |
else |
v = _cairo_fixed_from_double (glyph->x); |
box.p1.x = v + scaled_glyph->bbox.p1.x; |
box.p2.x = v + scaled_glyph->bbox.p2.x; |
|
if (round_xy) |
v = _cairo_fixed_from_int (_cairo_lround (glyph->y)); |
else |
v = _cairo_fixed_from_double (glyph->y); |
box.p1.y = v + scaled_glyph->bbox.p1.y; |
box.p2.y = v + scaled_glyph->bbox.p2.y; |
|
_cairo_box_round_to_rectangle (&box, extents); |
} |
_cairo_scaled_font_thaw_cache (scaled_font); |
return status; |
} |
|
/* |
* Compute a device-space bounding box for the glyphs. |
*/ |
2071,11 → 2207,20 |
cairo_box_t box = { { INT_MAX, INT_MAX }, { INT_MIN, INT_MIN }}; |
cairo_scaled_glyph_t *glyph_cache[64]; |
cairo_bool_t overlap = overlap_out ? FALSE : TRUE; |
cairo_round_glyph_positions_t round_glyph_positions = _cairo_font_options_get_round_glyph_positions (&scaled_font->options); |
int i; |
|
if (unlikely (scaled_font->status)) |
return scaled_font->status; |
|
if (num_glyphs == 1) { |
if (overlap_out) |
*overlap_out = FALSE; |
return _cairo_scaled_font_single_glyph_device_extents (scaled_font, |
glyphs, |
extents); |
} |
|
_cairo_scaled_font_freeze_cache (scaled_font); |
|
memset (glyph_cache, 0, sizeof (glyph_cache)); |
2099,10 → 2244,16 |
glyph_cache[cache_index] = scaled_glyph; |
} |
|
if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON) |
x = _cairo_fixed_from_int (_cairo_lround (glyphs[i].x)); |
else |
x = _cairo_fixed_from_double (glyphs[i].x); |
x1 = x + scaled_glyph->bbox.p1.x; |
x2 = x + scaled_glyph->bbox.p2.x; |
|
if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON) |
y = _cairo_fixed_from_int (_cairo_lround (glyphs[i].y)); |
else |
y = _cairo_fixed_from_double (glyphs[i].y); |
y1 = y + scaled_glyph->bbox.p1.y; |
y2 = y + scaled_glyph->bbox.p2.y; |
2133,17 → 2284,28 |
return CAIRO_STATUS_SUCCESS; |
} |
|
void |
cairo_bool_t |
_cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t *scaled_font, |
const cairo_glyph_t *glyphs, |
int num_glyphs, |
cairo_rectangle_int_t *extents) |
{ |
double x0 = HUGE_VAL, x1 = -HUGE_VAL; |
double y0 = HUGE_VAL, y1 = -HUGE_VAL; |
double x0, x1, y0, y1, pad; |
int i; |
|
for (i = 0; i < num_glyphs; i++) { |
/* If any of the factors are suspect (i.e. the font is broken), bail */ |
if (scaled_font->fs_extents.max_x_advance == 0 || |
scaled_font->fs_extents.height == 0 || |
scaled_font->max_scale == 0) |
{ |
return FALSE; |
} |
|
assert (num_glyphs); |
|
x0 = x1 = glyphs[0].x; |
y0 = y1 = glyphs[0].y; |
for (i = 1; i < num_glyphs; i++) { |
double g; |
|
g = glyphs[i].x; |
2155,20 → 2317,19 |
if (g > y1) y1 = g; |
} |
|
if (x0 <= x1 && y0 <= y1) { |
extents->x = floor (x0 - scaled_font->extents.max_x_advance); |
extents->width = ceil (x1 + scaled_font->extents.max_x_advance); |
extents->width -= extents->x; |
pad = MAX(scaled_font->fs_extents.max_x_advance, |
scaled_font->fs_extents.height); |
pad *= scaled_font->max_scale; |
|
extents->y = floor (y0 - scaled_font->extents.ascent); |
extents->height = ceil (y1 + scaled_font->extents.descent); |
extents->height -= extents->y; |
} else { |
extents->x = extents->y = 0; |
extents->width = extents->height = 0; |
extents->x = floor (x0 - pad); |
extents->width = ceil (x1 + pad) - extents->x; |
extents->y = floor (y0 - pad); |
extents->height = ceil (y1 + pad) - extents->y; |
return TRUE; |
} |
} |
|
#if 0 |
/* XXX win32 */ |
cairo_status_t |
_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, |
cairo_operator_t op, |
2184,7 → 2345,7 |
int num_glyphs, |
cairo_region_t *clip_region) |
{ |
cairo_status_t status; |
cairo_int_status_t status; |
cairo_surface_t *mask = NULL; |
cairo_format_t mask_format = CAIRO_FORMAT_A1; /* shut gcc up */ |
cairo_surface_pattern_t mask_pattern; |
2215,7 → 2376,7 |
glyphs += num_glyphs - remaining_glyphs; |
num_glyphs = remaining_glyphs; |
if (remaining_glyphs == 0) |
status = CAIRO_STATUS_SUCCESS; |
status = CAIRO_INT_STATUS_SUCCESS; |
if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
return _cairo_scaled_font_set_error (scaled_font, status); |
} |
2265,6 → 2426,7 |
break; |
case CAIRO_FORMAT_RGB16_565: |
case CAIRO_FORMAT_RGB24: |
case CAIRO_FORMAT_RGB30: |
case CAIRO_FORMAT_INVALID: |
default: |
ASSERT_NOT_REACHED; |
2358,6 → 2520,7 |
cairo_surface_destroy (mask); |
return _cairo_scaled_font_set_error (scaled_font, status); |
} |
#endif |
|
/* Add a single-device-unit rectangle to a path. */ |
static cairo_status_t |
2470,7 → 2633,7 |
int num_glyphs, |
cairo_path_fixed_t *path) |
{ |
cairo_status_t status; |
cairo_int_status_t status; |
int i; |
|
status = scaled_font->status; |
2485,9 → 2648,9 |
glyphs[i].index, |
CAIRO_SCALED_GLYPH_INFO_PATH, |
&scaled_glyph); |
if (status == CAIRO_STATUS_SUCCESS) { |
if (status == CAIRO_INT_STATUS_SUCCESS) { |
status = _cairo_path_fixed_append (path, |
scaled_glyph->path, CAIRO_DIRECTION_FORWARD, |
scaled_glyph->path, |
_cairo_fixed_from_double (glyphs[i].x), |
_cairo_fixed_from_double (glyphs[i].y)); |
|
2672,6 → 2835,8 |
cairo_scaled_glyph_page_t *page; |
cairo_status_t status; |
|
assert (scaled_font->cache_frozen); |
|
/* only the first page in the list may contain available slots */ |
if (! cairo_list_is_empty (&scaled_font->glyph_pages)) { |
page = cairo_list_last_entry (&scaled_font->glyph_pages, |
2697,7 → 2862,7 |
status = _cairo_cache_init (&cairo_scaled_glyph_page_cache, |
NULL, |
_cairo_scaled_glyph_page_can_remove, |
_cairo_scaled_glyph_page_destroy, |
_cairo_scaled_glyph_page_pluck, |
MAX_GLYPH_PAGES_CACHED); |
if (unlikely (status)) { |
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); |
2739,8 → 2904,14 |
_cairo_scaled_glyph_fini (scaled_font, scaled_glyph); |
|
if (--page->num_glyphs == 0) { |
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex); |
/* Temporarily disconnect callback to avoid recursive locking */ |
cairo_scaled_glyph_page_cache.entry_destroy = NULL; |
_cairo_cache_remove (&cairo_scaled_glyph_page_cache, |
&page->cache_entry); |
_cairo_scaled_glyph_page_destroy (scaled_font, page); |
cairo_scaled_glyph_page_cache.entry_destroy = _cairo_scaled_glyph_page_pluck; |
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); |
} |
} |
|
2777,7 → 2948,7 |
cairo_scaled_glyph_info_t info, |
cairo_scaled_glyph_t **scaled_glyph_ret) |
{ |
cairo_status_t status = CAIRO_STATUS_SUCCESS; |
cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; |
cairo_scaled_glyph_t *scaled_glyph; |
cairo_scaled_glyph_info_t need_info; |
|
2786,6 → 2957,9 |
if (unlikely (scaled_font->status)) |
return scaled_font->status; |
|
assert (CAIRO_MUTEX_IS_LOCKED(scaled_font->mutex)); |
assert (scaled_font->cache_frozen); |
|
if (CAIRO_INJECT_FAULT ()) |
return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
|
2801,6 → 2975,7 |
|
memset (scaled_glyph, 0, sizeof (cairo_scaled_glyph_t)); |
_cairo_scaled_glyph_set_index (scaled_glyph, index); |
cairo_list_init (&scaled_glyph->dev_privates); |
|
/* ask backend to initialize metrics and shape fields */ |
status = |
2861,11 → 3036,13 |
* cairo_scaled_font_get_font_face: |
* @scaled_font: a #cairo_scaled_font_t |
* |
* Gets the font face that this scaled font uses. This is the |
* font face passed to cairo_scaled_font_create(). |
* Gets the font face that this scaled font uses. This might be the |
* font face passed to cairo_scaled_font_create(), but this does not |
* hold true for all possible cases. |
* |
* Return value: The #cairo_font_face_t with which @scaled_font was |
* created. |
* created. This object is owned by cairo. To keep a reference to it, |
* you must call cairo_scaled_font_reference(). |
* |
* Since: 1.2 |
**/ |