diff options
-rw-r--r-- | src/cairo-directfb-surface.c | 15 | ||||
-rw-r--r-- | src/cairo-glitz-surface.c | 40 | ||||
-rw-r--r-- | src/cairo-image-surface.c | 29 | ||||
-rw-r--r-- | src/cairo-mutex-list-private.h | 3 | ||||
-rw-r--r-- | src/cairo-pattern.c | 135 | ||||
-rw-r--r-- | src/cairo-pdf-surface.c | 3 | ||||
-rw-r--r-- | src/cairo-surface.c | 57 | ||||
-rw-r--r-- | src/cairo-win32-surface.c | 29 | ||||
-rw-r--r-- | src/cairo-xcb-surface.c | 39 | ||||
-rw-r--r-- | src/cairo-xlib-surface.c | 45 | ||||
-rw-r--r-- | src/cairoint.h | 16 |
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); |