summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cairo-color.c7
-rw-r--r--src/cairo-debug.c2
-rw-r--r--src/cairo-mutex-list.h2
-rw-r--r--src/cairo-pattern.c63
-rwxr-xr-xsrc/cairoint.h7
-rw-r--r--test/Makefile.am1
-rw-r--r--test/solid-pattern-cache-stress.c83
7 files changed, 163 insertions, 2 deletions
diff --git a/src/cairo-color.c b/src/cairo-color.c
index ad6316e10..257f8d261 100644
--- a/src/cairo-color.c
+++ b/src/cairo-color.c
@@ -160,3 +160,10 @@ _cairo_color_get_rgba_premultiplied (cairo_color_t *color,
*blue = color->blue * color->alpha;
*alpha = color->alpha;
}
+
+cairo_bool_t
+_cairo_color_equal (const cairo_color_t *color_a,
+ const cairo_color_t *color_b)
+{
+ return memcmp (color_a, color_b, sizeof (cairo_color_t)) == 0;
+}
diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index 7c299325f..dd57dd780 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -68,4 +68,6 @@ cairo_debug_reset_static_data (void)
#if CAIRO_HAS_FT_FONT
_cairo_ft_font_reset_static_data ();
#endif
+
+ _cairo_pattern_reset_static_data ();
}
diff --git a/src/cairo-mutex-list.h b/src/cairo-mutex-list.h
index 7c7bf8f8d..c054e11aa 100644
--- a/src/cairo-mutex-list.h
+++ b/src/cairo-mutex-list.h
@@ -34,6 +34,8 @@
#ifndef CAIRO_MUTEX_LIST_H
#define CAIRO_MUTEX_LIST_H
+CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_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 263907118..6ebe0caba 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -259,18 +259,77 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
pattern->gradient.c2.radius = _cairo_fixed_from_double (fabs (radius1));
}
+/* We use a small cache here, because we don't want to constantly
+ * reallocate simple colors. */
+#define MAX_PATTERN_CACHE_SIZE 16
+static struct {
+ struct {
+ cairo_color_t color;
+ cairo_solid_pattern_t *pattern;
+ } cache[MAX_PATTERN_CACHE_SIZE];
+ int size;
+} solid_pattern_cache;
+
cairo_pattern_t *
_cairo_pattern_create_solid (const cairo_color_t *color)
{
- cairo_solid_pattern_t *pattern;
+ static int cache_index;
+ void *pattern;
+
+ CAIRO_MUTEX_LOCK (_cairo_pattern_solid_cache_lock);
+
+ /* Check cache first. */
+ if (cache_index < solid_pattern_cache.size &&
+ _cairo_color_equal (
+ &solid_pattern_cache.cache[cache_index].color, color))
+ goto DONE;
+ for (cache_index = 0; cache_index < solid_pattern_cache.size; cache_index++)
+ if (_cairo_color_equal (
+ &solid_pattern_cache.cache[cache_index].color, color))
+ goto DONE;
+
+ /* Not cached, need to create a new pattern. */
pattern = malloc (sizeof (cairo_solid_pattern_t));
if (pattern == NULL)
return (cairo_pattern_t *) &cairo_pattern_nil.base;
_cairo_pattern_init_solid (pattern, color);
- return &pattern->base;
+ /* And insert it into the cache. */
+ if (solid_pattern_cache.size < MAX_PATTERN_CACHE_SIZE) {
+ solid_pattern_cache.size ++;
+ /* cache_index == solid_pattern_cache.size */
+ } else {
+ /* Evict an old pattern. */
+ cache_index = rand () % MAX_PATTERN_CACHE_SIZE;
+ cairo_pattern_destroy (
+ &solid_pattern_cache.cache[cache_index].pattern->base);
+ }
+
+ solid_pattern_cache.cache[cache_index].color = *color;
+ solid_pattern_cache.cache[cache_index].pattern = pattern;
+
+DONE:
+ pattern = cairo_pattern_reference (
+ &solid_pattern_cache.cache[cache_index].pattern->base);
+ CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_cache_lock);
+
+ return pattern;
+}
+
+void
+_cairo_pattern_reset_static_data (void)
+{
+ int i;
+
+ CAIRO_MUTEX_LOCK (_cairo_pattern_solid_cache_lock);
+
+ for (i = 0; i < solid_pattern_cache.size; i++)
+ cairo_pattern_destroy (&solid_pattern_cache.cache[i].pattern->base);
+ solid_pattern_cache.size = 0;
+
+ CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_cache_lock);
}
static const cairo_pattern_t *
diff --git a/src/cairoint.h b/src/cairoint.h
index 35f211759..7ce7cd1b9 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1546,6 +1546,10 @@ _cairo_color_get_rgba_premultiplied (cairo_color_t *color,
double *blue,
double *alpha);
+cairo_private cairo_bool_t
+_cairo_color_equal (const cairo_color_t *color_a,
+ const cairo_color_t *color_b);
+
/* cairo-font.c */
cairo_private void
@@ -2407,6 +2411,9 @@ cairo_private cairo_status_t
_cairo_pattern_get_extents (cairo_pattern_t *pattern,
cairo_rectangle_int16_t *extents);
+cairo_private void
+_cairo_pattern_reset_static_data (void);
+
cairo_private cairo_status_t
_cairo_gstate_set_antialias (cairo_gstate_t *gstate,
cairo_antialias_t antialias);
diff --git a/test/Makefile.am b/test/Makefile.am
index 11e988130..792584efd 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -86,6 +86,7 @@ self-intersecting \
set-source \
show-text-current-point \
skew-extreme \
+solid-pattern-cache-stress \
source-clip \
source-clip-scale \
source-surface-scale-paint \
diff --git a/test/solid-pattern-cache-stress.c b/test/solid-pattern-cache-stress.c
new file mode 100644
index 000000000..93e2f697f
--- /dev/null
+++ b/test/solid-pattern-cache-stress.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright ? 2007 Chris Wilson.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_draw_function_t draw;
+
+cairo_test_t test = {
+ "solid-pattern-cache-stress",
+ "Stress the solid pattern cache and ensure it behaves",
+ 0, 0,
+ draw
+};
+#include <cairo.h>
+#include <stdlib.h>
+
+#define LOOPS 10
+#define NRAND 100
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ int loop;
+ int i;
+
+ for (loop = 0; loop < LOOPS; loop++) {
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
+ cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); /* red */
+ cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); /* green */
+ cairo_set_source_rgb (cr, 1.0, 1.0, 0.0); /* yellow */
+ cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); /* blue */
+ cairo_set_source_rgb (cr, 1.0, 0.0, 1.0); /* magenta */
+ cairo_set_source_rgb (cr, 0.0, 1.0, 1.0); /* cyan */
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); /* black */
+ cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 1.0); /* red */
+ cairo_set_source_rgba (cr, 0.0, 1.0, 0.0, 1.0); /* green */
+ cairo_set_source_rgba (cr, 1.0, 1.0, 0.0, 1.0); /* yellow */
+ cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 1.0); /* blue */
+ cairo_set_source_rgba (cr, 1.0, 0.0, 1.0, 1.0); /* magenta */
+ cairo_set_source_rgba (cr, 0.0, 1.0, 1.0, 1.0); /* cyan */
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0); /* white */
+
+ for (i = 0; i < NRAND; i++)
+ cairo_set_source_rgba (cr,
+ drand48 (),
+ drand48 (),
+ drand48 (),
+ drand48 ());
+ }
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test);
+}
+