diff --git a/src/cairo-clip.c b/src/cairo-clip.c diff --git a/src/cairo-color.c b/src/cairo-color.c index a348839..0688167 100644 --- a/src/cairo-color.c +++ b/src/cairo-color.c @@ -159,3 +159,10 @@ _cairo_color_get_rgba_premultiplied (cai *blue = color->blue * color->alpha; *alpha = color->alpha; } + +cairo_bool_t +_cairo_color_equal (cairo_color_t *color_a, + cairo_color_t *color_b) +{ + return (memcmp (color_a, color_b, sizeof (cairo_color_t)) == 0); +} diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c index 686510d..96ee212 100644 --- a/src/cairo-directfb-surface.c +++ b/src/cairo-directfb-surface.c @@ -1514,6 +1514,15 @@ _cairo_directfb_surface_show_glyphs ( vo } #endif /* DFB_SHOW_GLYPHS */ +static cairo_bool_t +_cairo_directfb_surface_is_compatible (void *surface_a, + void *surface_b) +{ + 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*/ @@ -1564,7 +1573,8 @@ #if DFB_SHOW_GLYPHS #else NULL, /* show_glyphs */ #endif - NULL /* snapshot */ + NULL, /* snapshot */ + _cairo_directfb_is_compatible }; diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index f492739..79e0162 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -1799,6 +1799,19 @@ _cairo_glitz_surface_scaled_glyph_fini ( } } +static cairo_bool_t +_cairo_glitz_surface_is_compatible (void *surface_a, + void *surface_b) +{ + cairo_glitz_surface_t *a = (cairo_glitz_surface_t*) surface_a; + cairo_glitz_surface_t *b = (cairo_glitz_surface_t*) surface_b; + + glitz_drawable *drawable_a = glitz_surface_get_drawable (a->surface); + glitz_drawable *drawable_b = glitz_surface_get_drawable (b->surface); + + return (drawable_a == drawable_b); +} + #define FIXED_TO_FLOAT(f) (((glitz_float_t) (f)) / 65536) static cairo_status_t @@ -2194,7 +2207,16 @@ static const cairo_surface_backend_t cai _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 }; static const cairo_surface_backend_t * diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index b488d1f..28f8561 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -1020,6 +1020,8 @@ _cairo_pattern_acquire_surface_for_gradi return status; } +#define MAX_CACHE_SIZE 16 + static cairo_int_status_t _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern, cairo_surface_t *dst, @@ -1030,12 +1032,59 @@ _cairo_pattern_acquire_surface_for_solid cairo_surface_t **out, cairo_surface_attributes_t *attribs) { - *out = _cairo_surface_create_similar_solid (dst, - CAIRO_CONTENT_COLOR_ALPHA, - 1, 1, - &pattern->color); - if ((*out)->status) - return CAIRO_STATUS_NO_MEMORY; + /* We have a small cache here, because we don't want to constantly + * recreate surfaces for simple solid colors */ + static struct { + cairo_color_t color; + cairo_surface_t *surface; + } cache[MAX_CACHE_SIZE]; + static int cache_size = 0; + static int i = 0; + CAIRO_MUTEX_DECLARE (cache_lock); + + cairo_surface_t *surface; + cairo_status_t status; + + CAIRO_MUTEX_LOCK (cache_lock); + + /* Check cache first */ + if (i < cache_size) + if (_cairo_color_equal (&cache[i].color, &pattern->color) && + _cairo_surface_is_compatible (cache[i].surface, dst)) + goto DONE; + + for (i = 0; i < cache_size; i++) + if (_cairo_color_equal (&cache[i].color, &pattern->color) && + _cairo_surface_is_compatible (cache[i].surface, dst)) + goto DONE; + + /* Not cached, need to create new */ + surface = _cairo_surface_create_similar_solid (dst, + CAIRO_CONTENT_COLOR_ALPHA, + 1, 1, + &pattern->color); + if (surface->status) { + status = CAIRO_STATUS_NO_MEMORY; + + goto UNLOCK; + } + + /* Cache new */ + if (cache_size < MAX_CACHE_SIZE) + cache_size++; + else { + i = rand () % MAX_CACHE_SIZE; + + /* Evict old */ + cairo_surface_destroy (cache[i].surface); + } + + cache[i].color = pattern->color; + cache[i].surface = surface; + +DONE: + + *out = cairo_surface_reference (cache[i].surface); attribs->x_offset = attribs->y_offset = 0; cairo_matrix_init_identity (&attribs->matrix); @@ -1043,7 +1092,13 @@ _cairo_pattern_acquire_surface_for_solid attribs->filter = CAIRO_FILTER_NEAREST; attribs->acquired = FALSE; - return CAIRO_STATUS_SUCCESS; + status = CAIRO_STATUS_SUCCESS; + +UNLOCK: + + CAIRO_MUTEX_UNLOCK (cache_lock); + + return status; } /** diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 2bff0da..78cad9b 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -1078,6 +1078,32 @@ _cairo_surface_snapshot (cairo_surface_t return _cairo_surface_fallback_snapshot (surface); } +/** + * _cairo_surface_is_compatible + * @surface_a: a #cairo_surface_t + * @surface_b: a #cairo_surface_t + * + * Find out whether the given surfaces share the same backend, + * and if so, whether they can be considered compatible. + * + * The definition of "compatible" depends on the backend. In the + * xlib case, it means the surfaces share the same display. + * + * Return value: TRUE if the surfaces are compatible. + **/ +cairo_bool_t +_cairo_surface_is_compatible (cairo_surface_t *surface_a, + cairo_surface_t *surface_b) +{ + if (surface_a->backend != surface_b->backend) + return FALSE; + + if (surface_a->backend->is_compatible) + return surface_a->backend->is_compatible (surface_a, surface_b); + + 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 be7e706..81eb916 100644 --- a/src/cairo-win32-surface.c +++ b/src/cairo-win32-surface.c @@ -1609,6 +1609,16 @@ _cairo_win32_surface_show_glyphs (void return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED; } +static cairo_bool_t +_cairo_win32_surface_is_compatible (void *surface_a, + void *surface_b) +{ + cairo_win32_surface_t *a = (cairo_win32_surface_t*) surface_a; + cairo_win32_surface_t *b = (cairo_win32_surface_t*) surface_b; + + return (a->dc == b->dc); +} + #undef STACK_GLYPH_SIZE /** @@ -1879,7 +1889,8 @@ static const cairo_surface_backend_t cai NULL, /* fill */ _cairo_win32_surface_show_glyphs, - NULL /* snapshot */ + NULL, /* snapshot */ + _cairo_win32_surface_is_compatible }; /* diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index 2fdf8a1..8df859d 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -1578,6 +1578,10 @@ _cairo_xcb_surface_show_glyphs (void int num_glyphs, cairo_scaled_font_t *scaled_font); +static cairo_bool_t +_cairo_xcb_surface_is_compatible (void *surface_a, + void *surface_b); + /* XXX: move this to the bottom of the file, XCB and Xlib */ static const cairo_surface_backend_t cairo_xcb_surface_backend = { @@ -1609,7 +1613,8 @@ static const cairo_surface_backend_t cai NULL, /* stroke */ NULL, /* fill */ _cairo_xcb_surface_show_glyphs, - NULL /* snapshot */ + NULL, /* snapshot */ + _cairo_xcb_surface_is_compatible }; /** @@ -2451,3 +2456,13 @@ _cairo_xcb_surface_show_glyphs (void return status; } + +static cairo_bool_t +_cairo_xcb_surface_is_compatible (void *surface_a, + void *surface_b) +{ + cairo_xcb_surface_t *a = (cairo_xcb_surface_t*) surface_a; + cairo_xcb_surface_t *b = (cairo_xcb_surface_t*) surface_b; + + return (a->dpy == b->dpy); +} diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 6a0d3e4..9228c95 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -74,6 +74,10 @@ _cairo_xlib_surface_show_glyphs (void int num_glyphs, cairo_scaled_font_t *scaled_font); +static cairo_bool_t +_cairo_xlib_surface_is_compatible (void *surface_a, + void *surface_b); + /* * Instead of taking two round trips for each blending request, * assume that if a particular drawable fails GetImage that it will @@ -1783,7 +1787,8 @@ static const cairo_surface_backend_t cai NULL, /* stroke */ NULL, /* fill */ _cairo_xlib_surface_show_glyphs, - NULL /* snapshot */ + NULL, /* snapshot */ + _cairo_xlib_surface_is_compatible }; /** @@ -2913,3 +2918,13 @@ _cairo_xlib_surface_show_glyphs (void return status; } + +static cairo_bool_t +_cairo_xlib_surface_is_compatible (void *surface_a, + void *surface_b) +{ + cairo_xlib_surface_t *a = (cairo_xlib_surface_t*) surface_a; + cairo_xlib_surface_t *b = (cairo_xlib_surface_t*) surface_b; + + return (a->dpy == b->dpy); +} diff --git a/src/cairo.c b/src/cairo.c diff --git a/src/cairoint.h b/src/cairoint.h index 060b988..01c0e2a 100755 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -933,6 +933,10 @@ struct _cairo_surface_backend { cairo_surface_t * (*snapshot) (void *surface); + + cairo_bool_t + (*is_compatible) (void *surface_a, + void *surface_b); }; typedef struct _cairo_format_masks { @@ -1497,6 +1501,10 @@ _cairo_color_get_rgba_premultiplied (cai double *blue, double *alpha); +cairo_private cairo_bool_t +_cairo_color_equal (cairo_color_t *color_a, + cairo_color_t *color_b); + /* cairo-font.c */ cairo_private void @@ -1922,6 +1930,10 @@ _cairo_surface_clone_similar (cairo_surf cairo_private cairo_surface_t * _cairo_surface_snapshot (cairo_surface_t *surface); +cairo_private cairo_bool_t +_cairo_surface_is_compatible (cairo_surface_t *surface_a, + cairo_surface_t *surface_b); + cairo_private unsigned int _cairo_surface_get_current_clip_serial (cairo_surface_t *surface);