[ft] Support font_face->get_implementation

The lazy resolution of patterns was defeating the scaled_font cache as
ft-fonts that resolved to the same unscaled font were being given different
font-faces upon creation. We can keep the lazy resolution by simply asking
the ft backend to create a fully resolved ft-font-face when we need to
create a scaled-font. This font is then keyed by the resolved font-face
and so will match all future lazily resolved identical patterns.
This commit is contained in:
Chris Wilson 2009-06-07 18:59:36 +01:00
parent a29426f4bf
commit 6d693f6bd7
4 changed files with 97 additions and 92 deletions

View file

@ -149,13 +149,11 @@ static cairo_status_t
_cairo_ft_font_options_substitute (const cairo_font_options_t *options,
FcPattern *pattern);
static cairo_status_t
static cairo_font_face_t *
_cairo_ft_resolve_pattern (FcPattern *pattern,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_ft_unscaled_font_t **unscaled,
cairo_ft_options_t *ft_options);
const cairo_font_options_t *options);
#endif
@ -1533,38 +1531,40 @@ _cairo_ft_options_merge (cairo_ft_options_t *options,
}
static cairo_status_t
_cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_ft_options_t ft_options,
cairo_scaled_font_t **font_out)
_cairo_ft_font_face_scaled_font_create (void *abstract_font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_scaled_font_t **font_out)
{
cairo_ft_font_face_t *font_face = abstract_font_face;
cairo_ft_scaled_font_t *scaled_font;
FT_Face face;
FT_Size_Metrics *metrics;
cairo_font_extents_t fs_metrics;
cairo_status_t status;
cairo_ft_unscaled_font_t *unscaled;
face = _cairo_ft_unscaled_font_lock_face (unscaled);
assert (font_face->unscaled);
face = _cairo_ft_unscaled_font_lock_face (font_face->unscaled);
if (unlikely (face == NULL)) /* backend error */
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
scaled_font = malloc (sizeof(cairo_ft_scaled_font_t));
scaled_font = malloc (sizeof (cairo_ft_scaled_font_t));
if (unlikely (scaled_font == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL;
}
scaled_font->unscaled = unscaled = font_face->unscaled;
_cairo_unscaled_font_reference (&unscaled->base);
scaled_font->unscaled = unscaled;
_cairo_font_options_init_copy (&scaled_font->ft_options.base, options);
_cairo_ft_options_merge (&scaled_font->ft_options, &ft_options);
_cairo_ft_options_merge (&scaled_font->ft_options, &font_face->ft_options);
status = _cairo_scaled_font_init (&scaled_font->base,
font_face,
&font_face->base,
font_matrix, ctm, options,
&_cairo_ft_scaled_font_backend);
if (unlikely (status))
@ -1644,7 +1644,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
_cairo_unscaled_font_destroy (&unscaled->base);
free (scaled_font);
FAIL:
_cairo_ft_unscaled_font_unlock_face (unscaled);
_cairo_ft_unscaled_font_unlock_face (font_face->unscaled);
*font_out = _cairo_scaled_font_create_in_error (status);
return CAIRO_STATUS_SUCCESS; /* non-backend error */
}
@ -2294,16 +2294,13 @@ _cairo_ft_font_face_destroy (void *abstract_face)
#endif
}
static cairo_status_t
_cairo_ft_font_face_scaled_font_create (void *abstract_face,
static cairo_font_face_t *
_cairo_ft_font_face_get_implementation (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)
const cairo_font_options_t *options)
{
cairo_ft_font_face_t *font_face = abstract_face;
cairo_ft_unscaled_font_t *unscaled = NULL;
cairo_ft_options_t ft_options;
/* The handling of font options is different depending on how the
* font face was created. When the user creates a font face with
@ -2320,34 +2317,14 @@ _cairo_ft_font_face_scaled_font_create (void *abstract_face,
* unscaled font. Otherwise, use the ones stored in font_face.
*/
if (font_face->pattern) {
cairo_status_t status;
status = _cairo_ft_resolve_pattern (font_face->pattern,
font_matrix,
ctm,
options,
&unscaled,
&ft_options);
if (unlikely (status)) {
/* XXX It is possible for a failure to generate the unscaled font
* here could indicate that the font_face itself is broken - for
* which we should propagate the error.
*/
*scaled_font = _cairo_scaled_font_create_in_error (status);
return CAIRO_STATUS_SUCCESS;
}
} else
#endif
{
unscaled = font_face->unscaled;
ft_options = font_face->ft_options;
return _cairo_ft_resolve_pattern (font_face->pattern,
font_matrix,
ctm,
options);
}
#endif
return _cairo_ft_scaled_font_create (unscaled,
&font_face->base,
font_matrix, ctm,
options, ft_options,
scaled_font);
return abstract_face;
}
const cairo_font_face_backend_t _cairo_ft_font_face_backend = {
@ -2358,7 +2335,8 @@ const cairo_font_face_backend_t _cairo_ft_font_face_backend = {
NULL,
#endif
_cairo_ft_font_face_destroy,
_cairo_ft_font_face_scaled_font_create
_cairo_ft_font_face_scaled_font_create,
_cairo_ft_font_face_get_implementation
};
#if CAIRO_HAS_FC_FONT
@ -2573,13 +2551,11 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options,
_cairo_ft_font_options_substitute (options, pattern);
}
static cairo_status_t
static cairo_font_face_t *
_cairo_ft_resolve_pattern (FcPattern *pattern,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *font_options,
cairo_ft_unscaled_font_t **unscaled,
cairo_ft_options_t *ft_options)
const cairo_font_options_t *font_options)
{
cairo_status_t status;
@ -2587,6 +2563,9 @@ _cairo_ft_resolve_pattern (FcPattern *pattern,
FcPattern *resolved;
cairo_ft_font_transform_t sf;
FcResult result;
cairo_ft_unscaled_font_t *unscaled;
cairo_ft_options_t ft_options;
cairo_font_face_t *font_face;
scale = *ctm;
scale.x0 = scale.y0 = 0;
@ -2595,42 +2574,48 @@ _cairo_ft_resolve_pattern (FcPattern *pattern,
&scale);
status = _compute_transform (&sf, &scale);
if (status)
return status;
if (unlikely (status))
return (cairo_font_face_t *)&_cairo_font_face_nil;
pattern = FcPatternDuplicate (pattern);
if (pattern == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_face_t *)&_cairo_font_face_nil;
if (! FcPatternAddDouble (pattern, FC_PIXEL_SIZE, sf.y_scale)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
font_face = (cairo_font_face_t *)&_cairo_font_face_nil;
goto FREE_PATTERN;
}
if (! FcConfigSubstitute (NULL, pattern, FcMatchPattern)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
font_face = (cairo_font_face_t *)&_cairo_font_face_nil;
goto FREE_PATTERN;
}
status = _cairo_ft_font_options_substitute (font_options, pattern);
if (status)
if (status) {
font_face = (cairo_font_face_t *)&_cairo_font_face_nil;
goto FREE_PATTERN;
}
FcDefaultSubstitute (pattern);
resolved = FcFontMatch (NULL, pattern, &result);
if (!resolved) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
font_face = (cairo_font_face_t *)&_cairo_font_face_nil;
goto FREE_PATTERN;
}
status = _cairo_ft_unscaled_font_create_for_pattern (resolved, unscaled);
if (unlikely (status))
status = _cairo_ft_unscaled_font_create_for_pattern (resolved, &unscaled);
if (unlikely (status)) {
font_face = (cairo_font_face_t *)&_cairo_font_face_nil;
goto FREE_RESOLVED;
}
assert (*unscaled != NULL);
assert (unscaled != NULL);
_get_pattern_ft_options (resolved, ft_options);
_get_pattern_ft_options (resolved, &ft_options);
font_face = _cairo_ft_font_face_create (unscaled, &ft_options);
_cairo_unscaled_font_destroy (&unscaled->base);
FREE_RESOLVED:
FcPatternDestroy (resolved);
@ -2638,7 +2623,7 @@ FREE_RESOLVED:
FREE_PATTERN:
FcPatternDestroy (pattern);
return status;
return font_face;
}
/**

View file

@ -899,12 +899,11 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
/* Note that degenerate ctm or font_matrix *are* allowed.
* We want to support a font size of 0. */
if (font_face->backend->type == CAIRO_FONT_TYPE_TOY) {
/* indirect implementation, lookup the face that is used for the toy face */
font_face = _cairo_toy_font_face_get_implementation (font_face);
if (unlikely (font_face->status))
return _cairo_scaled_font_create_in_error (font_face->status);
if (font_face->backend->get_implementation != NULL) {
font_face = font_face->backend->get_implementation (font_face,
font_matrix,
ctm,
options);
}
font_map = _cairo_scaled_font_map_lock ();
@ -1018,6 +1017,12 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
return scaled_font;
}
/* Our caching above is defeated if the backend switches fonts on us -
* e.g. old incarnations of toy-font-face and lazily resolved
* ft-font-faces
*/
assert (scaled_font->font_face == font_face);
scaled_font->original_font_face =
cairo_font_face_reference (original_font_face);
@ -1043,6 +1048,9 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
cairo_scaled_font_destroy (old);
if (font_face != original_font_face)
cairo_font_face_destroy (font_face);
return scaled_font;
}
slim_hidden_def (cairo_scaled_font_create);

