[cairo-commit] 7 commits - src/cairo-path-fixed.c src/cairo-pdf-surface.c src/cairo-rtree.c src/cairo-rtree-private.h src/cairo-spline.c src/cairo-xlib-display.c src/Makefile.sources test/Makefile.am test/Makefile.sources test/meta-surface-pattern.pdf.argb32.ref.png test/meta-surface-pattern.pdf.rgb24.ref.png test/overlapping-glyphs.argb32.ref.png test/overlapping-glyphs.c test/overlapping-glyphs.pdf.argb32.xfail.png test/overlapping-glyphs.pdf.rgb24.xfail.png test/overlapping-glyphs.rgb24.ref.png test/scale-offset-image.pdf.xfail.png test/scale-offset-similar.pdf.xfail.png util/cairo-script

Chris Wilson ickle at kemper.freedesktop.org
Mon Jul 27 02:19:57 PDT 2009


 src/Makefile.sources                         |    2 
 src/cairo-path-fixed.c                       |   12 
 src/cairo-pdf-surface.c                      |   16 +
 src/cairo-rtree-private.h                    |  124 +++++++++
 src/cairo-rtree.c                            |  349 +++++++++++++++++++++++++++
 src/cairo-spline.c                           |    9 
 src/cairo-xlib-display.c                     |    6 
 test/Makefile.am                             |    4 
 test/Makefile.sources                        |    1 
 test/meta-surface-pattern.pdf.argb32.ref.png |binary
 test/meta-surface-pattern.pdf.rgb24.ref.png  |binary
 test/overlapping-glyphs.argb32.ref.png       |binary
 test/overlapping-glyphs.c                    |  123 +++++++++
 test/overlapping-glyphs.pdf.argb32.xfail.png |binary
 test/overlapping-glyphs.pdf.rgb24.xfail.png  |binary
 test/overlapping-glyphs.rgb24.ref.png        |binary
 test/scale-offset-image.pdf.xfail.png        |binary
 test/scale-offset-similar.pdf.xfail.png      |binary
 util/cairo-script/cairo-script-operators.c   |    6 
 19 files changed, 652 insertions(+)

New commits:
commit 6ca3720ba66f443e70c961f7d4fdac604c831e97
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Jul 27 10:06:34 2009 +0100

    [test] Overlapping glyphs
    
    Add a test case to explicitly check handling of overlapping glyphs.

diff --git a/test/Makefile.am b/test/Makefile.am
index ec5dfac..b794283 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -679,6 +679,10 @@ REFERENCE_IMAGES = \
 	over-between-source.svg12.rgb24.xfail.png \
 	over-between-source.xlib.ref.png \
 	over-between-source.xlib.rgb24.ref.png \
+	overlapping-glyphs.argb32.ref.png \
+	overlapping-glyphs.rgb24.ref.png \
+	overlapping-glyphs.pdf.argb32.xfail.png \
+	overlapping-glyphs.pdf.rgb24.xfail.png \
 	paint-repeat.ref.png \
 	paint-source-alpha.ref.png \
 	paint-source-alpha.svg.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 573ca84..0e7e487 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -131,6 +131,7 @@ test_sources = \
 	over-around-source.c				\
 	over-below-source.c				\
 	over-between-source.c				\
+	overlapping-glyphs.c				\
 	paint.c						\
 	paint-repeat.c					\
 	paint-source-alpha.c				\
