void _cairo_scaled_font_map_destroy (void) { int i; cairo_scaled_font_map_t *font_map = cairo_scaled_font_map; cairo_scaled_font_t *scaled_font; if (font_map == NULL) return; CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex); for (i = 0; i < font_map->num_holdovers; i++) { scaled_font = font_map->holdovers[i]; /* We should only get here through the reset_static_data path * and there had better not be any active references at that * point. */ assert (scaled_font->ref_count == 0); _cairo_hash_table_remove (font_map->hash_table, &scaled_font->hash_entry); _cairo_scaled_font_fini (scaled_font); free (scaled_font); } _cairo_hash_table_destroy (font_map->hash_table); free (cairo_scaled_font_map); cairo_scaled_font_map = NULL; }
/** * cairo_scaled_font_create: * @font_face: a #cairo_font_face_t * @font_matrix: font space to user space transformation matrix for the * font. In the simplest case of a N point font, this matrix is * just a scale by N, but it can also be used to shear the font * or stretch it unequally along the two axes. See * cairo_set_font_matrix(). * @ctm: user to device transformation matrix with which the font will * be used. * @options: options to use when getting metrics for the font and * rendering with it. * * Creates a #cairo_scaled_font_t object from a font face and matrices that * describe the size of the font and the environment in which it will * be used. * * Return value: a newly created #cairo_scaled_font_t. Destroy with * cairo_scaled_font_destroy() **/ cairo_scaled_font_t * cairo_scaled_font_create (cairo_font_face_t *font_face, const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, const cairo_font_options_t *options) { cairo_status_t status; cairo_scaled_font_map_t *font_map; cairo_scaled_font_t key, *scaled_font = NULL; if (font_face->status) return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; font_map = _cairo_scaled_font_map_lock (); if (font_map == NULL) goto UNWIND; _cairo_scaled_font_init_key (&key, font_face, font_matrix, ctm, options); /* Return existing scaled_font if it exists in the hash table. */ if (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry, (cairo_hash_entry_t**) &scaled_font)) { _cairo_scaled_font_map_unlock (); return cairo_scaled_font_reference (scaled_font); } /* 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); if (status) goto UNWIND_FONT_MAP_LOCK; status = _cairo_hash_table_insert (font_map->hash_table, &scaled_font->hash_entry); if (status) goto UNWIND_SCALED_FONT_CREATE; _cairo_scaled_font_map_unlock (); return scaled_font; UNWIND_SCALED_FONT_CREATE: /* We can't call _cairo_scaled_font_destroy here since it expects * that the font has already been successfully inserted into the * hash table. */ _cairo_scaled_font_fini (scaled_font); free (scaled_font); UNWIND_FONT_MAP_LOCK: _cairo_scaled_font_map_unlock (); UNWIND: return NULL; }
/** * cairo_scaled_font_destroy: * @scaled_font: a #cairo_scaled_font_t * * 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(). **/ void cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) { cairo_scaled_font_map_t *font_map; if (scaled_font == NULL) return; if (scaled_font->ref_count == (unsigned int)-1) return; /* cairo_scaled_font_t objects are cached and shared between * threads. This works because these objects are immutable. Except * that the reference count is mutable, so we have to do locking * around any modification of the reference count. */ font_map = _cairo_scaled_font_map_lock (); { assert (font_map != NULL); assert (scaled_font->ref_count > 0); if (--(scaled_font->ref_count) == 0) { /* Rather than immediately destroying this object, we put it into * the font_map->holdovers array in case it will get used again * soon. To make room for it, we do actually destroy the * least-recently-used holdover. */ if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) { cairo_scaled_font_t *lru; lru = font_map->holdovers[0]; assert (lru->ref_count == 0); _cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry); _cairo_scaled_font_fini (lru); free (lru); font_map->num_holdovers--; memmove (&font_map->holdovers[0], &font_map->holdovers[1], font_map->num_holdovers * sizeof (cairo_scaled_font_t*)); } font_map->holdovers[font_map->num_holdovers] = scaled_font; font_map->num_holdovers++; } } _cairo_scaled_font_map_unlock (); }
static cairo_status_t _cairo_user_font_face_scaled_font_create (void *abstract_face, const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, const cairo_font_options_t *options, cairo_scaled_font_t **scaled_font) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_user_font_face_t *font_face = abstract_face; cairo_user_scaled_font_t *user_scaled_font = NULL; cairo_font_extents_t font_extents = {1., 0., 1., 1., 0.}; font_face->immutable = TRUE; user_scaled_font = malloc (sizeof (cairo_user_scaled_font_t)); if (user_scaled_font == NULL) return CAIRO_STATUS_NO_MEMORY; status = _cairo_scaled_font_init (&user_scaled_font->base, &font_face->base, font_matrix, ctm, options, &cairo_user_scaled_font_backend); if (status) { free (user_scaled_font); return status; } /* XXX metrics hinting? */ /* compute a normalized version of font scale matrix to compute * extents in. This is to minimize error caused by the cairo_fixed_t * representation. */ { double fixed_scale, x_scale, y_scale; user_scaled_font->extent_scale = user_scaled_font->base.scale_inverse; status = _cairo_matrix_compute_basis_scale_factors (&user_scaled_font->extent_scale, &x_scale, &y_scale, 1); if (status == CAIRO_STATUS_SUCCESS) { if (x_scale == 0) x_scale = 1.; if (y_scale == 0) y_scale = 1.; user_scaled_font->snap_x_scale = x_scale; user_scaled_font->snap_y_scale = y_scale; /* since glyphs are pretty much 1.0x1.0, we can reduce error by * scaling to a larger square. say, 1024.x1024. */ fixed_scale = 1024.; x_scale /= fixed_scale; y_scale /= fixed_scale; cairo_matrix_scale (&user_scaled_font->extent_scale, 1. / x_scale, 1. / y_scale); user_scaled_font->extent_x_scale = x_scale; user_scaled_font->extent_y_scale = y_scale; } } if (status == CAIRO_STATUS_SUCCESS && font_face->scaled_font_methods.init != NULL) { cairo_t *cr; /* Lock the scaled_font mutex such that user doesn't accidentally try * to use it just yet. */ CAIRO_MUTEX_LOCK (user_scaled_font->base.mutex); /* Give away fontmap lock such that user-font can use other fonts */ _cairo_scaled_font_register_placeholder_and_unlock_font_map (&user_scaled_font->base); cr = _cairo_user_scaled_font_create_meta_context (user_scaled_font); status = font_face->scaled_font_methods.init (&user_scaled_font->base, cr, &font_extents); if (status == CAIRO_STATUS_SUCCESS) status = cairo_status (cr); cairo_destroy (cr); _cairo_scaled_font_unregister_placeholder_and_lock_font_map (&user_scaled_font->base); CAIRO_MUTEX_UNLOCK (user_scaled_font->base.mutex); } if (status == CAIRO_STATUS_SUCCESS) status = _cairo_scaled_font_set_metrics (&user_scaled_font->base, &font_extents); if (status != CAIRO_STATUS_SUCCESS) { _cairo_scaled_font_fini (&user_scaled_font->base); free (user_scaled_font); } else { user_scaled_font->default_glyph_extents.x_bearing = 0.; user_scaled_font->default_glyph_extents.y_bearing = -font_extents.ascent; user_scaled_font->default_glyph_extents.width = 0.; user_scaled_font->default_glyph_extents.height = font_extents.ascent + font_extents.descent; user_scaled_font->default_glyph_extents.x_advance = font_extents.max_x_advance; user_scaled_font->default_glyph_extents.y_advance = 0.; *scaled_font = &user_scaled_font->base; } return status; }