[mime-data] Copy a reference to the mime-data on snapshotting.

Instead of doing a full-copy of the mime data (which can be 10K-100K,
or even larger) just copy a reference to the original mime to the
snapshot surface (as suggested by Behdad).
This commit is contained in:
Chris Wilson 2008-11-03 23:45:12 +00:00
parent 4f032ca35a
commit 9021755012
4 changed files with 65 additions and 46 deletions

View file

@ -1035,8 +1035,6 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
cairo_status_t status;
cairo_surface_pattern_t pattern;
cairo_image_surface_t *image;
const unsigned char *mime_data;
unsigned int mime_data_length;
void *image_extra;
status = _cairo_surface_acquire_source_image (surface,
@ -1081,28 +1079,11 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
* For now, just copy "image/jpeg", but in future we should construct
* an array of known types and iterate.
*/
cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_JPEG,
&mime_data, &mime_data_length);
if (mime_data != NULL) {
unsigned char *mime_data_copy;
mime_data_copy = malloc (mime_data_length);
if (mime_data == NULL) {
cairo_surface_destroy (snapshot);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
memcpy (mime_data_copy, mime_data, mime_data_length);
status = cairo_surface_set_mime_data (snapshot,
CAIRO_MIME_TYPE_JPEG,
mime_data_copy,
mime_data_length,
free);
if (status) {
free (mime_data_copy);
cairo_surface_destroy (snapshot);
return _cairo_surface_create_in_error (status);
}
status = _cairo_surface_copy_mime_data (snapshot, surface,
CAIRO_MIME_TYPE_JPEG);
if (status) {
cairo_surface_destroy (snapshot);
return _cairo_surface_create_in_error (status);
}
snapshot->is_snapshot = TRUE;

View file

@ -637,6 +637,9 @@ _cairo_mime_data_destroy (void *ptr)
{
cairo_mime_data_t *mime_data = ptr;
if (! _cairo_reference_count_dec_and_test (&mime_data->ref_count))
return;
if (mime_data->destroy && mime_data->data)
mime_data->destroy (mime_data->data);
@ -679,36 +682,64 @@ cairo_surface_set_mime_data (cairo_surface_t *surface,
if (status)
return _cairo_surface_set_error (surface, status);
mime_data = _cairo_user_data_array_get_data (&surface->user_data,
(cairo_user_data_key_t *) mime_type);
if (mime_data != NULL) {
if (mime_data->destroy && mime_data->data)
mime_data->destroy (mime_data->data);
mime_data = malloc (sizeof (cairo_mime_data_t));
if (mime_data == NULL)
return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY));
mime_data->data = (unsigned char *) data;
mime_data->length = length;
mime_data->destroy = destroy;
} else {
mime_data = malloc (sizeof (cairo_mime_data_t));
if (mime_data == NULL)
return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY));
CAIRO_REFERENCE_COUNT_INIT (&mime_data->ref_count, 1);
mime_data->data = (unsigned char *) data;
mime_data->length = length;
mime_data->destroy = destroy;
mime_data->data = (unsigned char *) data;
mime_data->length = length;
mime_data->destroy = destroy;
status = _cairo_user_data_array_set_data (&surface->user_data,
(cairo_user_data_key_t *) mime_type,
mime_data,
_cairo_mime_data_destroy);
if (status)
return _cairo_surface_set_error (surface, status);
}
status = _cairo_user_data_array_set_data (&surface->user_data,
(cairo_user_data_key_t *) mime_type,
mime_data,
_cairo_mime_data_destroy);
if (status)
return _cairo_surface_set_error (surface, status);
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_surface_set_mime_data);
cairo_status_t
_cairo_surface_copy_mime_data (cairo_surface_t *dst,
cairo_surface_t *src,
const char *mime_type)
{
cairo_status_t status;
cairo_mime_data_t *mime_data;
if (dst->status)
return dst->status;
if (src->status)
return _cairo_surface_set_error (dst, src->status);
status = _cairo_intern_string (&mime_type, -1);
if (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 (status) {
_cairo_mime_data_destroy (mime_data);
return _cairo_surface_set_error (dst, status);
}
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_surface_set_font_options:
* @surface: a #cairo_surface_t

View file

@ -41,6 +41,7 @@
#include "cairo.h"
#include "cairo-fixed-type-private.h"
#include "cairo-reference-count-private.h"
typedef struct _cairo_array cairo_array_t;
typedef struct _cairo_cache cairo_cache_t;
@ -344,6 +345,7 @@ typedef enum _cairo_image_transparency {
} cairo_image_transparency_t;
struct _cairo_mime_data {
cairo_reference_count_t ref_count;
unsigned char *data;
unsigned int length;
cairo_destroy_func_t destroy;

View file

@ -1665,6 +1665,11 @@ _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
cairo_private cairo_surface_t *
_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_private cairo_status_t
_cairo_surface_set_error (cairo_surface_t *surface,
cairo_status_t status);