diff --git a/test/overlapping-glyphs.argb32.ref.png b/test/overlapping-glyphs.argb32.ref.png
new file mode 100644
index 0000000..2e2d60c
Binary files /dev/null and b/test/overlapping-glyphs.argb32.ref.png differ
diff --git a/test/overlapping-glyphs.c b/test/overlapping-glyphs.c
new file mode 100644
index 0000000..690a6dd
--- /dev/null
+++ b/test/overlapping-glyphs.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright © 2009 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"
+
+#include <assert.h>
+
+#define TEXT_SIZE 12
+#define HEIGHT (TEXT_SIZE + 4)
+#define WIDTH 50
+
+#define MAX_GLYPHS 80
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_glyph_t glyphs_stack[MAX_GLYPHS], *glyphs;
+    const char *cairo = "Cairo";
+    const char *giza = "Giza";
+    cairo_text_extents_t cairo_extents;
+    cairo_text_extents_t giza_extents;
+    int count, num_glyphs;
+    double x0, y0;
+
+    /* We draw in the default black, so paint white first. */
+    cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+    cairo_paint (cr);
+
+    cairo_select_font_face (cr, "Bitstream Vera Sans",
+			    CAIRO_FONT_SLANT_NORMAL,
+			    CAIRO_FONT_WEIGHT_NORMAL);
+    cairo_set_font_size (cr, TEXT_SIZE);
+
+    /* We want to overlap two strings, so compute overlapping glyphs.  */
+
+    cairo_text_extents (cr, cairo, &cairo_extents);
+    cairo_text_extents (cr, giza, &giza_extents);
+
+    x0 = WIDTH/2. - (cairo_extents.width/2. + cairo_extents.x_bearing);
+    y0 = HEIGHT/2. - (cairo_extents.height/2. + cairo_extents.y_bearing);
+    glyphs = glyphs_stack;
+    count = MAX_GLYPHS;
+    cairo_scaled_font_text_to_glyphs (cairo_get_scaled_font (cr),
+				      x0, y0,
+				      cairo, strlen (cairo),
+				      &glyphs, &count,
+				      NULL, NULL,
+				      NULL);
+    assert (glyphs == glyphs_stack);
+    num_glyphs = count;
+
+    x0 = WIDTH/2. - (giza_extents.width/2. + giza_extents.x_bearing);
+    y0 = HEIGHT/2. - (giza_extents.height/2. + giza_extents.y_bearing);
+    glyphs = glyphs_stack + count;
+    count = MAX_GLYPHS - count;
+    cairo_scaled_font_text_to_glyphs (cairo_get_scaled_font (cr),
+				      x0, y0,
+				      giza, strlen (giza),
+				      &glyphs, &count,
+				      NULL, NULL,
+				      NULL);
+    assert (glyphs == glyphs_stack + num_glyphs);
+    glyphs = glyphs_stack;
+    num_glyphs += count;
+
+    cairo_set_source_rgba (cr, 0, 0, 0, .5); /* translucent black, gray! */
+    cairo_show_glyphs (cr, glyphs, num_glyphs);
+
+    /* and compare with filling */
+    cairo_translate (cr, 0, HEIGHT);
+    cairo_glyph_path (cr, glyphs, num_glyphs);
+    cairo_fill (cr);
+
+    /* switch to using an unbounded operator for added complexity */
+    cairo_set_operator (cr, CAIRO_OPERATOR_IN);
+
+    cairo_translate (cr, WIDTH, -HEIGHT);
+    cairo_save (cr);
+    cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
+    cairo_clip (cr);
+    cairo_show_glyphs (cr, glyphs, num_glyphs);
+    cairo_restore (cr);
+
+    cairo_translate (cr, 0, HEIGHT);
+    cairo_save (cr);
+    cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
+    cairo_clip (cr);
+    cairo_glyph_path (cr, glyphs, num_glyphs);
+    cairo_fill (cr);
+    cairo_restore (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (overlapping_glyphs,
+	    "Test handing of overlapping glyphs",
+	    "text, glyphs", /* keywords */
+	    NULL, /* requirements */
+	    2 * WIDTH, 2 * HEIGHT,
+	    NULL, draw)
+
diff --git a/test/overlapping-glyphs.pdf.argb32.xfail.png b/test/overlapping-glyphs.pdf.argb32.xfail.png
new file mode 100644
index 0000000..e3e4337
Binary files /dev/null and b/test/overlapping-glyphs.pdf.argb32.xfail.png differ
diff --git a/test/overlapping-glyphs.pdf.rgb24.xfail.png b/test/overlapping-glyphs.pdf.rgb24.xfail.png
new file mode 100644
index 0000000..a3f1d70
Binary files /dev/null and b/test/overlapping-glyphs.pdf.rgb24.xfail.png differ
diff --git a/test/overlapping-glyphs.rgb24.ref.png b/test/overlapping-glyphs.rgb24.ref.png
new file mode 100644
index 0000000..d978138
Binary files /dev/null and b/test/overlapping-glyphs.rgb24.ref.png differ
commit 09a2b2ed3189fe12483cbd673c24ceddc2c20f3f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Jul 27 10:14:24 2009 +0100

    [xlib] Fast-path the likely case of retrieving a known xrender_format
    
    If we know the CPU can read pointers atomically, then we can simply peek
    into the cached_xrender_formats to see if we already have a match, before
    taking the mutex. (Acquiring the mutex here is a minor nuisance that
    appears on the callgrind profiles.)

diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index 92e96ba..d9ee904 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -514,6 +514,12 @@ _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t	*display,
 {
     XRenderPictFormat *xrender_format;
 
+#if ! ATOMIC_OP_NEEDS_MEMORY_BARRIER
+    xrender_format = display->cached_xrender_formats[format];
+    if (likely (xrender_format != NULL))
+	return xrender_format;
+#endif
+
     CAIRO_MUTEX_LOCK (display->mutex);
     xrender_format = display->cached_xrender_formats[format];
     if (xrender_format == NULL) {
commit efb3445ee1553c91e62f6b0fe50ab72d65f5c81c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Jul 27 10:18:25 2009 +0100

    Add a simple rectangle tree (rtree) implementation
    
    In order to efficient store small images, we need to pack them into a
    large texture. The rtree handles allocation of small rectangles out of a
    much larger whole. As well as tracking free rectangles, it can also be
    used to note which parts of the texture are 'pinned' -- that is have
    operations currently pending and so can not be modified until that batch
    of operations have been flushed. When the rtree is full, i.e. there is no
    single free rectangle to accommodate the allocation request, it will
    randomly evict an unpinned block large enough to fit the request. The
    block may comprise just a single glyph, or a subtree of many glyphs. This
    may not be the best strategy, but it is an effective start.

diff --git a/src/Makefile.sources b/src/Makefile.sources
index 1a1d35f..dd8501e 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -80,6 +80,7 @@ cairo_private = \
 	cairo-private.h \
 	cairo-reference-count-private.h \
 	cairo-region-private.h \
+	cairo-rtree-private.h \
 	cairo-scaled-font-private.h \
 	cairo-skiplist-private.h \
 	cairo-spans-private.h \
@@ -133,6 +134,7 @@ cairo_sources = \
 	cairo-polygon.c \
 	cairo-rectangle.c \
 	cairo-region.c \
+	cairo-rtree.c \
 	cairo-scaled-font.c \
 	cairo-skiplist.c \
 	cairo-slope.c \
diff --git a/src/cairo-rtree-private.h b/src/cairo-rtree-private.h
new file mode 100644
index 0000000..72dc8ce
--- /dev/null
+++ b/src/cairo-rtree-private.h
@@ -0,0 +1,124 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributor(s):
+ *      Chris Wilson <chris at chris-wilson.co.uk>
+ *
+ */
+
+#ifndef CAIRO_RTREE_PRIVATE_H
+#define CAIRO_RTREE_PRIVATE_H
+
+#include "cairo-compiler-private.h"
+#include "cairo-types-private.h"
+
+#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
+
+enum {
+    CAIRO_RTREE_NODE_AVAILABLE,
+    CAIRO_RTREE_NODE_DIVIDED,
+    CAIRO_RTREE_NODE_OCCUPIED,
+};
+
+typedef struct _cairo_rtree_node {
+    struct _cairo_rtree_node *children[4], *parent;
+    cairo_list_t link;
+    uint16_t pinned;
+    uint16_t state;
+    uint16_t x, y;
+    uint16_t width, height;
+} cairo_rtree_node_t;
+
+typedef struct _cairo_rtree {
+    cairo_rtree_node_t root;
+    int min_size;
+    void (*evict) (void *node);
+    cairo_list_t pinned;
+    cairo_list_t available;
+    cairo_list_t evictable;
+    cairo_freepool_t node_freepool;
+} cairo_rtree_t;
+
+cairo_private cairo_rtree_node_t *
+_cairo_rtree_node_create (cairo_rtree_t		 *rtree,
+		          cairo_rtree_node_t	 *parent,
+			  int			  x,
+			  int			  y,
+			  int			  width,
+			  int			  height);
+
+cairo_private cairo_status_t
+_cairo_rtree_node_insert (cairo_rtree_t *rtree,
+	                  cairo_rtree_node_t *node,
+			  int width,
+			  int height,
+			  cairo_rtree_node_t **out);
+
+cairo_private void
+_cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node);
+
+cairo_private void
+_cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node);
+
+cairo_private void
+_cairo_rtree_init (cairo_rtree_t	*rtree,
+	           int			 width,
+		   int			 height,
+		   int			 min_size,
+		   int			 node_size,
+		   void			 (*evict) (void *node));
+
+cairo_private cairo_int_status_t
+_cairo_rtree_insert (cairo_rtree_t	     *rtree,
+		     int		      width,
+	             int		      height,
+	             cairo_rtree_node_t	    **out);
+
+cairo_private cairo_int_status_t
+_cairo_rtree_evict_random (cairo_rtree_t	 *rtree,
+		           int			  width,
+		           int			  height,
+		           cairo_rtree_node_t	**out);
+
+cairo_private void *
+_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node);
+
+cairo_private void
+_cairo_rtree_unpin (cairo_rtree_t *rtree);
+
+cairo_private void
+_cairo_rtree_reset (cairo_rtree_t *rtree);
+
+cairo_private void
+_cairo_rtree_fini (cairo_rtree_t *rtree);
+
+#endif /* CAIRO_RTREE_PRIVATE_H */
diff --git a/src/cairo-rtree.c b/src/cairo-rtree.c
new file mode 100644
index 0000000..c0dfe31
--- /dev/null
+++ b/src/cairo-rtree.c
@@ -0,0 +1,349 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributor(s):
+ *      Chris Wilson <chris at chris-wilson.co.uk>
+ *
+ */
+
+#include "cairoint.h"
+
+#include "cairo-rtree-private.h"
+
+cairo_rtree_node_t *
+_cairo_rtree_node_create (cairo_rtree_t		 *rtree,
+		          cairo_rtree_node_t	 *parent,
+			  int			  x,
+			  int			  y,
+			  int			  width,
+			  int			  height)
+{
+    cairo_rtree_node_t *node;
+
+    node = _cairo_freepool_alloc (&rtree->node_freepool);
+    if (node == NULL) {
+	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	return NULL;
+    }
+
+    node->children[0] = NULL;
+    node->parent = parent;
+    node->state  = CAIRO_RTREE_NODE_AVAILABLE;
+    node->pinned = FALSE;
+    node->x	 = x;
+    node->y	 = y;
+    node->width  = width;
+    node->height = height;
+
+    cairo_list_add (&node->link, &rtree->available);
+
+    return node;
+}
+
+void
+_cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
+{
+    int i;
+
+    cairo_list_del (&node->link);
+
+    if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
+	if (rtree->evict != NULL)
+	    rtree->evict (node);
+    } else {
+	for (i = 0; i < 4 && node->children[i] != NULL; i++)
+	    _cairo_rtree_node_destroy (rtree, node->children[i]);
+    }
+
+    _cairo_freepool_free (&rtree->node_freepool, node);
+}
+
+void
+_cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
+{
+    int i;
+
+    assert (node->pinned == FALSE);
+
+    do {
+	assert (node->state == CAIRO_RTREE_NODE_DIVIDED);
+
+	for (i = 0;  i < 4 && node->children[i] != NULL; i++)
+	    if (node->children[i]->state != CAIRO_RTREE_NODE_AVAILABLE)
+		return;
+
+	for (i = 0; i < 4 && node->children[i] != NULL; i++)
+	    _cairo_rtree_node_destroy (rtree, node->children[i]);
+
+	node->children[0] = NULL;
+	node->state = CAIRO_RTREE_NODE_AVAILABLE;
+	cairo_list_move (&node->link, &rtree->available);
+
+	node = node->parent;
+    } while (node != NULL && ! node->pinned);
+}
+
+cairo_status_t
+_cairo_rtree_node_insert (cairo_rtree_t *rtree,
+	                  cairo_rtree_node_t *node,
+			  int width,
+			  int height,
+			  cairo_rtree_node_t **out)
+{
+    int w, h, i;
+
+    assert (node->state == CAIRO_RTREE_NODE_AVAILABLE);
+    assert (node->pinned == FALSE);
+
+    if (node->width  - width  > rtree->min_size ||
+	node->height - height > rtree->min_size)
+    {
+	w = node->width  - width;
+	h = node->height - height;
+
+	i = 0;
+	node->children[i] = _cairo_rtree_node_create (rtree, node,
+						      node->x, node->y,
+						      width, height);
+	if (unlikely (node->children[i] == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	i++;
+
+	if (w > rtree->min_size) {
+	    node->children[i] = _cairo_rtree_node_create (rtree, node,
+							  node->x + width,
+							  node->y,
+							  w, height);
+	    if (unlikely (node->children[i] == NULL))
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    i++;
+	}
+
+	if (h > rtree->min_size) {
+	    node->children[i] = _cairo_rtree_node_create (rtree, node,
+							  node->x,
+							  node->y + height,
+							  width, h);
+	    if (unlikely (node->children[i] == NULL))
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    i++;
+
+	    if (w > rtree->min_size) {
+		node->children[i] = _cairo_rtree_node_create (rtree, node,
+							      node->x + width,
+							      node->y + height,
+							      w, h);
+		if (unlikely (node->children[i] == NULL))
+		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		i++;
+	    }
+	}
+
+	if (i < 4)
+	    node->children[i] = NULL;
+
+	node->state = CAIRO_RTREE_NODE_DIVIDED;
+	cairo_list_move (&node->link, &rtree->evictable);
+	node = node->children[0];
+    }
+
+    node->state = CAIRO_RTREE_NODE_OCCUPIED;
+    cairo_list_move (&node->link, &rtree->evictable);
+    *out = node;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_int_status_t
+_cairo_rtree_insert (cairo_rtree_t	     *rtree,
+		     int		      width,
+	             int		      height,
+	             cairo_rtree_node_t	    **out)
+{
+    cairo_rtree_node_t *node;
+
+    cairo_list_foreach_entry (node, cairo_rtree_node_t,
+			      &rtree->available, link)
+    {
+	if (node->width >= width && node->height >= height)
+	    return _cairo_rtree_node_insert (rtree, node, width, height, out);
+    }
+
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static uint32_t
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+    static uint32_t x;
+    return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+cairo_int_status_t
+_cairo_rtree_evict_random (cairo_rtree_t	 *rtree,
+		           int			  width,
+		           int			  height,
+		           cairo_rtree_node_t		**out)
+{
+    cairo_rtree_node_t *node;
+    int i, cnt;
+
+    cnt = 0;
+    cairo_list_foreach_entry (node, cairo_rtree_node_t,
+			      &rtree->evictable, link)
+    {
+	if (node->width >= width && node->height >= height)
+	    cnt++;
+    }
+
+    if (cnt == 0)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    cnt = hars_petruska_f54_1_random () % cnt;
+    cairo_list_foreach_entry (node, cairo_rtree_node_t,
+			      &rtree->evictable, link)
+    {
+	if (node->width >= width && node->height >= height && cnt-- == 0) {
+	    if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
+		if (rtree->evict != NULL)
+		    rtree->evict (node);
+	    } else {
+		for (i = 0; i < 4 && node->children[i] != NULL; i++)
+		    _cairo_rtree_node_destroy (rtree, node->children[i]);
+		node->children[0] = NULL;
+	    }
+
+	    node->state = CAIRO_RTREE_NODE_AVAILABLE;
+	    cairo_list_move (&node->link, &rtree->available);
+
+	    *out = node;
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    }
+
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+void *
+_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
+{
+    void *ptr = node;
+
+    while (node->pinned == FALSE) {
+	cairo_list_move (&node->link, &rtree->pinned);
+	node->pinned = TRUE;
+	node = node->parent;
+	if (node == NULL)
+	    break;
+    }
+
+    return ptr;
+}
+
+void
+_cairo_rtree_unpin (cairo_rtree_t *rtree)
+{
+    cairo_rtree_node_t *node, *next;
+
+    cairo_list_foreach_entry_safe (node, next,
+	                           cairo_rtree_node_t, &rtree->pinned, link)
+    {
+	node->pinned = FALSE;
+	cairo_list_move (&node->link, &rtree->evictable);
+    }
+}
+
+void
+_cairo_rtree_init (cairo_rtree_t	*rtree,
+	           int			 width,
+		   int			 height,
+		   int			 min_size,
+		   int			 node_size,
+		   void			 (*evict) (void *node))
+{
+    rtree->evict = evict;
+
+    assert (node_size >= (int) sizeof (cairo_rtree_node_t));
+    _cairo_freepool_init (&rtree->node_freepool, node_size);
+
+    cairo_list_init (&rtree->available);
+    cairo_list_init (&rtree->pinned);
+    cairo_list_init (&rtree->evictable);
+
+    rtree->min_size = min_size;
+
+    memset (&rtree->root, 0, sizeof (rtree->root));
+    rtree->root.width = width;
+    rtree->root.height = height;
+    rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE;
+    cairo_list_add (&rtree->root.link, &rtree->available);
+}
+
+void
+_cairo_rtree_reset (cairo_rtree_t *rtree)
+{
+    int i;
+
+    if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
+	if (rtree->evict != NULL)
+	    rtree->evict (&rtree->root);
+    } else {
+	for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++)
+	    _cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
+	rtree->root.children[0] = NULL;
+    }
+
+    cairo_list_init (&rtree->available);
+    cairo_list_init (&rtree->evictable);
+    cairo_list_init (&rtree->pinned);
+
+    rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE;
+    rtree->root.pinned = FALSE;
+    cairo_list_add (&rtree->root.link, &rtree->available);
+}
+
+void
+_cairo_rtree_fini (cairo_rtree_t *rtree)
+{
+    int i;
+
+    if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
+	if (rtree->evict != NULL)
+	    rtree->evict (&rtree->root);
+    } else {
+	for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++)
+	    _cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
+    }
+
+    _cairo_freepool_fini (&rtree->node_freepool);
+}
commit c72ca2f2296b5fbc5859059b98221e5ffe087dae
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jul 26 09:07:48 2009 +0100

    [path] Convert straight curve-to to line-to
    
    Avoid the high cost associated with curves if we can convert the curve to
    a straight line.

diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index 9819353..3befe42 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -488,6 +488,7 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t	*path,
 {
     cairo_status_t status;
     cairo_point_t point[3];
+    cairo_slope_t slope, tangent;
 
     /* make sure subpaths are started properly */
     if (! path->has_current_point) {
@@ -502,6 +503,17 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t	*path,
     point[0].x = x0; point[0].y = y0;
     point[1].x = x1; point[1].y = y1;
     point[2].x = x2; point[2].y = y2;
+
+    _cairo_slope_init (&slope, &path->current_point, &point[2]);
+    _cairo_slope_init (&tangent, &path->current_point, &point[0]);
+    if (_cairo_slope_compare (&slope, &tangent) == 0) {
+	_cairo_slope_init (&tangent, &point[1], &point[2]);
+	if (_cairo_slope_compare (&slope, &tangent) == 0) {
+	    /* just a straight line... */
+	    return _cairo_path_fixed_line_to (path, x2, y2);
+	}
+    }
+
     status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
     if (unlikely (status))
 	return status;
commit f3d265559a2f97152ce8f307ea3ce83463083088
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jul 26 09:03:36 2009 +0100

    [spline] Treat a straight spline as degenerate.
    
    The fallback for degenerate splines is to treat them as a line-to, so if
    the spline is straight, we can just replace it with a simple line-to by
    treating as degenerate.

diff --git a/src/cairo-spline.c b/src/cairo-spline.c
index 45eedbd..8bebcb2 100644
--- a/src/cairo-spline.c
+++ b/src/cairo-spline.c
@@ -43,6 +43,8 @@ _cairo_spline_init (cairo_spline_t *spline,
 		    const cairo_point_t *a, const cairo_point_t *b,
 		    const cairo_point_t *c, const cairo_point_t *d)
 {
+    cairo_slope_t slope;
+
     spline->add_point_func = add_point_func;
     spline->closure = closure;
 
@@ -67,6 +69,13 @@ _cairo_spline_init (cairo_spline_t *spline,
     else
 	_cairo_slope_init (&spline->final_slope, &spline->knots.a, &spline->knots.d);
 
+    _cairo_slope_init (&slope, &spline->knots.a, &spline->knots.d);
+    if (_cairo_slope_compare (&slope, &spline->initial_slope) == 0 &&
+	_cairo_slope_compare (&slope, &spline->final_slope) == 0)
+    {
+	return FALSE; /* just a straight line... */
+    }
+
     return TRUE;
 }
 
commit 25858d524d158531a71a2e772551b1e497d9d423
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jul 26 08:13:28 2009 +0100

    [script] Fix reference to font source after transferring to mmap
    
    After diverting the pointers to accommodate lazy decompressing of the
    source, the bytecode pointer was left pointing to the original location
    that had already been freed - thus passing an invalid block to FreeType
    and unsurprisingly then, blowing up.

diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index b769994..b1f287e 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -1709,6 +1709,12 @@ _ft_create_for_source (csi_t *ctx,
 	if (--source->base.ref == 0)
 	    csi_string_free (ctx, source);
 
+	if (source->deflate) {
+	    _csi_free (ctx, bytes);
+	    bytes = data->blob.bytes + vec[0].num_bytes;
+	} else
+	    bytes = data->blob.bytes;
+
 	data->source = NULL;
 	data->bytes = NULL;
     } else {
commit ede0f7e7df4e17ddc1ffe98dcdfe0115a58e7b14
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 25 07:19:22 2009 +0100

    [pdf] Eliminate redundant whole-page clip.
    
    We do not to emit a clip if it covers the whole page.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 12d0e3b..4038f30 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -244,6 +244,19 @@ _cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface,
 						  &surface->cairo_to_pdf);
 }
 
+static cairo_bool_t
+_path_covers_bbox (cairo_pdf_surface_t *surface,
+		   cairo_path_fixed_t *path)
+{
+    cairo_box_t box;
+
+    return _cairo_path_fixed_is_rectangle (path, &box) &&
+	   box.p1.x <= 0 &&
+	   box.p1.y <= 0 &&
+	   box.p2.x >= _cairo_fixed_from_double (surface->width) &&
+	   box.p2.y >= _cairo_fixed_from_double (surface->height);
+}
+
 static cairo_status_t
 _cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
 						cairo_path_fixed_t	*path,
@@ -269,6 +282,9 @@ _cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
 	return CAIRO_STATUS_SUCCESS;
     }
 
+    if (_path_covers_bbox (surface, path))
+	return CAIRO_STATUS_SUCCESS;
+
     return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
 }
 
diff --git a/test/meta-surface-pattern.pdf.argb32.ref.png b/test/meta-surface-pattern.pdf.argb32.ref.png
index 786587c..0433222 100644
Binary files a/test/meta-surface-pattern.pdf.argb32.ref.png and b/test/meta-surface-pattern.pdf.argb32.ref.png differ
diff --git a/test/meta-surface-pattern.pdf.rgb24.ref.png b/test/meta-surface-pattern.pdf.rgb24.ref.png
index f542dab..b59a9ca 100644
Binary files a/test/meta-surface-pattern.pdf.rgb24.ref.png and b/test/meta-surface-pattern.pdf.rgb24.ref.png differ
diff --git a/test/scale-offset-image.pdf.xfail.png b/test/scale-offset-image.pdf.xfail.png
index 4c7fe28..3eacbbc 100644
Binary files a/test/scale-offset-image.pdf.xfail.png and b/test/scale-offset-image.pdf.xfail.png differ
diff --git a/test/scale-offset-similar.pdf.xfail.png b/test/scale-offset-similar.pdf.xfail.png
index 4b600f4..7808aeb 100644
Binary files a/test/scale-offset-similar.pdf.xfail.png and b/test/scale-offset-similar.pdf.xfail.png differ


More information about the cairo-commit mailing list