summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cairo-directfb-surface.c15
-rw-r--r--src/cairo-glitz-surface.c40
-rw-r--r--src/cairo-image-surface.c29
-rw-r--r--src/cairo-mutex-list-private.h3
-rw-r--r--src/cairo-pattern.c135
-rw-r--r--src/cairo-pdf-surface.c3
-rw-r--r--src/cairo-surface.c57
-rw-r--r--src/cairo-win32-surface.c29
-rw-r--r--src/cairo-xcb-surface.c39
-rw-r--r--src/cairo-xlib-surface.c45
-rw-r--r--src/cairoint.h16
11 files changed, 388 insertions, 23 deletions
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 4a628461..a7c99265 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -1511,6 +1511,17 @@ _cairo_directfb_surface_show_glyphs ( void *abstract_dst,
#endif /* DFB_SHOW_GLYPHS */
+static cairo_bool_t
+_cairo_directfb_surface_is_simlar (void *surface_a,
+ void *surface_b,
+ cairo_content_t content)
+{
+ cairo_directfb_surface_t *a = (cairo_directfb_surface_t *) surface_a;
+ cairo_directfb_surface_t *b = (cairo_directfb_surface_t *) surface_b;
+
+ return a->dfb == b->dfb;
+}
+
static cairo_surface_backend_t cairo_directfb_surface_backend = {
CAIRO_SURFACE_TYPE_DIRECTFB, /*type*/
_cairo_directfb_surface_create_similar,/*create_similar*/
@@ -1560,7 +1571,9 @@ static cairo_surface_backend_t cairo_directfb_surface_backend = {
#else
NULL, /* show_glyphs */
#endif
- NULL /* snapshot */
+ NULL, /* snapshot */
+ _cairo_directfb_is_similar,
+ NULL /* reset */
};
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 09e67550..5c8cc6b8 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -2175,6 +2175,33 @@ _cairo_glitz_surface_flush (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
+static cairo_bool_t
+_cairo_glitz_surface_is_similar (void *surface_a,
+ void *surface_b,
+ cairo_content_t content)
+{
+ cairo_glitz_surface_t *a = (cairo_glitz_surface_t *) surface_a;
+ cairo_glitz_surface_t *b = (cairo_glitz_surface_t *) surface_b;
+
+ glitz_drawable_t *drawable_a = glitz_surface_get_drawable (a->surface);
+ glitz_drawable_t *drawable_b = glitz_surface_get_drawable (b->surface);
+
+ return drawable_a == drawable_b;
+}
+
+static cairo_status_t
+_cairo_glitz_surface_reset (void *abstract_surface)
+{
+ cairo_glitz_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ status = _cairo_glitz_surface_set_clip_region (surface, NULL);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static const cairo_surface_backend_t cairo_glitz_surface_backend = {
CAIRO_SURFACE_TYPE_GLITZ,
_cairo_glitz_surface_create_similar,
@@ -2197,7 +2224,18 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_flush,
NULL, /* mark_dirty_rectangle */
_cairo_glitz_surface_scaled_font_fini,
- _cairo_glitz_surface_scaled_glyph_fini
+ _cairo_glitz_surface_scaled_glyph_fini,
+
+ NULL, /* paint */
+ NULL, /* mask */
+ NULL, /* stroke */
+ NULL, /* fill */
+ NULL, /* show_glyphs */
+
+ NULL, /* snapshot */
+ _cairo_glitz_surface_is_compatible,
+
+ _cairo_glitz_surface_reset
};
static const cairo_surface_backend_t *
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 3aa4cb4f..441947f6 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -1071,6 +1071,19 @@ _cairo_image_surface_get_font_options (void *abstract_surface,
cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
}
+static cairo_status_t
+_cairo_image_surface_reset (void *abstract_surface)
+{
+ cairo_image_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ status = _cairo_image_surface_set_clip_region (surface, NULL);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
/**
* _cairo_surface_is_image:
* @surface: a #cairo_surface_t
@@ -1103,7 +1116,21 @@ const cairo_surface_backend_t cairo_image_surface_backend = {
NULL, /* intersect_clip_path */
_cairo_image_surface_get_extents,
NULL, /* old_show_glyphs */
- _cairo_image_surface_get_font_options
+ _cairo_image_surface_get_font_options,
+ NULL, /* flush */
+ NULL, /* mark_dirty_rectangle */
+ NULL, //* font_fini */
+ NULL, //* glyph_fini */
+
+ NULL, /* paint */
+ NULL, /* mask */
+ NULL, /* stroke */
+ NULL, /* fill */
+ NULL, /* show_glyphs */
+ NULL, /* snapshot */
+ NULL, /* is_similar */
+
+ _cairo_image_surface_reset
};
/* A convenience function for when one needs to coerce an image
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index 37378310..abb4a9a3 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -32,7 +32,8 @@
*/
-CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_cache_lock);
+CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_pattern_cache_lock);
+CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock);
CAIRO_MUTEX_DECLARE (_cairo_font_face_mutex);
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex);
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index b6c8df7f..ef7fc05e 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -285,7 +285,7 @@ _cairo_pattern_create_solid (const cairo_color_t *color,
{
cairo_solid_pattern_t *pattern = NULL;
- CAIRO_MUTEX_LOCK (_cairo_pattern_solid_cache_lock);
+ CAIRO_MUTEX_LOCK (_cairo_pattern_solid_pattern_cache_lock);
if (solid_pattern_cache.size) {
int i = --solid_pattern_cache.size %
@@ -294,7 +294,7 @@ _cairo_pattern_create_solid (const cairo_color_t *color,
solid_pattern_cache.patterns[i] = NULL;
}
- CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_cache_lock);
+ CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_pattern_cache_lock);
if (pattern == NULL) {
/* None cached, need to create a new pattern. */
@@ -309,12 +309,12 @@ _cairo_pattern_create_solid (const cairo_color_t *color,
return &pattern->base;
}
-void
-_cairo_pattern_reset_static_data (void)
+static void
+_cairo_pattern_reset_solid_pattern_cache (void)
{
int i;
- CAIRO_MUTEX_LOCK (_cairo_pattern_solid_cache_lock);
+ CAIRO_MUTEX_LOCK (_cairo_pattern_solid_pattern_cache_lock);
for (i = 0; i < MIN (ARRAY_LENGTH (solid_pattern_cache.patterns), solid_pattern_cache.size); i++) {
free (solid_pattern_cache.patterns[i]);
@@ -322,7 +322,7 @@ _cairo_pattern_reset_static_data (void)
}
solid_pattern_cache.size = 0;
- CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_cache_lock);
+ CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_pattern_cache_lock);
}
static const cairo_pattern_t *
@@ -636,7 +636,7 @@ cairo_pattern_destroy (cairo_pattern_t *pattern)
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
int i;
- CAIRO_MUTEX_LOCK (_cairo_pattern_solid_cache_lock);
+ CAIRO_MUTEX_LOCK (_cairo_pattern_solid_pattern_cache_lock);
i = solid_pattern_cache.size++ %
ARRAY_LENGTH (solid_pattern_cache.patterns);
@@ -646,7 +646,7 @@ cairo_pattern_destroy (cairo_pattern_t *pattern)
solid_pattern_cache.patterns[i] = (cairo_solid_pattern_t *) pattern;
- CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_cache_lock);
+ CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_pattern_cache_lock);
} else {
free (pattern);
}
@@ -1241,6 +1241,35 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
return status;
}
+/* We maintain a small cache here, because we don't want to constantly
+ * recreate surfaces for simple solid colors. */
+#define MAX_SURFACE_CACHE_SIZE 16
+static struct {
+ struct _cairo_pattern_solid_surface_cache{
+ cairo_color_t color;
+ cairo_surface_t *surface;
+ } cache[MAX_SURFACE_CACHE_SIZE];
+ int size;
+} solid_surface_cache;
+
+static cairo_bool_t
+_cairo_pattern_solid_surface_matches (
+ const struct _cairo_pattern_solid_surface_cache *cache,
+ const cairo_solid_pattern_t *pattern,
+ cairo_surface_t *dst)
+{
+ if (cache->surface->ref_count != 1)
+ return FALSE;
+
+ if (! _cairo_color_equal (&cache->color, &pattern->color))
+ return FALSE;
+
+ if (! _cairo_surface_is_similar (cache->surface, dst, pattern->content))
+ return FALSE;
+
+ return TRUE;
+}
+
static cairo_int_status_t
_cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
cairo_surface_t *dst,
@@ -1251,13 +1280,61 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
cairo_surface_t **out,
cairo_surface_attributes_t *attribs)
{
- *out = _cairo_surface_create_similar_solid (dst,
- pattern->content,
- 1, 1,
- &pattern->color,
- &pattern->base);
- if ((*out)->status)
- return CAIRO_STATUS_NO_MEMORY;
+ static int i;
+
+ cairo_surface_t *surface;
+ cairo_status_t status;
+
+ CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
+
+ /* Check cache first */
+ if (i < solid_surface_cache.size &&
+ _cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
+ pattern,
+ dst))
+ {
+ if (! _cairo_surface_reset (solid_surface_cache.cache[i].surface))
+ goto DONE;
+ }
+
+ for (i = 0 ; i < solid_surface_cache.size; i++) {
+ if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
+ pattern,
+ dst))
+ {
+ if (! _cairo_surface_reset (solid_surface_cache.cache[i].surface))
+ goto DONE;
+ }
+ }
+
+ /* Not cached, need to create new */
+ surface = _cairo_surface_create_similar_solid (dst,
+ pattern->content,
+ 1, 1,
+ &pattern->color,
+ &pattern->base);
+ if (surface->status) {
+ status = surface->status;
+ goto UNLOCK;
+ }
+
+ assert (_cairo_surface_is_similar (surface, dst, pattern->content));
+
+ /* Cache new */
+ if (solid_surface_cache.size < MAX_SURFACE_CACHE_SIZE) {
+ solid_surface_cache.size++;
+ } else {
+ i = rand () % MAX_SURFACE_CACHE_SIZE;
+
+ /* Evict old */
+ cairo_surface_destroy (solid_surface_cache.cache[i].surface);
+ }
+
+ solid_surface_cache.cache[i].color = pattern->color;
+ solid_surface_cache.cache[i].surface = surface;
+
+DONE:
+ *out = cairo_surface_reference (solid_surface_cache.cache[i].surface);
attribs->x_offset = attribs->y_offset = 0;
cairo_matrix_init_identity (&attribs->matrix);
@@ -1265,7 +1342,26 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
attribs->filter = CAIRO_FILTER_NEAREST;
attribs->acquired = FALSE;
- return CAIRO_STATUS_SUCCESS;
+ status = CAIRO_STATUS_SUCCESS;
+
+UNLOCK:
+ CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
+
+ return status;
+}
+
+static void
+_cairo_pattern_reset_solid_surface_cache (void)
+{
+ int i;
+
+ CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
+
+ for (i = 0; i < solid_surface_cache.size; i++)
+ cairo_surface_destroy (solid_surface_cache.cache[i].surface);
+ solid_surface_cache.size = 0;
+
+ CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
}
/**
@@ -2063,3 +2159,10 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
return CAIRO_STATUS_SUCCESS;
}
+
+void
+_cairo_pattern_reset_static_data (void)
+{
+ _cairo_pattern_reset_solid_pattern_cache ();
+ _cairo_pattern_reset_solid_surface_cache ();
+}
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 00dcd7c7..f488bde9 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -3637,6 +3637,9 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
_cairo_pdf_surface_fill,
_cairo_pdf_surface_show_glyphs,
NULL, /* snapshot */
+
+ NULL, /* is_compatible */
+ NULL, /* reset */
};
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend = {
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index cf8acf09..7c8a1e32 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -407,6 +407,34 @@ cairo_surface_destroy (cairo_surface_t *surface)
slim_hidden_def(cairo_surface_destroy);
/**
+ * cairo_surface_reset:
+ * @surface: a #cairo_surface_t
+ *
+ * Resets the surface back to defaults such that it may be reused in lieu
+ * of creating a new surface.
+ **/
+cairo_status_t
+_cairo_surface_reset (cairo_surface_t *surface)
+{
+ if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID)
+ return CAIRO_STATUS_SUCCESS;
+
+ assert (surface->ref_count == 1);
+
+ _cairo_user_data_array_fini (&surface->user_data);
+
+ if (surface->backend->reset != NULL) {
+ cairo_status_t status = surface->backend->reset (surface);
+ if (status)
+ return status;
+ }
+
+ _cairo_surface_init (surface, surface->backend, surface->content);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
* cairo_surface_get_reference_count:
* @surface: a #cairo_surface_t
*
@@ -1062,6 +1090,35 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
return _cairo_surface_fallback_snapshot (surface);
}
+/**
+ * _cairo_surface_is_similar
+ * @surface_a: a #cairo_surface_t
+ * @surface_b: a #cairo_surface_t
+ * @content: a #cairo_content_t
+ *
+ * Find out whether the given surfaces share the same backend,
+ * and if so, whether they can be considered similar.
+ *
+ * The definition of "similar" depends on the backend. In
+ * general, it means that the surface is equivalent to one
+ * that would have been generated by a call to cairo_surface_create_similar.
+ *
+ * Return value: TRUE if the surfaces are similar.
+ **/
+cairo_bool_t
+_cairo_surface_is_similar (cairo_surface_t *surface_a,
+ cairo_surface_t *surface_b,
+ cairo_content_t content)
+{
+ if (surface_a->backend != surface_b->backend)
+ return FALSE;
+
+ if (surface_a->backend->is_similar != NULL)
+ return surface_a->backend->is_similar (surface_a, surface_b, content);
+
+ return TRUE;
+}
+
cairo_status_t
_cairo_surface_composite (cairo_operator_t op,
cairo_pattern_t *src,
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index a907fd8e..450887a1 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1855,6 +1855,30 @@ cairo_win32_surface_get_image (cairo_surface_t *surface)
return ((cairo_win32_surface_t*)surface)->image;
}
+static cairo_bool_t
+_cairo_win32_surface_is_similar (void *surface_a,
+ void *surface_b,
+ cairo_content_t content)
+{
+ cairo_win32_surface_t *a = surface_a;
+ cairo_win32_surface_t *b = surface_b;
+
+ return a->dc == b->dc;
+}
+
+static cairo_status_t
+_cairo_win32_surface_reset (void *abstract_surface)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ status = _cairo_win32_surface_set_clip_region (surface, NULL);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static const cairo_surface_backend_t cairo_win32_surface_backend = {
CAIRO_SURFACE_TYPE_WIN32,
_cairo_win32_surface_create_similar,
@@ -1885,7 +1909,10 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = {
NULL, /* fill */
_cairo_win32_surface_show_glyphs,
- NULL /* snapshot */
+ NULL, /* snapshot */
+ _cairo_win32_surface_is_similar,
+
+ _cairo_win32_surface_reset
};
/* Notes:
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index e8ab0fbb..304300a6 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -1577,6 +1577,39 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
int num_glyphs,
cairo_scaled_font_t *scaled_font);
+static cairo_bool_t
+_cairo_xcb_surface_is_similar (void *surface_a,
+ void *surface_b,
+ cairo_content_t content)
+{
+ cairo_xcb_surface_t *a = surface_a;
+ cairo_xcb_surface_t *b = surface_b;
+ xcb_render_pictforminfo_t xrender_format;
+
+ if (! _cairo_xcb_surface_same_screen (dst, src))
+ return FALSE;
+
+ /* now check that the target is a similar format */
+ xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (b->dpy,
+ _cairo_format_from_content (content));
+
+ return a->xrender_format == xrender_format;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_reset (void *abstract_surface)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ status = _cairo_xcb_surface_set_clip_region (surface, NULL);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
/* XXX: move this to the bottom of the file, XCB and Xlib */
static const cairo_surface_backend_t cairo_xcb_surface_backend = {
@@ -1608,7 +1641,11 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = {
NULL, /* stroke */
NULL, /* fill */
_cairo_xcb_surface_show_glyphs,
- NULL /* snapshot */
+ NULL, /* snapshot */
+
+ _cairo_xcb_surface_is_similar,
+
+ _cairo_xcb_surface_reset
};
/**
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 4f0c2081..9dbe8cf0 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1805,6 +1805,46 @@ static void
_cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font);
+static cairo_bool_t
+_cairo_xlib_surface_is_similar (void *surface_a,
+ void *surface_b,
+ cairo_content_t content)
+{
+ cairo_xlib_surface_t *a = surface_a;
+ cairo_xlib_surface_t *b = surface_b;
+ XRenderPictFormat *xrender_format = b->xrender_format;
+
+ if (!_cairo_xlib_surface_same_screen (a, b))
+ return FALSE;
+
+ /* now inspect the content to check that a is similar to b */
+ if (xrender_format == NULL && b->visual != NULL)
+ xrender_format = XRenderFindVisualFormat (b->dpy, b->visual);
+
+ if (xrender_format == NULL ||
+ _xrender_format_to_content (xrender_format) != content)
+ {
+ xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (b->dpy,
+ _cairo_format_from_content (content));
+ }
+
+
+ return a->xrender_format == xrender_format;
+}
+
+static cairo_status_t
+_cairo_xlib_surface_reset (void *abstract_surface)
+{
+ cairo_xlib_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ status = _cairo_xlib_surface_set_clip_region (surface, NULL);
+ if (status)
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static const cairo_surface_backend_t cairo_xlib_surface_backend = {
CAIRO_SURFACE_TYPE_XLIB,
_cairo_xlib_surface_create_similar,
@@ -1834,7 +1874,10 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
NULL, /* stroke */
NULL, /* fill */
_cairo_xlib_surface_show_glyphs,
- NULL /* snapshot */
+ NULL, /* snapshot */
+ _cairo_xlib_surface_is_similar,
+
+ _cairo_xlib_surface_reset
};
/**
diff --git a/src/cairoint.h b/src/cairoint.h
index 3d1b17df..43c9ca5e 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -890,6 +890,14 @@ struct _cairo_surface_backend {
cairo_surface_t *
(*snapshot) (void *surface);
+
+ cairo_bool_t
+ (*is_similar) (void *surface_a,
+ void *surface_b,
+ cairo_content_t content);
+
+ cairo_warn cairo_status_t
+ (*reset) (void *surface);
};
typedef struct _cairo_format_masks {
@@ -1868,6 +1876,14 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_private cairo_surface_t *
_cairo_surface_snapshot (cairo_surface_t *surface);
+cairo_private cairo_bool_t
+_cairo_surface_is_similar (cairo_surface_t *surface_a,
+ cairo_surface_t *surface_b,
+ cairo_content_t content);
+
+cairo_private cairo_status_t
+_cairo_surface_reset (cairo_surface_t *surface);
+
cairo_private unsigned int
_cairo_surface_get_current_clip_serial (cairo_surface_t *surface);