View file

@ -387,28 +387,36 @@ _cairo_toy_font_face_scaled_font_create (void *abstract_font_face
return _cairo_font_face_set_error (&font_face->base, CAIRO_STATUS_FONT_TYPE_MISMATCH);
}
static cairo_font_face_t *
_cairo_toy_font_face_get_implementation (void *abstract_font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options)
{
cairo_toy_font_face_t *font_face = abstract_font_face;
if (font_face->impl_face) {
cairo_font_face_t *impl = font_face->impl_face;
if (impl->backend->get_implementation != NULL) {
return impl->backend->get_implementation (impl,
font_matrix,
ctm,
options);
}
return cairo_font_face_reference (impl);
}
return abstract_font_face;
}
static cairo_bool_t
_cairo_font_face_is_toy (cairo_font_face_t *font_face)
{
return font_face->backend == &_cairo_toy_font_face_backend;
}
cairo_font_face_t *
_cairo_toy_font_face_get_implementation (cairo_font_face_t *font_face)
{
cairo_toy_font_face_t *toy_font_face;
if (font_face->status)
return NULL;
toy_font_face = (cairo_toy_font_face_t *) font_face;
if (! _cairo_font_face_is_toy (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return NULL;
}
return toy_font_face->impl_face ? toy_font_face->impl_face : font_face;
}
/**
* cairo_toy_font_face_get_family:
* @font_face: A toy font face
@ -495,7 +503,8 @@ static const cairo_font_face_backend_t _cairo_toy_font_face_backend = {
CAIRO_FONT_TYPE_TOY,
NULL, /* create_for_toy */
_cairo_toy_font_face_destroy,
_cairo_toy_font_face_scaled_font_create
_cairo_toy_font_face_scaled_font_create,
_cairo_toy_font_face_get_implementation
};
void

View file

@ -525,6 +525,12 @@ struct _cairo_font_face_backend {
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_scaled_font_t **scaled_font);
cairo_font_face_t *
(*get_implementation) (void *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options);
};
extern const cairo_private struct _cairo_font_face_backend _cairo_user_font_face_backend;
@ -1427,9 +1433,6 @@ _cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
cairo_private void
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
cairo_private cairo_font_face_t *
_cairo_toy_font_face_get_implementation (cairo_font_face_t *font_face);
/* cairo-font-face-twin.c */
cairo_private cairo_status_t