[surface] Separate the mime-data from the user-data.

Move the mime-data into its own array so that it cannot be confused with
user-data and we do not need to hard-code the copy list during
snapshotting. The copy-on-snapshotting code becomes far simpler and will
accommodate all future mime-types.

Keeping mime-data separate from user-data is important due to the
principle of least surprise - the API is different and so it would be
surprising if you queried for user-data and were returned an opaque
mime-data pointer, and vice versa. (Note this should have been prevented
by using interned strings, but conceptually it is cleaner to make the
separation.) Also it aides in trimming the user data arrays which are
linearly searched.

Based on the original patch by Adrian Johnson:
http://cgit.freedesktop.org/~ajohnson/cairo/commit/?h=metadata&id=37e607cc777523ad12a2d214708d79ecbca5b380
This commit is contained in:
Chris Wilson 2009-02-13 12:56:46 +00:00
parent 2280de9d02
commit adaf70a93f
5 changed files with 77 additions and 43 deletions

View file

@ -494,3 +494,39 @@ _cairo_user_data_array_set_data (cairo_user_data_array_t *array,
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_user_data_array_copy (cairo_user_data_array_t *dst,
cairo_user_data_array_t *src)
{
/* discard any existing user-data */
if (dst->num_elements != 0) {
_cairo_user_data_array_fini (dst);
_cairo_user_data_array_init (dst);
}
if (src->num_elements == 0)
return CAIRO_STATUS_SUCCESS;
return _cairo_array_append_multiple (dst,
_cairo_array_index (src, 0),
src->num_elements);
}
void
_cairo_user_data_array_foreach (cairo_user_data_array_t *array,
void (*func) (void *key,
void *elt,
void *closure),
void *closure)
{
cairo_user_data_slot_t *slots;
int i, num_slots;
num_slots = array->num_elements;
slots = _cairo_array_index (array, 0);
for (i = 0; i < num_slots; i++) {
if (slots[i].user_data != NULL)
func (slots[i].key, slots[i].user_data, closure);
}
}

View file

@ -1121,12 +1121,6 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
cairo_surface_pattern_t pattern;
cairo_image_surface_t *image;
void *image_extra;
const char *mime_types[] = {
CAIRO_MIME_TYPE_JPEG,
CAIRO_MIME_TYPE_PNG,
CAIRO_MIME_TYPE_JP2,
NULL
}, **mime_type;
status = _cairo_surface_acquire_source_image (surface,
&image, &image_extra);
@ -1137,13 +1131,11 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
image->width,
image->height);
if (cairo_surface_status (snapshot)) {
_cairo_surface_release_source_image (surface,
image, image_extra);
_cairo_surface_release_source_image (surface, image, image_extra);
return snapshot;
}
_cairo_pattern_init_for_surface (&pattern, &image->base);
status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
&pattern.base,
NULL,
@ -1153,11 +1145,14 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
0, 0,
image->width,
image->height);
_cairo_pattern_fini (&pattern.base);
_cairo_surface_release_source_image (surface,
image, image_extra);
_cairo_surface_release_source_image (surface, image, image_extra);
if (unlikely (status)) {
cairo_surface_destroy (snapshot);
return _cairo_surface_create_in_error (status);
}
status = _cairo_surface_copy_mime_data (snapshot, surface);
if (unlikely (status)) {
cairo_surface_destroy (snapshot);
return _cairo_surface_create_in_error (status);
@ -1166,14 +1161,6 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
snapshot->device_transform = surface->device_transform;
snapshot->device_transform_inverse = surface->device_transform_inverse;
for (mime_type = mime_types; *mime_type; mime_type++) {
status = _cairo_surface_copy_mime_data (snapshot, surface, *mime_type);
if (unlikely (status)) {
cairo_surface_destroy (snapshot);
return _cairo_surface_create_in_error (status);
}
}
snapshot->is_snapshot = TRUE;
return snapshot;

View file

@ -57,6 +57,7 @@ struct _cairo_surface {
cairo_status_t status;
cairo_bool_t finished;
cairo_user_data_array_t user_data;
cairo_user_data_array_t mime_data;
cairo_matrix_t device_transform;
cairo_matrix_t device_transform_inverse;

View file

@ -51,6 +51,7 @@ const cairo_surface_t name = { \
status, /* status */ \
FALSE, /* finished */ \
{ 0, 0, 0, NULL, }, /* user_data */ \
{ 0, 0, 0, NULL, }, /* mime_data */ \
{ 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform */ \
{ 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform_inverse */ \
0.0, /* x_resolution */ \
@ -194,6 +195,7 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->finished = FALSE;
_cairo_user_data_array_init (&surface->user_data);
_cairo_user_data_array_init (&surface->mime_data);
cairo_matrix_init_identity (&surface->device_transform);
cairo_matrix_init_identity (&surface->device_transform_inverse);
@ -437,6 +439,7 @@ cairo_surface_destroy (cairo_surface_t *surface)
cairo_surface_finish (surface);
_cairo_user_data_array_fini (&surface->user_data);
_cairo_user_data_array_fini (&surface->mime_data);
free (surface);
}
@ -459,6 +462,7 @@ _cairo_surface_reset (cairo_surface_t *surface)
assert (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count) == 1);
_cairo_user_data_array_fini (&surface->user_data);
_cairo_user_data_array_fini (&surface->mime_data);
if (surface->backend->reset != NULL) {
cairo_status_t status = surface->backend->reset (surface);
@ -620,7 +624,7 @@ cairo_surface_get_mime_data (cairo_surface_t *surface,
return;
}
mime_data = _cairo_user_data_array_get_data (&surface->user_data,
mime_data = _cairo_user_data_array_get_data (&surface->mime_data,
(cairo_user_data_key_t *) mime_type);
if (mime_data == NULL)
return;
@ -696,7 +700,7 @@ cairo_surface_set_mime_data (cairo_surface_t *surface,
} else
mime_data = NULL;
status = _cairo_user_data_array_set_data (&surface->user_data,
status = _cairo_user_data_array_set_data (&surface->mime_data,
(cairo_user_data_key_t *) mime_type,
mime_data,
_cairo_mime_data_destroy);
@ -711,13 +715,19 @@ cairo_surface_set_mime_data (cairo_surface_t *surface,
}
slim_hidden_def (cairo_surface_set_mime_data);
static void
_cairo_mime_data_reference (void *key, void *elt, void *closure)
{
cairo_mime_data_t *mime_data = elt;
_cairo_reference_count_inc (&mime_data->ref_count);
}
cairo_status_t
_cairo_surface_copy_mime_data (cairo_surface_t *dst,
cairo_surface_t *src,
const char *mime_type)
cairo_surface_t *src)
{
cairo_status_t status;
cairo_mime_data_t *mime_data;
if (dst->status)
return dst->status;
@ -725,25 +735,15 @@ _cairo_surface_copy_mime_data (cairo_surface_t *dst,
if (src->status)
return _cairo_surface_set_error (dst, src->status);
status = _cairo_intern_string (&mime_type, -1);
/* first copy the mime-data, discarding any already set on dst */
status = _cairo_user_data_array_copy (&dst->mime_data, &src->mime_data);
if (unlikely (status))
return _cairo_surface_set_error (dst, status);
mime_data = _cairo_user_data_array_get_data (&src->user_data,
(cairo_user_data_key_t *) mime_type);
if (mime_data == NULL)
return CAIRO_STATUS_SUCCESS;
_cairo_reference_count_inc (&mime_data->ref_count);
status = _cairo_user_data_array_set_data (&dst->user_data,
(cairo_user_data_key_t *) mime_type,
mime_data,
_cairo_mime_data_destroy);
if (unlikely (status)) {
_cairo_mime_data_destroy (mime_data);
return _cairo_surface_set_error (dst, status);
}
/* now increment the reference counters for the copies */
_cairo_user_data_array_foreach (&dst->mime_data,
_cairo_mime_data_reference,
NULL);
return CAIRO_STATUS_SUCCESS;
}

View file

@ -330,6 +330,17 @@ _cairo_user_data_array_set_data (cairo_user_data_array_t *array,
void *user_data,
cairo_destroy_func_t destroy);
cairo_private cairo_status_t
_cairo_user_data_array_copy (cairo_user_data_array_t *dst,
cairo_user_data_array_t *src);
cairo_private void
_cairo_user_data_array_foreach (cairo_user_data_array_t *array,
void (*func) (void *key,
void *elt,
void *closure),
void *closure);
#define _CAIRO_HASH_INIT_VALUE 5381
cairo_private unsigned long
@ -1742,8 +1753,7 @@ _cairo_surface_create_in_error (cairo_status_t status);
cairo_private cairo_status_t
_cairo_surface_copy_mime_data (cairo_surface_t *dst,
cairo_surface_t *src,
const char *mime_type);
cairo_surface_t *src);
cairo_private cairo_status_t
_cairo_surface_set_error (cairo_surface_t *surface,