Update cairo to 1.12.12
authorDongyeon Kim <dy5.kim@samsung.com>
Mon, 18 Mar 2013 05:32:27 +0000 (14:32 +0900)
committerDongyeon Kim <dy5.kim@samsung.com>
Tue, 19 Mar 2013 06:18:33 +0000 (15:18 +0900)
141 files changed:
NEWS
TC/perf/Makefile [deleted file]
TC/perf/common.c [deleted file]
TC/perf/common.h [deleted file]
TC/perf/fill [deleted file]
TC/perf/fill.c [deleted file]
TC/perf/image [deleted file]
TC/perf/image.c [deleted file]
TC/perf/image1.png [deleted file]
TC/perf/image2.png [deleted file]
TC/perf/main.c [deleted file]
TC/perf/stroke [deleted file]
TC/perf/stroke.c [deleted file]
TC/testcase/tslist
boilerplate/cairo-boilerplate-egl.c
boilerplate/cairo-boilerplate-glx.c
boilerplate/cairo-boilerplate-xcb.c
cairo-version.h
configure.ac
debian/changelog
packaging/cairo.spec
perf/cairo-perf-chart.c
perf/cairo-perf-trace.c
perf/cairo-perf.c
src/Makefile.sources
src/cairo-cff-subset.c
src/cairo-cogl-surface.c
src/cairo-composite-rectangles.c [changed mode: 0644->0755]
src/cairo-compositor-private.h
src/cairo-damage-private.h
src/cairo-damage.c
src/cairo-default-context.c [changed mode: 0644->0755]
src/cairo-egl-context.c
src/cairo-ft-font.c
src/cairo-gl-composite.c [changed mode: 0644->0755]
src/cairo-gl-device.c
src/cairo-gl-dispatch.c
src/cairo-gl-glyphs.c [changed mode: 0644->0755]
src/cairo-gl-gradient-private.h [changed mode: 0644->0755]
src/cairo-gl-gradient.c [changed mode: 0644->0755]
src/cairo-gl-msaa-compositor.c [changed mode: 0644->0755]
src/cairo-gl-operand.c [changed mode: 0644->0755]
src/cairo-gl-private.h [changed mode: 0644->0755]
src/cairo-gl-shaders.c [changed mode: 0644->0755]
src/cairo-gl-spans-compositor.c
src/cairo-gl-surface.c
src/cairo-gl-traps-compositor.c
src/cairo-glx-context.c
src/cairo-gstate.c
src/cairo-image-compositor.c
src/cairo-image-surface-inline.h
src/cairo-image-surface.c
src/cairo-mask-compositor.c
src/cairo-mempool.c
src/cairo-path-fill.c
src/cairo-path-fixed-private.h
src/cairo-path-fixed.c
src/cairo-path-stroke-polygon.c
src/cairo-path-stroke-traps.c [new file with mode: 0644]
src/cairo-path-stroke.c
src/cairo-pen.c
src/cairo-recording-surface.c
src/cairo-rectangle.c
src/cairo-scaled-font.c
src/cairo-script-surface.c
src/cairo-spans-compositor-private.h
src/cairo-spans-compositor.c
src/cairo-stroke-style.c
src/cairo-surface.c
src/cairo-traps-compositor.c
src/cairo-traps-private.h
src/cairo-traps.c
src/cairo-type1-subset.c
src/cairo-xcb-connection-core.c
src/cairo-xcb-shm.c
src/cairo-xcb-surface-cairo.c [deleted file]
src/cairo-xcb-surface-render.c
src/cairo-xcb-surface.c
src/cairo-xlib-core-compositor.c
src/cairo-xlib-display.c
src/cairo-xlib-private.h
src/cairo-xlib-render-compositor.c
src/cairo-xlib-source.c
src/cairo-xlib-surface-shm.c
src/cairo-xlib-surface.c
src/cairo.h
src/cairoint.h
src/test-base-compositor-surface.c
src/win32/cairo-win32-display-surface.c
test/Makefile.sources
test/cairo-test.c
test/cairo-test.h
test/invalid-matrix.c
test/mime-surface.c [deleted file]
test/reference/arc-looping-dash.ref.png
test/reference/bug-source-cu.rgb24.ref.png
test/reference/caps-tails-curve.ref.png
test/reference/clip-nesting.rgb24.ref.png
test/reference/clip-stroke-unbounded.argb32.ref.png
test/reference/clip-stroke-unbounded.rgb24.ref.png
test/reference/image-bug-710072-unaligned.egl.argb32.ref.png
test/reference/mask.argb32.ref.png
test/reference/mask.rgb24.ref.png
test/reference/pthread-same-source.egl.argb32.ref.png
test/reference/record-fill-alpha.ref.png
test/reference/record-paint-alpha-clip-mask.ref.png
test/reference/record1414x-text-transform.ref.png
test/reference/record2x-text-transform.ref.png
test/reference/record90-paint-alpha-clip-mask.ref.png [new file with mode: 0644]
test/reference/record90-paint-alpha-clip.ref.png [new file with mode: 0644]
test/reference/record90-text-transform.ref.png [new file with mode: 0644]
test/reference/recording-surface-extend-none.argb32.ref.png
test/reference/recording-surface-extend-none.rgb24.ref.png
test/reference/recording-surface-extend-pad.argb32.ref.png
test/reference/recording-surface-extend-pad.rgb24.ref.png
test/reference/recording-surface-extend-reflect.argb32.ref.png
test/reference/recording-surface-extend-reflect.rgb24.ref.png
test/reference/recording-surface-extend-repeat.argb32.ref.png
test/reference/recording-surface-extend-repeat.rgb24.ref.png
test/reference/recording-surface-over.argb32.ref.png [new file with mode: 0644]
test/reference/recording-surface-over.rgb24.ref.png
test/reference/recording-surface-source.argb32.ref.png
test/reference/recording-surface-source.rgb24.ref.png
test/reference/reflected-stroke.ref.png
test/reference/rel-path.rgb24.ref.png
test/reference/stroke-clipped.ref.png [new file with mode: 0644]
test/reference/xcb-huge-subimage.ref.png [new file with mode: 0644]
test/stroke-clipped.c [new file with mode: 0644]
test/xcb-huge-subimage.c [new file with mode: 0644]
util/cairo-fdr/Makefile.am
util/cairo-gobject/cairo-gobject.h
util/cairo-script/Makefile.am
util/cairo-script/cairo-script-file.c
util/cairo-script/cairo-script-interpreter.h
util/cairo-script/cairo-script-objects.c
util/cairo-script/cairo-script-operators.c
util/cairo-script/cairo-script-private.h
util/cairo-script/cairo-script-scanner.c
util/cairo-sphinx/Makefile.am
util/cairo-trace/trace.c
util/show-polygon.c

diff --git a/NEWS b/NEWS
index f14a51e..dfcccb7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,153 @@
+Release 1.12.12 (2013-01-31 Chris Wilson <chris@chris-wilson.co.uk>)
+===================================================================
+The goal of this release is to fix the synchronisation problems that
+were exhibited in the SHM transport for cairo-xlib. This cropped up
+any place that tried to rapidly push fresh pixel data to the X server
+through an ordinary image surface, such as gimp-2.9 and evince.
+
+Bug fixes
+---------
+
+   Avoid replacing the entire image when uploading subimages
+   https://bugs.freedesktop.org/show_bug.cgi?id=59635
+
+   Force synchronisation for scratch SHM image buffers, so that we do
+   not overwrite data as it is being read by X.
+   https://bugs.freedesktop.org/show_bug.cgi?id=59635 (also)
+
+   Fix typos in detecting multisampling for the GL (MSAA) backend.
+
+   Fix a memory leak in the GL (MSAA) backend.
+
+   Fix a reference counting bug when mapping a GL surface to an image.
+
+
+Release 1.12.10 (2013-01-16 Chris Wilson <chris@chris-wilson.co.uk>)
+===================================================================
+A heap of bug fixes everywhere, and the gradual completion of the MSAA
+backend for cairo-gl. Perhaps the most noteworthy set of the bugfixes
+was the crusage lead by Behdad Eshfabod to make font handling by
+pango/cairo/fontconfig fully threadsafe. This testing revealed a couple
+of races that needed fixing in Cairo's scaled-font and glyph cache.
+
+Bug fixes
+---------
+
+  Append coincident elements to the recording's surface bbtree so that
+  the list is not corrupted and the overlapping elements lost.
+
+  Fix cairo-trace to correctly record map-to-image/unmap-image and then
+  replay them.
+
+  Ignore MappingNotifies when running the XCB testsuite as they are sent
+  to all clients when the keyboard changes. The testsuite would detect
+  the unexpected event and complain.
+
+  Handle very large large images in the XCB backend.
+
+  Fix a memory leak in the xlib/shm layer, and prevent use of the SHM
+  surfaces after the display is closed.
+  https://bugs.freedesktop.org/show_bug.cgi
+
+  Handle resizing of bitmap fonts, in preparation for a fix to
+  fontconfig to correctly pass on the user request for scaling.
+
+  Always include subroutine 4 (hint replacement idion) when subsetting
+  type 1 fonts in order to prevent a crash in cgpdftops on Mac OS/X
+
+  Fix a couple of typos in the cairo-gobject.h header files for
+  introspection.
+
+  Prevent a mutex deadlock when freeing a scaled-glyph containing a
+  recording-surface that itself references another scaled-glyph.
+  https://bugs.freedesktop.org/show_bug.cgi?id=54950
+
+  Make scaled-font cache actually thread-safe and prevent
+  use-after-frees.
+
+  Restore support for older versions of XRender. A couple of typos and a
+  few forgotten chunks prevented the xlib compositor from running
+  correctly with XRender < 0.10. Note that there are still a few
+  regressions remaining.
+
+
+Release 1.12.8 (2012-11-24 Chris Wilson <chris@chris-wilson.co.uk>)
+===================================================================
+Another couple of weeks and a few more bugs have been found and fixed,
+it is time to push the next point release. Many thanks to everyone who
+reported their issues and helped us track down the bugs and helped
+testing the fixes.
+
+Bug fixes
+---------
+
+  Expand the sanity checking for broken combinations of XSendEvent and
+  ShmCompletionEvent.
+
+  Notice that "The X.Org Foundation" sometimes also identifies itself
+  as "The Xorg Foundation".
+
+  Handle various ages of libXext and its Shm headers.
+
+  Fix the invalid clipping of the source drawable when using SHM
+  transport to upload images.
+  https://bugs.freedesktop.org/show_bug.cgi?id=56547
+
+  Handle all Type1 postscript operators for better font compatibility.
+  https://bugs.freedesktop.org/show_bug.cgi?id=56265
+
+  Fix a couple of memory leaks in Type1 font subsetting
+  https://bugs.freedesktop.org/show_bug.cgi?id=56566
+
+  Tighten the evaluation of the start/stop pen vertices, and catch a few
+  instances where we would use a fan instead of a bevel.
+  https://bugs.freedesktop.org/show_bug.cgi?id=56432
+
+  Fix assumption that geometric clipping always succeeds with the
+  span-compositor.
+  https://bugs.freedesktop.org/show_bug.cgi?id=56574
+
+  Fix call to spline intersection when evaluating whether a stoke is
+  visible.
+
+  Remember to copy inferior sources when using SHM to readback the
+  surface for use as a source.
+
+Release 1.12.6 (2012-10-22 Chris Wilson <chris@chris-wilson.co.uk>)
+===================================================================
+Thanks to everyone who download cairo-1.12.4 and gave us their feedback.
+It truly was invaluable and has helped us to fix many portability issues
+that crept in with some of the new features. This release aims to fix
+those stability issues and run on a wider range of systems.
+
+Bug fixes
+---------
+
+  Fix the recording surface to actually snapshot the source and so fix
+  PDF drawing.
+
+  Calling XSendEvent with an XShmCompletionEvent is incompatabile with
+  older Xorg servers.
+
+  Reorder CloseDisplay chain so that XShm is not reinstantiated after
+  shutdown, causing a potential crash if the Display was immediately
+  recreated using the same memory address.
+
+  Make sure that the Xserver has attached to the SHM segment before
+  deleting it from the global namespace on systems that do not support
+  deferred deletion.
+
+  Type1 subsetting support for PDF (and PS) was once again improved to
+  work with a larger number of PDF readers.
+
+  GLESv2 build fixes and improved support for embedded GPUs.
+
+  Tweak the invisible pen detection for applications that are currently
+  using too large values for geometric tolerance.
+
+  A build fix for older freetype libraries.
+
+
 Release 1.12.4 (2012-10-05 Chris Wilson <chris@chris-wilson.co.uk>)
 ===================================================================
 More bugs, and more importantly, more fixes. On the cairo-gl side, we
diff --git a/TC/perf/Makefile b/TC/perf/Makefile
deleted file mode 100644 (file)
index bc9ebc5..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-CC = gcc
-
-all : fill stroke image
-
-fill: main.c common.c fill.c
-        $(CC) main.c common.c fill.c -g -o fill `pkg-config --cflags --libs cairo elementary opengl-es-20` -lecore_x -levas -lecore
-
-stroke: main.c common.c stroke.c
-        $(CC) main.c common.c stroke.c -g -o stroke `pkg-config --cflags --libs cairo elementary opengl-es-20` -lecore_x -levas -lecore
-
-image: main.c common.c image.c
-        $(CC) main.c common.c image.c -g -o image `pkg-config --cflags --libs cairo elementary opengl-es-20` -lecore_x -levas -lecore
-
-clean:
-        rm -rf *.0 fill stroke image
diff --git a/TC/perf/common.c b/TC/perf/common.c
deleted file mode 100755 (executable)
index 8b2818b..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include "common.h"
-
-void clearCairo(cairo_t *cr, double width, double height)
-{
-    cairo_set_source_rgba(cr, 1, 1, 1, 1);
-    cairo_rectangle(cr, 0.0, 0.0, width, height);
-    cairo_fill(cr);
-}
-
-void cairoSquare(cairo_t *cr, double x, double y, double length)
-{
-    cairo_rectangle(cr, x, y, length, length);
-    cairo_fill(cr);
-}
-
-void cairoSquareStroke(cairo_t *cr, double x, double y, double length)
-{
-    cairo_rectangle(cr, x, y, length, length);
-    cairo_stroke(cr);
-}
-
-void cairoCircle(cairo_t *cr, double x, double y, double radius)
-{
-    cairo_arc(cr, x, y, radius, 0.0, 2.0 * M_PI);
-    cairo_fill(cr);
-}
-
-void cairoCircleStroke(cairo_t *cr, double x, double y, double radius)
-{
-    cairo_arc(cr, x, y, radius, 0.0, 2.0 * M_PI);
-    cairo_stroke(cr);
-}
-
-void cairoTriangle(cairo_t *cr, double x, double y, double side)
-{
-    cairo_move_to(cr, x, y);
-    cairo_line_to(cr, x + side, y + side);
-    cairo_line_to(cr, x, y + side);
-    cairo_close_path(cr);
-    cairo_fill(cr);
-}
-
-void cairoTriangleStroke(cairo_t *cr, double x, double y, double side)
-{
-    cairo_move_to(cr, x, y);
-    cairo_line_to(cr, x + side, y);
-    cairo_line_to(cr, x, y + side);
-    cairo_close_path(cr);
-    cairo_stroke(cr);
-}
diff --git a/TC/perf/common.h b/TC/perf/common.h
deleted file mode 100755 (executable)
index 647a6d7..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include <Ecore_X.h>
-#include <Elementary.h>
-#include <cairo.h>
-#include <cairo-gl.h>
-
-void clearCairo(cairo_t *cr, double width, double height);
-void cairoSquare(cairo_t *cr, double x, double y, double length);
-void cairoSquareStroke(cairo_t *cr, double x, double y, double length);
-void cairoCircle(cairo_t *cr, double x, double y, double radius);
-void cairoCircleStroke(cairo_t *cr, double x, double y, double radius);
-void cairoTriangle(cairo_t *cr, double x, double y, double side);
-void cairoTriangleStroke(cairo_t *cr, double x, double y, double side);
-
diff --git a/TC/perf/fill b/TC/perf/fill
deleted file mode 100755 (executable)
index c44d12f..0000000
Binary files a/TC/perf/fill and /dev/null differ
diff --git a/TC/perf/fill.c b/TC/perf/fill.c
deleted file mode 100755 (executable)
index 4d1395d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include "common.h"
-
-#define RENDER_LOOP 100
-
-extern int WIDTH, HEIGHT;
-
-int preRender(cairo_t *cr)
-{
-    return 1;
-}
-
-int render(cairo_t *cr)
-{
-    int i;
-    double r, g, b, a;
-
-    clearCairo(cr, WIDTH, HEIGHT);
-    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-
-    for(i = 0; i < RENDER_LOOP; i++)
-    {
-        r = drand48();
-        g = drand48();
-        b = drand48();
-        a = drand48();
-        float x = drand48() * WIDTH;
-        float y = drand48() * HEIGHT;
-        float side = drand48() * 300;
-        int shape = drand48() * 3;
-
-        cairo_set_source_rgba(cr, r, g, b, a);
-
-        if(shape == 0)
-            cairoSquare(cr, x, y, side);
-        else if(shape == 1)
-            cairoCircle(cr, x, y, side/2);
-        else
-            cairoTriangle(cr, x, y, side);
-    }
-
-    return 1;
-}
-
-int postRender(cairo_t *cr)
-{
-    return 1;
-}
-
diff --git a/TC/perf/image b/TC/perf/image
deleted file mode 100755 (executable)
index 5df743d..0000000
Binary files a/TC/perf/image and /dev/null differ
diff --git a/TC/perf/image.c b/TC/perf/image.c
deleted file mode 100755 (executable)
index f8f6587..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include "common.h"
-
-#define RENDER_LOOP 100
-
-extern int WIDTH, HEIGHT;
-
-extern cairo_device_t *cairo_device;
-cairo_pattern_t *pattern1, *pattern2;
-int image_width, image_height;
-
-int preRender(cairo_t *cr)
-{
-    { // Image 1
-        cairo_surface_t *image_surface = cairo_image_surface_create_from_png("./image1.png");
-        image_width = cairo_image_surface_get_width(image_surface);
-        image_height = cairo_image_surface_get_height(image_surface);
-
-        if(cairo_surface_get_type(cairo_get_target(cr)) == CAIRO_SURFACE_TYPE_IMAGE) {
-            pattern1 = cairo_pattern_create_for_surface(image_surface);
-        } else {
-            cairo_surface_t *gl_surface = cairo_gl_surface_create(cairo_device, CAIRO_CONTENT_COLOR_ALPHA,
-                        image_width, image_height);
-            cairo_t *cr_gl = cairo_create(gl_surface);
-            cairo_set_source_surface(cr_gl, image_surface, 0, 0);
-            cairo_paint(cr_gl);
-
-            pattern1 = cairo_pattern_create_for_surface(gl_surface);
-
-            cairo_surface_destroy(gl_surface);
-            cairo_destroy(cr_gl);
-        }
-        cairo_surface_destroy(image_surface);
-    }
-    { // Image 2
-        cairo_surface_t *image_surface = cairo_image_surface_create_from_png("./image2.png");
-        image_width = cairo_image_surface_get_width(image_surface);
-        image_height = cairo_image_surface_get_height(image_surface);
-
-        if(cairo_surface_get_type(cairo_get_target(cr)) == CAIRO_SURFACE_TYPE_IMAGE) {
-            pattern2 = cairo_pattern_create_for_surface(image_surface);
-        } else {
-            cairo_surface_t *gl_surface = cairo_gl_surface_create(cairo_device, CAIRO_CONTENT_COLOR_ALPHA,
-                        image_width, image_height);
-            cairo_t *cr_gl = cairo_create(gl_surface);
-            cairo_set_source_surface(cr_gl, image_surface, 0, 0);
-            cairo_paint(cr_gl);
-
-            pattern2 = cairo_pattern_create_for_surface(gl_surface);
-
-            cairo_surface_destroy(gl_surface);
-            cairo_destroy(cr_gl);
-        }
-        cairo_surface_destroy(image_surface);
-    }
-
-    return 1;
-}
-
-int render(cairo_t *cr)
-{
-    int i;
-
-    clearCairo(cr, WIDTH, HEIGHT);
-    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-
-    for(i = 0; i < RENDER_LOOP; i++)
-    {
-        float x = drand48() * WIDTH - image_width / 2;
-        float y = drand48() * HEIGHT - image_height / 2;
-        int index = drand48() * 2;
-
-        cairo_identity_matrix(cr);
-        cairo_translate(cr, x, y);
-        if(index == 0)
-            cairo_set_source(cr, pattern1);
-        else
-            cairo_set_source(cr, pattern2);
-        cairoSquare(cr, 0, 0, image_width);
-    }
-
-    return 1;
-}
-
-int postRender(cairo_t *cr)
-{
-    cairo_pattern_destroy(pattern1);
-    cairo_pattern_destroy(pattern2);
-    return 1;
-}
-
diff --git a/TC/perf/image1.png b/TC/perf/image1.png
deleted file mode 100755 (executable)
index b45c7bd..0000000
Binary files a/TC/perf/image1.png and /dev/null differ
diff --git a/TC/perf/image2.png b/TC/perf/image2.png
deleted file mode 100755 (executable)
index 0ec9cf5..0000000
Binary files a/TC/perf/image2.png and /dev/null differ
diff --git a/TC/perf/main.c b/TC/perf/main.c
deleted file mode 100755 (executable)
index b0fa8b7..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include <Ecore_X.h>
-#include <Elementary.h>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <cairo.h>
-#include <cairo-gl.h>
-
-#define SURFACE_TYPE_IMAGE  0
-#define SURFACE_TYPE_GL     1
-#define TOTAL_TIME      100
-
-int WIDTH, HEIGHT;
-
-//Ecore Evas variables
-Ecore_X_Window window;
-Evas_Object *img;
-
-//EGL variables
-EGLDisplay egl_display;
-EGLSurface egl_surface;
-EGLContext egl_context;
-
-//Cairo variables
-cairo_device_t *cairo_device;
-cairo_surface_t *cairo_surface;
-cairo_t *cr;
-
-Eina_Bool renderMain(void *data)
-{
-    static int counter = 0;
-    static float totalTime = 0;
-    static float totalPaint = 0;
-    static float totalUpdate = 0;
-    struct timeval paintStart, paintStop, updateStop;
-
-    cairo_save(cr);
-    gettimeofday(&paintStart, NULL);
-    /* ########## PAINT : START ########## */
-    render(cr);
-    /* ########## PAINT : END ########## */
-    gettimeofday(&paintStop, NULL);
-    /* ########## UPDATE : START ########## */
-    if(cairo_surface_get_type(cairo_get_target(cr)) == CAIRO_SURFACE_TYPE_GL) {
-        cairo_gl_surface_swapbuffers(cairo_get_target(cr));
-    } else {
-        unsigned char *imageData = cairo_image_surface_get_data(cairo_get_target(cr));
-        evas_object_image_data_set(img, imageData);
-        evas_object_image_data_update_add(img, 0, 0, WIDTH, HEIGHT);
-        ecore_x_sync();
-    }
-    /* ########## UPDATE : END ########## */
-    gettimeofday(&updateStop, NULL);
-    cairo_restore(cr);
-
-    totalTime += updateStop.tv_usec - paintStart.tv_usec;
-    totalTime += (updateStop.tv_sec - paintStart.tv_sec)*1000000;
-    totalPaint += (paintStop.tv_usec - paintStart.tv_usec);
-    totalPaint += (paintStop.tv_sec - paintStart.tv_sec)*1000000;
-    totalUpdate += (updateStop.tv_usec - paintStop.tv_usec);
-    totalUpdate += (updateStop.tv_sec - paintStop.tv_sec)*1000000;
-    counter++;
-
-    if(counter == TOTAL_TIME)
-    {
-        float fps =  TOTAL_TIME / totalTime * 1000000.0f;
-        printf("fps = %0.2f\n", fps);
-        printf("average paint time = %0.1f usec, update time = %0.1f usec\n", totalPaint/TOTAL_TIME, totalUpdate/TOTAL_TIME);
-
-        elm_exit();
-        return 0;
-    }
-}
-
-void initELMWindow(int surface_type)
-{
-    Evas_Object *win = elm_win_add(NULL, "cairotest", ELM_WIN_BASIC);
-    elm_win_autodel_set(win, EINA_TRUE);
-    ecore_x_screen_size_get(ecore_x_default_screen_get(), &WIDTH, &HEIGHT);
-    evas_object_resize(win, WIDTH, HEIGHT);
-    evas_object_show(win);
-
-    if (surface_type == SURFACE_TYPE_IMAGE) {
-        Evas_Object *img_win = elm_image_add(win);
-        img = evas_object_image_filled_add(evas_object_evas_get(img_win));
-        elm_win_resize_object_add(win, img);
-        evas_object_image_content_hint_set(img, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
-        evas_object_image_size_set(img, WIDTH, HEIGHT);
-        evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888);
-        evas_object_image_alpha_set(img, 0);
-        evas_object_show(img_win);
-        evas_object_show(img);
-    } else if(surface_type == SURFACE_TYPE_GL) {
-        window = ecore_x_window_new(0, 0, 0, WIDTH, HEIGHT);
-        ecore_x_icccm_title_set(window, "window");
-        ecore_x_netwm_name_set(window, "window");
-        ecore_x_input_multi_select(window);
-        ecore_x_icccm_transient_for_set(window, elm_win_xwindow_get(win));
-        ecore_x_window_show(window);
-    }
-}
-
-void initEGL(int surface_type)
-{
-    if(surface_type != SURFACE_TYPE_GL)
-        return;
-
-    setenv("ELM_ENGINE", "gl", 1);
-
-    egl_display = eglGetDisplay((EGLNativeDisplayType) ecore_x_display_get());
-    if(egl_display == EGL_NO_DISPLAY)
-    {
-        printf("cannot get egl display\n");
-        exit(1);
-    }
-
-    EGLint major, minor;
-    if(!eglInitialize(egl_display, &major, &minor))
-    {
-        printf("cannot initialize egl\n");
-        exit(-1);
-    }
-
-    if(!eglBindAPI(EGL_OPENGL_ES_API))
-    {
-        printf("cannot bind egl to gles2 API\n");
-        exit(-1);
-    }
-
-    EGLConfig egl_config;
-    EGLint num;
-
-    EGLint attr[] =
-    {
-        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-        EGL_STENCIL_SIZE, 0,
-        EGL_SAMPLES, 4,
-        EGL_RED_SIZE, 8,
-        EGL_GREEN_SIZE, 8,
-        EGL_BLUE_SIZE, 8,
-        EGL_ALPHA_SIZE, 8,
-        EGL_NONE
-    };
-
-
-    if(!eglChooseConfig(egl_display, attr, &egl_config, 1, &num))
-    {
-        printf("cannot choose config\n");
-        exit(-1);
-    }
-
-    if(num != 1)
-    {
-        printf("did not get exactly one config = %d\n", num);
-        exit(-1);
-    }
-
-    egl_surface = eglCreateWindowSurface(egl_display,
-        egl_config, (NativeWindowType) window, NULL);
-    if(egl_surface == EGL_NO_SURFACE)
-    {
-        printf("cannot create surface\n");
-        exit(-1);
-    }
-
-    EGLint e = eglGetError();
-    //printf("egl error = %x\n", e);
-
-    EGLint ctxattr[] =
-    {
-        EGL_CONTEXT_CLIENT_VERSION, 2,
-        EGL_NONE
-    };
-
-    egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, ctxattr);
-    if(egl_context == EGL_NO_CONTEXT)
-    {
-        EGLint e = eglGetError();
-        printf("cannot create context, error = %x\n", e);
-        exit(-1);
-    }
-
-    EGLint value;
-    EGLBoolean result = eglQueryContext(egl_display, egl_context, EGL_CONTEXT_CLIENT_VERSION, &value);
-    //printf("Context version = %x, result = %d\n", value, result);
-
-    eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
-}
-
-void destroyEGL(int surface_type)
-{
-    if(surface_type != SURFACE_TYPE_GL)
-        return;
-
-    eglDestroyContext(egl_display, egl_context);
-    eglDestroySurface(egl_display, egl_surface);
-    eglTerminate(egl_display);
-}
-
-void initCairo(int surface_type)
-{
-    if(surface_type == SURFACE_TYPE_IMAGE) {
-        printf("== CREATE IMAGE SURFACE ==\n");
-        cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
-    } else if(surface_type == SURFACE_TYPE_GL) {
-        printf("== CREATE GL SURFACE ==\n");
-        setenv("CAIRO_GL_COMPOSITOR", "msaa", 1);
-        cairo_device = cairo_egl_device_create(egl_display, egl_context);
-        cairo_gl_device_set_thread_aware(cairo_device, 0);
-        cairo_surface = cairo_gl_surface_create_for_egl(cairo_device, egl_surface, WIDTH, HEIGHT);
-    }
-    cr = cairo_create(cairo_surface);
-}
-
-void destroyCairo(int surface_type)
-{
-    cairo_surface_destroy(cairo_surface);
-    cairo_destroy(cr);
-
-    if(surface_type == SURFACE_TYPE_GL) {
-        cairo_device_destroy(cairo_device);
-    }
-}
-
-int main(int argc, char **argv)
-{
-    int surface_type = SURFACE_TYPE_GL;
-
-    if(argc == 2)
-        surface_type = atoi(argv[1]);
-
-    elm_init(argc, argv);
-
-    initELMWindow(surface_type);
-    initEGL(surface_type);
-    initCairo(surface_type);
-
-    preRender(cr);
-    Ecore_Animator *animator = ecore_animator_add(renderMain, (void *)cr);
-    elm_run();
-    postRender(cr);
-
-    destroyCairo(surface_type);
-    destroyEGL(surface_type);
-    elm_shutdown();
-
-    return 0;
-}
-
diff --git a/TC/perf/stroke b/TC/perf/stroke
deleted file mode 100755 (executable)
index 809ad22..0000000
Binary files a/TC/perf/stroke and /dev/null differ
diff --git a/TC/perf/stroke.c b/TC/perf/stroke.c
deleted file mode 100755 (executable)
index 317f004..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Cairo Performance Test Framework
- * (c) 2012 Samsung Electronics, Inc.
- * All rights reserved.
- *
- * Measures rendering performance for image, gl backends
- *
- * This software is a confidential and proprietary information of Samsung
- * Electronics, Inc. ("Confidential Information"). You shall not disclose such
- * Confidential Information and shall use it only in accordance with the terms
- * of the license agreement you entered into with Samsung Electronics.
- *
- * Author: Dongyeon Kim <dy5.kim@samsung.com>
- */
-
-#include "common.h"
-
-#define RENDER_LOOP 100
-
-extern int WIDTH, HEIGHT;
-
-int preRender(cairo_t *cr)
-{
-    return 1;
-}
-
-int render(cairo_t *cr)
-{
-    int i;
-    double r, g, b, a;
-
-    clearCairo(cr, WIDTH, HEIGHT);
-    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-
-    for(i = 0; i < RENDER_LOOP; i++)
-    {
-        r = drand48();
-        g = drand48();
-        b = drand48();
-        a = drand48();
-        float x = drand48() * WIDTH;
-        float y = drand48() * HEIGHT;
-        float side = drand48() * 300;
-        int shape = drand48() *3;
-        float width = drand48() * 50 + 1;
-        int line_cap = drand48() * 3;
-        cairo_line_cap_t line_cap_style = CAIRO_LINE_CAP_BUTT;
-        if(line_cap == 1)
-            line_cap_style = CAIRO_LINE_CAP_ROUND;
-        else if(line_cap == 2)
-            line_cap_style = CAIRO_LINE_CAP_SQUARE;
-        int line_join = drand48() * 3;
-        cairo_line_join_t line_join_style = CAIRO_LINE_JOIN_MITER;
-        if(line_join == 1)
-            line_join_style = CAIRO_LINE_JOIN_ROUND;
-        else if(line_join == 2)
-            line_join_style = CAIRO_LINE_JOIN_BEVEL;
-
-        double dash[] = {0.0, 0.0};
-        dash[0] = drand48() * 50;
-        dash[1] = drand48() * 50;
-
-        cairo_set_dash(cr, dash, 2, 0);
-        cairo_set_line_width(cr, width);
-        cairo_set_line_join(cr, line_join_style);
-        cairo_set_line_cap(cr, line_cap_style);
-
-        cairo_set_source_rgba(cr, r, g, b, a);
-
-        if(shape == 0)
-            cairoSquareStroke(cr, x, y, side);
-        else if(shape == 1)
-            cairoCircleStroke(cr, x, y, side/2);
-        else
-            cairoTriangleStroke(cr, x, y, side);
-    }
-
-    return 1;
-}
-
-int postRender(cairo_t *cr)
-{
-    return 1;
-}
-
index c3e5d9d..65657da 100644 (file)
@@ -25,7 +25,7 @@
 /testcase/utc_big_little_triangle_image
 #/testcase/utc_big_trap_image
 /testcase/utc_bilevel_image_image
-/testcase/utc_bitmap_font_image
+#/testcase/utc_bitmap_font_image
 /testcase/utc_bug_40410_image
 /testcase/utc_bug_bo_rectangular_image
 /testcase/utc_bug_bo_ricotz_image
 /testcase/utc_big_little_triangle_gl
 /testcase/utc_big_trap_gl
 /testcase/utc_bilevel_image_gl
-/testcase/utc_bitmap_font_gl
+#/testcase/utc_bitmap_font_gl
 /testcase/utc_bug_40410_gl
 /testcase/utc_bug_bo_rectangular_gl
 /testcase/utc_bug_bo_ricotz_gl
index e1a46e4..1462b14 100644 (file)
@@ -90,6 +90,7 @@ _cairo_boilerplate_egl_create_surface (const char              *name,
 #elif CAIRO_HAS_GLESV2_SURFACE
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
 #endif
+       EGL_SAMPLES, 4,
        EGL_NONE
     };
     const EGLint ctx_attribs[] = {
@@ -130,6 +131,7 @@ _cairo_boilerplate_egl_create_surface (const char            *name,
     }
 
     gltc->device = cairo_egl_device_create (gltc->dpy, gltc->ctx);
+       cairo_gl_device_set_thread_aware (gltc->device, FALSE);
 
     if (width < 1)
        width = 1;
index 4d3d6db..52cd99f 100644 (file)
@@ -144,44 +144,21 @@ _cairo_boilerplate_gl_create_surface (const char          *name,
 }
 
 static cairo_surface_t *
-_cairo_boilerplate_gl_create_window (const char                       *name,
-                                    cairo_content_t            content,
-                                    double                     width,
-                                    double                     height,
-                                    double                     max_width,
-                                    double                     max_height,
-                                    cairo_boilerplate_mode_t   mode,
-                                    void                     **closure)
+_cairo_boilerplate_gl_create_window_common (int                                rgba_attribs[],
+                                           cairo_content_t             content,
+                                           double                      width,
+                                           double                      height,
+                                           double                      max_width,
+                                           double                      max_height,
+                                           cairo_boilerplate_mode_t    mode,
+                                           gl_target_closure_t         *gltc)
 {
-    int rgba_attribs[] = { GLX_RGBA,
-                          GLX_RED_SIZE, 1,
-                          GLX_GREEN_SIZE, 1,
-                          GLX_BLUE_SIZE, 1,
-                          GLX_ALPHA_SIZE, 1,
-                          GLX_DOUBLEBUFFER,
-                          None };
-
-    int msaa_attribs[] = { GLX_RGBA,
-                          GLX_RED_SIZE, 1,
-                          GLX_GREEN_SIZE, 1,
-                          GLX_BLUE_SIZE, 1,
-                          GLX_ALPHA_SIZE, 1,
-                          GLX_STENCIL_SIZE, 1,
-                          GLX_SAMPLES, 4,
-                          GLX_SAMPLE_BUFFERS, 1,
-                          GLX_DOUBLEBUFFER,
-                          None };
-
     XVisualInfo *vi;
     GLXContext ctx;
-    gl_target_closure_t *gltc;
     cairo_surface_t *surface;
     Display *dpy;
     XSetWindowAttributes attr;
 
-    gltc = calloc (1, sizeof (gl_target_closure_t));
-    *closure = gltc;
-
     width = ceil (width);
     height = ceil (height);
 
@@ -201,11 +178,7 @@ _cairo_boilerplate_gl_create_window (const char                   *name,
     if (mode == CAIRO_BOILERPLATE_MODE_TEST)
        XSynchronize (gltc->dpy, 1);
 
-    vi = glXChooseVisual (dpy, DefaultScreen (dpy), msaa_attribs);
-
-    if (vi == NULL)
-       vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
-
+    vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
     if (vi == NULL) {
        fprintf (stderr, "Failed to create RGBA, double-buffered visual\n");
        XCloseDisplay (dpy);
@@ -235,22 +208,25 @@ _cairo_boilerplate_gl_create_window (const char                  *name,
     gltc->surface = surface = cairo_gl_surface_create_for_window (gltc->device,
                                                                  gltc->drawable,
                                                                  width, height);
-    if (cairo_surface_status (surface))
+    if (cairo_surface_status (surface)) {
        _cairo_boilerplate_gl_cleanup (gltc);
-
+       return NULL;
+    }
     return surface;
 }
 
 static cairo_surface_t *
-_cairo_boilerplate_gl_create_window_db (const char               *name,
-                                       cairo_content_t            content,
-                                       double                     width,
-                                       double                     height,
-                                       double                     max_width,
-                                       double                     max_height,
-                                       cairo_boilerplate_mode_t   mode,
-                                       void                     **closure)
+_cairo_boilerplate_gl_create_window (const char                       *name,
+                                    cairo_content_t            content,
+                                    double                     width,
+                                    double                     height,
+                                    double                     max_width,
+                                    double                     max_height,
+                                    cairo_boilerplate_mode_t   mode,
+                                    void                     **closure)
 {
+    gl_target_closure_t *gltc;
+
     int rgba_attribs[] = { GLX_RGBA,
                           GLX_RED_SIZE, 1,
                           GLX_GREEN_SIZE, 1,
@@ -259,7 +235,28 @@ _cairo_boilerplate_gl_create_window_db (const char           *name,
                           GLX_DOUBLEBUFFER,
                           None };
 
-    int msaa_attribs[] = { GLX_RGBA,
+    gltc = calloc (1, sizeof (gl_target_closure_t));
+    *closure = gltc;
+
+    return _cairo_boilerplate_gl_create_window_common (rgba_attribs, content,
+                                                      width, height,
+                                                      max_width, max_height,
+                                                      mode, gltc);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_gl_create_window_msaa (const char                  *name,
+                                         cairo_content_t               content,
+                                         double                        width,
+                                         double                        height,
+                                         double                        max_width,
+                                         double                        max_height,
+                                         cairo_boilerplate_mode_t      mode,
+                                         void                        **closure)
+{
+    gl_target_closure_t *gltc;
+
+    int rgba_attribs[] = { GLX_RGBA,
                           GLX_RED_SIZE, 1,
                           GLX_GREEN_SIZE, 1,
                           GLX_BLUE_SIZE, 1,
@@ -270,70 +267,48 @@ _cairo_boilerplate_gl_create_window_db (const char                  *name,
                           GLX_DOUBLEBUFFER,
                           None };
 
-    XVisualInfo *vi;
-    GLXContext ctx;
-    gl_target_closure_t *gltc;
-    cairo_surface_t *surface;
-    Display *dpy;
-    XSetWindowAttributes attr;
-    cairo_status_t status;
-
     gltc = calloc (1, sizeof (gl_target_closure_t));
     *closure = gltc;
+    return _cairo_boilerplate_gl_create_window_common (rgba_attribs, content,
+                                                      width, height,
+                                                      max_width, max_height,
+                                                      mode, gltc);
 
-    width = ceil (width);
-    height = ceil (height);
-
-    if (width == 0)
-       width = 1;
-    if (height == 0)
-       height = 1;
+}
 
-    dpy = XOpenDisplay (NULL);
-    gltc->dpy = dpy;
-    if (!gltc->dpy) {
-       fprintf (stderr, "Failed to open display: %s\n", XDisplayName(0));
-       free (gltc);
-       return NULL;
-    }
+static cairo_surface_t *
+_cairo_boilerplate_gl_create_window_db (const char               *name,
+                                       cairo_content_t            content,
+                                       double                     width,
+                                       double                     height,
+                                       double                     max_width,
+                                       double                     max_height,
+                                       cairo_boilerplate_mode_t   mode,
+                                       void                     **closure)
+{
+    cairo_status_t status;
+    cairo_surface_t *surface;
+    gl_target_closure_t *gltc;
 
-    if (mode == CAIRO_BOILERPLATE_MODE_TEST)
-       XSynchronize (gltc->dpy, 1);
+    int rgba_attribs[] = { GLX_RGBA,
+                          GLX_RED_SIZE, 1,
+                          GLX_GREEN_SIZE, 1,
+                          GLX_BLUE_SIZE, 1,
+                          GLX_ALPHA_SIZE, 1,
+                          GLX_DOUBLEBUFFER,
+                          None };
 
-    vi = glXChooseVisual (dpy, DefaultScreen (dpy), msaa_attribs);
+    gltc = calloc (1, sizeof (gl_target_closure_t));
+    *closure = gltc;
 
-    if (vi == NULL)
-       vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
+    surface = _cairo_boilerplate_gl_create_window_common (rgba_attribs, content,
+                                                         width, height,
+                                                         max_width, max_height,
+                                                         mode, gltc);
 
-    if (vi == NULL) {
-       fprintf (stderr, "Failed to create RGBA, double-buffered visual\n");
-       XCloseDisplay (dpy);
-       free (gltc);
+   if (! surface)
        return NULL;
-    }
 
-    attr.colormap = XCreateColormap (dpy,
-                                    RootWindow (dpy, vi->screen),
-                                    vi->visual,
-                                    AllocNone);
-    attr.border_pixel = 0;
-    attr.override_redirect = True;
-    gltc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0,
-                                   width, height, 0, vi->depth,
-                                   InputOutput, vi->visual,
-                                   CWOverrideRedirect | CWBorderPixel | CWColormap,
-                                   &attr);
-    XMapWindow (dpy, gltc->drawable);
-
-    ctx = glXCreateContext (dpy, vi, NULL, True);
-    XFree (vi);
-
-    gltc->ctx = ctx;
-    gltc->device = cairo_glx_device_create (dpy, ctx);
-
-    gltc->surface = cairo_gl_surface_create_for_window (gltc->device,
-                                                       gltc->drawable,
-                                                       width, height);
     surface = cairo_surface_create_similar (gltc->surface, content, width, height);
     status = cairo_surface_set_user_data (surface, &gl_closure_key, gltc, NULL);
     if (status == CAIRO_STATUS_SUCCESS)
@@ -446,6 +421,21 @@ static const cairo_boilerplate_target_t targets[] = {
        FALSE, FALSE, FALSE
     },
     {
+       "gl-window-msaa", "gl", NULL, NULL,
+       CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
+       "cairo_gl_surface_create_for_window",
+       _cairo_boilerplate_gl_create_window_msaa,
+       cairo_surface_create_similar,
+       NULL,
+       _cairo_boilerplate_gl_finish_window,
+       _cairo_boilerplate_get_image_surface,
+       cairo_surface_write_to_png,
+       _cairo_boilerplate_gl_cleanup,
+       _cairo_boilerplate_gl_synchronize,
+        _cairo_boilerplate_gl_describe,
+       FALSE, FALSE, FALSE
+    },
+    {
        "gl-window&", "gl", NULL, NULL,
        CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
        "cairo_gl_surface_create_for_window",
index 979f5b5..ffefecb 100644 (file)
@@ -46,9 +46,15 @@ typedef struct _xcb_target_closure {
 static cairo_status_t
 _cairo_boilerplate_xcb_handle_errors (xcb_target_closure_t *xtc)
 {
-    xcb_generic_event_t *ev;
+    xcb_generic_event_t *ev = NULL;
 
-    if ((ev = xcb_poll_for_event (xtc->c)) != NULL) {
+    /* Ignore all MappingNotify events; those might happen without us causing them */
+    do {
+       free(ev);
+       ev = xcb_poll_for_event(xtc->c);
+    } while (ev != NULL && ev->response_type == XCB_MAPPING_NOTIFY);
+
+    if (ev != NULL) {
        if (ev->response_type == CAIRO_XCB_ERROR) {
            xcb_generic_error_t *error = (xcb_generic_error_t *) ev;
 
index 1c43907..7314595 100644 (file)
@@ -3,6 +3,6 @@
 
 #define CAIRO_VERSION_MAJOR 1
 #define CAIRO_VERSION_MINOR 12
-#define CAIRO_VERSION_MICRO 4
+#define CAIRO_VERSION_MICRO 12
 
 #endif
index 006e773..a6d55de 100644 (file)
@@ -47,6 +47,18 @@ AC_CHECK_LIB(z, compress,
         [have_libz="no (requires zlib http://www.gzip.org/zlib/)"])],
         [have_libz="no (requires zlib http://www.gzip.org/zlib/)"])
 
+save_LIBS="$LIBS"
+AC_CHECK_LIB(lzo2, lzo2a_decompress,
+        [AC_CHECK_HEADER(lzo/lzo2a.h, [
+         have_lzo=yes
+         AC_DEFINE(HAVE_LZO, 1, [Define to 1 if you have lzo available])
+         lzo_LIBS="-llzo2"
+        ],
+        [have_lzo="no (requires lzpo http://www.oberhumer.com/opensource/lzo/)"])],
+        [have_lzo="no (requires lzpo http://www.oberhumer.com/opensource/lzo/)"])
+AC_SUBST(lzo_LIBS)
+LIBS="$save_LIBS"
+
 AC_CHECK_LIB(dl, dlsym,
             [have_dlsym=yes; have_dl=yes],
             [have_dlsym=no; have_dl=no])
@@ -65,8 +77,7 @@ dnl ===========================================================================
 CAIRO_ENABLE_SURFACE_BACKEND(xlib, Xlib, auto, [
   xlib_REQUIRES="x11 xext"
   PKG_CHECK_MODULES(xlib, $xlib_REQUIRES, ,
-                   [AC_MSG_RESULT(no)
-                    xlib_REQUIRES=""
+                   [xlib_REQUIRES=""
                     AC_PATH_XTRA
                     if test "x$no_x" = xyes; then
                       use_xlib="no (requires X development libraries)"
@@ -74,6 +85,42 @@ CAIRO_ENABLE_SURFACE_BACKEND(xlib, Xlib, auto, [
                       xlib_NONPKGCONFIG_LIBS="$X_PRE_LIBS $X_LIBS -lX11 -lXext $X_EXTRA_LIBS"
                       xlib_NONPKGCONFIG_CFLAGS=$X_CFLAGS
                     fi])
+
+  AC_CHECK_HEADER(sys/ipc.h)
+  AC_CHECK_HEADER(sys/shm.h)
+
+  if test "$ac_cv_header_sys_ipc_h" = "yes" -a "$ac_cv_header_sys_shm_h" = "yes"; then
+      AC_MSG_CHECKING(whether shmctl IPC_RMID allowes subsequent attaches)
+      AC_TRY_RUN([
+                 #include <sys/types.h>
+                 #include <sys/ipc.h>
+                 #include <sys/shm.h>
+                 int main()
+                 {
+                     char *shmaddr;
+                     int id = shmget (IPC_PRIVATE, 4, IPC_CREAT | 0600);
+                     if (id == -1) return 2;
+                     shmaddr = shmat (id, 0, 0);
+                     shmctl (id, IPC_RMID, 0);
+                     if ((char*) shmat (id, 0, 0) == (char*) -1) {
+                         shmdt (shmaddr);
+                         return 1;
+                     }
+                     shmdt (shmaddr);
+                     shmdt (shmaddr);
+                     return 0;
+                 }
+                 ],
+                 AC_DEFINE(IPC_RMID_DEFERRED_RELEASE, 1,
+                           [Define to 1 if shared memory segments are released deferred.])
+                 AC_MSG_RESULT(yes),
+                 AC_MSG_RESULT(no),
+                 AC_MSG_RESULT(assuming no))
+      fi
+
+      AC_CHECK_HEADERS([X11/extensions/XShm.h X11/extensions/shmproto.h X11/extensions/shmstr.h], [], [],
+                      [#include <X11/Xlibint.h>
+                       #include <X11/Xproto.h>])
 ])
 
 CAIRO_ENABLE_SURFACE_BACKEND(xlib_xrender, Xlib Xrender, auto, [
@@ -84,13 +131,13 @@ CAIRO_ENABLE_SURFACE_BACKEND(xlib_xrender, Xlib Xrender, auto, [
     xlib_xrender_BASE=cairo-xlib
     xlib_xrender_REQUIRES="xrender >= 0.6"
     PKG_CHECK_MODULES(xlib_xrender, $xlib_xrender_REQUIRES, ,
-                     [AC_MSG_RESULT(no)
-                      xlib_xrender_REQUIRES=""
+                     [xlib_xrender_REQUIRES=""
                       old_CPPFLAGS=$CPPFLAGS
                       CPPFLAGS="$CPPFLAGS $xlib_CFLAGS $xlib_NONPKGCONFIG_CFLAGS"
                       AC_CHECK_HEADER(X11/extensions/Xrender.h,
                                       [xlib_xrender_NONPKGCONFIG_LIBS="-lXrender"],
-                                      [use_xlib_xrender="no (requires $xlib_xrender_REQUIRES http://freedesktop.org/Software/xlibs)"])
+                                      [use_xlib_xrender="no (requires $xlib_xrender_REQUIRES http://freedesktop.org/Software/xlibs)"],
+                                      [#include <X11/X.h>])
                       CPPFLAGS=$old_CPPFLAGS
                      ])
 
@@ -110,16 +157,14 @@ dnl ===========================================================================
 CAIRO_ENABLE_SURFACE_BACKEND(xcb, XCB, auto, [
   xcb_REQUIRES="xcb >= 1.6 xcb-render >= 1.6"
   PKG_CHECK_MODULES(xcb, $xcb_REQUIRES, ,
-                   [AC_MSG_RESULT(no)
-                   use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"])
+                   [use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"])
 ])
 
 CAIRO_ENABLE_FUNCTIONS(xlib_xcb, Xlib/XCB, no, [
   if test "x$use_xcb" = "xyes" -a "x$use_xlib" = "xyes"; then
     xlib_xcb_REQUIRES="x11-xcb"
     PKG_CHECK_MODULES(xlib_xcb, $xlib_xcb_REQUIRES, ,
-                     [AC_MSG_RESULT(no)
-                     use_xlib_xcb="no (requires $xlib_xcb_REQUIRES http://xcb.freedesktop.org)"])
+                     [use_xlib_xcb="no (requires $xlib_xcb_REQUIRES http://xcb.freedesktop.org)"])
   else
     use_xlib_xcb="no (requires both --enable-xlib and --enable-xcb)"
   fi
@@ -129,8 +174,7 @@ CAIRO_ENABLE_FUNCTIONS(xcb_shm, XCB/SHM, auto, [
   if test "x$use_xcb" = "xyes"; then
       xcb_shm_REQUIRES="xcb-shm"
       PKG_CHECK_MODULES(xcb_shm, $xcb_shm_REQUIRES, ,
-                       [AC_MSG_RESULT(no)
-                       use_xcb_shm="no (requires $xcb_shm http://xcb.freedesktop.org)"])
+                       [use_xcb_shm="no (requires $xcb_shm http://xcb.freedesktop.org)"])
   else
     use_xcb_shm="no (requires --enable-xcb)"
   fi
@@ -141,8 +185,7 @@ dnl ===========================================================================
 CAIRO_ENABLE_SURFACE_BACKEND(qt, Qt, no, [
   qt_REQUIRES="QtGui >= 4.4.0"
   PKG_CHECK_MODULES(qt, $qt_REQUIRES, ,
-                   [AC_MSG_RESULT(no)
-                    qt_REQUIRES=""
+                   [qt_REQUIRES=""
                     use_qt="no (requires Qt4 development libraries)"
                     ])
 ])
@@ -250,8 +293,8 @@ dnl ===========================================================================
 
 CAIRO_ENABLE_SURFACE_BACKEND(drm, DRM, no, [
   drm_REQUIRES="libudev >= 136"
-  PKG_CHECK_MODULES(drm, $drm_REQUIRES, , [AC_MSG_RESULT(no)
-  use_drm="no (requires $drm_REQUIRES, udev is available from git://git.kernel.org/pub/scm/linux/hotplug/udev.git)"])
+  PKG_CHECK_MODULES(drm, $drm_REQUIRES, ,
+   [use_drm="no (requires $drm_REQUIRES, udev is available from git://git.kernel.org/pub/scm/linux/hotplug/udev.git)"])
 ])
 
 CAIRO_ENABLE_SURFACE_BACKEND(gallium, Gallium3D, no, [
@@ -290,7 +333,7 @@ CAIRO_ENABLE_FUNCTIONS(png, PNG, yes, [
   fi
 
   if test "x$use_png" = "xyes" ; then 
-    PKG_CHECK_MODULES(png, $png_REQUIRES, , AC_MSG_RESULT(no))
+    PKG_CHECK_MODULES(png, $png_REQUIRES, , )
   else
     AC_MSG_WARN([Could not find libpng in the pkg-config search path])
   fi    
@@ -344,7 +387,7 @@ dnl ===========================================================================
 
 CAIRO_ENABLE_SURFACE_BACKEND(directfb, directfb, no, [
   directfb_REQUIRES=directfb
-  PKG_CHECK_MODULES(directfb, $directfb_REQUIRES, , AC_MSG_RESULT(no)
+  PKG_CHECK_MODULES(directfb, $directfb_REQUIRES, ,
                    [use_directfb="no (requires $directfb_REQUIRES http://www.directfb.org)"])
 ])
 
@@ -447,8 +490,7 @@ CAIRO_ENABLE_FONT_BACKEND(ft, FreeType, auto, [
 
     PKG_CHECK_MODULES(FREETYPE, freetype2 >= $FREETYPE_MIN_VERSION,
                       [freetype_pkgconfig=yes],
-                     [AC_MSG_RESULT(no)
-                      freetype_pkgconfig=no])
+                     [freetype_pkgconfig=no])
   
     if test "x$freetype_pkgconfig" = "xyes"; then
       ft_REQUIRES="freetype2 >= $FREETYPE_MIN_VERSION $ft_REQUIRES"
@@ -482,7 +524,7 @@ CAIRO_ENABLE_FONT_BACKEND(fc, Fontconfig, auto, [
   if test "x$use_fc" = "xyes"; then
     fc_REQUIRES="fontconfig >= $FONTCONFIG_MIN_VERSION"
     PKG_CHECK_MODULES(FONTCONFIG, $fc_REQUIRES,,
-                     [AC_MSG_RESULT(no); use_fc="no (requires $fc_REQUIRES)"])
+                     [use_fc="no (requires $fc_REQUIRES)"])
   fi
   fc_CFLAGS="$FONTCONFIG_CFLAGS"
   fc_LIBS="$FONTCONFIG_LIBS"
@@ -493,15 +535,8 @@ if test "x$use_ft" = "xyes"; then
   _save_cflags="$CFLAGS"
   LIBS="$LIBS $ft_LIBS"
   CFLAGS="$CFLAGS $ft_CFLAGS"
-  AC_CHECK_MEMBER(FT_Bitmap_Size.y_ppem,
-                  HAVE_FT_BITMAP_SIZE_Y_PPEM=1,
-                  HAVE_FT_BITMAP_SIZE_Y_PPEM=0,
-                  [#include <ft2build.h>
-                   #include FT_FREETYPE_H])
-  AC_DEFINE_UNQUOTED(HAVE_FT_BITMAP_SIZE_Y_PPEM,$HAVE_FT_BITMAP_SIZE_Y_PPEM,
-                     [FT_Bitmap_Size structure includes y_ppem field])
 
-  AC_CHECK_FUNCS(FT_GlyphSlot_Embolden FT_GlyphSlot_Oblique FT_Load_Sfnt_Table FT_Library_SetLcdFilter)
+  AC_CHECK_FUNCS(FT_Get_X11_Font_Format FT_GlyphSlot_Embolden FT_GlyphSlot_Oblique FT_Load_Sfnt_Table FT_Library_SetLcdFilter)
 
   LIBS="$_save_libs"
   CFLAGS="$_save_cflags"
@@ -620,8 +655,8 @@ dnl ===========================================================================
 
 CAIRO_ENABLE_SURFACE_BACKEND(image, image, always, [
   pixman_REQUIRES="pixman-1 >= 0.22.0"
-  PKG_CHECK_MODULES(pixman, $pixman_REQUIRES, , [AC_MSG_RESULT(no)
-  use_image="no (requires $pixman_REQUIRES http://cairographics.org/releases/)"])
+  PKG_CHECK_MODULES(pixman, $pixman_REQUIRES, ,
+    [use_image="no (requires $pixman_REQUIRES http://cairographics.org/releases/)"])
   image_REQUIRES=$pixman_REQUIRES
   image_CFLAGS=$pixman_CFLAGS
   image_LIBS=$pixman_LIBS
@@ -668,13 +703,13 @@ dnl Build gobject integration library
 
 CAIRO_ENABLE_FUNCTIONS(gobject, gobject, auto, [
   gobject_REQUIRES="gobject-2.0 glib-2.0"
-  PKG_CHECK_MODULES(GOBJECT, $gobject_REQUIRES, , [AC_MSG_RESULT(no)
-  use_gobject="no (requires $gobject_REQUIRES http://download.gnome.org/pub/GNOME/sources/glib/)"])
+  PKG_CHECK_MODULES(GOBJECT, $gobject_REQUIRES, ,
+    [use_gobject="no (requires $gobject_REQUIRES http://download.gnome.org/pub/GNOME/sources/glib/)"])
   gobject_NONPKGCONFIG_EXTRA_LIBS="-L\${libdir} -lcairo-gobject"
 ])
 dnl I'm too lazy to fix the caching properly
 if test "x$use_gobject" = "xyes"; then
-  PKG_CHECK_MODULES(GOBJECT, $gobject_REQUIRES)
+  PKG_CHECK_MODULES(GOBJECT, $gobject_REQUIRES, : )
 fi
 
 dnl ===========================================================================
index 83c3828..10dd24f 100644 (file)
@@ -1,3 +1,59 @@
+cairo (1.12.8-slp2+3) unstable; urgency=low
+
+  * Remove gobject, script-interpreter libraries from package
+  * Git: framework/graphics/cairo
+  * Tag: cairo_1.12.8+3
+
+ -- Dongyeon Kim <dy5.kim@samsung.com>  Tue, 05 Feb 2013 14:00:47 +0900
+
+cairo (1.12.8-slp2+2) unstable; urgency=low
+
+  * gl: Bug fix of the clip handling
+  * Git: framework/graphics/cairo
+  * Tag: cairo_1.12.8+2
+
+ -- Dongyeon Kim <dy5.kim@samsung.com>  Wed, 23 Jan 2013 16:28:17 +0900
+
+cairo (1.12.8-slp2+1) unstable; urgency=low
+
+  * Update cairo to 1.12.8
+  * Git: framework/graphics/cairo
+  * Tag: cairo_1.12.8+1
+
+ -- Dongyeon Kim <dy5.kim@samsung.com>  Fri, 11 Jan 2013 18:09:24 +0900
+
+cairo (1.12.6-slp2+2) unstable; urgency=low
+
+  * Bug fixes for stroke and gradients
+  * Git: framework/graphics/cairo
+  * Tag: cairo_1.12.6-slp2+2
+
+ -- Dongyeon Kim <dy5.kim@samsung.com>  Thu, 03 Jan 2013 11:35:33 +0900
+
+cairo (1.12.6-slp2+1) unstable; urgency=low
+
+  * Update cairo to 1.12.6
+  * Git: framework/graphics/cairo
+  * Tag: cairo_1.12.6-slp2+1
+
+ -- Dongyeon Kim <dy5.kim@samsung.com>  Wed, 28 Nov 2012 10:13:41 +0900
+
+cairo (1.12.4-slp2+3) unstable; urgency=low
+
+  * gl: Fix gradient cache overflow
+  * Git: framework/graphics/cairo
+  * Tag: cairo_1.12.4-slp2+3
+
+ -- Dongyeon Kim <dy5.kim@samsung.com>  Tue, 06 Nov 2012 10:22:48 +0900
+
+cairo (1.12.4-slp2+2) unstable; urgency=low
+
+  * Various bug fixes
+  * Git: framework/graphics/cairo
+  * Tag: cairo_1.12.4-slp2+2
+
+ -- Dongyeon Kim <dy5.kim@samsung.com>  Wed, 24 Oct 2012 19:23:38 +0900
+
 cairo (1.12.4-slp2+1) unstable; urgency=low
 
   * Update cairo to 1.12.4
index e29dca1..2dc7e04 100644 (file)
@@ -1,7 +1,7 @@
 #sbs-git:slp/unmodified/cairo cairo 1.11.3 076a40b95caaadbc4a05b92a1a1d7840427e05b7
 Name:       cairo
 Summary:    A vector graphics library
-Version:    1.12.4
+Version:    1.12.12
 Release:    1
 Group:      System/Libraries
 License:    LGPLv2 or MPLv1.1
@@ -81,13 +81,15 @@ cat COPYING COPYING-LGPL-2.1 COPYING-MPL-1.1 > %{buildroot}/usr/share/license/%{
 
 %files
 %manifest cairo.manifest
-%{_libdir}/libcairo*.so.*
+%{_libdir}/libcairo.so.*
 /usr/share/license/%{name}
+%exclude %{_libdir}/libcairo-*.so.*
 
 %files devel
 %manifest cairo.manifest
 %{_includedir}/*
 %{_libdir}/libcairo*.so
+%{_libdir}/libcairo-*.so.*
 %{_libdir}/pkgconfig/*
 %exclude %{_bindir}/cairo-trace
 %exclude %{_libdir}/cairo/libcairo-trace.so
index a993ce8..5a41d02 100644 (file)
@@ -45,6 +45,7 @@ struct chart {
     int width, height;
     int num_tests, num_reports;
     double min_value, max_value;
+    double *average;
 
     cairo_bool_t use_html;
     cairo_bool_t relative;
@@ -142,12 +143,20 @@ find_ranges (struct chart *chart)
     int num_tests = 0;
     double slow_sum = 0, fast_sum = 0, sum;
     int slow_count = 0, fast_count = 0;
+    int *count;
     int i;
 
     num_values = 0;
     size_values = 64;
     values = xmalloc (size_values * sizeof (double));
 
+    chart->average = xmalloc(chart->num_reports * sizeof(double));
+    count = xmalloc(chart->num_reports * sizeof(int));
+    for (i = 0; i < chart->num_reports; i++) {
+       chart->average[i] = 0;
+       count[i] = 0;
+    }
+
     tests = xmalloc (chart->num_reports * sizeof (test_report_t *));
     for (i = 0; i < chart->num_reports; i++)
        tests[i] = chart->reports[i].tests;
@@ -202,6 +211,9 @@ find_ranges (struct chart *chart)
                if (test_time == 0)
                    test_time = report_time;
 
+               chart->average[i] += report_time / test_time;
+               count[i]++;
+
                if (chart->relative) {
                    if (test_time != report_time) {
                        double v = to_factor (test_time / report_time);
@@ -232,14 +244,22 @@ find_ranges (struct chart *chart)
        }
     }
 
+    for (i = 0; i < chart->num_reports; i++) {
+       if (count[i])
+           chart->average[i] = count[i] / chart->average[i];
+       else
+           chart->average[i] = 1.;
+    }
+
     if (chart->relative)
        trim_outliers (values, num_values, &min, &max);
     chart->min_value = min;
     chart->max_value = max;
-    chart->num_tests = num_tests;
+    chart->num_tests = num_tests + !!chart->relative;
 
     free (values);
     free (tests);
+    free (count);
 
     printf ("%d: slow[%d] average: %f, fast[%d] average: %f, %f\n",
            num_values, slow_count, slow_sum / slow_count, fast_count, fast_sum / fast_count, sum / num_values);
@@ -451,6 +471,91 @@ add_chart (struct chart *c,
 }
 
 static void
+add_average (struct chart *c,
+            int                 test,
+            int                 report,
+            double      value)
+{
+    double dx, dy, x;
+    cairo_text_extents_t extents;
+    char buf[80];
+    double y;
+
+    if (fabs (value) < 0.1)
+       return;
+
+    dy = (c->height/2. - PAD) / MAX (-c->min_value, c->max_value);
+    /* the first report is always skipped, as it is used as the baseline */
+    dx = c->width / (double) (c->num_tests * c->num_reports);
+    x = dx * (c->num_reports * test + report - .5);
+
+    cairo_rectangle (c->cr,
+                    floor (x), c->height / 2.,
+                    floor (x + dx) - floor (x),
+                    ceil (-dy*value - c->height/2.) + c->height/2.);
+    if (dx < 5) {
+       set_report_color (c, report);
+       cairo_fill (c->cr);
+    } else {
+       set_report_gradient (c, report,
+                            floor (x), c->height / 2.,
+                            floor (x + dx) - floor (x),
+                            ceil (-dy*value - c->height/2.) + c->height/2.);
+
+       cairo_fill_preserve (c->cr);
+       cairo_save (c->cr);
+       cairo_clip_preserve (c->cr);
+       set_report_color (c, report);
+       cairo_stroke (c->cr);
+       cairo_restore (c->cr);
+    }
+
+    /* Skip the label if the difference between the two is less than 0.1% */
+    if (fabs (value) < 0.1)
+       return;
+
+    cairo_save (c->cr);
+    cairo_set_font_size (c->cr, dx - 2);
+
+    if (value < 0) {
+       sprintf (buf, "%.1f", -value/100 + 1);
+    } else {
+       sprintf (buf, "%.1f", value/100 + 1);
+    }
+    cairo_text_extents (c->cr, buf, &extents);
+
+    /* will it be clipped? */
+    y = -dy * value;
+    if (y < -c->height/2) {
+       y = -c->height/2;
+    } else if (y > c->height/2) {
+       y = c->height/2;
+    }
+
+    if (y < 0) {
+       if (y > -extents.width - 6)
+           y -= extents.width + 6;
+    } else {
+       if (y < extents.width + 6)
+           y += extents.width + 6;
+    }
+
+    cairo_translate (c->cr,
+                    floor (x) + (floor (x + dx) - floor (x))/2,
+                    floor (y) + c->height/2.);
+    cairo_rotate (c->cr, -M_PI/2);
+    if (y < 0) {
+       cairo_move_to (c->cr, -extents.x_bearing -extents.width - 4, -extents.y_bearing/2);
+    } else {
+       cairo_move_to (c->cr, 2, -extents.y_bearing/2);
+    }
+
+    cairo_set_source_rgb (c->cr, .95, .95, .95);
+    cairo_show_text (c->cr, buf);
+    cairo_restore (c->cr);
+}
+
+static void
 add_label (struct chart *c,
           int           test,
           const char   *label)
@@ -825,6 +930,11 @@ cairo_perf_reports_compare (struct chart *chart,
 
        num_test++;
     }
+    if (chart->relative) {
+       add_label (chart, num_test, "(geometric mean)");
+       for (i = 0; i < chart->num_reports; i++)
+           add_average (chart, num_test, i, to_factor (chart->average[i]));
+    }
     free (tests);
 
     if (print) {
@@ -955,9 +1065,7 @@ main (int    argc,
        add_legend (&chart);
 
        cairo_surface_write_to_png (cairo_get_target (chart.cr),
-                                   chart.relative ?
-                                   "cairo-perf-chart-relative.png" :
-                                   "cairo-perf-chart-absolute.png");
+                                   chart.relative ? "relative.png" : "absolute.png");
        cairo_destroy (chart.cr);
     }
 
index bd0cb07..f27f8e4 100644 (file)
@@ -171,10 +171,12 @@ done:
 }
 
 static void
-clear_surface (cairo_surface_t *surface)
+fill_surface (cairo_surface_t *surface)
 {
     cairo_t *cr = cairo_create (surface);
-    cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+    /* This needs to be an operation that the backends can't optimise away */
+    cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.5);
+    cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
     cairo_paint (cr);
     cairo_destroy (cr);
 }
@@ -299,6 +301,19 @@ _similar_surface_create (void               *closure,
     return surface;
 }
 
+static cairo_surface_t *
+_source_image_create (void             *closure,
+                     cairo_format_t     format,
+                     int                width,
+                     int                height,
+                     long               uid)
+{
+    struct trace *args = closure;
+
+    return cairo_surface_create_similar_image (args->surface,
+                                              format, width, height);
+}
+
 static cairo_t *
 _context_create (void           *closure,
                 cairo_surface_t *surface)
@@ -643,7 +658,8 @@ cairo_perf_trace (cairo_perf_t                         *perf,
        _context_create,
        NULL, /* context_destroy */
        NULL, /* show_page */
-       NULL /* copy_page */
+       NULL, /* copy_page */
+       _source_image_create,
     };
 
     args.tile_size = perf->tile_size;
@@ -700,6 +716,8 @@ cairo_perf_trace (cairo_perf_t                         *perf,
                                               1, 1,
                                               CAIRO_BOILERPLATE_MODE_PERF,
                                               &args.closure);
+       fill_surface(args.surface); /* remove any clear flags */
+
        if (perf->observe) {
            cairo_surface_t *obs;
            obs = cairo_surface_create_observer (args.surface,
@@ -754,7 +772,7 @@ cairo_perf_trace (cairo_perf_t                         *perf,
            fill[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_fill_elapsed (observer));
            glyphs[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_glyphs_elapsed (observer));
        } else {
-           clear_surface (args.surface); /* queue a write to the sync'ed surface */
+           fill_surface (args.surface); /* queue a write to the sync'ed surface */
            cairo_perf_timer_stop ();
            times[i] = cairo_perf_timer_elapsed ();
        }
index f049d6d..f858cd7 100644 (file)
@@ -82,6 +82,9 @@ cairo_perf_timer_start (void)
 void
 cairo_perf_timer_stop (void)
 {
+    if (cairo_perf_timer_synchronize)
+       cairo_perf_timer_synchronize (cairo_perf_timer_synchronize_closure);
+
     timer = _cairo_time_get_delta (timer);
 }
 
index 439f378..6b55adc 100644 (file)
@@ -195,6 +195,7 @@ cairo_sources = \
        cairo-path-stroke.c \
        cairo-path-stroke-boxes.c \
        cairo-path-stroke-polygon.c \
+       cairo-path-stroke-traps.c \
        cairo-path-stroke-tristrip.c \
        cairo-pattern.c \
        cairo-pen.c \
@@ -465,3 +466,4 @@ cairo_cogl_sources = cairo-cogl-surface.c \
                     cairo-cogl-gradient.c \
                     cairo-cogl-context.c \
                     cairo-cogl-utils.c
+
index e3040fc..bd8d5b5 100644 (file)
@@ -2787,7 +2787,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t  *scaled_font_subset,
     if (backend->is_synthetic && backend->is_synthetic (scaled_font_subset->scaled_font))
        return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    font = malloc (sizeof (cairo_cff_font_t));
+    font = calloc (1, sizeof (cairo_cff_font_t));
     if (unlikely (font == NULL))
         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
@@ -2862,11 +2862,11 @@ fail4:
 fail3:
     free (font->subset_font_name);
 fail2:
-    free (font->data);
-    free (font->font_name);
     free (font->ps_name);
     _cairo_array_fini (&font->output);
 fail1:
+    free (font->data);
+    free (font->font_name);
     free (font);
 
     return status;
index d192d75..27c3676 100644 (file)
@@ -2037,8 +2037,10 @@ _cairo_cogl_stroke_to_primitive (cairo_cogl_surface_t        *surface,
 
     _cairo_traps_init (&traps);
 
-    status = _cairo_path_fixed_stroke_to_traps (path, style, ctm, ctm_inverse, tolerance,
-                                               &traps);
+    status = _cairo_path_fixed_stroke_polygon_to_traps (path, style,
+                                                       ctm, ctm_inverse,
+                                                       tolerance,
+                                                       &traps);
     if (unlikely (status))
        goto BAIL;
 
old mode 100644 (file)
new mode 100755 (executable)
index 774f7ff..f288bb7
@@ -61,7 +61,7 @@ _cairo_composite_rectangles_check_lazy_init (cairo_composite_rectangles_t *exten
 
     if (type == CAIRO_PATTERN_TYPE_SURFACE) {
     cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
-    cairo_surface_t *pattern_surface = pattern_surface = surface_pattern->surface;
+    cairo_surface_t *pattern_surface = surface_pattern->surface;
 
        /* XXX: both source and target are GL surface */
        if (cairo_surface_get_type (pattern_surface) == CAIRO_SURFACE_TYPE_GL &&
@@ -636,6 +636,13 @@ _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *exten
     if (unlikely (status))
        return status;
 
+    if (overlap && *overlap &&
+       scaled_font->options.antialias == CAIRO_ANTIALIAS_NONE &&
+       _cairo_pattern_is_opaque_solid (&extents->source_pattern.base))
+    {
+       *overlap = FALSE;
+    }
+
     return _cairo_composite_rectangles_intersect (extents, clip);
 }
 
@@ -657,6 +664,15 @@ _cairo_composite_rectangles_lazy_init_for_glyphs (cairo_composite_rectangles_t *
                                            clip, &should_be_lazy))
        return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
+    if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE &&
+        _cairo_scaled_font_glyph_approximate_extents (scaled_font,
+                                                      glyphs, num_glyphs,
+                                                      &extents->source))
+    {
+    if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
+    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+    }
+
     status = _cairo_scaled_font_glyph_device_extents (scaled_font,
                                                      glyphs, num_glyphs,
                                                      &extents->source,
@@ -664,6 +680,13 @@ _cairo_composite_rectangles_lazy_init_for_glyphs (cairo_composite_rectangles_t *
     if (unlikely (status))
        return status;
 
+    if (*overlap &&
+        scaled_font->options.antialias == CAIRO_ANTIALIAS_NONE &&
+        _cairo_pattern_is_opaque_solid (extents->original_source_pattern))
+    {
+    *overlap = FALSE;
+    }
+
     extents->clip = _cairo_clip_copy (clip);
 
     return CAIRO_INT_STATUS_SUCCESS;
index 7b56d17..b70f131 100755 (executable)
@@ -130,6 +130,9 @@ struct cairo_mask_compositor {
                                 cairo_boxes_t          *boxes);
 
     cairo_int_status_t
+       (*check_composite) (const cairo_composite_rectangles_t *extents);
+
+    cairo_int_status_t
        (*composite)            (void                   *dst,
                                 cairo_operator_t        op,
                                 cairo_surface_t        *src,
index 28768fd..97b177e 100644 (file)
@@ -60,6 +60,9 @@ cairo_private cairo_damage_t *
 _cairo_damage_create (void);
 
 cairo_private cairo_damage_t *
+_cairo_damage_create_in_error (cairo_status_t status);
+
+cairo_private cairo_damage_t *
 _cairo_damage_add_box (cairo_damage_t *damage,
                       const cairo_box_t *box);
 
index 1e06b26..63191fe 100644 (file)
 static const cairo_damage_t __cairo_damage__nil = { CAIRO_STATUS_NO_MEMORY };
 
 cairo_damage_t *
+_cairo_damage_create_in_error (cairo_status_t status)
+{
+    _cairo_error_throw (status);
+    return (cairo_damage_t *) &__cairo_damage__nil;
+}
+
+cairo_damage_t *
 _cairo_damage_create (void)
 {
     cairo_damage_t *damage;
old mode 100644 (file)
new mode 100755 (executable)
index 3d828ef..b211115
@@ -149,23 +149,28 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
     } else {
        cairo_surface_t *parent_surface;
        cairo_rectangle_int_t extents;
-       cairo_bool_t is_empty;
+       cairo_bool_t bounded, is_empty;
 
        parent_surface = _cairo_gstate_get_target (cr->gstate);
 
        /* Get the extents that we'll use in creating our new group surface */
-       is_empty = _cairo_surface_get_extents (parent_surface, &extents);
+       bounded = _cairo_surface_get_extents (parent_surface, &extents);
        if (clip)
+           /* XXX: This assignment just fixes a compiler warning? */
            is_empty = _cairo_rectangle_intersect (&extents,
                                                   _cairo_clip_get_extents (clip));
 
-       /* XXX unbounded surface creation */
-
-       group_surface = _cairo_surface_create_similar_solid (parent_surface,
-                                                            content,
-                                                            extents.width,
-                                                            extents.height,
-                                                            CAIRO_COLOR_TRANSPARENT);
+       if (!bounded) {
+           /* XXX: Generic solution? */
+           group_surface = cairo_recording_surface_create (content, NULL);
+           extents.x = extents.y = 0;
+       } else {
+           group_surface = _cairo_surface_create_similar_solid (parent_surface,
+                                                                content,
+                                                                extents.width,
+                                                                extents.height,
+                                                                CAIRO_COLOR_TRANSPARENT);
+       }
        status = group_surface->status;
        if (unlikely (status))
            goto bail;
@@ -294,8 +299,11 @@ _cairo_default_context_set_source_rgba (void *abstract_cr, double red, double gr
     _cairo_default_context_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
 
     pattern = cairo_pattern_create_rgba (red, green, blue, alpha);
-    if (unlikely (pattern->status))
-       return pattern->status;
+    if (unlikely (pattern->status)) {
+        status = pattern->status;
+        cairo_pattern_destroy (pattern);
+        return pattern->status;
+    }
 
     status = _cairo_default_context_set_source (cr, pattern);
     cairo_pattern_destroy (pattern);
@@ -318,8 +326,11 @@ _cairo_default_context_set_source_surface (void *abstract_cr,
     _cairo_default_context_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black);
 
     pattern = cairo_pattern_create_for_surface (surface);
-    if (unlikely (pattern->status))
-       return pattern->status;
+    if (unlikely (pattern->status)) {
+        status = pattern->status;
+        cairo_pattern_destroy (pattern);
+        return status;
+    }
 
     cairo_matrix_init_translate (&matrix, -x, -y);
     cairo_pattern_set_matrix (pattern, &matrix);
index 924fb69..fd3967f 100644 (file)
@@ -50,9 +50,7 @@ typedef struct _cairo_egl_context {
 
     EGLSurface dummy_surface;
 
-    EGLDisplay previous_display;
     EGLContext previous_context;
-    EGLSurface previous_surface;
 } cairo_egl_context_t;
 
 typedef struct _cairo_egl_surface {
@@ -66,9 +64,7 @@ static cairo_bool_t
 _context_acquisition_changed_egl_state (cairo_egl_context_t *ctx,
                                        EGLSurface current_surface)
 {
-    return !(ctx->previous_display == ctx->display &&
-            ctx->previous_surface == current_surface &&
-            ctx->previous_context == ctx->context);
+    return ctx->previous_context != ctx->context;
 }
 
 static EGLSurface
@@ -85,20 +81,7 @@ _egl_get_current_surface (cairo_egl_context_t *ctx)
 static void
 _egl_query_current_state (cairo_egl_context_t *ctx)
 {
-    ctx->previous_display = eglGetCurrentDisplay ();
-    ctx->previous_surface = eglGetCurrentSurface (EGL_DRAW);
     ctx->previous_context = eglGetCurrentContext ();
-
-    /* If any of the values were none, assume they are all none. Not all
-       drivers seem well behaved when it comes to using these values across
-       multiple threads. */
-    if (ctx->previous_surface == EGL_NO_SURFACE
-       || ctx->previous_display == EGL_NO_DISPLAY
-       || ctx->previous_context == EGL_NO_CONTEXT) {
-       ctx->previous_surface = EGL_NO_SURFACE;
-       ctx->previous_display = EGL_NO_DISPLAY;
-       ctx->previous_context = EGL_NO_CONTEXT;
-    }
 }
 
 static void
@@ -112,7 +95,6 @@ _egl_acquire (void *abstract_ctx)
        return;
 
     _cairo_gl_context_reset (&ctx->base);
-
     eglMakeCurrent (ctx->display,
                    current_surface, current_surface, ctx->context);
 }
index bd616b5..8ebadb4 100644 (file)
@@ -708,7 +708,8 @@ _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled)
 
 static cairo_status_t
 _compute_transform (cairo_ft_font_transform_t *sf,
-                   cairo_matrix_t      *scale)
+                   cairo_matrix_t      *scale,
+                   cairo_ft_unscaled_font_t *unscaled)
 {
     cairo_status_t status;
     double x_scale, y_scale;
@@ -736,6 +737,30 @@ _compute_transform (cairo_ft_font_transform_t *sf,
     if (y_scale < 1.0)
       y_scale = 1.0;
 
+    if (unscaled && (unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) == 0) {
+       double min_distance = DBL_MAX;
+       int i;
+       int best_i = 0;
+       double best_x_size = 0;
+       double best_y_size = 0;
+
+       for (i = 0; i < unscaled->face->num_fixed_sizes; i++) {
+           double x_size = unscaled->face->available_sizes[i].y_ppem / 64.;
+           double y_size = unscaled->face->available_sizes[i].y_ppem / 64.;
+           double distance = fabs (y_size - y_scale);
+
+           if (distance <= min_distance) {
+               min_distance = distance;
+               best_i = i;
+               best_x_size = x_size;
+               best_y_size = y_size;
+           }
+       }
+
+       x_scale = best_x_size;
+       y_scale = best_y_size;
+    }
+
     sf->x_scale = x_scale;
     sf->y_scale = y_scale;
 
@@ -773,7 +798,7 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
     unscaled->have_scale = TRUE;
     unscaled->current_scale = *scale;
 
-    status = _compute_transform (&sf, scale);
+    status = _compute_transform (&sf, scale, unscaled);
     if (unlikely (status))
        return status;
 
@@ -798,44 +823,12 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
 
     FT_Set_Transform(unscaled->face, &mat, NULL);
 
-    if ((unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) != 0) {
-       error = FT_Set_Char_Size (unscaled->face,
-                                 sf.x_scale * 64.0 + .5,
-                                 sf.y_scale * 64.0 + .5,
-                                 0, 0);
-       if (error)
-           return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    } else {
-       double min_distance = DBL_MAX;
-       int i;
-       int best_i = 0;
-
-       for (i = 0; i < unscaled->face->num_fixed_sizes; i++) {
-#if HAVE_FT_BITMAP_SIZE_Y_PPEM
-           double size = unscaled->face->available_sizes[i].y_ppem / 64.;
-#else
-           double size = unscaled->face->available_sizes[i].height;
-#endif
-           double distance = fabs (size - sf.y_scale);
-
-           if (distance <= min_distance) {
-               min_distance = distance;
-               best_i = i;
-           }
-       }
-#if HAVE_FT_BITMAP_SIZE_Y_PPEM
-       error = FT_Set_Char_Size (unscaled->face,
-                                 unscaled->face->available_sizes[best_i].x_ppem,
-                                 unscaled->face->available_sizes[best_i].y_ppem,
-                                 0, 0);
-       if (error)
-#endif
-           error = FT_Set_Pixel_Sizes (unscaled->face,
-                                       unscaled->face->available_sizes[best_i].width,
-                                       unscaled->face->available_sizes[best_i].height);
-       if (error)
-           return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
+    error = FT_Set_Char_Size (unscaled->face,
+                             sf.x_scale * 64.0 + .5,
+                             sf.y_scale * 64.0 + .5,
+                             0, 0);
+    if (error)
+      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -2521,6 +2514,22 @@ _cairo_index_to_glyph_name (void          *abstract_font,
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
 
+static cairo_bool_t
+_ft_is_type1 (FT_Face face)
+{
+#if HAVE_FT_GET_X11_FONT_FORMAT
+    const char *font_format = FT_Get_X11_Font_Format (face);
+    if (font_format &&
+       (strcmp (font_format, "Type 1") == 0 ||
+        strcmp (font_format, "CFF") == 0))
+    {
+       return TRUE;
+    }
+#endif
+
+    return FALSE;
+}
+
 static cairo_int_status_t
 _cairo_ft_load_type1_data (void                    *abstract_font,
                           long              offset,
@@ -2533,7 +2542,6 @@ _cairo_ft_load_type1_data (void               *abstract_font,
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
     unsigned long available_length;
     unsigned long ret;
-    const char *font_format;
 
     assert (length != NULL);
 
@@ -2551,11 +2559,7 @@ _cairo_ft_load_type1_data (void              *abstract_font,
     }
 #endif
 
-    font_format = FT_Get_X11_Font_Format (face);
-    if (!font_format ||
-       !(strcmp (font_format, "Type 1") == 0 ||
-         strcmp (font_format, "CFF") == 0))
-    {
+    if (! _ft_is_type1 (face)) {
         status = CAIRO_INT_STATUS_UNSUPPORTED;
        goto unlock;
     }
@@ -3077,7 +3081,7 @@ _cairo_ft_resolve_pattern (FcPattern                    *pattern,
                            font_matrix,
                            &scale);
 
-    status = _compute_transform (&sf, &scale);
+    status = _compute_transform (&sf, &scale, NULL);
     if (unlikely (status))
        return (cairo_font_face_t *)&_cairo_font_face_nil;
 
old mode 100644 (file)
new mode 100755 (executable)
index 33184ae..46de481
@@ -51,7 +51,6 @@
 #include "cairo-clip-private.h"
 #include "cairo-error-private.h"
 #include "cairo-image-surface-private.h"
-#include "cairo-traps-private.h"
 
 union fi {
     float f;
@@ -129,6 +128,12 @@ _cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
 }
 
 void
+_cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup)
+{
+    setup->multisample = TRUE;
+}
+
+void
 _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
                                      cairo_region_t *clip_region)
 {
@@ -146,7 +151,7 @@ static void
 _cairo_gl_composite_bind_to_shader (cairo_gl_context_t   *ctx,
                                    cairo_gl_composite_t *setup)
 {
-    _cairo_gl_shader_bind_matrix4f(ctx, "ModelViewProjectionMatrix",
+    _cairo_gl_shader_bind_matrix4f(ctx, CAIRO_GL_SHADER_SLOT_MVPMAT,
                                   ctx->modelviewprojection_matrix);
     _cairo_gl_operand_bind_to_shader (ctx, &setup->src,  CAIRO_GL_TEX_SOURCE);
     _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK);
@@ -316,11 +321,18 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
 
 static void
 _cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
+                              cairo_bool_t        spans_enabled,
                               unsigned int        vertex_size,
                               unsigned int        vertex_offset)
 {
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
 
+    if (! spans_enabled) {
+       dispatch->DisableVertexAttribArray (CAIRO_GL_COVERAGE_ATTRIB_INDEX);
+       ctx->spans = FALSE;
+       return;
+    }
+
     dispatch->VertexAttribPointer (CAIRO_GL_COVERAGE_ATTRIB_INDEX, 4,
                                   GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
                                   ctx->vb + vertex_offset);
@@ -554,22 +566,6 @@ _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
     return CAIRO_STATUS_SUCCESS;
 }
 
-void
-_cairo_gl_scissor_to_extents (cairo_gl_surface_t       *surface,
-                             const cairo_rectangle_int_t       *extents)
-{
-    int x1, y1, height;
-
-    x1 = extents->x;
-    y1 = extents->y;
-    height = extents->height;
-
-    if (_cairo_gl_surface_is_texture (surface) == FALSE)
-       y1 = surface->height - (y1 + height);
-    glScissor (x1, y1, extents->width, height);
-    glEnable (GL_SCISSOR_TEST);
-}
-
 static void
 _scissor_to_doubles (cairo_gl_surface_t        *surface,
                     double x1, double y1,
@@ -581,11 +577,10 @@ _scissor_to_doubles (cairo_gl_surface_t   *surface,
     if (_cairo_gl_surface_is_texture (surface) == FALSE)
        y1 = surface->height - (y1 + height);
     glScissor (x1, y1, x2 - x1, height);
-    glEnable (GL_SCISSOR_TEST);
 }
 
-static void
-_scissor_to_rectangle (cairo_gl_surface_t *surface,
+void
+_cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
                       const cairo_rectangle_int_t *r)
 {
     _scissor_to_doubles (surface, r->x, r->y, r->x+r->width, r->y+r->height);
@@ -616,36 +611,20 @@ _cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx,
     ctx->vertex_size = size_per_vertex;
 }
 
-void
-_disable_stencil_buffer (void)
-{
-    if (glIsEnabled (GL_STENCIL_TEST))
-        glDisable (GL_STENCIL_TEST);
-}
-
-void
-_disable_scissor_buffer (void)
-{
-    if (glIsEnabled (GL_SCISSOR_TEST))
-        glDisable (GL_SCISSOR_TEST);
-}
-
 static cairo_int_status_t
 _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
                                            cairo_gl_context_t *ctx,
-                                           int vertex_size,
-                                           cairo_bool_t equal_clip)
+                                           int vertex_size)
 {
     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
 
     cairo_gl_surface_t *dst = setup->dst;
     cairo_clip_t *clip = setup->clip;
-    cairo_traps_t traps;
-    const cairo_rectangle_int_t *clip_extents;
 
     if (clip->num_boxes == 1 && clip->path == NULL) {
-       _scissor_to_box (dst, &clip->boxes[0]);
-       goto disable_stencil_buffer_and_return;
+    _scissor_to_box (dst, &clip->boxes[0]);
+    _enable_scissor_buffer (ctx);
+    goto disable_stencil_buffer_and_return;
     }
 
     if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
@@ -653,26 +632,36 @@ _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
        goto disable_stencil_buffer_and_return;
     }
 
+    /* The clip is not rectangular, so use the stencil buffer. */
     if (! ctx->states_cache.depth_mask ) {
        glDepthMask (GL_TRUE);
        ctx->states_cache.depth_mask = TRUE;
     }
-    glEnable (GL_STENCIL_TEST);
-    clip_extents = _cairo_clip_get_extents ((const cairo_clip_t *)clip);
-    _cairo_gl_scissor_to_extents (dst, clip_extents);
 
-    if (equal_clip)
-       return CAIRO_INT_STATUS_SUCCESS;
+    _enable_stencil_buffer (ctx);
+
+    _disable_scissor_buffer (ctx);
+
+    cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
+    if (_cairo_clip_equal (old_clip, setup->clip))
+        goto activate_stencil_buffer_and_return;
+
+      /* Clear the stencil buffer, but only the areas that we are
+       * going to be drawing to. */
+    if (old_clip)
+        _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (old_clip));
+    _enable_scissor_buffer (ctx);
+    setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
 
     glClearStencil (0);
     glClear (GL_STENCIL_BUFFER_BIT);
+    _disable_scissor_buffer (ctx);
+
     glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
     glStencilFunc (GL_EQUAL, 1, 0xffffffff);
     glColorMask (0, 0, 0, 0);
 
-    _cairo_traps_init (&traps);
-    status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip, &traps);
-    _cairo_traps_fini (&traps);
+    status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);
 
     if (unlikely (status)) {
        glColorMask (1, 1, 1, 1);
@@ -685,13 +674,14 @@ _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
     _cairo_gl_composite_flush (ctx);
     _cairo_gl_composite_setup_vbo (ctx, vertex_size);
 
+activate_stencil_buffer_and_return:
     glColorMask (1, 1, 1, 1);
     glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
     glStencilFunc (GL_EQUAL, 1, 0xffffffff);
     return CAIRO_INT_STATUS_SUCCESS;
 
 disable_stencil_buffer_and_return:
-    _disable_stencil_buffer ();
+    _disable_stencil_buffer (ctx);
     return status;
 }
 
@@ -700,121 +690,104 @@ _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
                                    cairo_gl_context_t *ctx,
                                    int vertex_size)
 {
-    cairo_bool_t same_clip;
+    cairo_bool_t clip_changing = TRUE;
+    cairo_bool_t clip_region_changing = TRUE;
 
-    if (! ctx->clip && ! setup->clip && ! ctx->clip_region)
-       goto finish;
+    if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region)
+       goto disable_all_clipping;
 
-    same_clip = _cairo_clip_equal (ctx->clip, setup->clip);
+    clip_changing = ! _cairo_clip_equal (ctx->clip, setup->clip);
+    clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
     if (! _cairo_gl_context_is_flushed (ctx) &&
-       (! cairo_region_equal (ctx->clip_region, setup->clip_region) ||
-        ! same_clip))
+       (clip_region_changing || clip_changing))
        _cairo_gl_composite_flush (ctx);
 
-    cairo_region_destroy (ctx->clip_region);
-    ctx->clip_region = cairo_region_reference (setup->clip_region);
-
     assert (!setup->clip_region || !setup->clip);
 
-    if (! same_clip) {
+    /* setup->clip is only used by the msaa compositor and setup->clip_region
+     * only by the other compositors, so it's safe to wait to clean up obsolete
+     * clips. */
+    if (clip_region_changing) {
+       cairo_region_destroy (ctx->clip_region);
+       ctx->clip_region = cairo_region_reference (setup->clip_region);
+    }
+    if (clip_changing) {
        _cairo_clip_destroy (ctx->clip);
        ctx->clip = _cairo_clip_copy (setup->clip);
     }
 
-    if (ctx->clip_region) {
-       _disable_stencil_buffer ();
-       glEnable (GL_SCISSOR_TEST);
-       return CAIRO_INT_STATUS_SUCCESS;
-    }
+    /* For clip regions, we scissor right before drawing. */
+    if (setup->clip_region)
+       goto disable_all_clipping;
 
     if (setup->clip)
-           return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
-                                                           vertex_size,
-                                                           same_clip);
-
-finish:
-    _disable_stencil_buffer ();
-    _disable_scissor_buffer ();
+       return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
+                                                           vertex_size);
+disable_all_clipping:
+    _disable_stencil_buffer (ctx);
+    _disable_scissor_buffer (ctx);
     return CAIRO_INT_STATUS_SUCCESS;
 }
 
 cairo_status_t
-_cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
-                                      cairo_gl_context_t **ctx_out,
-                                      cairo_bool_t multisampling)
+_cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
+                                    cairo_gl_context_t *ctx)
 {
     unsigned int dst_size, src_size, mask_size, vertex_size;
-    cairo_gl_context_t *ctx;
     cairo_status_t status;
-    cairo_bool_t component_alpha;
     cairo_gl_shader_t *shader;
+    cairo_bool_t component_alpha;
     cairo_operator_t op = setup->op;
     cairo_surface_t *mask_surface = NULL;
 
-    assert (setup->dst);
-
-    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
-    if (unlikely (status))
-       return status;
-
-    _cairo_gl_context_set_destination (ctx, setup->dst, multisampling);
-
-    if (ctx->states_cache.blend_enabled == FALSE) {
-       glEnable (GL_BLEND);
-       ctx->states_cache.blend_enabled = TRUE;
-    }
-
     component_alpha =
        setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
        setup->mask.texture.attributes.has_component_alpha;
 
     /* Do various magic for component alpha */
     if (component_alpha) {
-        status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
-        if (unlikely (status))
-            goto FAIL;
-    } else {
-        if (ctx->pre_shader) {
-            _cairo_gl_composite_flush (ctx);
-            ctx->pre_shader = NULL;
-        }
+       status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
+       if (unlikely (status))
+           return status;
+     } else {
+       if (ctx->pre_shader) {
+           _cairo_gl_composite_flush (ctx);
+           ctx->pre_shader = NULL;
+       }
     }
 
     status = _cairo_gl_get_shader_by_type (ctx,
                                           &setup->src,
                                           &setup->mask,
                                           setup->spans,
-                                           component_alpha ?
+                                          component_alpha ?
                                           CAIRO_GL_SHADER_IN_CA_SOURCE :
                                           CAIRO_GL_SHADER_IN_NORMAL,
                                            &shader);
     if (unlikely (status)) {
-        ctx->pre_shader = NULL;
-        goto FAIL;
+       ctx->pre_shader = NULL;
+       return status;
     }
     if (ctx->current_shader != shader)
         _cairo_gl_composite_flush (ctx);
 
     status = CAIRO_STATUS_SUCCESS;
 
-    dst_size  = 2 * sizeof (GLfloat);
-    src_size  = _cairo_gl_operand_get_vertex_size (&setup->src);
+    dst_size = 2 * sizeof (GLfloat);
+    src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
     mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
     vertex_size = dst_size + src_size + mask_size;
 
     if (setup->spans)
-           vertex_size += sizeof (GLfloat);
+       vertex_size += sizeof (GLfloat);
 
     _cairo_gl_composite_setup_vbo (ctx, vertex_size);
 
     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size);
     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size);
-    if (setup->spans)
-       _cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size + mask_size);
-    else {
-        ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COVERAGE_ATTRIB_INDEX);
-        ctx->spans = FALSE;
-    }
+
+    _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size,
+                                  dst_size + src_size + mask_size);
 
     /* XXX: Shoot me - we have converted CLEAR to DEST_OUT,
        so the dst_factor would be GL_ONE_MINUS_SRC_ALPHA, if the
@@ -832,15 +805,38 @@ _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
     _cairo_gl_set_operator (ctx, setup->op, component_alpha);
 
     if (_cairo_gl_context_is_flushed (ctx)) {
-        if (ctx->pre_shader) {
-            _cairo_gl_set_shader (ctx, ctx->pre_shader);
-            _cairo_gl_composite_bind_to_shader (ctx, setup);
-        }
-        _cairo_gl_set_shader (ctx, shader);
-        _cairo_gl_composite_bind_to_shader (ctx, setup);
+       if (ctx->pre_shader) {
+           _cairo_gl_set_shader (ctx, ctx->pre_shader);
+           _cairo_gl_composite_bind_to_shader (ctx, setup);
+       }
+       _cairo_gl_set_shader (ctx, shader);
+       _cairo_gl_composite_bind_to_shader (ctx, setup);
     }
 
-    status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size);
+    return status;
+}
+
+cairo_status_t
+_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
+                          cairo_gl_context_t **ctx_out)
+{
+    cairo_gl_context_t *ctx;
+    cairo_status_t status;
+
+    assert (setup->dst);
+
+    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
+    if (unlikely (status))
+       return status;
+
+    _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);
+    if (ctx->states_cache.blend_enabled == FALSE) {
+       glEnable (GL_BLEND);
+       ctx->states_cache.blend_enabled = TRUE;
+    }
+    _cairo_gl_set_operands_and_operator (setup, ctx);
+
+    status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
     if (unlikely (status))
        goto FAIL;
 
@@ -853,13 +849,6 @@ FAIL:
     return status;
 }
 
-cairo_status_t
-_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
-                           cairo_gl_context_t **ctx_out)
-{
-    return _cairo_gl_composite_begin_multisample (setup, ctx_out, FALSE);
-}
-
 static inline void
 _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
 {
@@ -942,7 +931,8 @@ _cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx,
 
        cairo_region_get_rectangle (ctx->clip_region, i, &rect);
 
-       _scissor_to_rectangle (ctx->current_target, &rect);
+       _cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
+       _enable_scissor_buffer (ctx);
        _cairo_gl_composite_draw_triangles (ctx, count);
     }
 }
@@ -997,104 +987,89 @@ _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
 }
 
 static inline void
-_cairo_gl_composite_operand_emit (cairo_gl_operand_t *operand,
-                        GLfloat ** vb,
-                        GLfloat x,
-                        GLfloat y)
+_cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
+                                GLfloat x, GLfloat y)
 {
-    switch (operand->type) {
-    default:
-    case CAIRO_GL_OPERAND_COUNT:
-        ASSERT_NOT_REACHED;
-    case CAIRO_GL_OPERAND_NONE:
-        break;
-    case CAIRO_GL_OPERAND_CONSTANT:
-        if (operand->use_color_attribute) {
-            fi.bytes[0] = operand->constant.color[0] * 255;
-            fi.bytes[1] = operand->constant.color[1] * 255;
-            fi.bytes[2] = operand->constant.color[2] * 255;
-            fi.bytes[3] = operand->constant.color[3] * 255;
-            *(*vb)++ = fi.f;
-        }
-        break;
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-        {
-           double s = x;
-           double t = y;
+    GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
 
-           cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
+    *vb++ = x;
+    *vb++ = y;
 
-           *(*vb)++ = s;
-           *(*vb)++ = t;
-        }
-       break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-        {
-            cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
-            double s = x;
-            double t = y;
-
-            cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
-            *(*vb)++ = s;
-            *(*vb)++ = t;
-
-           if (operand->texture.use_atlas) {
-               *(*vb)++ = operand->texture.p1.x;
-               *(*vb)++ = operand->texture.p1.y;
-               *(*vb)++ = operand->texture.p2.x;
-               *(*vb)++ = operand->texture.p2.y;
-           }
-        }
-        break;
-    }
+    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
+    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK  ], &vb, x, y);
+
+    ctx->vb_offset += ctx->vertex_size;
 }
 
 static inline void
-_cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
-                                 GLfloat x,
-                                 GLfloat y,
-                                 uint8_t alpha)
+_cairo_gl_composite_emit_alpha_vertex (cairo_gl_context_t *ctx,
+                                      GLfloat x, GLfloat y, uint8_t alpha)
 {
     GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
+    union fi {
+       float f;
+       GLbyte bytes[4];
+    } fi;
 
     *vb++ = x;
     *vb++ = y;
 
-    _cairo_gl_composite_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
-    _cairo_gl_composite_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK  ], &vb, x, y);
+    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
+    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK  ], &vb, x, y);
 
-    if (ctx->spans) {
-
-       fi.bytes[0] = 0;
-       fi.bytes[1] = 0;
-       fi.bytes[2] = 0;
-       fi.bytes[3] = alpha;
-       *vb++ = fi.f;
-    }
+    fi.bytes[0] = 0;
+    fi.bytes[1] = 0;
+    fi.bytes[2] = 0;
+    fi.bytes[3] = alpha;
+    *vb++ = fi.f;
 
     ctx->vb_offset += ctx->vertex_size;
 }
 
-static inline void
+static void
 _cairo_gl_composite_emit_point (cairo_gl_context_t     *ctx,
-                               const cairo_point_t     *point,
-                               uint8_t alpha)
+                               const cairo_point_t     *point)
 {
     _cairo_gl_composite_emit_vertex (ctx,
                                     _cairo_fixed_to_double (point->x),
-                                    _cairo_fixed_to_double (point->y),
-                                    alpha);
+                                    _cairo_fixed_to_double (point->y));
 }
 
-void
+static void
 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
-                               GLfloat x1,
-                               GLfloat y1,
-                               GLfloat x2,
-                               GLfloat y2,
+                               GLfloat x1, GLfloat y1,
+                               GLfloat x2, GLfloat y2)
+{
+    _cairo_gl_composite_prepare_buffer (ctx, 6,
+                                       CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
+
+    _cairo_gl_composite_emit_vertex (ctx, x1, y1);
+    _cairo_gl_composite_emit_vertex (ctx, x2, y1);
+    _cairo_gl_composite_emit_vertex (ctx, x1, y2);
+
+    _cairo_gl_composite_emit_vertex (ctx, x2, y1);
+    _cairo_gl_composite_emit_vertex (ctx, x2, y2);
+    _cairo_gl_composite_emit_vertex (ctx, x1, y2);
+}
+
+cairo_gl_emit_rect_t
+_cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx)
+{
+    return _cairo_gl_composite_emit_rect;
+}
+
+void
+_cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
+                            GLfloat x1, GLfloat y1,
+                            GLfloat x2, GLfloat y2)
+{
+    _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2);
+}
+
+static void
+_cairo_gl_composite_emit_span (cairo_gl_context_t *ctx,
+                               GLfloat x1, GLfloat y1,
+                               GLfloat x2, GLfloat y2,
                                uint8_t alpha)
 {
     if (ctx->draw_mode != CAIRO_GL_VERTEX) {
@@ -1105,28 +1080,79 @@ _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
     _cairo_gl_composite_prepare_buffer (ctx, 6,
                                        CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
 
-    _cairo_gl_composite_emit_vertex (ctx, x1, y1, alpha);
-    _cairo_gl_composite_emit_vertex (ctx, x2, y1, alpha);
-    _cairo_gl_composite_emit_vertex (ctx, x1, y2, alpha);
+    _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y1, alpha);
+    _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
+    _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
+
+    _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
+    _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y2, alpha);
+    _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
+}
+
+static void
+_cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx,
+                                    GLfloat x1, GLfloat y1,
+                                    GLfloat x2, GLfloat y2,
+                                    uint8_t alpha)
+{
+    GLfloat *v;
+    union fi {
+       float f;
+       GLbyte bytes[4];
+    } fi;
+
+    _cairo_gl_composite_prepare_buffer (ctx, 6,
+                                       CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
+    v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
+
+    v[15] = v[ 6] = v[0] = x1;
+    v[10] = v[ 4] = v[1] = y1;
+    v[12] = v[ 9] = v[3] = x2;
+    v[16] = v[13] = v[7] = y2;
+
+    fi.bytes[0] = 0;
+    fi.bytes[1] = 0;
+    fi.bytes[2] = 0;
+    fi.bytes[3] = alpha;
+    v[17] =v[14] = v[11] = v[8] = v[5] = v[2] = fi.f;
+
+    ctx->vb_offset += 6*3 * sizeof(GLfloat);
+}
+
+cairo_gl_emit_span_t
+_cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx)
+{
+    if (ctx->operands[CAIRO_GL_TEX_MASK].type != CAIRO_GL_OPERAND_NONE)
+       return _cairo_gl_composite_emit_span;
 
-    _cairo_gl_composite_emit_vertex (ctx, x2, y1, alpha);
-    _cairo_gl_composite_emit_vertex (ctx, x2, y2, alpha);
-    _cairo_gl_composite_emit_vertex (ctx, x1, y2, alpha);
+    switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_CONSTANT:
+       return _cairo_gl_composite_emit_solid_span;
+
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+    case CAIRO_GL_OPERAND_TEXTURE:
+       return _cairo_gl_composite_emit_span;
+    }
 }
 
 static inline void
 _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
-                                       GLfloat x,
-                                       GLfloat y,
-                                       GLfloat glyph_x,
-                                       GLfloat glyph_y)
+                                      GLfloat x, GLfloat y,
+                                      GLfloat glyph_x, GLfloat glyph_y)
 {
     GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
 
     *vb++ = x;
     *vb++ = y;
 
-    _cairo_gl_composite_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
+    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
 
     *vb++ = glyph_x;
     *vb++ = glyph_y;
@@ -1134,16 +1160,12 @@ _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
     ctx->vb_offset += ctx->vertex_size;
 }
 
-void
+static void
 _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
-                                GLfloat x1,
-                                GLfloat y1,
-                                GLfloat x2,
-                                GLfloat y2,
-                                GLfloat glyph_x1,
-                                GLfloat glyph_y1,
-                                GLfloat glyph_x2,
-                                GLfloat glyph_y2)
+                                GLfloat x1, GLfloat y1,
+                                GLfloat x2, GLfloat y2,
+                                GLfloat glyph_x1, GLfloat glyph_y1,
+                                GLfloat glyph_x2, GLfloat glyph_y2)
 {
     if (ctx->draw_mode != CAIRO_GL_VERTEX) {
        _cairo_gl_composite_flush (ctx);
@@ -1162,6 +1184,55 @@ _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
     _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
 }
 
+static void
+_cairo_gl_composite_emit_solid_glyph (cairo_gl_context_t *ctx,
+                                     GLfloat x1, GLfloat y1,
+                                     GLfloat x2, GLfloat y2,
+                                     GLfloat glyph_x1, GLfloat glyph_y1,
+                                     GLfloat glyph_x2, GLfloat glyph_y2)
+{
+    GLfloat *v;
+
+    _cairo_gl_composite_prepare_buffer (ctx, 6,
+                                       CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
+
+    v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
+
+    v[20] = v[ 8] = v[0] = x1;
+    v[13] = v[ 5] = v[1] = y1;
+    v[22] = v[10] = v[2] = glyph_x1;
+    v[15] = v[ 7] = v[3] = glyph_y1;
+
+    v[16] = v[12] = v[4] = x2;
+    v[18] = v[14] = v[6] = glyph_x2;
+
+    v[21] = v[17] = v[ 9] = y2;
+    v[23] = v[19] = v[11] = glyph_y2;
+
+    ctx->vb_offset += 4 * 6 * sizeof (GLfloat);
+}
+
+cairo_gl_emit_glyph_t
+_cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx)
+{
+    switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_CONSTANT:
+       if (! ctx->operands[CAIRO_GL_TEX_SOURCE].use_color_attribute)
+           return _cairo_gl_composite_emit_solid_glyph;
+
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+    case CAIRO_GL_OPERAND_TEXTURE:
+       return _cairo_gl_composite_emit_glyph;
+    }
+}
+
 void
 _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
 {
@@ -1170,13 +1241,10 @@ _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
 }
 
 cairo_status_t
-_cairo_gl_composite_init (cairo_gl_composite_t *setup,
-                          cairo_operator_t op,
-                          cairo_gl_surface_t *dst,
-                          cairo_bool_t assume_component_alpha)
+_cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
+                                 cairo_operator_t op,
+                                 cairo_bool_t assume_component_alpha)
 {
-    memset (setup, 0, sizeof (cairo_gl_composite_t));
-
     if (assume_component_alpha) {
         if (op != CAIRO_OPERATOR_CLEAR &&
             op != CAIRO_OPERATOR_OVER &&
@@ -1187,8 +1255,26 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
             return UNSUPPORTED ("unsupported operator");
     }
 
-    setup->dst = dst;
     setup->op = op;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gl_composite_init (cairo_gl_composite_t *setup,
+                          cairo_operator_t op,
+                          cairo_gl_surface_t *dst,
+                          cairo_bool_t assume_component_alpha)
+{
+    cairo_status_t status;
+
+    memset (setup, 0, sizeof (cairo_gl_composite_t));
+
+    status = _cairo_gl_composite_set_operator (setup, op,
+                                              assume_component_alpha);
+    if (status)
+       return status;
+
+    setup->dst = dst;
     setup->clip_region = dst->clip_region;
 
     return CAIRO_STATUS_SUCCESS;
@@ -1248,14 +1334,14 @@ _cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t   *ctx,
     _cairo_gl_composite_prepare_buffer (ctx, 4,
                                        CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
 
-    _cairo_gl_composite_emit_point (ctx, &quad[0], 0);
-    _cairo_gl_composite_emit_point (ctx, &quad[1], 0);
+    _cairo_gl_composite_emit_point (ctx, &quad[0]);
+    _cairo_gl_composite_emit_point (ctx, &quad[1]);
 
     /* Cairo stores quad vertices in counter-clockwise order, but we need to
        emit them from top to bottom in the triangle strip, so we need to reverse
        the order of the last two vertices. */
-    _cairo_gl_composite_emit_point (ctx, &quad[3], 0);
-    _cairo_gl_composite_emit_point (ctx, &quad[2], 0);
+    _cairo_gl_composite_emit_point (ctx, &quad[3]);
+    _cairo_gl_composite_emit_point (ctx, &quad[2]);
 
     return _cairo_gl_composite_append_vertex_indices (ctx, 4, TRUE);
 }
@@ -1273,9 +1359,9 @@ _cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t *ctx,
     _cairo_gl_composite_prepare_buffer (ctx, 3,
                                        CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
 
-    _cairo_gl_composite_emit_point (ctx, &triangle[0], 0);
-    _cairo_gl_composite_emit_point (ctx, &triangle[1], 0);
-    _cairo_gl_composite_emit_point (ctx, &triangle[2], 0);
+    _cairo_gl_composite_emit_point (ctx, &triangle[0]);
+    _cairo_gl_composite_emit_point (ctx, &triangle[1]);
+    _cairo_gl_composite_emit_point (ctx, &triangle[2]);
     return _cairo_gl_composite_append_vertex_indices (ctx, 3, TRUE);
 }
 
@@ -1292,7 +1378,7 @@ _cairo_gl_composite_emit_point_as_single_line (cairo_gl_context_t  *ctx,
     _cairo_gl_composite_prepare_buffer (ctx, 2,
                                        CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
 
-    _cairo_gl_composite_emit_point (ctx, &point[0], 0);
-    _cairo_gl_composite_emit_point (ctx, &point[1], 0);
+    _cairo_gl_composite_emit_point (ctx, &point[0]);
+    _cairo_gl_composite_emit_point (ctx, &point[1]);
     return _cairo_gl_composite_append_vertex_indices (ctx, num_indices, FALSE);
 }
index 76d57ab..aa91f72 100644 (file)
@@ -54,8 +54,7 @@ _cairo_gl_image_cache_init (cairo_gl_context_t *ctx)
     cairo_surface_t *cache_surface = _cairo_gl_surface_create_scratch (ctx,
                                                CAIRO_CONTENT_COLOR_ALPHA,
                                                IMAGE_CACHE_WIDTH,
-                                               IMAGE_CACHE_HEIGHT,
-                                               FALSE);
+                                               IMAGE_CACHE_HEIGHT);
     if (unlikely (cache_surface->status)) {
        cairo_surface_destroy (cache_surface);
        return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -121,7 +120,7 @@ _gl_flush (void *device)
 
     _cairo_gl_context_reset (ctx);
 
-    _disable_scissor_buffer ();
+    _disable_scissor_buffer (ctx);
 
     if (ctx->states_cache.blend_enabled == TRUE ) {
        glDisable (GL_BLEND);
@@ -146,10 +145,6 @@ _gl_finish (void *device)
     for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
        _cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
 
-    if (ctx->shared_depth_stencil)
-       ctx->dispatch.DeleteRenderbuffers (1, &ctx->shared_depth_stencil);
-    if (ctx->shared_msaa_depth_stencil)
-       ctx->dispatch.DeleteRenderbuffers (1, &ctx->shared_msaa_depth_stencil);
 
     _cairo_gl_image_cache_fini (ctx);
 
@@ -205,6 +200,22 @@ _cairo_gl_msaa_compositor_enabled (void)
     return env && strcmp(env, "msaa") == 0;
 }
 
+static cairo_bool_t
+test_can_read_bgra (cairo_gl_flavor_t gl_flavor)
+{
+    /* Desktop GL always supports BGRA formats. */
+    if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+       return TRUE;
+
+    assert (gl_flavor == CAIRO_GL_FLAVOR_ES);
+
+   /* For OpenGL ES we have to look for the specific extension and BGRA only
+    * matches cairo's integer packed bytes on little-endian machines. */
+    if (!_cairo_is_little_endian())
+       return FALSE;
+    return _cairo_gl_has_extension ("EXT_read_format_bgra");
+}
+
 cairo_status_t
 _cairo_gl_context_init (cairo_gl_context_t *ctx)
 {
@@ -214,6 +225,9 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor ();
     int n;
 
+    cairo_bool_t is_desktop = gl_flavor == CAIRO_GL_FLAVOR_DESKTOP;
+    cairo_bool_t is_gles = gl_flavor == CAIRO_GL_FLAVOR_ES;
+
     _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
 
     /* XXX The choice of compositor should be made automatically at runtime.
@@ -236,7 +250,7 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
        return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
 
     /* Check for required extensions */
-    if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
+    if (is_desktop) {
        if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) {
            ctx->tex_target = GL_TEXTURE_2D;
            ctx->has_npot_repeat = TRUE;
@@ -247,52 +261,53 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
            return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
     } else {
        ctx->tex_target = GL_TEXTURE_2D;
-       if (_cairo_gl_has_extension ("GL_OES_texture_npot"))
+       if (_cairo_gl_has_extension ("GL_OES_texture_npot") ||
+           _cairo_gl_has_extension ("GL_IMG_texture_npot"))
            ctx->has_npot_repeat = TRUE;
        else
            ctx->has_npot_repeat = FALSE;
     }
 
-    if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
-       gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
+    if (is_desktop && gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
        ! _cairo_gl_has_extension ("GL_ARB_pixel_buffer_object"))
        return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
 
-    if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
-       ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
+    if (is_gles && ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
        return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
 
-    ctx->has_map_buffer = (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
-                          (gl_flavor == CAIRO_GL_FLAVOR_ES &&
-                           _cairo_gl_has_extension ("GL_OES_mapbuffer")));
+    ctx->has_map_buffer =
+       is_desktop || (is_gles && _cairo_gl_has_extension ("GL_OES_mapbuffer"));
+
+    ctx->can_read_bgra = test_can_read_bgra (gl_flavor);
 
     ctx->has_mesa_pack_invert =
        _cairo_gl_has_extension ("GL_MESA_pack_invert");
 
     ctx->has_packed_depth_stencil =
-       ((gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
-        _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
-       (gl_flavor == CAIRO_GL_FLAVOR_ES &&
-        _cairo_gl_has_extension ("GL_OES_packed_depth_stencil")));
+       (is_desktop && _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
+       (is_gles && _cairo_gl_has_extension ("GL_OES_packed_depth_stencil"));
 
     ctx->num_samples = 1;
 
 #if CAIRO_HAS_GL_SURFACE
-    if (ctx->has_packed_depth_stencil &&
-       _cairo_gl_has_extension ("GL_ARB_framebuffer_object")) {
+    if (is_desktop && ctx->has_packed_depth_stencil &&
+       (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
+        _cairo_gl_has_extension ("GL_ARB_framebuffer_object") ||
+        (_cairo_gl_has_extension ("GL_EXT_framebuffer_blit") &&
+         _cairo_gl_has_extension ("GL_EXT_framebuffer_multisample")))) {
        glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
     }
 #endif
 
 #if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_EXT)
-    if (ctx->has_packed_depth_stencil &&
+    if (is_gles && ctx->has_packed_depth_stencil &&
        _cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture")) {
        glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
     }
 #endif
 
 #if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_IMG)
-    if (ctx->has_packed_depth_stencil &&
+    if (is_gles && ctx->has_packed_depth_stencil &&
        _cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture")) {
        glGetIntegerv(GL_MAX_SAMPLES_IMG, &ctx->num_samples);
     }
@@ -502,7 +517,7 @@ _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
                                           surface->msaa_rb);
 
     /* Cairo surfaces start out initialized to transparent (black) */
-    _disable_scissor_buffer ();
+    _disable_scissor_buffer (ctx);
     glClearColor (0, 0, 0, 0);
     // reset cached clear colors
     memset (&ctx->states_cache.clear_red, 0, sizeof (double) * 4);
@@ -510,54 +525,36 @@ _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
 }
 #endif
 
-static void
-_cairo_gl_replace_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
-                                            int width,
-                                            int height)
-{
-    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-
-    if (ctx->shared_msaa_depth_stencil)
-       dispatch->DeleteRenderbuffers (1, &ctx->shared_msaa_depth_stencil);
-
-    dispatch->GenRenderbuffers (1, &ctx->shared_msaa_depth_stencil);
-    dispatch->BindRenderbuffer (GL_RENDERBUFFER, ctx->shared_msaa_depth_stencil);
-    dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER, ctx->num_samples,
-                                             _get_depth_stencil_format (ctx),
-                                             width, height);
-    ctx->shared_msaa_depth_stencil_width = width;
-    ctx->shared_msaa_depth_stencil_height = height;
-}
-
 static cairo_bool_t
 _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
                                            cairo_gl_surface_t *surface)
 {
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    if (surface->msaa_depth_stencil)
+       return TRUE;
+
     _cairo_gl_ensure_framebuffer (ctx, surface);
 #if CAIRO_HAS_GL_SURFACE
     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
        _cairo_gl_ensure_multisampling (ctx, surface);
 #endif
 
-    if (! ctx->shared_msaa_depth_stencil ||
-        ctx->shared_msaa_depth_stencil_width < surface->width ||
-        ctx->shared_msaa_depth_stencil_height < surface->height) {
-       _cairo_gl_replace_msaa_depth_stencil_buffer (ctx,
-                                                    surface->width,
-                                                    surface->height);
-    }
+    dispatch->GenRenderbuffers (1, &surface->msaa_depth_stencil);
+    dispatch->BindRenderbuffer (GL_RENDERBUFFER,
+                               surface->msaa_depth_stencil);
 
-    assert (ctx->shared_msaa_depth_stencil);
-    if (surface->msaa_depth_stencil == ctx->shared_msaa_depth_stencil)
-       return TRUE;
+    dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER,
+                                             ctx->num_samples,
+                                             _get_depth_stencil_format (ctx),
+                                             surface->width,
+                                             surface->height);
 
 #if CAIRO_HAS_GL_SURFACE
     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
        dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
                                           GL_DEPTH_STENCIL_ATTACHMENT,
                                           GL_RENDERBUFFER,
-                                          ctx->shared_msaa_depth_stencil);
+                                          surface->msaa_depth_stencil);
     }
 #endif
 
@@ -566,16 +563,14 @@ _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
        dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
                                           GL_DEPTH_ATTACHMENT,
                                           GL_RENDERBUFFER,
-                                          ctx->shared_msaa_depth_stencil);
+                                          surface->msaa_depth_stencil);
        dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
                                           GL_STENCIL_ATTACHMENT,
                                           GL_RENDERBUFFER,
-                                          ctx->shared_msaa_depth_stencil);
+                                          surface->msaa_depth_stencil);
     }
 #endif
 
-    surface->msaa_depth_stencil = ctx->shared_msaa_depth_stencil;
-
     if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
        surface->msaa_depth_stencil = 0;
@@ -585,50 +580,27 @@ _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
     return TRUE;
 }
 
-static void
-_cairo_gl_replace_depth_stencil_buffer (cairo_gl_context_t *ctx,
-                                       int width,
-                                       int height)
-{
-    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-
-    if (ctx->shared_depth_stencil)
-       dispatch->DeleteRenderbuffers (1, &ctx->shared_depth_stencil);
-
-    dispatch->GenRenderbuffers (1, &ctx->shared_depth_stencil);
-    dispatch->BindRenderbuffer (GL_RENDERBUFFER, ctx->shared_depth_stencil);
-    dispatch->RenderbufferStorage (GL_RENDERBUFFER,
-                                  _get_depth_stencil_format (ctx),
-                                  width, height);
-    ctx->shared_depth_stencil_width = width;
-    ctx->shared_depth_stencil_height = height;
-}
-
 static cairo_bool_t
 _cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t *ctx,
                                       cairo_gl_surface_t *surface)
 {
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
 
-    _cairo_gl_ensure_framebuffer (ctx, surface);
+    if (surface->depth_stencil)
+       return TRUE;
 
-    if (! ctx->shared_depth_stencil ||
-        ctx->shared_depth_stencil_width < surface->width ||
-        ctx->shared_depth_stencil_height < surface->height) {
-       _cairo_gl_replace_depth_stencil_buffer (ctx,
-                                               surface->width,
-                                               surface->height);
-    }
+    _cairo_gl_ensure_framebuffer (ctx, surface);
 
-    if (surface->depth_stencil == ctx->shared_depth_stencil)
-       return TRUE;
+    dispatch->GenRenderbuffers (1, &surface->depth_stencil);
+    dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
+    dispatch->RenderbufferStorage (GL_RENDERBUFFER,
+                                  _get_depth_stencil_format (ctx),
+                                  surface->width, surface->height);
 
     dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
-                                      GL_RENDERBUFFER, ctx->shared_depth_stencil);
+                                      GL_RENDERBUFFER, surface->depth_stencil);
     dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                      GL_RENDERBUFFER, ctx->shared_depth_stencil);
-    surface->depth_stencil = ctx->shared_depth_stencil;
-
+                                      GL_RENDERBUFFER, surface->depth_stencil);
     if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        dispatch->DeleteRenderbuffers (1, &surface->depth_stencil);
        surface->depth_stencil = 0;
@@ -714,8 +686,6 @@ _cairo_gl_activate_surface_as_multisampling (cairo_gl_context_t *ctx,
     _cairo_gl_composite_flush (ctx);
     glEnable (GL_MULTISAMPLE);
 
-    _disable_scissor_buffer ();
-
     /* The last time we drew to the surface, we were not using multisampling,
        so we need to blit from the non-multisampling framebuffer into the
        multisampling framebuffer. */
@@ -746,8 +716,6 @@ _cairo_gl_activate_surface_as_nonmultisampling (cairo_gl_context_t *ctx,
     _cairo_gl_composite_flush (ctx);
     glDisable (GL_MULTISAMPLE);
 
-    _disable_scissor_buffer ();
-
     /* The last time we drew to the surface, we were using multisampling,
        so we need to blit from the multisampling framebuffer into the
        non-multisampling framebuffer. */
@@ -855,4 +823,7 @@ void _cairo_gl_context_reset (cairo_gl_context_t *ctx)
     ctx->states_cache.active_texture = CAIRO_GL_ENUM_UNINITIALIZED;
 
     ctx->states_cache.depth_mask = FALSE;
+
+    /* FIXME:  this is hack to fix mali driver */
+    glDisable (GL_DITHER);
 }
index 9407b2f..76c3115 100644 (file)
@@ -211,9 +211,8 @@ _cairo_gl_dispatch_init_multisampling (cairo_gl_dispatch_t *dispatch,
                                       int gl_version,
                                       cairo_gl_flavor_t gl_flavor)
 {
-    /* For the multisampling table, the there are two GLES versions
-     * of the extension, so we put one in the EXT slot and one in
-     * the real ES slot.*/
+    /* For the multisampling table, there are two GLES versions of the
+     * extension, so we put one in the EXT slot and one in the real ES slot.*/
     cairo_gl_dispatch_name_t dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
     if (gl_flavor == CAIRO_GL_FLAVOR_ES) {
        if (_cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture"))
old mode 100644 (file)
new mode 100755 (executable)
index 9fed648..51afc5f
@@ -182,7 +182,6 @@ cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx,
 {
     cairo_gl_glyph_cache_t *cache;
     cairo_content_t content;
-    cairo_bool_t true_alpha = FALSE;
 
     switch (format) {
     case CAIRO_FORMAT_RGB30:
@@ -196,7 +195,6 @@ cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx,
     case CAIRO_FORMAT_A1:
        cache = &ctx->glyph_cache[1];
         content = CAIRO_CONTENT_ALPHA;
-       true_alpha = TRUE;
        break;
     default:
     case CAIRO_FORMAT_INVALID:
@@ -205,18 +203,16 @@ cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx,
     }
 
     if (unlikely (cache->surface == NULL)) {
-        cairo_surface_t *surface;
+       cairo_surface_t *surface;
 
-       surface = _cairo_gl_surface_create_scratch (ctx,
-                                                   content,
-                                                   GLYPH_CACHE_WIDTH,
-                                                   GLYPH_CACHE_HEIGHT,
-                                                   true_alpha);
+       surface = _cairo_gl_surface_create_scratch_for_caching (ctx,
+                                                               content,
+                                                               GLYPH_CACHE_WIDTH,
+                                                               GLYPH_CACHE_HEIGHT);
+       if (unlikely (surface->status))
+           return surface->status;
 
-        if (unlikely (surface->status))
-            return surface->status;
-
-        _cairo_surface_release_device_reference (surface);
+       _cairo_surface_release_device_reference (surface);
 
        cache->surface = (cairo_gl_surface_t *)surface;
        cache->surface->operand.texture.attributes.has_component_alpha =
@@ -240,6 +236,7 @@ render_glyphs (cairo_gl_surface_t *dst,
     cairo_format_t last_format = CAIRO_FORMAT_INVALID;
     cairo_gl_glyph_cache_t *cache = NULL;
     cairo_gl_context_t *ctx;
+    cairo_gl_emit_glyph_t emit;
     cairo_gl_composite_t setup;
     cairo_int_status_t status;
     int i = 0;
@@ -331,6 +328,8 @@ render_glyphs (cairo_gl_surface_t *dst,
             status = _cairo_gl_context_release (ctx, status);
            if (unlikely (status))
                goto FINISH;
+
+           emit = _cairo_gl_context_choose_emit_glyph (ctx);
        }
 
        if (scaled_glyph->dev_private_key != cache) {
@@ -366,10 +365,10 @@ render_glyphs (cairo_gl_surface_t *dst,
        y2 = y1 + scaled_glyph->surface->height;
 
        glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
-       _cairo_gl_composite_emit_glyph (ctx,
-                                       x1, y1, x2, y2,
-                                        glyph->p1.x, glyph->p1.y,
-                                        glyph->p2.x, glyph->p2.y);
+       emit (ctx,
+             x1, y1, x2, y2,
+             glyph->p1.x, glyph->p1.y,
+             glyph->p2.x, glyph->p2.y);
     }
 
     status = CAIRO_STATUS_SUCCESS;
old mode 100644 (file)
new mode 100755 (executable)
index 77f9bbd..c76c7b2
@@ -69,6 +69,7 @@ typedef struct _cairo_gl_gradient {
     cairo_reference_count_t       ref_count;
     cairo_device_t               *device; /* NB: we don't hold a reference */
     GLuint                        tex;
+    int                           tex_width;
     unsigned int                 n_stops;
     const cairo_gradient_stop_t  *stops;
     cairo_gradient_stop_t         stops_embedded[1];
old mode 100644 (file)
new mode 100755 (executable)
index 1c1f972..45e38e1
@@ -258,7 +258,8 @@ _cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
 
     CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 2);
     gradient->cache_entry.hash = hash;
-    gradient->cache_entry.size = tex_width;
+    gradient->cache_entry.size = sizeof (cairo_gl_gradient_t *);
+    gradient->tex_width = tex_width;
     gradient->device = &ctx->base;
     gradient->n_stops = n_stops;
     gradient->stops = gradient->stops_embedded;
@@ -328,6 +329,8 @@ _cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient)
        return;
 
     if (_cairo_gl_context_acquire (gradient->device, &ctx) == CAIRO_STATUS_SUCCESS) {
+       /* The gradient my still be active in the last operation, so flush */
+       _cairo_gl_composite_flush (ctx);
         glDeleteTextures (1, &gradient->tex);
         ignore = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
     }
old mode 100644 (file)
new mode 100755 (executable)
index 3a3adf7..39f5db4
@@ -45,8 +45,8 @@
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-compositor-private.h"
 #include "cairo-gl-private.h"
+#include "cairo-path-private.h"
 #include "cairo-traps-private.h"
-#include "cairo-surface-subsurface-inline.h"
 
 static cairo_bool_t
 can_use_msaa_compositor (cairo_gl_surface_t *surface,
@@ -76,25 +76,60 @@ _draw_trap (cairo_gl_context_t              *ctx,
 {
     cairo_point_t quad[4];
 
-    quad[0].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
-                                                         &trap->left.p2,
-                                                         trap->top);
+    if (trap->left.p1.x == trap->left.p2.x) {
+        quad[0].x = trap->left.p1.x;
+        quad[1].x = trap->left.p1.x;
+    } else {
+        cairo_fixed_t x, dy;
+        x = trap->left.p1.x;
+        dy = trap->left.p2.y - trap->left.p1.y;
+
+        if (trap->top == trap->left.p1.y)
+            quad[0].x = x;
+        else if (trap->top == trap->left.p2.y)
+            quad[0].x = trap->left.p2.x;
+        else if (dy != 0)
+            quad[0].x = x + _cairo_fixed_mul_div_floor (trap->top - trap->left.p1.y,
+                                                        trap->left.p2.x - trap->left.p1.x, dy);
+
+        if (trap->bottom == trap->left.p2.y)
+            quad[1].x = trap->left.p2.x;
+        else if (trap->bottom == trap->left.p1.y)
+            quad[1].x = x;
+        else if (dy != 0)
+            quad[1].x = x + _cairo_fixed_mul_div_floor (trap->bottom - trap->left.p1.y,
+                                                        trap->left.p2.x - trap->left.p1.x, dy);
+    }
     quad[0].y = trap->top;
-
-    quad[1].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
-                                                     &trap->left.p2,
-                                                     trap->bottom);
     quad[1].y = trap->bottom;
 
-    quad[2].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
-                                                     &trap->right.p2,
-                                                     trap->bottom);
+    if (trap->right.p1.x == trap->right.p2.x) {
+        quad[2].x = trap->right.p1.x;
+        quad[3].x = trap->right.p1.x;
+    } else {
+        cairo_fixed_t x, dy;
+        x = trap->right.p1.x;
+        dy = trap->right.p2.y - trap->right.p1.y;
+
+        if (trap->bottom == trap->right.p2.y)
+            quad[2].x = trap->right.p2.x;
+        else if (trap->bottom == trap->right.p1.y)
+            quad[2].x = x;
+        else if (dy != 0)
+            quad[2].x = x + _cairo_fixed_mul_div_floor (trap->bottom - trap->right.p1.y,
+                                                        trap->right.p2.x - trap->right.p1.x, dy);
+
+        if (trap->top == trap->right.p1.y)
+            quad[3].x = x;
+        else if (trap->top == trap->right.p2.y)
+            quad[3].x = trap->right.p2.x;
+        else if (dy != 0)
+            quad[3].x = x + _cairo_fixed_mul_div_floor (trap->top - trap->right.p1.y,
+                                                        trap->right.p2.x - trap->right.p1.x, dy);
+    }
     quad[2].y = trap->bottom;
-
-    quad[3].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
-                                                     &trap->right.p2,
-                                                     trap->top);
     quad[3].y = trap->top;
+
     return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
 }
 
@@ -116,37 +151,24 @@ _draw_traps (cairo_gl_context_t           *ctx,
 }
 
 static cairo_int_status_t
-_cairo_gl_msaa_compositor_draw_quad (cairo_gl_context_t        *ctx,
-                                    cairo_gl_composite_t       *setup,
-                                    cairo_box_t                *box)
-{
-    cairo_point_t quad[4];
-
-    quad[0].x = box->p1.x;
-    quad[0].y = box->p1.y;
-
-    quad[1].x = box->p1.x;
-    quad[1].y = box->p2.y;
-
-    quad[2].x = box->p2.x;
-    quad[2].y = box->p2.y;
-
-    quad[3].x = box->p2.x;
-    quad[3].y = box->p1.y;
-
-    return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
-}
-
-static cairo_int_status_t
 _draw_int_rect (cairo_gl_context_t     *ctx,
                cairo_gl_composite_t    *setup,
                cairo_rectangle_int_t   *rect)
 {
     cairo_box_t box;
+    cairo_point_t quad[4];
 
     _cairo_box_from_rectangle (&box, rect);
+    quad[0].x = box.p1.x;
+    quad[0].y = box.p1.y;
+    quad[1].x = box.p1.x;
+    quad[1].y = box.p2.y;
+    quad[2].x = box.p2.x;
+    quad[2].y = box.p2.y;
+    quad[3].x = box.p2.x;
+    quad[3].y = box.p1.y;
 
-    return _cairo_gl_msaa_compositor_draw_quad (ctx, setup, &box);
+    return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
 }
 
 static cairo_int_status_t
@@ -176,30 +198,26 @@ _draw_triangle_fan (cairo_gl_context_t            *ctx,
     return CAIRO_STATUS_SUCCESS;
 }
 
-cairo_int_status_t
-_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t                *ctx,
-                                    cairo_gl_composite_t       *setup,
-                                    cairo_clip_t               *clip,
-                                    cairo_traps_t              *traps)
+static cairo_int_status_t
+_clip_to_traps (cairo_clip_t *clip,
+               cairo_traps_t *traps)
 {
     cairo_int_status_t status;
-
     cairo_polygon_t polygon;
     cairo_antialias_t antialias;
     cairo_fill_rule_t fill_rule;
 
-    if (! clip)
-       return CAIRO_INT_STATUS_UNSUPPORTED;
+    _cairo_traps_init (traps);
 
-    if (clip->num_boxes == 1 && ! clip->path)
-       return _cairo_gl_msaa_compositor_draw_quad (ctx, setup,
-                                                   &clip->boxes[0]);
+    if (clip->num_boxes == 1 && clip->path == NULL) {
+       cairo_boxes_t boxes;
+       _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
+       return _cairo_traps_init_boxes (traps, &boxes);
+    }
 
-    if (traps->num_traps == 0) {
-       status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule,
-                                         &antialias);
-       if (unlikely (status))
-           return status;
+    status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias);
+    if (unlikely (status))
+       return status;
 
     /* We ignore the antialias mode of the clip here, since the user requested
      * unantialiased rendering of their path and we expect that this stencil
@@ -211,16 +229,30 @@ _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t           *ctx,
      * antialiased polygon is open to interpretation. And we choose the fast
      * option.
      */
-       status = _cairo_bentley_ottmann_tessellate_polygon (traps,
-                                                           &polygon,
-                                                           fill_rule);
-       _cairo_polygon_fini (&polygon);
-       if (unlikely (status))
-           return status;
-    }
 
-    status = _draw_traps (ctx, setup, traps);
+    _cairo_traps_init (traps);
+    status = _cairo_bentley_ottmann_tessellate_polygon (traps,
+                                                       &polygon,
+                                                       fill_rule);
+    _cairo_polygon_fini (&polygon);
+
+    return status;
+}
+
+cairo_int_status_t
+_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
+                                    cairo_gl_composite_t *setup,
+                                    cairo_clip_t *clip)
+{
+    cairo_int_status_t status;
+    cairo_traps_t traps;
 
+    status = _clip_to_traps (clip, &traps);
+    if (unlikely (status))
+       return status;
+    status = _draw_traps (ctx, setup, &traps);
+
+    _cairo_traps_fini (&traps);
     return status;
 }
 
@@ -313,9 +345,6 @@ _cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
 {
     uint32_t is_bounded;
 
-    if (_cairo_clip_is_all_clipped (composite->clip))
-       return;
-
     /* We don't need to check CAIRO_OPERATOR_BOUND_BY_MASK in these
        situations. */
     is_bounded = composite->is_bounded;
@@ -328,48 +357,12 @@ _cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
     composite->is_bounded = is_bounded;
 }
 
-static void
-_gl_pattern_fix_reference_count (const cairo_pattern_t *pattern)
-{
-   cairo_pattern_type_t pattern_type = cairo_pattern_get_type ((cairo_pattern_t *)pattern);
-
-   /* We need to increase reference count on surface and gradient if
-      the original_source_pattern is a cairo_gl_source_t type. */
-    if (pattern_type == CAIRO_PATTERN_TYPE_SURFACE) {
-
-       cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)pattern;
-       cairo_surface_t *pattern_surface = surface_pattern->surface;
-
-       if (cairo_surface_get_type (pattern_surface) == CAIRO_SURFACE_TYPE_GL &&
-           ! pattern_surface->device &&
-           ! _cairo_surface_is_subsurface (pattern_surface)) {
-
-           cairo_gl_source_t *_source = (cairo_gl_source_t *)pattern_surface;
-
-           switch (_source->operand.type) {
-           case CAIRO_GL_OPERAND_TEXTURE:
-               cairo_surface_reference (&(_source->operand.texture.owns_surface)->base);
-               break;
-           case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-           case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
-           case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
-           case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-               _cairo_gl_gradient_reference (_source->operand.gradient.gradient);
-               break;
-           default:
-           case CAIRO_GL_OPERAND_NONE:
-           case CAIRO_GL_OPERAND_CONSTANT:
-           case CAIRO_GL_OPERAND_COUNT:
-               break;
-           }
-       }
-    }
-}
-
-/* We use two passes to paint with SOURCE operator */
-/* The first pass, we use mask as source, to get dst1 = (1 - ma) * dst) with
- * DEST_OUT operator.  In the second pass, we use ADD operator to achieve
- * result = (src * ma) + dst1.  Combining two passes, we have
+/* Masking with the SOURCE operator requires two passes. In the first
+ * pass we use the mask as the source to get:
+ * result = (1 - ma) * dst
+ * In the second pass we use the add operator to achieve:
+ * result = (src * ma) + dst
+ * Combined this produces:
  * result = (src * ma) + (1 - ma) * dst
  */
 static cairo_int_status_t
@@ -380,84 +373,76 @@ _cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compos
     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
     cairo_gl_context_t *ctx = NULL;
     cairo_int_status_t status;
+
+    cairo_clip_t *clip = composite->clip;
     cairo_traps_t traps;
 
-    _cairo_traps_init (&traps);
+    /* If we have a non-rectangular clip, we can avoid using the stencil buffer
+     * for clipping and just draw the clip polygon. */
+    if (clip) {
+       status = _clip_to_traps (clip, &traps);
+       if (unlikely (status)) {
+           _cairo_traps_fini (&traps);
+           return status;
+       }
+    }
 
     status = _cairo_gl_composite_init (&setup,
                                       CAIRO_OPERATOR_DEST_OUT,
                                       dst,
                                       FALSE /* assume_component_alpha */);
     if (unlikely (status))
-       goto finish;
-
-    _gl_pattern_fix_reference_count (composite->original_mask_pattern);
-
+       return status;
     status = _cairo_gl_composite_set_source (&setup,
-                                            &composite->mask_pattern.base,
+                                            composite->original_mask_pattern,
                                             &composite->mask_sample_area,
                                             &composite->bounded,
                                             FALSE);
     if (unlikely (status))
        goto finish;
-
-    status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE);
+    _cairo_gl_composite_set_multisample (&setup);
+    status = _cairo_gl_composite_begin (&setup, &ctx);
     if (unlikely (status))
        goto finish;
 
-    if (! composite->clip)
+    if (! clip)
        status = _draw_int_rect (ctx, &setup, &composite->bounded);
     else
-       status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps);
+       status = _draw_traps (ctx, &setup, &traps);
 
-    _cairo_gl_composite_fini (&setup);
-    status = _cairo_gl_context_release (ctx, status);
-    ctx = NULL;
-    if (unlikely (status))
-        return status;
-
-     /* second pass */
-    status = _cairo_gl_composite_init (&setup,
-                                      CAIRO_OPERATOR_ADD,
-                                      dst,
-                                      FALSE /* assume_component_alpha */);
+    /* Now draw the second pass. */
+    _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD,
+                                     FALSE /* assume_component_alpha */);
     if (unlikely (status))
-       goto finish;
-
-    _gl_pattern_fix_reference_count (composite->original_source_pattern);
-
+        goto finish;
     status = _cairo_gl_composite_set_source (&setup,
-                                            &composite->source_pattern.base,
+                                            composite->original_source_pattern,
                                             &composite->source_sample_area,
                                             &composite->bounded,
                                             FALSE);
     if (unlikely (status))
        goto finish;
-
     status = _cairo_gl_composite_set_mask (&setup,
-                                          &composite->mask_pattern.base,
+                                          composite->original_mask_pattern,
                                           &composite->source_sample_area,
                                           &composite->bounded);
     if (unlikely (status))
        goto finish;
-
-    /* We always use multisampling here, because we do not yet have the smarts
-       to calculate when the clip or the source requires it. */
-    status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE);
+    status = _cairo_gl_set_operands_and_operator (&setup, ctx);
     if (unlikely (status))
        goto finish;
 
-    if (! composite->clip)
+    if (! clip)
        status = _draw_int_rect (ctx, &setup, &composite->bounded);
     else
-       status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps);
+       status = _draw_traps (ctx, &setup, &traps);
 
 finish:
-    _cairo_traps_fini (&traps);
     _cairo_gl_composite_fini (&setup);
-
     if (ctx)
        status = _cairo_gl_context_release (ctx, status);
+    if (clip)
+       _cairo_traps_fini (&traps);
 
     return status;
 }
@@ -471,8 +456,8 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t    *compositor,
     cairo_gl_context_t *ctx = NULL;
     cairo_int_status_t status;
     cairo_operator_t op = composite->op;
-    cairo_traps_t traps;
     cairo_bool_t use_color_attribute = FALSE;
+    cairo_clip_t *clip = composite->clip;
 
     if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT))
        return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -486,12 +471,13 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t  *compositor,
        ! _cairo_pattern_is_opaque (&composite->mask_pattern.base,
                                    &composite->mask_sample_area)) {
 
-       /* If the source is opaque the operation reduces to OVER. */
-       if (_cairo_pattern_is_opaque (&composite->source_pattern.base,
-                                     &composite->source_sample_area))
-           op = CAIRO_OPERATOR_OVER;
-       else
+       if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
+                                     &composite->source_sample_area)) {
            return _cairo_gl_msaa_compositor_mask_source_operator (compositor, composite);
+       }
+
+       /* If the source is opaque the operation reduces to OVER. */
+       op = CAIRO_OPERATOR_OVER;
     }
 
     if (_should_use_unbounded_surface (composite)) {
@@ -527,9 +513,7 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t    *compositor,
                                       dst,
                                       FALSE /* assume_component_alpha */);
     if (unlikely (status))
-       goto finish;
-
-    _gl_pattern_fix_reference_count (composite->original_source_pattern);
+       return status;
 
     if (! composite->clip ||
        (composite->clip->num_boxes == 1 && ! composite->clip->path))
@@ -554,18 +538,16 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t  *compositor,
 
     /* We always use multisampling here, because we do not yet have the smarts
        to calculate when the clip or the source requires it. */
-    status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE);
+     _cairo_gl_composite_set_multisample (&setup);
+
+    status = _cairo_gl_composite_begin (&setup, &ctx);
     if (unlikely (status))
        goto finish;
 
-    _cairo_traps_init (&traps);
-
-    if (! composite->clip)
+    if (! clip)
        status = _draw_int_rect (ctx, &setup, &composite->bounded);
     else
-       status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, composite->clip, &traps);
-
-    _cairo_traps_fini (&traps);
+       status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, clip);
 
 finish:
     _cairo_gl_composite_fini (&setup);
@@ -622,7 +604,7 @@ _is_continuous_arc (const cairo_path_fixed_t   *path,
 }
 
 static cairo_int_status_t
-_prevent_overlapping_drawing (cairo_gl_context_t               *ctx,
+_prevent_overlapping_strokes (cairo_gl_context_t               *ctx,
                              cairo_gl_composite_t              *setup,
                              cairo_composite_rectangles_t      *composite,
                              const cairo_path_fixed_t          *path,
@@ -643,7 +625,7 @@ _prevent_overlapping_drawing (cairo_gl_context_t            *ctx,
        _cairo_pattern_is_opaque_solid (pattern))
        return CAIRO_INT_STATUS_SUCCESS;
 
-   if (glIsEnabled (GL_STENCIL_TEST) == FALSE) {
+    if (ctx->states_cache.stencil_test_enabled == FALSE) {
        /* In case we have pending operations we have to flush before
          adding the stencil buffer. */
        _cairo_gl_composite_flush (ctx);
@@ -656,17 +638,23 @@ _prevent_overlapping_drawing (cairo_gl_context_t          *ctx,
            ctx->states_cache.depth_mask = TRUE;
        }
        glEnable (GL_STENCIL_TEST);
+       ctx->states_cache.stencil_test_enabled = TRUE;
 
-       /* If we don't have clip, then we will setup clip extents based on
-          approximate stroke extent. */
-       if (! setup->clip) {
+       /* We scissor here so that we don't have to clear the entire stencil
+        * buffer. If the scissor test is already enabled, it was enabled
+        * for clipping. In that case, instead of calculating an intersection,
+        * we just reuse it, and risk clearing too much. */
+       if (ctx->states_cache.scissor_test_enabled == FALSE) {
            _cairo_path_fixed_approximate_stroke_extents (path, style, ctm,
                                                          &stroke_extents);
-           _cairo_gl_scissor_to_extents (setup->dst, &stroke_extents);
+           _cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents);
+            glEnable (GL_SCISSOR_TEST);
+            ctx->states_cache.scissor_test_enabled = TRUE;
        }
-
        glClearStencil (1);
        glClear (GL_STENCIL_BUFFER_BIT);
+       _disable_scissor_buffer (ctx);
+
        glStencilFunc (GL_EQUAL, 1, 1);
     }
 
@@ -675,9 +663,8 @@ _prevent_overlapping_drawing (cairo_gl_context_t            *ctx,
        is disabled. */
     glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO);
 
-    /* we need to clean up clip cache */
-    _cairo_clip_destroy (ctx->clip);
-    ctx->clip = NULL;
+    _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
+    setup->dst->clip_on_stencil_buffer = NULL;
 
     return CAIRO_INT_STATUS_SUCCESS;
 }
@@ -772,9 +759,10 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor,
        goto finish;
 
     _cairo_gl_msaa_compositor_set_clip (composite, &info.setup);
+    if (antialias != CAIRO_ANTIALIAS_NONE)
+       _cairo_gl_composite_set_multisample (&info.setup);
 
-    status = _cairo_gl_composite_begin_multisample (&info.setup, &info.ctx,
-       antialias != CAIRO_ANTIALIAS_NONE);
+    status = _cairo_gl_composite_begin (&info.setup, &info.ctx);
     if (unlikely (status))
        goto finish;
 
@@ -783,8 +771,8 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t  *compositor,
 
        if (! (_is_continuous_arc (path, style) ||
               _is_continuous_single_line (path, style))) {
-           status = _prevent_overlapping_drawing (info.ctx, &info.setup,
-                                                  composite, path,
+           status = _prevent_overlapping_strokes (info.ctx, &info.setup,
+                                                  composite, path,
                                                   style, ctm);
            if (unlikely (status))
                goto finish;
@@ -823,9 +811,8 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t  *compositor,
        _cairo_traps_fini (&traps);
     } else {
        if (!_is_continuous_single_line (path, style)) {
-           status = _prevent_overlapping_drawing (info.ctx, &info.setup,
-                                                  composite, path,
-                                                  style, ctm);
+           status = _prevent_overlapping_strokes (info.ctx, &info.setup,
+                                                  composite, path, style, ctm);
            if (unlikely (status))
                goto finish;
        }
@@ -853,54 +840,26 @@ finish:
 }
 
 static cairo_int_status_t
-_cairo_gl_msaa_compositor_fill_rectilinear (const cairo_compositor_t *compositor,
-                                           cairo_composite_rectangles_t *composite,
-                                           const cairo_path_fixed_t *path,
-                                           cairo_fill_rule_t fill_rule,
-                                           double tolerance,
-                                           cairo_antialias_t antialias,
-                                           cairo_clip_t *clip)
+_draw_simple_quad_path (cairo_gl_context_t *ctx,
+                       cairo_gl_composite_t *setup,
+                       const cairo_path_fixed_t *path)
 {
-    cairo_gl_composite_t setup;
-    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
-    cairo_gl_context_t *ctx = NULL;
+    cairo_point_t triangle[3];
     cairo_int_status_t status;
-    int i;
-
-    status = _cairo_gl_composite_init (&setup,
-                                      composite->op,
-                                      dst,
-                                      FALSE /* assume_component_alpha */);
-    if (unlikely (status))
-       goto cleanup_setup;
-
-    status = _cairo_gl_composite_set_source (&setup,
-                                            composite->original_source_pattern,
-                                            &composite->source_sample_area,
-                                            &composite->bounded,
-                                            TRUE);
-    if (unlikely (status))
-       goto cleanup_setup;
-
-    status = _cairo_gl_composite_begin_multisample (&setup, &ctx,
-       antialias != CAIRO_ANTIALIAS_NONE);
-    if (unlikely (status))
-       goto cleanup_setup;
-
-    for (i = 0; i < clip->num_boxes; i++) {
-       status = _cairo_gl_msaa_compositor_draw_quad (ctx, &setup,
-                                                     &clip->boxes[i]);
-       if (unlikely (status))
-           goto cleanup_setup;
-    }
-
-cleanup_setup:
-    _cairo_gl_composite_fini (&setup);
-
-    if (ctx)
-       status = _cairo_gl_context_release (ctx, status);
+    const cairo_point_t *points;
+
+    points = cairo_path_head (path)->points;
+    triangle[0] = points[0];
+    triangle[1] = points[1];
+    triangle[2] = points[2];
+    status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
+    if (status)
+       return status;
 
-    return status;
+    triangle[0] = points[2];
+    triangle[1] = points[3];
+    triangle[2] = points[0];
+    return _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
 }
 
 static cairo_int_status_t
@@ -914,9 +873,9 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t    *compositor,
     cairo_gl_composite_t setup;
     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
     cairo_gl_context_t *ctx = NULL;
-    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
+    cairo_int_status_t status;
     cairo_traps_t traps;
-    cairo_bool_t use_color_attr = FALSE;
+    cairo_bool_t draw_path_with_traps;
 
     if (! can_use_msaa_compositor (dst, antialias))
        return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -942,48 +901,19 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t  *compositor,
        return _paint_back_unbounded_surface (compositor, composite, surface);
     }
 
-    if (_cairo_path_fixed_fill_is_rectilinear (path) &&
-       composite->clip != NULL &&
-       composite->clip->num_boxes == 1 &&
-       composite->clip->path == NULL) {
-       cairo_clip_t *clip = _cairo_clip_copy (composite->clip);
-       clip = _cairo_clip_intersect_rectilinear_path (clip,
-                                                      path,
-                                                      fill_rule,
-                                                      antialias);
-       if (clip->num_boxes)
-               status = _cairo_gl_msaa_compositor_fill_rectilinear (compositor,
-                                                                    composite,
-                                                                    path,
-                                                                    fill_rule,
-                                                                    tolerance,
-                                                                    antialias,
-                                                                    clip);
-       _cairo_clip_destroy (clip);
+    draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path);
 
-       return status;
+    if (draw_path_with_traps) {
+       _cairo_traps_init (&traps);
+       status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
+       if (unlikely (status))
+           goto cleanup_traps;
     }
 
     status = _cairo_gl_composite_init (&setup,
                                       composite->op,
                                       dst,
                                       FALSE /* assume_component_alpha */);
-    if (unlikely (status)) {
-        _cairo_gl_composite_fini (&setup);
-       return status;
-    }
-
-    _cairo_traps_init (&traps);
-
-    if (_cairo_path_fixed_fill_is_rectilinear (path)) {
-       status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
-                                                             fill_rule,
-                                                             antialias,
-                                                             &traps);
-       use_color_attr = TRUE;
-    } else
-       status = _cairo_path_fixed_fill_to_traps (path, fill_rule,
-                                                 tolerance, &traps);
     if (unlikely (status))
        goto cleanup_traps;
 
@@ -991,18 +921,22 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t  *compositor,
                                             composite->original_source_pattern,
                                             &composite->source_sample_area,
                                             &composite->bounded,
-                                            use_color_attr);
+                                            !draw_path_with_traps);
     if (unlikely (status))
        goto cleanup_setup;
 
     _cairo_gl_msaa_compositor_set_clip (composite, &setup);
+    if (antialias != CAIRO_ANTIALIAS_NONE)
+       _cairo_gl_composite_set_multisample (&setup);
 
-    status = _cairo_gl_composite_begin_multisample (&setup, &ctx,
-       antialias != CAIRO_ANTIALIAS_NONE);
+    status = _cairo_gl_composite_begin (&setup, &ctx);
     if (unlikely (status))
        goto cleanup_setup;
 
-    status = _draw_traps (ctx, &setup, &traps);
+    if (! draw_path_with_traps)
+       status = _draw_simple_quad_path (ctx, &setup, path);
+    else
+       status = _draw_traps (ctx, &setup, &traps);
     if (unlikely (status))
         goto cleanup_setup;
 
@@ -1013,7 +947,8 @@ cleanup_setup:
        status = _cairo_gl_context_release (ctx, status);
 
 cleanup_traps:
-    _cairo_traps_fini (&traps);
+    if (draw_path_with_traps)
+       _cairo_traps_fini (&traps);
 
     return status;
 }
old mode 100644 (file)
new mode 100755 (executable)
index d77db14..04cf353
@@ -50,7 +50,6 @@
 #include "cairo-image-surface-private.h"
 #include "cairo-surface-backend-private.h"
 #include "cairo-surface-offset-private.h"
-#include "cairo-surface-snapshot-inline.h"
 #include "cairo-surface-subsurface-inline.h"
 #include "cairo-rtree-private.h"
 
@@ -131,6 +130,7 @@ _cairo_gl_copy_texture (cairo_gl_surface_t *dst,
     cairo_gl_dispatch_t *dispatch;
     cairo_gl_surface_t *cache_surface;
     cairo_gl_surface_t *target;
+    cairo_surface_pattern_t pattern;
 
     if (! _cairo_gl_surface_is_texture (image))
        return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -148,21 +148,31 @@ _cairo_gl_copy_texture (cairo_gl_surface_t *dst,
     if (replace)
        _cairo_gl_composite_flush (ctx_out);
 
-    /* Bind framebuffer of source image. */
+    image->needs_to_cache = FALSE;
     dispatch = &ctx_out->dispatch;
     cache_surface = ctx_out->image_cache.surface;
     target = ctx_out->current_target;
 
-    _cairo_gl_ensure_framebuffer (ctx_out, image);
-    dispatch->BindFramebuffer (GL_FRAMEBUFFER, image->fb);
-    glBindTexture (ctx_out->tex_target, cache_surface->tex);
+    /* paint image to dst */
+    _cairo_pattern_init_for_surface (&pattern, &image->base);
+    cairo_matrix_init_translate (&pattern.base.matrix, -x, -y);
 
-    glCopyTexSubImage2D (ctx_out->tex_target, 0, x, y, 0, 0, width, height);
+    status = _cairo_surface_paint (&cache_surface->base,
+                                   CAIRO_OPERATOR_SOURCE,
+                                   &pattern.base, NULL);
+
+    _cairo_gl_composite_flush (ctx_out);
+    _cairo_pattern_fini (&pattern.base);
+
+    /* restore ctx status */
     dispatch->BindFramebuffer (GL_FRAMEBUFFER, target->fb);
     ctx_out->current_target = target;
     *ctx = ctx_out;
 
-    return CAIRO_INT_STATUS_SUCCESS;
+    if (unlikely (status))
+        return _cairo_gl_context_release (ctx_out, status);
+
+    return status;
 }
 
 static cairo_int_status_t
@@ -262,6 +272,7 @@ _cairo_gl_image_cache_add_image (cairo_gl_context_t *ctx,
        (*image_node)->p1.y /= IMAGE_CACHE_HEIGHT;
        (*image_node)->p2.y /= IMAGE_CACHE_HEIGHT;
     }
+    (*image_node)->user_data_removed = FALSE;
     image->content_changed = FALSE;
     /* Set user data. */
     status = cairo_surface_set_user_data (&image->base,
@@ -308,9 +319,7 @@ _cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand,
            _cairo_gl_surface_create_scratch (ctx,
                                              sub->target->content,
                                              sub->extents.width,
-                                             sub->extents.height,
-                                             FALSE);
-
+                                             sub->extents.height);
        if (surface->base.status)
            return _cairo_gl_context_release (ctx, surface->base.status);
 
@@ -388,12 +397,8 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
     }
 
     surface = (cairo_gl_surface_t *) sub->target;
-    if (surface->base.device &&
-        (surface->base.device != dst->base.device ||
-         (! surface->tex && ! surface->bounded_tex)))
-       return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    if (! _cairo_gl_surface_is_texture (surface))
+    if (surface->base.device && (surface->base.device != dst->base.device ||
+         (! _cairo_gl_surface_is_texture (surface) && ! surface->bounded_tex)))
        return CAIRO_INT_STATUS_UNSUPPORTED;
 
     status = _resolve_multisampling (surface);
@@ -478,33 +483,15 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
        if (_cairo_surface_is_subsurface (&surface->base))
            return _cairo_gl_subsurface_operand_init (operand, _src, dst,
                                                      sample, extents);
-       else if (_cairo_surface_is_snapshot (src->surface)) {
-           cairo_surface_snapshot_t *surface_snapshot;
-           cairo_pattern_t *sub_pattern;
-
-           surface_snapshot = (cairo_surface_snapshot_t *)src->surface;
-           surface = (cairo_gl_surface_t *)surface_snapshot->target;
-           if (surface->base.type != CAIRO_SURFACE_TYPE_GL)
-               return CAIRO_INT_STATUS_UNSUPPORTED;
-
-           if (_cairo_surface_is_subsurface (&surface->base)) {
-               sub_pattern = cairo_pattern_create_for_surface (&surface->base);
-               status = _cairo_gl_subsurface_operand_init (operand,
-                                                           sub_pattern,
-                                                           dst,
-                                                           sample,
-                                                           extents);
-               cairo_pattern_destroy (sub_pattern);
-               return status;
-           }
-       }
-       else
-           return CAIRO_INT_STATUS_UNSUPPORTED;
+
+       return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    if (surface->base.device &&
-        (surface->base.device != dst->base.device ||
-         (! surface->tex && ! surface->bounded_tex)))
+    if (surface->base.device && surface->base.device != dst->base.device)
+       return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (surface->base.device && ! _cairo_gl_surface_is_texture (surface) &&
+       ! surface->bounded_tex)
        return CAIRO_INT_STATUS_UNSUPPORTED;
 
     status = _resolve_multisampling (surface);
@@ -568,7 +555,7 @@ _cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
     cairo_gl_context_t *ctx;
     cairo_image_surface_t *image;
     cairo_bool_t src_is_gl_surface = FALSE;
-    pixman_format_code_t pixman_format;
+    cairo_rectangle_int_t map_extents;
 
     if (_src->type == CAIRO_PATTERN_TYPE_SURFACE) {
        cairo_surface_t* src_surface = ((cairo_surface_pattern_t *) _src)->surface;
@@ -582,31 +569,10 @@ _cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
     surface = (cairo_gl_surface_t *)
        _cairo_gl_surface_create_scratch (ctx,
                                          CAIRO_CONTENT_COLOR_ALPHA,
-                                         extents->width, extents->height,
-                                         FALSE);
-
-    /* XXX: This is a hack for driver that does not support PBO, we
-       don't need an extra step of downloading newly created texture
-       to image, we can create image directly. */
-    if (! _cairo_is_little_endian ())
-       pixman_format = PIXMAN_r8g8b8a8;
-    else
-       pixman_format = PIXMAN_a8b8g8r8;
-    image = (cairo_image_surface_t*)
-       _cairo_image_surface_create_with_pixman_format (NULL,
-                                                       pixman_format,
-                                                       extents->width,
-                                                       extents->height,
-                                                       -1);
-    if (unlikely (image->base.status)) {
-       status = _cairo_gl_context_release (ctx, status);
-
-       /* The error status in the image is issue that caused the problem. */
-       status = image->base.status;
-
-       cairo_surface_destroy (&image->base);
-       goto fail;
-    }
+                                         extents->width, extents->height);
+    map_extents = *extents;
+    map_extents.x = map_extents.y = 0;
+    image = _cairo_surface_map_to_image (&surface->base, &map_extents);
 
     /* If the pattern is a GL surface, it belongs to some other GL context,
        so we need to release this device while we paint it to the image. */
@@ -727,6 +693,8 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
        cairo_matrix_t m;
        cairo_circle_double_t circles[2];
        double x0, y0, r0, dx, dy, dr;
+       double scale = 1.0;
+       cairo_radial_pattern_t *radial_pattern = (cairo_radial_pattern_t *)gradient;
 
        /*
         * Some fragment shader implementations use half-floats to
@@ -740,18 +708,35 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
        _cairo_gradient_pattern_fit_to_range (gradient, 8.,
                                              &operand->gradient.m, circles);
 
+       /*
+        * Instead of using scaled data that might introducing rounding
+        * errors, we use original data directly
+        */
+       if (circles[0].center.x)
+               scale = radial_pattern->cd1.center.x / circles[0].center.x;
+       else if (circles[0].center.y)
+               scale = radial_pattern->cd1.center.y / circles[0].center.y;
+       else if (circles[0].radius)
+               scale = radial_pattern->cd1.radius / circles[0].radius;
+       else if (circles[1].center.x)
+               scale = radial_pattern->cd2.center.x / circles[1].center.x;
+       else if (circles[1].center.y)
+               scale = radial_pattern->cd2.center.y / circles[1].center.y;
+       else if (circles[1].radius)
+               scale = radial_pattern->cd2.radius / circles[1].radius;
+
        x0 = circles[0].center.x;
        y0 = circles[0].center.y;
        r0 = circles[0].radius;
-       dx = circles[1].center.x - x0;
-       dy = circles[1].center.y - y0;
-       dr = circles[1].radius   - r0;
+       dx = radial_pattern->cd2.center.x - radial_pattern->cd1.center.x;
+       dy = radial_pattern->cd2.center.y - radial_pattern->cd1.center.y;
+       dr = radial_pattern->cd2.radius   - radial_pattern->cd1.radius;
 
-       operand->gradient.a = dx * dx + dy * dy - dr * dr;
+       operand->gradient.a = (dx * dx + dy * dy - dr * dr)/(scale * scale);
        operand->gradient.radius_0 = r0;
-       operand->gradient.circle_d.center.x = dx;
-       operand->gradient.circle_d.center.y = dy;
-       operand->gradient.circle_d.radius   = dr;
+       operand->gradient.circle_d.center.x = dx / scale;
+       operand->gradient.circle_d.center.y = dy / scale;
+       operand->gradient.circle_d.radius       = dr / scale;
 
        if (operand->gradient.a == 0)
            operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
@@ -956,12 +941,7 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
                                   cairo_gl_operand_t *operand,
                                   cairo_gl_tex_t      tex_unit)
 {
-    char uniform_name[50];
-    char *custom_part;
-    static const char *names[] = { "source", "mask" };
-
-    strcpy (uniform_name, names[tex_unit]);
-    custom_part = uniform_name + strlen (names[tex_unit]);
+    cairo_gl_shader_slot_t slot = CAIRO_GL_SHADER_SLOT_SOURCE_CONSTANT;
 
     switch (operand->type) {
     default:
@@ -971,9 +951,9 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
         break;
     case CAIRO_GL_OPERAND_CONSTANT:
         if (!operand->use_color_attribute) {
-            strcpy (custom_part, "_constant");
+            slot = tex_unit == CAIRO_GL_TEX_SOURCE ? CAIRO_GL_SHADER_SLOT_SOURCE_CONSTANT : CAIRO_GL_SHADER_SLOT_MASK_CONSTANT;
             _cairo_gl_shader_bind_vec4 (ctx,
-                                        uniform_name,
+                                        slot,
                                         operand->constant.color[0],
                                         operand->constant.color[1],
                                         operand->constant.color[2],
@@ -982,22 +962,22 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
         break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-       strcpy (custom_part, "_a");
+       slot = tex_unit == CAIRO_GL_TEX_SOURCE ? CAIRO_GL_SHADER_SLOT_SOURCE_A : CAIRO_GL_SHADER_SLOT_MASK_A;
        _cairo_gl_shader_bind_float  (ctx,
-                                     uniform_name,
+                      slot,
                                      operand->gradient.a);
        /* fall through */
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
-       strcpy (custom_part, "_circle_d");
-       _cairo_gl_shader_bind_vec3   (ctx,
-                                     uniform_name,
+       slot = tex_unit == CAIRO_GL_TEX_SOURCE ? CAIRO_GL_SHADER_SLOT_SOURCE_CIRCLE_D : CAIRO_GL_SHADER_SLOT_MASK_CIRCLE_D;
+       _cairo_gl_shader_bind_vec3 (ctx,
+                      slot,
                                      operand->gradient.circle_d.center.x,
                                      operand->gradient.circle_d.center.y,
                                      operand->gradient.circle_d.radius);
-       strcpy (custom_part, "_radius_0");
-       _cairo_gl_shader_bind_float  (ctx,
-                                     uniform_name,
-                                     operand->gradient.radius_0);
+       slot = tex_unit == CAIRO_GL_TEX_SOURCE ? CAIRO_GL_SHADER_SLOT_SOURCE_RADIUS_0 : CAIRO_GL_SHADER_SLOT_MASK_RADIUS_0;
+       _cairo_gl_shader_bind_float (ctx,
+                                         slot,
+                                         operand->gradient.radius_0);
         /* fall through */
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
     case CAIRO_GL_OPERAND_TEXTURE:
@@ -1019,8 +999,8 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
                width = operand->gradient.gradient->cache_entry.size,
                height = 1;
            }
-           strcpy (custom_part, "_texdims");
-           _cairo_gl_shader_bind_vec2 (ctx, uniform_name, width, height);
+           slot = tex_unit == CAIRO_GL_TEX_SOURCE ? CAIRO_GL_SHADER_SLOT_SOURCE_TEXDIMS : CAIRO_GL_SHADER_SLOT_MASK_TEXDIMS;
+           _cairo_gl_shader_bind_vec2 (ctx, slot, width, height);
        }
         break;
     }
@@ -1096,6 +1076,67 @@ _cairo_gl_operand_get_vertex_size (cairo_gl_operand_t *operand)
     }
 }
 
+void
+_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
+                        GLfloat ** vb,
+                        GLfloat x,
+                        GLfloat y)
+{
+    switch (operand->type) {
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+       break;
+    case CAIRO_GL_OPERAND_CONSTANT: {
+        union fi {
+            float f;
+            GLbyte bytes[4];
+        } fi;
+        if (operand->use_color_attribute) {
+            fi.bytes[0] = operand->constant.color[0] * 255;
+            fi.bytes[1] = operand->constant.color[1] * 255;
+            fi.bytes[2] = operand->constant.color[2] * 255;
+            fi.bytes[3] = operand->constant.color[3] * 255;
+            *(*vb)++ = fi.f;
+        }
+        break;
+    }
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+        {
+           double s = x;
+           double t = y;
+
+           cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
+
+           *(*vb)++ = s;
+           *(*vb)++ = t;
+        }
+       break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+        {
+            cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
+            double s = x;
+            double t = y;
+
+            cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
+            *(*vb)++ = s;
+            *(*vb)++ = t;
+
+           if (operand->texture.use_atlas) {
+               *(*vb)++ = operand->texture.p1.x;
+               *(*vb)++ = operand->texture.p1.y;
+               *(*vb)++ = operand->texture.p2.x;
+               *(*vb)++ = operand->texture.p2.y;
+           }
+        }
+        break;
+    }
+}
+
 static inline cairo_int_status_t
 _cairo_gl_context_get_image_cache (cairo_gl_context_t     *ctx,
                                   cairo_gl_image_cache_t  **cache_out)
old mode 100644 (file)
new mode 100755 (executable)
index 5fa92b2..704dd5a
  * Random number that is hopefully big enough to not cause many cache evictions. */
 #define CAIRO_GL_MAX_SHADERS_PER_CONTEXT 64
 
-/* VBO size that we allocate, smaller size means we gotta flush more often */
-#define CAIRO_GL_VBO_SIZE (256*1024)
+/* VBO size that we allocate, smaller size means we gotta flush more often,
+ * but larger means hogging more memory and can cause trouble for drivers
+ * (especially on embedded devices). */
+#define CAIRO_GL_VBO_SIZE (16*1024)
 
 #define IMAGE_CACHE_WIDTH 2048
 #define IMAGE_CACHE_HEIGHT 2048
@@ -111,6 +113,41 @@ typedef enum cairo_gl_flavor {
     CAIRO_GL_FLAVOR_ES = 2
 } cairo_gl_flavor_t;
 
+/* Shortcuts for shader uniform locations. Table filled lazily on first access.
+ * Using these slots saves per-draw calls to glGetUniformLocation(). */
+typedef enum cairo_gl_shader_slot_t {
+    /* "ModelViewProjectionMatrix" */
+    CAIRO_GL_SHADER_SLOT_MVPMAT = 0,
+    /* "source_texdims" */
+    CAIRO_GL_SHADER_SLOT_SOURCE_TEXDIMS,
+    /* "source_constant" */
+    CAIRO_GL_SHADER_SLOT_SOURCE_CONSTANT,
+    /* "source_sampler" */
+    CAIRO_GL_SHADER_SLOT_SOURCE_SAMPLER,
+    /* "source_a" */
+    CAIRO_GL_SHADER_SLOT_SOURCE_A,
+    /* "source_circle_d" */
+    CAIRO_GL_SHADER_SLOT_SOURCE_CIRCLE_D,
+    /* "source_radius_0" */
+    CAIRO_GL_SHADER_SLOT_SOURCE_RADIUS_0,
+    /* "mask_texdims" */
+    CAIRO_GL_SHADER_SLOT_MASK_TEXDIMS,
+    /* "mask_constant" */
+    CAIRO_GL_SHADER_SLOT_MASK_CONSTANT,
+    /* "mask_sampler" */
+    CAIRO_GL_SHADER_SLOT_MASK_SAMPLER,
+    /* "mask_a" */
+    CAIRO_GL_SHADER_SLOT_MASK_A,
+    /* "mask_circle_d" */
+    CAIRO_GL_SHADER_SLOT_MASK_CIRCLE_D,
+    /* "mask_radius_0" */
+    CAIRO_GL_SHADER_SLOT_MASK_RADIUS_0,
+
+    CAIRO_GL_SHADER_SLOT_MAX
+
+} cairo_gl_shader_slot_t;
+
+
 /* Indices for vertex attributes used by BindAttribLocation etc */
 enum {
     CAIRO_GL_VERTEX_ATTRIB_INDEX = 0,
@@ -198,6 +235,7 @@ struct _cairo_gl_surface {
     cairo_bool_t supports_msaa;
     cairo_bool_t msaa_active; /* Whether the multisampling
                                 framebuffer is active or not. */
+    cairo_clip_t *clip_on_stencil_buffer;
 
     int owns_tex;
     cairo_bool_t needs_update;
@@ -225,6 +263,11 @@ typedef enum cairo_gl_tex {
 typedef struct cairo_gl_shader {
     GLuint fragment_shader;
     GLuint program;
+    /* Storage table for uniform locations.*/
+    GLint uniforms[CAIRO_GL_SHADER_SLOT_MAX];
+    /* Validity table for the above: initially set at 0, set to
+     * nonzero once corresponding item in uniforms is looked up. */
+    char uniforms_valid[CAIRO_GL_SHADER_SLOT_MAX];
 } cairo_gl_shader_t;
 
 typedef struct cairo_gl_image_cache {
@@ -287,6 +330,21 @@ typedef enum cairo_gl_primitive_type {
     CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS
 } cairo_gl_primitive_type_t;
 
+typedef void (*cairo_gl_emit_rect_t) (cairo_gl_context_t *ctx,
+                                     GLfloat x1, GLfloat y1,
+                                     GLfloat x2, GLfloat y2);
+
+typedef void (*cairo_gl_emit_span_t) (cairo_gl_context_t *ctx,
+                                     GLfloat x1, GLfloat y1,
+                                     GLfloat x2, GLfloat y2,
+                                     uint8_t alpha);
+
+typedef void (*cairo_gl_emit_glyph_t) (cairo_gl_context_t *ctx,
+                                      GLfloat x1, GLfloat y1,
+                                      GLfloat x2, GLfloat y2,
+                                      GLfloat glyph_x1, GLfloat glyph_y1,
+                                      GLfloat glyph_x2, GLfloat glyph_y2);
+
 #define cairo_gl_var_type_hash(src,mask,src_atlas_extend,mask_atlas_extend,src_use_atlas,mask_use_atlas, spans,dest) ((spans) << 11) | ((mask) << 9 | (src << 7) | (mask_atlas_extend << 5) | (src_atlas_extend << 3) | (mask_use_atlas << 2) | (src_use_atlas << 1) | (dest))
 #define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_TEXCOORDS << 11) | (CAIRO_GL_VAR_TEXCOORDS << 9) | (CAIRO_GL_VAR_TEXCOORDS << 5) | CAIRO_GL_VAR_TEXCOORDS)
 
@@ -389,6 +447,9 @@ typedef struct _cairo_gl_states {
 
     cairo_bool_t depth_mask;
 
+    cairo_bool_t scissor_test_enabled;
+    cairo_bool_t stencil_test_enabled;
+
 } cairo_gl_states_t;
 
 struct _cairo_gl_context {
@@ -440,19 +501,10 @@ struct _cairo_gl_context {
     cairo_bool_t has_map_buffer;
     cairo_bool_t has_packed_depth_stencil;
     cairo_bool_t has_npot_repeat;
+    cairo_bool_t can_read_bgra;
 
     cairo_bool_t thread_aware;
 
-    /* GL stencil and depth buffers are shared among all surfaces
-       to preserve memory. In the future this could be a pool of renderbuffers
-       with an eviction policy. */
-    GLuint shared_depth_stencil;
-    int shared_depth_stencil_width;
-    int shared_depth_stencil_height;
-    GLuint shared_msaa_depth_stencil;
-    int shared_msaa_depth_stencil_width;
-    int shared_msaa_depth_stencil_height;
-
     cairo_gl_image_cache_t image_cache;
     cairo_gl_draw_mode_t draw_mode;
     cairo_gl_states_t states_cache;
@@ -475,6 +527,7 @@ typedef struct _cairo_gl_composite {
     cairo_bool_t spans;
 
     cairo_clip_t *clip;
+    cairo_bool_t multisample;
 } cairo_gl_composite_t;
 
 typedef struct _cairo_gl_font {
@@ -582,6 +635,20 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
                                   cairo_gl_surface_t *surface,
                                   cairo_bool_t multisampling);
 
+cairo_private cairo_gl_emit_rect_t
+_cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx);
+
+cairo_private void
+_cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
+                            GLfloat x1, GLfloat y1,
+                            GLfloat x2, GLfloat y2);
+
+cairo_private cairo_gl_emit_span_t
+_cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx);
+
+cairo_private cairo_gl_emit_glyph_t
+_cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx);
+
 cairo_private void
 _cairo_gl_context_activate (cairo_gl_context_t *ctx,
                             cairo_gl_tex_t      tex_unit);
@@ -593,11 +660,41 @@ cairo_private cairo_bool_t
 _cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
                          cairo_gl_surface_t *surface);
 
-cairo_private void
-_disable_scissor_buffer (void);
+static cairo_always_inline void
+_disable_stencil_buffer (cairo_gl_context_t *ctx)
+{
+    if (ctx->states_cache.stencil_test_enabled == TRUE) {
+        glDisable (GL_STENCIL_TEST);
+        ctx->states_cache.stencil_test_enabled = FALSE;
+    }
+}
 
-cairo_private void
-_disable_stencil_buffer (void);
+static cairo_always_inline void
+_disable_scissor_buffer (cairo_gl_context_t *ctx)
+{
+    if (ctx->states_cache.scissor_test_enabled == TRUE) {
+        glDisable (GL_SCISSOR_TEST);
+        ctx->states_cache.scissor_test_enabled = FALSE;
+    }
+}
+
+static cairo_always_inline void
+_enable_stencil_buffer (cairo_gl_context_t *ctx)
+{
+    if (ctx->states_cache.stencil_test_enabled == FALSE) {
+        glEnable (GL_STENCIL_TEST);
+        ctx->states_cache.stencil_test_enabled = TRUE;
+    }
+}
+
+static cairo_always_inline void
+_enable_scissor_buffer (cairo_gl_context_t *ctx)
+{
+    if (ctx->states_cache.scissor_test_enabled == FALSE) {
+        glEnable (GL_SCISSOR_TEST);
+        ctx->states_cache.scissor_test_enabled = TRUE;
+    }
+}
 
 cairo_private cairo_status_t
 _cairo_gl_composite_init (cairo_gl_composite_t *setup,
@@ -608,6 +705,11 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
 cairo_private void
 _cairo_gl_composite_fini (cairo_gl_composite_t *setup);
 
+cairo_status_t
+_cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
+                                 cairo_operator_t op,
+                                 cairo_bool_t assume_component_alpha);
+
 cairo_private void
 _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
                                      cairo_region_t *clip_region);
@@ -644,33 +746,16 @@ _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
 cairo_private void
 _cairo_gl_composite_set_spans (cairo_gl_composite_t *setup);
 
+cairo_private void
+_cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup);
+
 cairo_private cairo_status_t
 _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
                            cairo_gl_context_t **ctx);
 
-cairo_private cairo_status_t
-_cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
-                                      cairo_gl_context_t **ctx_out,
-                                      cairo_bool_t multisampling);
-
-cairo_private void
-_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
-                               GLfloat x1,
-                               GLfloat y1,
-                               GLfloat x2,
-                               GLfloat y2,
-                               uint8_t alpha);
-
-cairo_private void
-_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
-                                GLfloat x1,
-                                GLfloat y1,
-                                GLfloat x2,
-                                GLfloat y2,
-                                GLfloat glyph_x1,
-                                GLfloat glyph_y1,
-                                GLfloat glyph_x2,
-                                GLfloat glyph_y2);
+cairo_status_t
+_cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
+                                    cairo_gl_context_t *ctx);
 
 cairo_private void
 _cairo_gl_composite_flush (cairo_gl_context_t *ctx);
@@ -744,16 +829,35 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
 
 cairo_private void
 _cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
-                            const char *name,
+                 cairo_gl_shader_slot_t slot,
                             float value);
 
 cairo_private void
+_cairo_gl_shader_bind_float_name (cairo_gl_context_t *ctx,
+                  const char *name,
+                  float value);
+
+cairo_private void
 _cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
-                           const char *name,
-                           float value0, float value1);
+                cairo_gl_shader_slot_t slot,
+                float value0,
+                float value1);
+
+cairo_private void
+_cairo_gl_shader_bind_vec2_name (cairo_gl_context_t *ctx,
+                const char *name,
+                float value0,
+                float value1);
 
 cairo_private void
 _cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
+                cairo_gl_shader_slot_t slot,
+                float value0,
+                float value1,
+                float value2);
+
+cairo_private void
+_cairo_gl_shader_bind_vec3_name (cairo_gl_context_t *ctx,
                            const char *name,
                            float value0,
                            float value1,
@@ -761,17 +865,33 @@ _cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
 
 cairo_private void
 _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
+                cairo_gl_shader_slot_t slot,
+                float value0, float value1,
+                float value2, float value3);
+
+cairo_private void
+_cairo_gl_shader_bind_vec4_name (cairo_gl_context_t *ctx,
                            const char *name,
                            float value0, float value1,
                            float value2, float value3);
 
 cairo_private void
 _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
+                  cairo_gl_shader_slot_t slot,
+                  cairo_matrix_t* m);
+
+cairo_private void
+_cairo_gl_shader_bind_matrix_name (cairo_gl_context_t *ctx,
                              const char *name,
                              cairo_matrix_t* m);
 
 cairo_private void
 _cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
+                cairo_gl_shader_slot_t slot,
+                GLfloat* gl_m);
+
+cairo_private void
+_cairo_gl_shader_bind_matrix4f_name (cairo_gl_context_t *ctx,
                                const char *name,
                                GLfloat* gl_m);
 
@@ -837,6 +957,12 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
                                   cairo_gl_tex_t      tex_unit);
 
 cairo_private void
+_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
+                        GLfloat ** vb,
+                        GLfloat x,
+                        GLfloat y);
+
+cairo_private void
 _cairo_gl_operand_copy (cairo_gl_operand_t *dst,
                        const cairo_gl_operand_t *src);
 
@@ -904,8 +1030,13 @@ cairo_private cairo_surface_t *
 _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
                                  cairo_content_t       content,
                                  int                   width,
-                                 int                   height,
-                                 cairo_bool_t          true_alpha);
+                                 int                   height);
+
+cairo_private cairo_surface_t *
+_cairo_gl_surface_create_scratch_for_caching (cairo_gl_context_t *ctx,
+                                             cairo_content_t content,
+                                             int width,
+                                             int height);
 
 cairo_private cairo_surface_t *
 _cairo_gl_pattern_to_source (cairo_surface_t *dst,
@@ -918,12 +1049,15 @@ _cairo_gl_pattern_to_source (cairo_surface_t *dst,
 cairo_private cairo_int_status_t
 _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
                                     cairo_gl_composite_t *setup,
-                                    cairo_clip_t *clip,
-                                    cairo_traps_t *traps);
+                                    cairo_clip_t *clip);
 
 cairo_private cairo_surface_t *
 _cairo_gl_white_source (void);
 
+cairo_private void
+_cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
+                               const cairo_rectangle_int_t *r);
+
 static inline cairo_gl_operand_t *
 source_to_operand (cairo_surface_t *surface)
 {
@@ -937,9 +1071,6 @@ _cairo_gl_glyph_cache_unlock (cairo_gl_glyph_cache_t *cache)
     _cairo_rtree_unpin (&cache->rtree);
 }
 
-cairo_private void
-_cairo_gl_scissor_to_extents (cairo_gl_surface_t       *surface,
-                             const cairo_rectangle_int_t       *extents);
 
 
 cairo_private cairo_bool_t
old mode 100644 (file)
new mode 100755 (executable)
index feebdfa..247297f
 #include "cairo-error-private.h"
 #include "cairo-output-stream-private.h"
 
+/* Lookup table of shader slot names, must be in same order as cairo_gl_shader_t enum. */
+static const char * _cairo_gl_shader_slot_names[CAIRO_GL_SHADER_SLOT_MAX] =
+{
+        "ModelViewProjectionMatrix",
+        "source_texdims",
+        "source_constant",
+        "source_sampler",
+        "source_a",
+        "source_circle_d",
+        "source_radius_0",
+        "mask_texdims",
+        "mask_constant",
+        "mask_sampler",
+        "mask_a",
+        "mask_circle_d",
+        "mask_radius_0"
+};
+
+static GLint _cairo_gl_lookup_shader_uniform(cairo_gl_context_t *ctx, cairo_gl_shader_t *shader, cairo_gl_shader_slot_t slot)
+{
+    if(shader->uniforms_valid[slot] == 0)
+    {
+        shader->uniforms[slot] = ctx->dispatch.GetUniformLocation (shader->program, _cairo_gl_shader_slot_names[slot]);
+        shader->uniforms_valid[slot] = 1;
+    }
+    return shader->uniforms[slot];
+}
+
+
 static cairo_status_t
 _cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
                                   cairo_gl_shader_t *shader,
@@ -140,6 +169,8 @@ _cairo_gl_shader_init (cairo_gl_shader_t *shader)
 {
     shader->fragment_shader = 0;
     shader->program = 0;
+    memset (shader->uniforms, 0, sizeof (shader->uniforms));
+    memset (shader->uniforms_valid, 0, sizeof (shader->uniforms_valid));
 }
 
 cairo_status_t
@@ -1030,12 +1061,12 @@ _cairo_gl_shader_set_samplers (cairo_gl_context_t *ctx,
     glGetIntegerv (GL_CURRENT_PROGRAM, &saved_program);
     dispatch->UseProgram (shader->program);
 
-    location = dispatch->GetUniformLocation (shader->program, "source_sampler");
+    location = _cairo_gl_lookup_shader_uniform (ctx, shader, CAIRO_GL_SHADER_SLOT_SOURCE_SAMPLER);
     if (location != -1) {
        dispatch->Uniform1i (location, CAIRO_GL_TEX_SOURCE);
     }
 
-    location = dispatch->GetUniformLocation (shader->program, "mask_sampler");
+    location = _cairo_gl_lookup_shader_uniform (ctx, shader, CAIRO_GL_SHADER_SLOT_MASK_SAMPLER);
     if (location != -1) {
        dispatch->Uniform1i (location, CAIRO_GL_TEX_MASK);
     }
@@ -1045,6 +1076,17 @@ _cairo_gl_shader_set_samplers (cairo_gl_context_t *ctx,
 
 void
 _cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
+                 cairo_gl_shader_slot_t slot,
+                 float value)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+    assert (location != -1);
+    dispatch->Uniform1f (location, value);
+}
+
+void
+_cairo_gl_shader_bind_float_name (cairo_gl_context_t *ctx,
                             const char *name,
                             float value)
 {
@@ -1057,6 +1099,18 @@ _cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
 
 void
 _cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
+                cairo_gl_shader_slot_t slot,
+                float value0,
+                float value1)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+    assert (location != -1);
+    dispatch->Uniform2f (location, value0, value1);
+}
+
+void
+_cairo_gl_shader_bind_vec2_name (cairo_gl_context_t *ctx,
                            const char *name,
                            float value0,
                            float value1)
@@ -1070,6 +1124,19 @@ _cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
 
 void
 _cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
+                cairo_gl_shader_slot_t slot,
+                float value0,
+                float value1,
+                float value2)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+    assert (location != -1);
+    dispatch->Uniform3f (location, value0, value1, value2);
+}
+
+void
+_cairo_gl_shader_bind_vec3_name (cairo_gl_context_t *ctx,
                            const char *name,
                            float value0,
                            float value1,
@@ -1084,6 +1151,18 @@ _cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
 
 void
 _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
+                cairo_gl_shader_slot_t slot,
+                float value0, float value1,
+                float value2, float value3)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+    assert (location != -1);
+    dispatch->Uniform4f (location, value0, value1, value2, value3);
+}
+
+void
+_cairo_gl_shader_bind_vec4_name (cairo_gl_context_t *ctx,
                            const char *name,
                            float value0, float value1,
                            float value2, float value3)
@@ -1097,6 +1176,21 @@ _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
 
 void
 _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
+                  cairo_gl_shader_slot_t slot, cairo_matrix_t* m)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+
+    float gl_m[9] = {
+    m->xx, m->xy, m->x0,
+    m->yx, m->yy, m->y0,
+    0,     0,     1};
+    assert (location != -1);
+    dispatch->UniformMatrix3fv (location, 1, GL_TRUE, gl_m);
+}
+
+void
+_cairo_gl_shader_bind_matrix_name (cairo_gl_context_t *ctx,
                              const char *name, cairo_matrix_t* m)
 {
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
@@ -1105,14 +1199,23 @@ _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
     float gl_m[9] = {
        m->xx, m->xy, m->x0,
        m->yx, m->yy, m->y0,
-       0,     0,     1
-    };
+       0,     0,     1};
     assert (location != -1);
     dispatch->UniformMatrix3fv (location, 1, GL_TRUE, gl_m);
 }
 
 void
 _cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
+                cairo_gl_shader_slot_t slot, GLfloat* gl_m)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = _cairo_gl_lookup_shader_uniform (ctx, ctx->current_shader, slot);
+    assert (location != -1);
+    dispatch->UniformMatrix4fv (location, 1, GL_FALSE, gl_m);
+}
+
+void
+_cairo_gl_shader_bind_matrix4f_name (cairo_gl_context_t *ctx,
                                const char *name, GLfloat* gl_m)
 {
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
index 861d697..a0bb123 100644 (file)
@@ -57,6 +57,8 @@ typedef struct _cairo_gl_span_renderer {
     cairo_gl_composite_t setup;
     double opacity;
 
+    cairo_gl_emit_span_t emit;
+
     int xmin, xmax;
     int ymin, ymax;
 
@@ -70,16 +72,17 @@ _cairo_gl_bounded_opaque_spans (void *abstract_renderer,
                                unsigned num_spans)
 {
     cairo_gl_span_renderer_t *r = abstract_renderer;
+    cairo_gl_emit_span_t emit = r->emit;
 
     if (num_spans == 0)
        return CAIRO_STATUS_SUCCESS;
 
     do {
        if (spans[0].coverage) {
-            _cairo_gl_composite_emit_rect (r->ctx,
-                                           spans[0].x, y,
-                                           spans[1].x, y + height,
-                                           spans[0].coverage);
+           emit (r->ctx,
+                 spans[0].x, y,
+                 spans[1].x, y + height,
+                 spans[0].coverage);
        }
 
        spans++;
@@ -95,16 +98,17 @@ _cairo_gl_bounded_spans (void *abstract_renderer,
                         unsigned num_spans)
 {
     cairo_gl_span_renderer_t *r = abstract_renderer;
+    cairo_gl_emit_span_t emit = r->emit;
 
     if (num_spans == 0)
        return CAIRO_STATUS_SUCCESS;
 
     do {
        if (spans[0].coverage) {
-            _cairo_gl_composite_emit_rect (r->ctx,
-                                           spans[0].x, y,
-                                           spans[1].x, y + height,
-                                           r->opacity * spans[0].coverage);
+           emit (r->ctx,
+                 spans[0].x, y,
+                 spans[1].x, y + height,
+                 r->opacity * spans[0].coverage);
        }
 
        spans++;
@@ -120,40 +124,41 @@ _cairo_gl_unbounded_spans (void *abstract_renderer,
                           unsigned num_spans)
 {
     cairo_gl_span_renderer_t *r = abstract_renderer;
+    cairo_gl_emit_span_t emit = r->emit;
 
     if (y > r->ymin) {
-        _cairo_gl_composite_emit_rect (r->ctx,
-                                       r->xmin, r->ymin,
-                                       r->xmax, y,
-                                       0);
+       emit (r->ctx,
+             r->xmin, r->ymin,
+             r->xmax, y,
+             0);
     }
 
     if (num_spans == 0) {
-        _cairo_gl_composite_emit_rect (r->ctx,
-                                       r->xmin, y,
-                                       r->xmax, y + height,
-                                       0);
+       emit (r->ctx,
+             r->xmin, y,
+             r->xmax, y + height,
+             0);
     } else {
         if (spans[0].x != r->xmin) {
-            _cairo_gl_composite_emit_rect (r->ctx,
-                                           r->xmin, y,
-                                           spans[0].x,     y + height,
-                                           0);
+           emit (r->ctx,
+                 r->xmin, y,
+                 spans[0].x,     y + height,
+                 0);
         }
 
         do {
-            _cairo_gl_composite_emit_rect (r->ctx,
-                                           spans[0].x, y,
-                                           spans[1].x, y + height,
-                                           r->opacity * spans[0].coverage);
+           emit (r->ctx,
+                 spans[0].x, y,
+                 spans[1].x, y + height,
+                 r->opacity * spans[0].coverage);
             spans++;
         } while (--num_spans > 1);
 
         if (spans[0].x != r->xmax) {
-            _cairo_gl_composite_emit_rect (r->ctx,
-                                           spans[0].x,     y,
-                                           r->xmax, y + height,
-                                           0);
+           emit (r->ctx,
+                 spans[0].x,     y,
+                 r->xmax, y + height,
+                 0);
         }
     }
 
@@ -169,40 +174,41 @@ _cairo_gl_clipped_spans (void *abstract_renderer,
                           unsigned num_spans)
 {
     cairo_gl_span_renderer_t *r = abstract_renderer;
+    cairo_gl_emit_span_t emit = r->emit;
 
     if (y > r->ymin) {
-        _cairo_gl_composite_emit_rect (r->ctx,
-                                       r->xmin, r->ymin,
-                                       r->xmax, y,
-                                       0);
+       emit (r->ctx,
+             r->xmin, r->ymin,
+             r->xmax, y,
+             0);
     }
 
     if (num_spans == 0) {
-        _cairo_gl_composite_emit_rect (r->ctx,
-                                       r->xmin, y,
-                                       r->xmax, y + height,
-                                       0);
+       emit (r->ctx,
+             r->xmin, y,
+             r->xmax, y + height,
+             0);
     } else {
         if (spans[0].x != r->xmin) {
-            _cairo_gl_composite_emit_rect (r->ctx,
-                                           r->xmin, y,
-                                           spans[0].x,     y + height,
-                                           0);
+           emit (r->ctx,
+                 r->xmin, y,
+                 spans[0].x,     y + height,
+                 0);
         }
 
         do {
-            _cairo_gl_composite_emit_rect (r->ctx,
-                                           spans[0].x, y,
-                                           spans[1].x, y + height,
-                                           r->opacity * spans[0].coverage);
+           emit (r->ctx,
+                 spans[0].x, y,
+                 spans[1].x, y + height,
+                 r->opacity * spans[0].coverage);
             spans++;
         } while (--num_spans > 1);
 
         if (spans[0].x != r->xmax) {
-            _cairo_gl_composite_emit_rect (r->ctx,
-                                           spans[0].x,     y,
-                                           r->xmax, y + height,
-                                           0);
+           emit (r->ctx,
+                 spans[0].x,     y,
+                 r->xmax, y + height,
+                 0);
         }
     }
 
@@ -214,12 +220,13 @@ static cairo_status_t
 _cairo_gl_finish_unbounded_spans (void *abstract_renderer)
 {
     cairo_gl_span_renderer_t *r = abstract_renderer;
+    cairo_gl_emit_span_t emit = r->emit;
 
     if (r->ymax > r->ymin) {
-        _cairo_gl_composite_emit_rect (r->ctx,
-                                       r->xmin, r->ymin,
-                                       r->xmax, r->ymax,
-                                       0);
+       emit (r->ctx,
+             r->xmin, r->ymin,
+             r->xmax, r->ymax,
+             0);
     }
 
     return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
@@ -238,6 +245,7 @@ emit_aligned_boxes (cairo_gl_context_t *ctx,
                    const cairo_boxes_t *boxes)
 {
     const struct _cairo_boxes_chunk *chunk;
+    cairo_gl_emit_rect_t emit = _cairo_gl_context_choose_emit_rect (ctx);
     int i;
 
     TRACE ((stderr, "%s: num_boxes=%d\n", __FUNCTION__, boxes->num_boxes));
@@ -247,7 +255,7 @@ emit_aligned_boxes (cairo_gl_context_t *ctx,
            int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
            int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
            int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
-           _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 255);
+           emit (ctx, x1, y1, x2, y2);
        }
     }
 }
@@ -291,6 +299,9 @@ draw_image_boxes (void *_dst,
     struct _cairo_boxes_chunk *chunk;
     int i;
 
+    if (_cairo_gl_surface_is_texture (dst))
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+
     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
        for (i = 0; i < chunk->count; i++) {
            cairo_box_t *b = &chunk->base[i];
@@ -476,6 +487,7 @@ _cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t        *_r,
     if (unlikely (status))
         goto FAIL;
 
+    r->emit = _cairo_gl_context_choose_emit_span (r->ctx);
     if (composite->is_bounded) {
        if (r->opacity == 1.)
            r->base.render_rows = _cairo_gl_bounded_opaque_spans;
index 0375285..b1eec20 100644 (file)
@@ -425,12 +425,12 @@ _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t   *ctx,
     return &surface->base;
 }
 
-cairo_surface_t *
-_cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
-                                 cairo_content_t       content,
-                                 int                   width,
-                                 int                   height,
-                                 cairo_bool_t          true_alpha)
+static cairo_surface_t *
+_create_scratch_internal (cairo_gl_context_t *ctx,
+                         cairo_content_t content,
+                         int width,
+                         int height,
+                         cairo_bool_t for_caching)
 {
     cairo_gl_surface_t *surface;
     GLenum format;
@@ -458,8 +458,10 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
        format = GL_RGBA;
        break;
     case CAIRO_CONTENT_ALPHA:
-       /* We want to be trying GL_ALPHA framebuffer objects here. */
-       if (true_alpha)
+       /* When using GL_ALPHA, compositing doesn't work properly, but for
+        * caching surfaces, we are just uploading pixel data, so it isn't
+        * an issue. */
+       if (for_caching)
            format = GL_ALPHA;
        else
            format = GL_RGBA;
@@ -483,6 +485,24 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
     return &surface->base;
 }
 
+cairo_surface_t *
+_cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
+                                 cairo_content_t       content,
+                                 int                   width,
+                                 int                   height)
+{
+    return _create_scratch_internal (ctx, content, width, height, FALSE);
+}
+
+cairo_surface_t *
+_cairo_gl_surface_create_scratch_for_caching (cairo_gl_context_t *ctx,
+                                             cairo_content_t content,
+                                             int width,
+                                             int height)
+{
+    return _create_scratch_internal (ctx, content, width, height, TRUE);
+}
+
 static cairo_status_t
 _cairo_gl_surface_clear (cairo_gl_surface_t  *surface,
                          const cairo_color_t *color)
@@ -512,6 +532,7 @@ _cairo_gl_surface_clear (cairo_gl_surface_t  *surface,
         a = 1.0;
     }
 
+    _disable_scissor_buffer (ctx);
     if (ctx->states_cache.clear_red != r ||
        ctx->states_cache.clear_green != g ||
        ctx->states_cache.clear_blue != b ||
@@ -524,14 +545,39 @@ _cairo_gl_surface_clear (cairo_gl_surface_t  *surface,
 
        glClearColor (r, g, b, a);
     }
-
-    _disable_scissor_buffer ();
     glClear (GL_COLOR_BUFFER_BIT);
 
+    if (a == 0)
+       surface->base.is_clear = TRUE;
+
     surface->content_changed = TRUE;
     return _cairo_gl_context_release (ctx, status);
 }
 
+static cairo_surface_t *
+_cairo_gl_surface_create_and_clear_scratch (cairo_gl_context_t *ctx,
+                                           cairo_content_t content,
+                                           int width,
+                                           int height)
+{
+    cairo_gl_surface_t *surface;
+    cairo_int_status_t status;
+
+    surface = (cairo_gl_surface_t *)
+       _cairo_gl_surface_create_scratch (ctx, content, width, height);
+    if (unlikely (surface->base.status))
+       return &surface->base;
+
+    /* Cairo surfaces start out initialized to transparent (black) */
+    status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
+    if (unlikely (status)) {
+       cairo_surface_destroy (&surface->base);
+       return _cairo_surface_create_in_error (status);
+    }
+
+    return &surface->base;
+}
+
 cairo_surface_t *
 cairo_gl_surface_create (cairo_device_t                *abstract_device,
                         cairo_content_t         content,
@@ -559,16 +605,13 @@ cairo_gl_surface_create (cairo_device_t           *abstract_device,
        return _cairo_surface_create_in_error (status);
 
     surface = (cairo_gl_surface_t *)
-       _cairo_gl_surface_create_scratch (ctx, content, width, height, FALSE);
+       _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height);
     if (unlikely (surface->base.status)) {
        status = _cairo_gl_context_release (ctx, surface->base.status);
        cairo_surface_destroy (&surface->base);
        return _cairo_surface_create_in_error (status);
     }
 
-    /* Cairo surfaces start out initialized to transparent (black) */
-    status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
-
     status = _cairo_gl_context_release (ctx, status);
     if (unlikely (status)) {
        cairo_surface_destroy (&surface->base);
@@ -761,8 +804,7 @@ _cairo_gl_surface_create_similar (void               *abstract_surface,
     if (unlikely (status))
        return _cairo_surface_create_in_error (status);
 
-    surface = _cairo_gl_surface_create_scratch (ctx, content, width,
-                                               height, FALSE);
+    surface = _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height);
 
     status = _cairo_gl_context_release (ctx, status);
     if (unlikely (status)) {
@@ -796,7 +838,7 @@ _cairo_gl_surface_fill_alpha_channel (cairo_gl_surface_t *dst,
     if (unlikely (status))
         goto CLEANUP;
 
-    _cairo_gl_composite_emit_rect (ctx, x, y, x + width, y + height, 0);
+    _cairo_gl_context_emit_rect (ctx, x, y, x + width, y + height);
 
     status = _cairo_gl_context_release (ctx, status);
 
@@ -917,7 +959,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 
         tmp = _cairo_gl_surface_create_scratch (ctx,
                                                 dst->base.content,
-                                                width, height, FALSE);
+                                                width, height);
         if (unlikely (tmp->status))
             goto FAIL;
 
@@ -992,10 +1034,14 @@ _cairo_gl_surface_finish (void *abstract_surface)
 
     if (surface->fb)
         ctx->dispatch.DeleteFramebuffers (1, &surface->fb);
+    if (surface->depth_stencil)
+        ctx->dispatch.DeleteRenderbuffers (1, &surface->depth_stencil);
     if (surface->owns_tex)
        glDeleteTextures (1, &surface->tex);
 
 #if CAIRO_HAS_GL_SURFACE
+    if (surface->msaa_depth_stencil)
+       ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
     if (surface->msaa_fb)
        ctx->dispatch.DeleteFramebuffers (1, &surface->msaa_fb);
     if (surface->msaa_rb)
@@ -1019,6 +1065,11 @@ _cairo_gl_surface_map_to_image (void      *abstract_surface,
     cairo_status_t status;
     int y;
 
+    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+    if (unlikely (status)) {
+       return _cairo_image_surface_create_in_error (status);
+    }
+
     /* Want to use a switch statement here but the compiler gets whiny. */
     if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
        format = GL_BGRA;
@@ -1040,25 +1091,26 @@ _cairo_gl_surface_map_to_image (void      *abstract_surface,
        return NULL;
     }
 
-    /*
-     * GLES2 supports only RGBA, UNSIGNED_BYTE so use that.
-     * We are also using this format for ALPHA as GLES2 does not
-     * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
-     * pixman image that is created has row_stride = row_width * bpp.
-     */
     if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES) {
-       format = GL_RGBA;
-       if (! _cairo_is_little_endian ()) {
-           if (surface->base.content == CAIRO_CONTENT_COLOR)
-               pixman_format = PIXMAN_r8g8b8x8;
-           else
-               pixman_format = PIXMAN_r8g8b8a8;
-       } else {
-           if (surface->base.content == CAIRO_CONTENT_COLOR)
-               pixman_format = PIXMAN_x8b8g8r8;
-           else
-               pixman_format = PIXMAN_a8b8g8r8;
+       /* If only RGBA is supported, we must download data in a compatible
+        * format. This means that pixman will convert the data on the CPU when
+        * interacting with other image surfaces. For ALPHA, GLES2 does not
+        * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
+        * pixman image that is created has row_stride = row_width * bpp. */
+       if (surface->base.content == CAIRO_CONTENT_ALPHA || !ctx->can_read_bgra) {
+           cairo_bool_t little_endian = _cairo_is_little_endian ();
+           format = GL_RGBA;
+
+           if (surface->base.content == CAIRO_CONTENT_COLOR) {
+               pixman_format = little_endian ?
+                   PIXMAN_x8b8g8r8 : PIXMAN_r8g8b8x8;
+           } else {
+               pixman_format = little_endian ?
+                   PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8;
+           }
        }
+
+       /* GLES2 only supports GL_UNSIGNED_BYTE. */
        type = GL_UNSIGNED_BYTE;
        cpp = 4;
     }
@@ -1069,20 +1121,20 @@ _cairo_gl_surface_map_to_image (void      *abstract_surface,
                                                        extents->width,
                                                        extents->height,
                                                        -1);
-    if (unlikely (image->base.status))
-       return image;
-
-    if (surface->base.serial == 0)
+    if (unlikely (image->base.status)) {
+       status = _cairo_gl_context_release (ctx, status);
        return image;
-
-    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
-    if (unlikely (status)) {
-       cairo_surface_destroy (&image->base);
-       return _cairo_image_surface_create_in_error (status);
     }
 
     cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y);
 
+    /* If the original surface has not been modified or
+     * is clear, we can avoid downloading data. */
+    if (surface->base.is_clear || surface->base.serial == 0) {
+       status = _cairo_gl_context_release (ctx, status);
+       return image;
+    }
+
     /* This is inefficient, as we'd rather just read the thing without making
      * it the destination.  But then, this is the fallback path, so let's not
      * fall back instead.
index e1409ab..00f514f 100644 (file)
@@ -50,6 +50,7 @@
 #include "cairo-image-surface-private.h"
 #include "cairo-spans-compositor-private.h"
 #include "cairo-surface-backend-private.h"
+#include "cairo-surface-offset-private.h"
 
 static cairo_int_status_t
 acquire (void *abstract_dst)
@@ -83,6 +84,9 @@ draw_image_boxes (void *_dst,
     struct _cairo_boxes_chunk *chunk;
     int i;
 
+    if (_cairo_gl_surface_is_texture (dst))
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+
     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
        for (i = 0; i < chunk->count; i++) {
            cairo_box_t *b = &chunk->base[i];
@@ -109,6 +113,7 @@ emit_aligned_boxes (cairo_gl_context_t *ctx,
                    const cairo_boxes_t *boxes)
 {
     const struct _cairo_boxes_chunk *chunk;
+    cairo_gl_emit_rect_t emit = _cairo_gl_context_choose_emit_rect (ctx);
     int i;
 
     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
@@ -117,7 +122,7 @@ emit_aligned_boxes (cairo_gl_context_t *ctx,
            int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
            int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
            int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
-           _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 0);
+           emit (ctx, x1, y1, x2, y2);
        }
     }
 }
@@ -227,7 +232,7 @@ composite (void                     *_dst,
         goto FAIL;
 
     /* XXX clip */
-    _cairo_gl_composite_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height, 0);
+    _cairo_gl_context_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height);
     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
 
 FAIL:
@@ -300,6 +305,36 @@ traps_to_operand (void *_dst,
        return image->status;
     }
 
+    /* GLES2 only supports RGB/RGBA when uploading */
+    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES) {
+       cairo_surface_pattern_t pattern;
+       cairo_surface_t *rgba_image;
+
+       /* XXX perform this fixup inside _cairo_gl_draw_image() */
+
+       rgba_image =
+           _cairo_image_surface_create_with_pixman_format (NULL,
+                                                           _cairo_is_little_endian () ?  PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8,
+                                                           extents->width,
+                                                           extents->height,
+                                                           0);
+       if (unlikely (rgba_image->status))
+           return rgba_image->status;
+
+       _cairo_pattern_init_for_surface (&pattern, image);
+       status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE,
+                                      &pattern.base, NULL);
+       _cairo_pattern_fini (&pattern.base);
+
+       cairo_surface_destroy (image);
+       image = rgba_image;
+
+       if (unlikely (status)) {
+           cairo_surface_destroy (image);
+           return status;
+       }
+    }
+
     mask = _cairo_surface_create_similar_scratch (_dst,
                                                  CAIRO_CONTENT_COLOR_ALPHA,
                                                  extents->width,
@@ -315,6 +350,7 @@ traps_to_operand (void *_dst,
                                           extents->width, extents->height,
                                           0, 0);
     cairo_surface_destroy (image);
+
     if (unlikely (status))
        goto error;
 
@@ -372,10 +408,10 @@ composite_traps (void                     *_dst,
         goto FAIL;
 
     /* XXX clip */
-    _cairo_gl_composite_emit_rect (ctx,
-                                  extents->x-dst_x, extents->y-dst_y,
-                                  extents->x-dst_x+extents->width,
-                                  extents->y-dst_y+extents->height, 0);
+    _cairo_gl_context_emit_rect (ctx,
+                                extents->x-dst_x, extents->y-dst_y,
+                                extents->x-dst_x+extents->width,
+                                extents->y-dst_y+extents->height);
     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
 
 FAIL:
@@ -468,10 +504,10 @@ composite_tristrip (void          *_dst,
         goto FAIL;
 
     /* XXX clip */
-    _cairo_gl_composite_emit_rect (ctx,
-                                  dst_x, dst_y,
-                                  dst_x+extents->width,
-                                  dst_y+extents->height, 0);
+    _cairo_gl_context_emit_rect (ctx,
+                                dst_x, dst_y,
+                                dst_x+extents->width,
+                                dst_y+extents->height);
     status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
 
 FAIL:
index fba870a..a041cd1 100644 (file)
@@ -53,8 +53,6 @@ typedef struct _cairo_glx_context {
     Window dummy_window;
     GLXContext context;
 
-    Display *previous_display;
-    GLXDrawable previous_drawable;
     GLXContext previous_context;
 
     cairo_bool_t has_multithread_makecurrent;
@@ -67,12 +65,9 @@ typedef struct _cairo_glx_surface {
 } cairo_glx_surface_t;
 
 static cairo_bool_t
-_context_acquisition_changed_glx_state (cairo_glx_context_t *ctx,
-                                       GLXDrawable current_drawable)
+_context_acquisition_changed_glx_state (cairo_glx_context_t *ctx)
 {
-    return !(ctx->previous_display == ctx->display &&
-            ctx->previous_drawable == current_drawable &&
-            ctx->previous_context == ctx->context);
+    return ctx->previous_context != ctx->context;
 }
 
 static GLXDrawable
@@ -89,20 +84,7 @@ _glx_get_current_drawable (cairo_glx_context_t *ctx)
 static void
 _glx_query_current_state (cairo_glx_context_t * ctx)
 {
-    ctx->previous_drawable = glXGetCurrentDrawable ();
-    ctx->previous_display = glXGetCurrentDisplay ();
     ctx->previous_context = glXGetCurrentContext ();
-
-    /* If any of the values were none, assume they are all none. Not all
-       drivers seem well behaved when it comes to using these values across
-       multiple threads. */
-    if (ctx->previous_drawable == None
-       || ctx->previous_display == None
-       || ctx->previous_context == None) {
-       ctx->previous_drawable = None;
-       ctx->previous_display = None;
-       ctx->previous_context = None;
-    }
 }
 
 static void
@@ -112,7 +94,7 @@ _glx_acquire (void *abstract_ctx)
     GLXDrawable current_drawable = _glx_get_current_drawable (ctx);
 
     _glx_query_current_state (ctx);
-    if (!_context_acquisition_changed_glx_state (ctx, current_drawable))
+    if (!_context_acquisition_changed_glx_state (ctx))
        return;
 
     _cairo_gl_context_reset (&ctx->base);
@@ -135,8 +117,7 @@ _glx_release (void *abstract_ctx)
     cairo_glx_context_t *ctx = abstract_ctx;
 
     if (ctx->has_multithread_makecurrent || !ctx->base.thread_aware ||
-       !_context_acquisition_changed_glx_state (ctx,
-                                               _glx_get_current_drawable (ctx))) {
+       !_context_acquisition_changed_glx_state (ctx)) {
        return;
     }
 
index c90f2f6..6319471 100644 (file)
@@ -1235,12 +1235,12 @@ _cairo_gstate_in_stroke (cairo_gstate_t     *gstate,
     _cairo_traps_init (&traps);
     _cairo_traps_limit (&traps, &limit, 1);
 
-    status = _cairo_path_fixed_stroke_to_traps (path,
-                                               &gstate->stroke_style,
-                                               &gstate->ctm,
-                                               &gstate->ctm_inverse,
-                                               gstate->tolerance,
-                                               &traps);
+    status = _cairo_path_fixed_stroke_polygon_to_traps (path,
+                                                       &gstate->stroke_style,
+                                                       &gstate->ctm,
+                                                       &gstate->ctm_inverse,
+                                                       gstate->tolerance,
+                                                       &traps);
     if (unlikely (status))
        goto BAIL;
 
@@ -1465,12 +1465,12 @@ _cairo_gstate_stroke_extents (cairo_gstate_t     *gstate,
        cairo_traps_t traps;
 
        _cairo_traps_init (&traps);
-       status = _cairo_path_fixed_stroke_to_traps (path,
-                                                   &gstate->stroke_style,
-                                                   &gstate->ctm,
-                                                   &gstate->ctm_inverse,
-                                                   gstate->tolerance,
-                                                   &traps);
+       status = _cairo_path_fixed_stroke_polygon_to_traps (path,
+                                                           &gstate->stroke_style,
+                                                           &gstate->ctm,
+                                                           &gstate->ctm_inverse,
+                                                           gstate->tolerance,
+                                                           &traps);
        empty = traps.num_traps == 0;
        if (! empty)
            _cairo_traps_extents (&traps, &extents);
index 1360a44..5dfdeae 100755 (executable)
 #include "cairo-traps-private.h"
 #include "cairo-tristrip-private.h"
 
+#if CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
+#include "cairo-thread-local-private.h"
+#endif
+
 static pixman_image_t *
 to_pixman_image (cairo_surface_t *s)
 {
@@ -760,31 +764,51 @@ check_composite_glyphs (const cairo_composite_rectangles_t *extents,
 }
 
 #if HAS_PIXMAN_GLYPHS
-#error
+#if CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
+CAIRO_DEFINE_THREAD_LOCAL (pixman_glyph_cache_t *, per_thread_glyph_cache);
+#else
 static pixman_glyph_cache_t *global_glyph_cache;
+#endif
 
 static inline pixman_glyph_cache_t *
 get_glyph_cache (void)
 {
-    if (!global_glyph_cache)
-       global_glyph_cache = pixman_glyph_cache_create ();
+    pixman_glyph_cache_t **glyph_cache = NULL;
 
-    return global_glyph_cache;
+#if CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
+    glyph_cache = CAIRO_GET_THREAD_LOCAL (per_thread_glyph_cache);
+#else
+    glyph_cache = &global_glyph_cache;
+#endif
+
+    if (! (*glyph_cache))
+       *glyph_cache = pixman_glyph_cache_create ();
+
+    return *glyph_cache;
 }
 
 void
 _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
                                cairo_scaled_glyph_t *scaled_glyph)
 {
+    pixman_glyph_cache_t *glyph_cache = NULL;
+
+#if CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
+    glyph_cache = *CAIRO_GET_THREAD_LOCAL (per_thread_glyph_cache);
+#else
+    glyph_cache = global_glyph_cache;
     CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
+#endif
 
-    if (global_glyph_cache) {
+    if (glyph_cache) {
        pixman_glyph_cache_remove (
-           global_glyph_cache, scaled_font,
+           glyph_cache, scaled_font,
            (void *)_cairo_scaled_glyph_index (scaled_glyph));
     }
 
+#if ! CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
     CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
+#endif
 }
 
 static cairo_int_status_t
@@ -806,7 +830,9 @@ composite_glyphs (void                              *_dst,
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
 
+#if ! CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
     CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
+#endif
 
     glyph_cache = get_glyph_cache();
     if (unlikely (glyph_cache == NULL)) {
@@ -834,23 +860,35 @@ composite_glyphs (void                            *_dst,
            cairo_scaled_glyph_t *scaled_glyph;
            cairo_image_surface_t *glyph_surface;
 
+#if ! CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
            /* This call can actually end up recursing, so we have to
             * drop the mutex around it.
             */
            CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
+#endif
+           _cairo_scaled_font_freeze_cache (info->font);
+
            status = _cairo_scaled_glyph_lookup (info->font, index,
                                                 CAIRO_SCALED_GLYPH_INFO_SURFACE,
                                                 &scaled_glyph);
+
+#if ! CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
            CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex);
+#endif
 
-           if (unlikely (status))
+           if (unlikely (status)) {
+               _cairo_scaled_font_thaw_cache (info->font);
                goto out_thaw;
+           }
 
            glyph_surface = scaled_glyph->surface;
            glyph = pixman_glyph_cache_insert (glyph_cache, info->font, (void *)index,
                                               glyph_surface->base.device_transform.x0,
                                               glyph_surface->base.device_transform.y0,
                                               glyph_surface->pixman_image);
+
+           _cairo_scaled_font_thaw_cache (info->font);
+
            if (unlikely (!glyph)) {
                status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
                goto out_thaw;
@@ -893,7 +931,10 @@ out_thaw:
        free(pglyphs);
 
 out_unlock:
+#if ! CAIRO_ENABLE_PER_THREAD_GLYPH_CACHE
     CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
+#endif
+
     return status;
 }
 #else
@@ -1131,11 +1172,17 @@ composite_glyphs (void                          *_dst,
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
 
-    if (info->num_glyphs == 1)
-       return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+    _cairo_scaled_font_freeze_cache (info->font);
+
+    if (info->num_glyphs == 1) {
+       status = composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+       goto out_thaw;
+    }
 
-    if (info->use_mask)
-       return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+    if (info->use_mask) {
+       status = composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+       goto out_thaw;
+    }
 
     op = _pixman_operator (op);
     dst = to_pixman_image (_dst);
@@ -1183,6 +1230,9 @@ composite_glyphs (void                            *_dst,
        }
     }
 
+out_thaw:
+    _cairo_scaled_font_thaw_cache (info->font);
+
     return status;
 }
 #endif
@@ -1539,6 +1589,7 @@ typedef struct _cairo_image_span_renderer {
            pixman_image_t *dst;
            int src_x, src_y;
            int mask_x, mask_y;
+           int run_length;
        } composite;
        struct finish {
            cairo_rectangle_int_t extents;
@@ -1547,7 +1598,8 @@ typedef struct _cairo_image_span_renderer {
            uint8_t *data;
        } mask;
     } u;
-    uint8_t buf[sizeof(cairo_abstract_span_renderer_t)-128];
+    uint8_t _buf[0];
+#define SZ_BUF (sizeof (cairo_abstract_span_renderer_t) - sizeof (cairo_image_span_renderer_t))
 } cairo_image_span_renderer_t;
 COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
 
@@ -2187,7 +2239,7 @@ _fill_xrgb32_lerp_opaque_spans (void *abstract_renderer, int y, int h,
                uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
                if (a == 0xff) {
                    if (len > 31) {
-                       pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
+                       pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32,
                                     spans[0].x, y, len, 1, r->u.fill.pixel);
                    } else {
                        uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
@@ -2207,7 +2259,7 @@ _fill_xrgb32_lerp_opaque_spans (void *abstract_renderer, int y, int h,
            if (a) {
                if (a == 0xff) {
                    if (spans[1].x - spans[0].x > 16) {
-                       pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
+                       pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32,
                                     spans[0].x, y, spans[1].x - spans[0].x, h,
                                     r->u.fill.pixel);
                    } else {
@@ -2251,7 +2303,7 @@ _fill_a8_lerp_spans (void *abstract_renderer, int y, int h,
 
     if (likely(h == 1)) {
        do {
-           uint8_t a = mul8_8 (spans[0].coverage, r->op);
+           uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
            if (a) {
                int len = spans[1].x - spans[0].x;
                uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x;
@@ -2266,7 +2318,7 @@ _fill_a8_lerp_spans (void *abstract_renderer, int y, int h,
        } while (--num_spans > 1);
     } else {
        do {
-           uint8_t a = mul8_8 (spans[0].coverage, r->op);
+           uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
            if (a) {
                int yy = y, hh = h;
                uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f;
@@ -2299,7 +2351,7 @@ _fill_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
 
     if (likely(h == 1)) {
        do {
-           uint8_t a = mul8_8 (spans[0].coverage, r->op);
+           uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
            if (a) {
                int len = spans[1].x - spans[0].x;
                uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
@@ -2312,7 +2364,7 @@ _fill_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
        } while (--num_spans > 1);
     } else {
        do {
-           uint8_t a = mul8_8 (spans[0].coverage, r->op);
+           uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
            if (a) {
                int yy = y, hh = h;
                do {
@@ -2345,7 +2397,7 @@ _blit_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
        uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride;
        uint8_t *dst = r->u.blit.data + y*r->u.blit.stride;
        do {
-           uint8_t a = mul8_8 (spans[0].coverage, r->op);
+           uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
            if (a) {
                uint32_t *s = (uint32_t*)src + spans[0].x;
                uint32_t *d = (uint32_t*)dst + spans[0].x;
@@ -2366,7 +2418,7 @@ _blit_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
        } while (--num_spans > 1);
     } else {
        do {
-           uint8_t a = mul8_8 (spans[0].coverage, r->op);
+           uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
            if (a) {
                int yy = y, hh = h;
                do {
@@ -2418,31 +2470,111 @@ _inplace_spans (void *abstract_renderer,
     }
 
     mask = (uint8_t *)pixman_image_get_data (r->mask);
-    x0 = spans[0].x;
+    x1 = x0 = spans[0].x;
     do {
        int len = spans[1].x - spans[0].x;
        *mask++ = spans[0].coverage;
        if (len > 1) {
-           memset (mask, spans[0].coverage, --len);
-           mask += len;
+           if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) {
+               if (x1 != x0) {
+                   pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+                                             x0 + r->u.composite.src_x,
+                                             y + r->u.composite.src_y,
+                                             0, 0,
+                                             x0, y,
+                                             x1 - x0, h);
+               }
+               pixman_image_composite32 (r->op, r->src, NULL, r->u.composite.dst,
+                                         spans[0].x + r->u.composite.src_x,
+                                         y + r->u.composite.src_y,
+                                         0, 0,
+                                         spans[0].x, y,
+                                         len, h);
+               mask = (uint8_t *)pixman_image_get_data (r->mask);
+               x0 = spans[1].x;
+           } else if (spans[0].coverage == 0x0 &&
+                      x1 - x0 > r->u.composite.run_length) {
+               pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+                                         x0 + r->u.composite.src_x,
+                                         y + r->u.composite.src_y,
+                                         0, 0,
+                                         x0, y,
+                                         x1 - x0, h);
+               mask = (uint8_t *)pixman_image_get_data (r->mask);
+               x0 = spans[1].x;
+           }else {
+               memset (mask, spans[0].coverage, --len);
+               mask += len;
+           }
        }
        x1 = spans[1].x;
        spans++;
     } while (--num_spans > 1);
 
-    pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
-                             x0 + r->u.composite.src_x,
-                             y + r->u.composite.src_y,
-                             0, 0,
-                             x0, y,
-                             x1 - x0, h);
+    if (x1 != x0) {
+       pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+                                 x0 + r->u.composite.src_x,
+                                 y + r->u.composite.src_y,
+                                 0, 0,
+                                 x0, y,
+                                 x1 - x0, h);
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-_inplace_src_spans (void *abstract_renderer,
-                   int y, int h,
+_inplace_opacity_spans (void *abstract_renderer, int y, int h,
+                       const cairo_half_open_span_t *spans,
+                       unsigned num_spans)
+{
+    cairo_image_span_renderer_t *r = abstract_renderer;
+    uint8_t *mask;
+    int x0, x1;
+
+    if (num_spans == 0)
+       return CAIRO_STATUS_SUCCESS;
+
+    mask = (uint8_t *)pixman_image_get_data (r->mask);
+    x1 = x0 = spans[0].x;
+    do {
+       int len = spans[1].x - spans[0].x;
+       uint8_t m = mul8_8(spans[0].coverage, r->bpp);
+       *mask++ = m;
+       if (len > 1) {
+           if (m == 0 &&
+               x1 - x0 > r->u.composite.run_length) {
+               pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+                                         x0 + r->u.composite.src_x,
+                                         y + r->u.composite.src_y,
+                                         0, 0,
+                                         x0, y,
+                                         x1 - x0, h);
+               mask = (uint8_t *)pixman_image_get_data (r->mask);
+               x0 = spans[1].x;
+           }else {
+               memset (mask, m, --len);
+               mask += len;
+           }
+       }
+       x1 = spans[1].x;
+       spans++;
+    } while (--num_spans > 1);
+
+    if (x1 != x0) {
+       pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+                                 x0 + r->u.composite.src_x,
+                                 y + r->u.composite.src_y,
+                                 0, 0,
+                                 x0, y,
+                                 x1 - x0, h);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_inplace_src_spans (void *abstract_renderer, int y, int h,
                    const cairo_half_open_span_t *spans,
                    unsigned num_spans)
 {
@@ -2454,10 +2586,10 @@ _inplace_src_spans (void *abstract_renderer,
        return CAIRO_STATUS_SUCCESS;
 
     x0 = spans[0].x;
-    m = r->buf;
+    m = r->_buf;
     do {
        int len = spans[1].x - spans[0].x;
-       if (spans[0].coverage == 0xff) {
+       if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) {
            if (spans[0].x != x0) {
 #if PIXMAN_HAS_OP_LERP
                pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
@@ -2492,7 +2624,7 @@ _inplace_src_spans (void *abstract_renderer,
                                      spans[0].x, y,
                                      spans[1].x - spans[0].x, h);
 
-           m = r->buf;
+           m = r->_buf;
            x0 = spans[1].x;
        } else if (spans[0].coverage == 0x0) {
            if (spans[0].x != x0) {
@@ -2521,7 +2653,7 @@ _inplace_src_spans (void *abstract_renderer,
 #endif
            }
 
-           m = r->buf;
+           m = r->_buf;
            x0 = spans[1].x;
        } else {
            *m++ = spans[0].coverage;
@@ -2562,6 +2694,96 @@ _inplace_src_spans (void *abstract_renderer,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_status_t
+_inplace_src_opacity_spans (void *abstract_renderer, int y, int h,
+                           const cairo_half_open_span_t *spans,
+                           unsigned num_spans)
+{
+    cairo_image_span_renderer_t *r = abstract_renderer;
+    uint8_t *mask;
+    int x0;
+
+    if (num_spans == 0)
+       return CAIRO_STATUS_SUCCESS;
+
+    x0 = spans[0].x;
+    mask = (uint8_t *)pixman_image_get_data (r->mask);
+    do {
+       int len = spans[1].x - spans[0].x;
+       uint8_t m = mul8_8(spans[0].coverage, r->bpp);
+       if (m == 0) {
+           if (spans[0].x != x0) {
+#if PIXMAN_HAS_OP_LERP
+               pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
+                                         r->src, r->mask, r->u.composite.dst,
+                                         x0 + r->u.composite.src_x,
+                                         y + r->u.composite.src_y,
+                                         0, 0,
+                                         x0, y,
+                                         spans[0].x - x0, h);
+#else
+               pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+                                         r->mask, NULL, r->u.composite.dst,
+                                         0, 0,
+                                         0, 0,
+                                         x0, y,
+                                         spans[0].x - x0, h);
+               pixman_image_composite32 (PIXMAN_OP_ADD,
+                                         r->src, r->mask, r->u.composite.dst,
+                                         x0 + r->u.composite.src_x,
+                                         y + r->u.composite.src_y,
+                                         0, 0,
+                                         x0, y,
+                                         spans[0].x - x0, h);
+#endif
+           }
+
+           mask = (uint8_t *)pixman_image_get_data (r->mask);
+           x0 = spans[1].x;
+       } else {
+           *mask++ = m;
+           if (len > 1) {
+               memset (mask, m, --len);
+               mask += len;
+           }
+       }
+       spans++;
+    } while (--num_spans > 1);
+
+    if (spans[0].x != x0) {
+#if PIXMAN_HAS_OP_LERP
+       pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
+                                 r->src, r->mask, r->u.composite.dst,
+                                 x0 + r->u.composite.src_x,
+                                 y + r->u.composite.src_y,
+                                 0, 0,
+                                 x0, y,
+                                 spans[0].x - x0, h);
+#else
+       pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+                                 r->mask, NULL, r->u.composite.dst,
+                                 0, 0,
+                                 0, 0,
+                                 x0, y,
+                                 spans[0].x - x0, h);
+       pixman_image_composite32 (PIXMAN_OP_ADD,
+                                 r->src, r->mask, r->u.composite.dst,
+                                 x0 + r->u.composite.src_x,
+                                 y + r->u.composite.src_y,
+                                 0, 0,
+                                 x0, y,
+                                 spans[0].x - x0, h);
+#endif
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void free_pixels (pixman_image_t *image, void *data)
+{
+       free (data);
+}
+
 static cairo_int_status_t
 inplace_renderer_init (cairo_image_span_renderer_t     *r,
                       const cairo_composite_rectangles_t *composite,
@@ -2569,12 +2791,13 @@ inplace_renderer_init (cairo_image_span_renderer_t      *r,
                       cairo_bool_t                      needs_clip)
 {
     cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
+    uint8_t *buf;
 
     if (composite->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
        return CAIRO_INT_STATUS_UNSUPPORTED;
 
     r->base.render_rows = NULL;
-    r->op = composite->mask_pattern.solid.color.alpha_short >> 8;
+    r->bpp = composite->mask_pattern.solid.color.alpha_short >> 8;
 
     if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
        const cairo_color_t *color;
@@ -2589,7 +2812,7 @@ inplace_renderer_init (cairo_image_span_renderer_t        *r,
             * typically small, too small to payback the startup overheads of
             * using SSE2 etc.
             */
-           if (r->op == 0xff) {
+           if (r->bpp == 0xff) {
                switch (dst->format) {
                case CAIRO_FORMAT_A8:
                    r->base.render_rows = _fill_a8_lerp_opaque_spans;
@@ -2651,24 +2874,26 @@ inplace_renderer_init (cairo_image_span_renderer_t      *r,
        }
     }
     if (r->base.render_rows == NULL) {
-       unsigned int width;
        const cairo_pattern_t *src = &composite->source_pattern.base;
-
-       if (r->op != 0xff)
-           return CAIRO_INT_STATUS_UNSUPPORTED;
+       unsigned int width;
 
        if (composite->is_bounded == 0)
            return CAIRO_INT_STATUS_UNSUPPORTED;
 
+       r->base.render_rows = r->bpp == 0xff ? _inplace_spans : _inplace_opacity_spans;
        width = (composite->bounded.width + 3) & ~3;
-       r->base.render_rows = _inplace_spans;
+
+       r->u.composite.run_length = 8;
+       if (src->type == CAIRO_PATTERN_TYPE_LINEAR ||
+           src->type == CAIRO_PATTERN_TYPE_RADIAL)
+               r->u.composite.run_length = 256;
        if (dst->base.is_clear &&
            (composite->op == CAIRO_OPERATOR_SOURCE ||
             composite->op == CAIRO_OPERATOR_OVER ||
             composite->op == CAIRO_OPERATOR_ADD)) {
            r->op = PIXMAN_OP_SRC;
        } else if (composite->op == CAIRO_OPERATOR_SOURCE) {
-           r->base.render_rows = _inplace_src_spans;
+           r->base.render_rows = r->bpp == 0xff ? _inplace_src_spans : _inplace_src_opacity_spans;
            r->u.composite.mask_y = r->composite->unbounded.y;
            width = (composite->unbounded.width + 3) & ~3;
        } else if (composite->op == CAIRO_OPERATOR_CLEAR) {
@@ -2678,9 +2903,6 @@ inplace_renderer_init (cairo_image_span_renderer_t        *r,
            r->op = _pixman_operator (composite->op);
        }
 
-       if (width > sizeof (r->buf))
-           return CAIRO_INT_STATUS_UNSUPPORTED;
-
        r->src = _pixman_image_for_pattern (dst, src, FALSE,
                                            &composite->bounded,
                                            &composite->source_sample_area,
@@ -2689,19 +2911,30 @@ inplace_renderer_init (cairo_image_span_renderer_t      *r,
            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
        /* Create an effectively unbounded mask by repeating the single line */
+       buf = r->_buf;
+       if (width > SZ_BUF) {
+           buf = malloc (width);
+           if (unlikely (buf == NULL)) {
+               pixman_image_unref (r->src);
+               return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+           }
+       }
        r->mask = pixman_image_create_bits (PIXMAN_a8,
                                            width, composite->unbounded.height,
-                                           (uint32_t *)r->buf, 0);
+                                           (uint32_t *)buf, 0);
        if (unlikely (r->mask == NULL)) {
            pixman_image_unref (r->src);
+           if (buf != r->_buf)
+               free (buf);
            return _cairo_error(CAIRO_STATUS_NO_MEMORY);
        }
 
+       if (buf != r->_buf)
+           pixman_image_set_destroy_function (r->mask, free_pixels, buf);
+
        r->u.composite.dst = dst->pixman_image;
     }
 
-    r->bpp = PIXMAN_FORMAT_BPP(dst->pixman_format);
-
     return CAIRO_INT_STATUS_SUCCESS;
 }
 
@@ -2717,7 +2950,8 @@ span_renderer_init (cairo_abstract_span_renderer_t        *_r,
     cairo_operator_t op = composite->op;
     cairo_int_status_t status;
 
-    TRACE ((stderr, "%s\n", __FUNCTION__));
+    TRACE ((stderr, "%s: antialias=%d, needs_clip=%d\n", __FUNCTION__,
+           antialias, needs_clip));
 
     if (needs_clip)
        return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -2802,7 +3036,7 @@ span_renderer_init (cairo_abstract_span_renderer_t        *_r,
 
     r->u.mask.extents = composite->unbounded;
     r->u.mask.stride = (r->u.mask.extents.width + 3) & ~3;
-    if (r->u.mask.extents.height * r->u.mask.stride > (int)sizeof (r->buf)) {
+    if (r->u.mask.extents.height * r->u.mask.stride > (int)sizeof (r->_buf)) {
        r->mask = pixman_image_create_bits (PIXMAN_a8,
                                            r->u.mask.extents.width,
                                            r->u.mask.extents.height,
@@ -2814,7 +3048,7 @@ span_renderer_init (cairo_abstract_span_renderer_t        *_r,
        r->mask = pixman_image_create_bits (PIXMAN_a8,
                                            r->u.mask.extents.width,
                                            r->u.mask.extents.height,
-                                           (uint32_t *)r->buf, r->u.mask.stride);
+                                           (uint32_t *)r->_buf, r->u.mask.stride);
 
        r->base.render_rows = _cairo_image_spans_and_zero;
        r->base.finish = _cairo_image_finish_spans_and_zero;
index a1662f2..743d5fd 100644 (file)
@@ -54,7 +54,6 @@ _cairo_image_surface_set_parent (cairo_image_surface_t *image,
                                 cairo_surface_t *parent)
 {
     image->parent = parent;
-    cairo_surface_reference (parent);
 }
 
 static inline cairo_bool_t
index 3fe6e43..20a1c03 100644 (file)
@@ -1240,7 +1240,14 @@ _cairo_image_surface_clone_subimage (cairo_surface_t             *surface,
     if (unlikely (status))
        goto error;
 
-    _cairo_image_surface_set_parent (to_image_surface (image), surface);
+    /* We use the parent as a flag during map-to-image/umap-image that the
+     * resultant image came from a fallback rather than as direct call
+     * to the backend's map_to_image(). Whilst we use it as a simple flag,
+     * we need to make sure the parent surface obeys the reference counting
+     * semantics and is consistent for all callers.
+     */
+    _cairo_image_surface_set_parent (to_image_surface (image),
+                                    cairo_surface_reference (surface));
 
     return to_image_surface (image);
 
index 7976a79..d0be144 100644 (file)
@@ -172,7 +172,7 @@ create_composite_mask (const cairo_mask_compositor_t *compositor,
     status = compositor->acquire (surface);
     if (unlikely (status)) {
        cairo_surface_destroy (surface);
-       return _cairo_surface_create_in_error (status);
+       return _cairo_int_surface_create_in_error (status);
     }
 
     if (!surface->is_clear) {
@@ -239,7 +239,7 @@ error:
     compositor->release (surface);
     if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
        cairo_surface_destroy (surface);
-       surface = _cairo_surface_create_in_error (status);
+       surface = _cairo_int_surface_create_in_error (status);
     }
     return surface;
 }
@@ -298,6 +298,38 @@ clip_and_composite_with_mask (const cairo_mask_compositor_t *compositor,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_surface_t *
+get_clip_source (const cairo_mask_compositor_t *compositor,
+                cairo_clip_t *clip,
+                cairo_surface_t *dst,
+                const cairo_rectangle_int_t *bounds,
+                int *out_x, int *out_y)
+{
+    cairo_surface_pattern_t pattern;
+    cairo_rectangle_int_t r;
+    cairo_surface_t *surface;
+
+    surface = _cairo_clip_get_image (clip, dst, bounds);
+    if (unlikely (surface->status))
+       return surface;
+
+    _cairo_pattern_init_for_surface (&pattern, surface);
+    pattern.base.filter = CAIRO_FILTER_NEAREST;
+    cairo_surface_destroy (surface);
+
+    r.x = r.y = 0;
+    r.width  = bounds->width;
+    r.height = bounds->height;
+
+    surface = compositor->pattern_to_surface (dst, &pattern.base, TRUE,
+                                             &r, &r, out_x, out_y);
+    _cairo_pattern_fini (&pattern.base);
+
+    *out_x += -bounds->x;
+    *out_y += -bounds->y;
+    return surface;
+}
+
 /* Handles compositing with a clip surface when we have to do the operation
  * in two pieces and combine them together.
  */
@@ -312,6 +344,7 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
     cairo_surface_t *dst = extents->surface;
     cairo_surface_t *tmp, *clip;
     cairo_status_t status;
+    int clip_x, clip_y;
 
     tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
                                                 extents->bounded.width,
@@ -332,20 +365,22 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
     if (unlikely (status))
        goto cleanup;
 
-    clip = _cairo_clip_get_image (extents->clip, dst, &extents->bounded);
+    clip = get_clip_source (compositor,
+                           extents->clip, dst, &extents->bounded,
+                           &clip_x, &clip_y);
     if (unlikely ((status = clip->status)))
        goto cleanup;
 
     if (dst->is_clear) {
        compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
                               0, 0,
-                              0, 0,
+                              clip_x, clip_y,
                               extents->bounded.x,      extents->bounded.y,
                               extents->bounded.width,  extents->bounded.height);
     } else {
        /* Punch the clip out of the destination */
        compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, clip, NULL,
-                              0, 0,
+                              clip_x, clip_y,
                               0, 0,
                               extents->bounded.x,     extents->bounded.y,
                               extents->bounded.width, extents->bounded.height);
@@ -353,7 +388,7 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
        /* Now add the two results together */
        compositor->composite (dst, CAIRO_OPERATOR_ADD, tmp, clip,
                               0, 0,
-                              0, 0,
+                              clip_x, clip_y,
                               extents->bounded.x,     extents->bounded.y,
                               extents->bounded.width, extents->bounded.height);
     }
@@ -515,17 +550,15 @@ fixup_unbounded_with_mask (const cairo_mask_compositor_t *compositor,
                           cairo_surface_t *dst,
                           const cairo_composite_rectangles_t *extents)
 {
-    cairo_clip_t *clip = extents->clip;
     cairo_surface_t *mask;
     int mask_x, mask_y;
 
-    mask = _cairo_clip_get_image (clip, dst, &extents->unbounded);
+    mask = get_clip_source (compositor,
+                           extents->clip, dst, &extents->unbounded,
+                           &mask_x, &mask_y);
     if (unlikely (mask->status))
        return mask->status;
 
-    mask_x = -extents->unbounded.x;
-    mask_y = -extents->unbounded.y;
-
     /* top */
     if (extents->bounded.y != extents->unbounded.y) {
        int x = extents->unbounded.x;
@@ -870,8 +903,9 @@ composite_boxes (const cairo_mask_compositor_t *compositor,
        int mask_x = 0, mask_y = 0;
 
        if (need_clip_mask) {
-           mask = _cairo_clip_get_image (extents->clip, dst,
-                                         &extents->bounded);
+           mask = get_clip_source (compositor,
+                                   extents->clip, dst, &extents->bounded,
+                                   &mask_x, &mask_y);
            if (unlikely (mask->status))
                return mask->status;
 
@@ -879,9 +913,6 @@ composite_boxes (const cairo_mask_compositor_t *compositor,
                source = NULL;
                op = CAIRO_OPERATOR_DEST_OUT;
            }
-
-           mask_x = -extents->bounded.x;
-           mask_y = -extents->bounded.y;
        }
 
        if (source || mask == NULL) {
@@ -960,6 +991,10 @@ _cairo_mask_compositor_paint (const cairo_compositor_t *_compositor,
     cairo_boxes_t boxes;
     cairo_int_status_t status;
 
+    status = compositor->check_composite (extents);
+    if (unlikely (status))
+       return status;
+
     _cairo_clip_steal_boxes (extents->clip, &boxes);
     status = clip_and_composite_boxes (compositor, extents, &boxes);
     _cairo_clip_unsteal_boxes (extents->clip, &boxes);
@@ -1210,9 +1245,13 @@ _cairo_mask_compositor_mask (const cairo_compositor_t *_compositor,
     const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
     cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
 
+    status = compositor->check_composite (extents);
+    if (unlikely (status))
+       return status;
+
     if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
        extents->clip->path == NULL &&
-       _cairo_clip_is_region (extents->clip)) {
+       _cairo_clip_is_region (extents->clip)) {
        status = clip_and_composite (compositor,
                                     composite_opacity_boxes,
                                     composite_opacity_boxes,
@@ -1242,9 +1281,12 @@ _cairo_mask_compositor_stroke (const cairo_compositor_t *_compositor,
     const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
     cairo_surface_t *mask;
     cairo_surface_pattern_t pattern;
-    cairo_int_status_t status;
+    cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = compositor->check_composite (extents);
+    if (unlikely (status))
+       return status;
 
-    status = CAIRO_INT_STATUS_UNSUPPORTED;
     if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
        cairo_boxes_t boxes;
 
@@ -1311,9 +1353,12 @@ _cairo_mask_compositor_fill (const cairo_compositor_t *_compositor,
     const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
     cairo_surface_t *mask;
     cairo_surface_pattern_t pattern;
-    cairo_int_status_t status;
+    cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = compositor->check_composite (extents);
+    if (unlikely (status))
+       return status;
 
-    status = CAIRO_INT_STATUS_UNSUPPORTED;
     if (_cairo_path_fixed_fill_is_rectilinear (path)) {
        cairo_boxes_t boxes;
 
@@ -1374,10 +1419,15 @@ _cairo_mask_compositor_glyphs (const cairo_compositor_t *_compositor,
                               int                       num_glyphs,
                               cairo_bool_t              overlap)
 {
+    const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
     cairo_surface_t *mask;
     cairo_surface_pattern_t pattern;
     cairo_int_status_t status;
 
+    status = compositor->check_composite (extents);
+    if (unlikely (status))
+       return CAIRO_INT_STATUS_UNSUPPORTED;
+
     mask = cairo_surface_create_similar_image (extents->surface,
                                               CAIRO_FORMAT_A8,
                                               extents->bounded.width,
index 296b739..96e4a62 100644 (file)
@@ -283,9 +283,18 @@ _cairo_mempool_init (cairo_mempool_t *pool,
                      void *base, size_t bytes,
                      int min_bits, int num_sizes)
 {
+    unsigned long tmp;
     int num_blocks;
     int i;
 
+    /* Align the start to an integral chunk */
+    tmp = ((unsigned long) base) & ((1 << min_bits) - 1);
+    if (tmp) {
+       tmp = (1 << min_bits) - tmp;
+       base = (char *)base + tmp;
+       bytes -= tmp;
+    }
+
     assert ((((unsigned long) base) & ((1 << min_bits) - 1)) == 0);
     assert (num_sizes < ARRAY_LENGTH (pool->free));
 
index 7719383..b38c2a8 100644 (file)
@@ -340,62 +340,3 @@ _cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path,
                                                                   boxes);
 }
 
-cairo_status_t
-_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
-                                            cairo_fill_rule_t        fill_rule,
-                                            cairo_antialias_t        antialias,
-                                            cairo_traps_t            *traps)
-{
-    cairo_box_t box;
-    cairo_status_t status;
-
-    traps->is_rectilinear = TRUE;
-    traps->is_rectangular = TRUE;
-
-    if (_cairo_path_fixed_is_box (path, &box)) {
-       if (antialias == CAIRO_ANTIALIAS_NONE) {
-           box.p1.x = _cairo_fixed_round_down (box.p1.x);
-           box.p1.y = _cairo_fixed_round_down (box.p1.y);
-           box.p2.x = _cairo_fixed_round_down (box.p2.x);
-           box.p2.y = _cairo_fixed_round_down (box.p2.y);
-       }
-       return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
-    } else {
-       cairo_path_fixed_iter_t iter;
-
-       _cairo_path_fixed_iter_init (&iter, path);
-       while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
-           if (box.p1.y > box.p2.y) {
-               cairo_fixed_t t;
-
-               t = box.p1.y;
-               box.p1.y = box.p2.y;
-               box.p2.y = t;
-
-               t = box.p1.x;
-               box.p1.x = box.p2.x;
-               box.p2.x = t;
-           }
-
-           if (antialias == CAIRO_ANTIALIAS_NONE) {
-               box.p1.x = _cairo_fixed_round_down (box.p1.x);
-               box.p1.y = _cairo_fixed_round_down (box.p1.y);
-               box.p2.x = _cairo_fixed_round_down (box.p2.x);
-               box.p2.y = _cairo_fixed_round_down (box.p2.y);
-           }
-
-           status = _cairo_traps_tessellate_rectangle (traps,
-                                                       &box.p1, &box.p2);
-           if (unlikely (status)) {
-               _cairo_traps_clear (traps);
-               return status;
-           }
-       }
-
-       if (_cairo_path_fixed_iter_at_end (&iter))
-           return _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, fill_rule);
-
-       _cairo_traps_clear (traps);
-       return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-}
index 9b7b403..cf7cd08 100644 (file)
@@ -59,6 +59,20 @@ typedef char cairo_path_op_t;
 #define CAIRO_PATH_BUF_SIZE ((512 - sizeof (cairo_path_buf_t)) \
                           / (2 * sizeof (cairo_point_t) + sizeof (cairo_path_op_t)))
 
+#define cairo_path_head(path__) (&(path__)->buf.base)
+#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__))
+
+#define cairo_path_buf_next(pos__) \
+    cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link)
+#define cairo_path_buf_prev(pos__) \
+    cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link)
+
+#define cairo_path_foreach_buf_start(pos__, path__) \
+    pos__ = cairo_path_head (path__); do
+#define cairo_path_foreach_buf_end(pos__, path__) \
+    while ((pos__ = cairo_path_buf_next (pos__)) !=  cairo_path_head (path__))
+
+
 typedef struct _cairo_path_buf {
     cairo_list_t link;
     unsigned int num_ops;
@@ -186,4 +200,7 @@ cairo_private cairo_bool_t
 _cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
                                 cairo_box_t *box);
 
+cairo_private cairo_bool_t
+_cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t *path);
+
 #endif /* CAIRO_PATH_FIXED_PRIVATE_H */
index 3f1ddc2..2c19881 100644 (file)
@@ -69,19 +69,6 @@ _cairo_path_buf_add_points (cairo_path_buf_t       *buf,
                            const cairo_point_t    *points,
                            int                     num_points);
 
-#define cairo_path_head(path__) (&(path__)->buf.base)
-#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__))
-
-#define cairo_path_buf_next(pos__) \
-    cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link)
-#define cairo_path_buf_prev(pos__) \
-    cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link)
-
-#define cairo_path_foreach_buf_start(pos__, path__) \
-    pos__ = cairo_path_head (path__); do
-#define cairo_path_foreach_buf_end(pos__, path__) \
-    while ((pos__ = cairo_path_buf_next (pos__)) !=  cairo_path_head (path__))
-
 void
 _cairo_path_fixed_init (cairo_path_fixed_t *path)
 {
@@ -1219,18 +1206,11 @@ _canonical_box (cairo_box_t *box,
     }
 }
 
-/*
- * Check whether the given path contains a single rectangle.
- */
-cairo_bool_t
-_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
-                         cairo_box_t *box)
+static inline cairo_bool_t
+_path_is_quad (const cairo_path_fixed_t *path)
 {
     const cairo_path_buf_t *buf = cairo_path_head (path);
 
-    if (! path->fill_is_rectilinear)
-       return FALSE;
-
     /* Do we have the right number of ops? */
     if (buf->num_ops < 4 || buf->num_ops > 6)
        return FALSE;
@@ -1265,22 +1245,87 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
        }
     }
 
-    /* Ok, we may have a box, if the points line up */
-    if (buf->points[0].y == buf->points[1].y &&
-       buf->points[1].x == buf->points[2].x &&
-       buf->points[2].y == buf->points[3].y &&
-       buf->points[3].x == buf->points[0].x)
-    {
+    return TRUE;
+}
+
+static inline cairo_bool_t
+_points_form_rect (const cairo_point_t *points)
+{
+    if (points[0].y == points[1].y &&
+       points[1].x == points[2].x &&
+       points[2].y == points[3].y &&
+       points[3].x == points[0].x)
+       return TRUE;
+    if (points[0].x == points[1].x &&
+       points[1].y == points[2].y &&
+       points[2].x == points[3].x &&
+       points[3].y == points[0].y)
+       return TRUE;
+    return FALSE;
+}
+
+/*
+ * Check whether the given path contains a single rectangle.
+ */
+cairo_bool_t
+_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
+                         cairo_box_t *box)
+{
+    const cairo_path_buf_t *buf;
+
+    if (! path->fill_is_rectilinear)
+       return FALSE;
+
+    if (! _path_is_quad (path))
+       return FALSE;
+
+    buf = cairo_path_head (path);
+    if (_points_form_rect (buf->points)) {
        _canonical_box (box, &buf->points[0], &buf->points[2]);
        return TRUE;
     }
 
-    if (buf->points[0].x == buf->points[1].x &&
-       buf->points[1].y == buf->points[2].y &&
-       buf->points[2].x == buf->points[3].x &&
-       buf->points[3].y == buf->points[0].y)
-    {
-       _canonical_box (box, &buf->points[0], &buf->points[2]);
+    return FALSE;
+}
+
+/* Determine whether two lines A->B and C->D intersect based on the 
+ * algorithm described here: http://paulbourke.net/geometry/lineline2d/ */
+static inline cairo_bool_t
+_lines_intersect_or_are_coincident (cairo_point_t a,
+                                   cairo_point_t b,
+                                   cairo_point_t c,
+                                   cairo_point_t d)
+{
+    cairo_int64_t numerator_a, numerator_b, denominator;
+
+    denominator = _cairo_int64_sub (_cairo_int32x32_64_mul (d.y - c.y, b.x - a.x),
+                                   _cairo_int32x32_64_mul (d.x - c.x, b.y - a.y));
+    numerator_a = _cairo_int64_sub (_cairo_int32x32_64_mul (d.x - c.x, a.y - c.y),
+                                   _cairo_int32x32_64_mul (d.y - c.y, a.x - c.x));
+    numerator_b = _cairo_int64_sub (_cairo_int32x32_64_mul (b.x - a.x, a.y - c.y),
+                                   _cairo_int32x32_64_mul (b.y - a.y, a.x - c.x));
+
+    if (_cairo_int64_is_zero (denominator)) {
+       /* If the denominator and numerators are both zero,
+        * the lines are coincident. */
+       if (_cairo_int64_is_zero (numerator_a) && _cairo_int64_is_zero (numerator_b))
+           return TRUE;
+
+       /* Otherwise, a zero denominator indicates the lines are
+       *  parallel and never intersect. */
+       return FALSE;
+    }
+
+    /* If either division would produce a number between 0 and 1, i.e.
+     * the numerator is smaller than the denominator and their signs are
+     * the same, then the lines intersect. */
+    if (_cairo_int64_lt (numerator_a, denominator) &&
+       ! (_cairo_int64_negative (numerator_a) ^ _cairo_int64_negative(denominator))) {
+       return TRUE;
+    }
+
+    if (_cairo_int64_lt (numerator_b, denominator) &&
+       ! (_cairo_int64_negative (numerator_b) ^ _cairo_int64_negative(denominator))) {
        return TRUE;
     }
 
@@ -1288,6 +1333,29 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
 }
 
 cairo_bool_t
+_cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t *path)
+{
+    const cairo_point_t *points;
+
+    if (! _path_is_quad (path))
+       return FALSE;
+
+    points = cairo_path_head (path)->points;
+    if (_points_form_rect (points))
+       return TRUE;
+
+    if (_lines_intersect_or_are_coincident (points[0], points[1],
+                                           points[3], points[2]))
+       return FALSE;
+
+    if (_lines_intersect_or_are_coincident (points[0], points[3],
+                                           points[1], points[2]))
+       return FALSE;
+
+    return TRUE;
+}
+
+cairo_bool_t
 _cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
                                 cairo_box_t *box)
 {
@@ -1376,11 +1444,13 @@ _cairo_path_fixed_is_single_line (const cairo_path_fixed_t *path)
 {
     const cairo_path_buf_t *buf = cairo_path_head (path);
 
-    if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
-       buf->op[1] != CAIRO_PATH_OP_LINE_TO)
+    if (buf->num_ops > 2)
        return FALSE;
+    if (buf->num_ops <= 1)
+       return TRUE;
 
-    return TRUE;
+    return buf->op[0] == CAIRO_PATH_OP_MOVE_TO &&
+       buf->op[1] == CAIRO_PATH_OP_LINE_TO;
 }
 
 cairo_bool_t
index f6e81e0..2c8fe5e 100644 (file)
@@ -1169,7 +1169,7 @@ curve_to (void *closure,
     cairo_stroke_face_t face;
 
     if (stroker->has_bounds &&
-       ! _cairo_spline_intersects (&stroker->current_face.point, b, c, b,
+       ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
                                    &stroker->bounds))
        return line_to (closure, d);
 
diff --git a/src/cairo-path-stroke-traps.c b/src/cairo-path-stroke-traps.c
new file mode 100644 (file)
index 0000000..304dea7
--- /dev/null
@@ -0,0 +1,1122 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright Â© 2002 University of Southern California
+ * Copyright Â© 2013 Intel Corporation
+ *
+ * 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *     Carl D. Worth <cworth@cworth.org>
+ *     Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-box-inline.h"
+#include "cairo-path-fixed-private.h"
+#include "cairo-slope-private.h"
+#include "cairo-stroke-dash-private.h"
+#include "cairo-traps-private.h"
+
+#include <float.h>
+
+struct stroker {
+    const cairo_stroke_style_t *style;
+
+    const cairo_matrix_t *ctm;
+    const cairo_matrix_t *ctm_inverse;
+    double spline_cusp_tolerance;
+    double half_line_width;
+    double tolerance;
+    double ctm_determinant;
+    cairo_bool_t ctm_det_positive;
+    cairo_line_join_t line_join;
+
+    cairo_traps_t *traps;
+
+    cairo_pen_t pen;
+
+    cairo_point_t first_point;
+
+    cairo_bool_t has_initial_sub_path;
+
+    cairo_bool_t has_current_face;
+    cairo_stroke_face_t current_face;
+
+    cairo_bool_t has_first_face;
+    cairo_stroke_face_t first_face;
+
+    cairo_stroker_dash_t dash;
+
+    cairo_bool_t has_bounds;
+    cairo_box_t tight_bounds;
+    cairo_box_t line_bounds;
+    cairo_box_t join_bounds;
+};
+
+static cairo_status_t
+stroker_init (struct stroker           *stroker,
+             const cairo_path_fixed_t  *path,
+             const cairo_stroke_style_t        *style,
+             const cairo_matrix_t      *ctm,
+             const cairo_matrix_t      *ctm_inverse,
+             double                     tolerance,
+             cairo_traps_t             *traps)
+{
+    cairo_status_t status;
+
+    stroker->style = style;
+    stroker->ctm = ctm;
+    stroker->ctm_inverse = NULL;
+    if (! _cairo_matrix_is_identity (ctm_inverse))
+       stroker->ctm_inverse = ctm_inverse;
+    stroker->line_join = style->line_join;
+    stroker->half_line_width = style->line_width / 2.0;
+    stroker->tolerance = tolerance;
+    stroker->traps = traps;
+
+    /* To test whether we need to join two segments of a spline using
+     * a round-join or a bevel-join, we can inspect the angle between the
+     * two segments. If the difference between the chord distance
+     * (half-line-width times the cosine of the bisection angle) and the
+     * half-line-width itself is greater than tolerance then we need to
+     * inject a point.
+     */
+    stroker->spline_cusp_tolerance = 1 - tolerance / stroker->half_line_width;
+    stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance;
+    stroker->spline_cusp_tolerance *= 2;
+    stroker->spline_cusp_tolerance -= 1;
+
+    stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
+    stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
+
+    status = _cairo_pen_init (&stroker->pen,
+                             stroker->half_line_width,
+                             tolerance, ctm);
+    if (unlikely (status))
+       return status;
+
+    stroker->has_current_face = FALSE;
+    stroker->has_first_face = FALSE;
+    stroker->has_initial_sub_path = FALSE;
+
+    _cairo_stroker_dash_init (&stroker->dash, style);
+
+    stroker->has_bounds = traps->num_limits;
+    if (stroker->has_bounds) {
+       /* Extend the bounds in each direction to account for the maximum area
+        * we might generate trapezoids, to capture line segments that are outside
+        * of the bounds but which might generate rendering that's within bounds.
+        */
+       double dx, dy;
+       cairo_fixed_t fdx, fdy;
+
+       stroker->tight_bounds = traps->bounds;
+
+       _cairo_stroke_style_max_distance_from_path (stroker->style, path,
+                                                   stroker->ctm, &dx, &dy);
+
+       _cairo_stroke_style_max_line_distance_from_path (stroker->style, path,
+                                                        stroker->ctm, &dx, &dy);
+
+       fdx = _cairo_fixed_from_double (dx);
+       fdy = _cairo_fixed_from_double (dy);
+
+       stroker->line_bounds = stroker->tight_bounds;
+       stroker->line_bounds.p1.x -= fdx;
+       stroker->line_bounds.p2.x += fdx;
+       stroker->line_bounds.p1.y -= fdy;
+       stroker->line_bounds.p2.y += fdy;
+
+       _cairo_stroke_style_max_join_distance_from_path (stroker->style, path,
+                                                        stroker->ctm, &dx, &dy);
+
+       fdx = _cairo_fixed_from_double (dx);
+       fdy = _cairo_fixed_from_double (dy);
+
+       stroker->join_bounds = stroker->tight_bounds;
+       stroker->join_bounds.p1.x -= fdx;
+       stroker->join_bounds.p2.x += fdx;
+       stroker->join_bounds.p1.y -= fdy;
+       stroker->join_bounds.p2.y += fdy;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+stroker_fini (struct stroker *stroker)
+{
+    _cairo_pen_fini (&stroker->pen);
+}
+
+static void
+translate_point (cairo_point_t *point, cairo_point_t *offset)
+{
+    point->x += offset->x;
+    point->y += offset->y;
+}
+
+static int
+join_is_clockwise (const cairo_stroke_face_t *in,
+                  const cairo_stroke_face_t *out)
+{
+    return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0;
+}
+
+static int
+slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
+{
+    double c = dx1 * dy2 - dx2 * dy1;
+    if (c > 0) return 1;
+    if (c < 0) return -1;
+    return 0;
+}
+
+static cairo_bool_t
+stroker_intersects_join (const struct stroker *stroker,
+                        const cairo_point_t *in,
+                        const cairo_point_t *out)
+{
+    cairo_line_t segment;
+
+    if (! stroker->has_bounds)
+       return TRUE;
+
+    segment.p1 = *in;
+    segment.p2 = *out;
+    return _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment);
+}
+
+static void
+join (struct stroker *stroker,
+      cairo_stroke_face_t *in,
+      cairo_stroke_face_t *out)
+{
+    int clockwise = join_is_clockwise (out, in);
+    cairo_point_t *inpt, *outpt;
+
+    if (in->cw.x == out->cw.x &&
+       in->cw.y == out->cw.y &&
+       in->ccw.x == out->ccw.x &&
+       in->ccw.y == out->ccw.y)
+    {
+       return;
+    }
+
+    if (clockwise) {
+       inpt = &in->ccw;
+       outpt = &out->ccw;
+    } else {
+       inpt = &in->cw;
+       outpt = &out->cw;
+    }
+
+    if (! stroker_intersects_join (stroker, inpt, outpt))
+           return;
+
+    switch (stroker->line_join) {
+    case CAIRO_LINE_JOIN_ROUND:
+       /* construct a fan around the common midpoint */
+       if ((in->dev_slope.x * out->dev_slope.x +
+            in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
+       {
+           int start, stop;
+           cairo_point_t tri[3];
+           cairo_pen_t *pen = &stroker->pen;
+
+           tri[0] = in->point;
+           tri[1] = *inpt;
+           if (clockwise) {
+               _cairo_pen_find_active_ccw_vertices (pen,
+                                                    &in->dev_vector, &out->dev_vector,
+                                                    &start, &stop);
+               while (start != stop) {
+                   tri[2] = in->point;
+                   translate_point (&tri[2], &pen->vertices[start].point);
+                   _cairo_traps_tessellate_triangle (stroker->traps, tri);
+                   tri[1] = tri[2];
+
+                   if (start-- == 0)
+                       start += pen->num_vertices;
+               }
+           } else {
+               _cairo_pen_find_active_cw_vertices (pen,
+                                                   &in->dev_vector, &out->dev_vector,
+                                                   &start, &stop);
+               while (start != stop) {
+                   tri[2] = in->point;
+                   translate_point (&tri[2], &pen->vertices[start].point);
+                   _cairo_traps_tessellate_triangle (stroker->traps, tri);
+                   tri[1] = tri[2];
+
+                   if (++start == pen->num_vertices)
+                       start = 0;
+               }
+           }
+           tri[2] = *outpt;
+           _cairo_traps_tessellate_triangle (stroker->traps, tri);
+           break;
+       }
+
+    case CAIRO_LINE_JOIN_MITER:
+    default: {
+       /* dot product of incoming slope vector with outgoing slope vector */
+       double in_dot_out = (-in->usr_vector.x * out->usr_vector.x +
+                            -in->usr_vector.y * out->usr_vector.y);
+       double ml = stroker->style->miter_limit;
+
+       /* Check the miter limit -- lines meeting at an acute angle
+        * can generate long miters, the limit converts them to bevel
+        *
+        * Consider the miter join formed when two line segments
+        * meet at an angle psi:
+        *
+        *         /.\
+        *        /. .\
+        *       /./ \.\
+        *      /./psi\.\
+        *
+        * We can zoom in on the right half of that to see:
+        *
+        *          |\
+        *          | \ psi/2
+        *          |  \
+        *          |   \
+        *          |    \
+        *          |     \
+        *        miter    \
+        *       length     \
+        *          |        \
+        *          |        .\
+        *          |    .     \
+        *          |.   line   \
+        *           \    width  \
+        *            \           \
+        *
+        *
+        * The right triangle in that figure, (the line-width side is
+        * shown faintly with three '.' characters), gives us the
+        * following expression relating miter length, angle and line
+        * width:
+        *
+        *      1 /sin (psi/2) = miter_length / line_width
+        *
+        * The right-hand side of this relationship is the same ratio
+        * in which the miter limit (ml) is expressed. We want to know
+        * when the miter length is within the miter limit. That is
+        * when the following condition holds:
+        *
+        *      1/sin(psi/2) <= ml
+        *      1 <= ml sin(psi/2)
+        *      1 <= ml² sin²(psi/2)
+        *      2 <= ml² 2 sin²(psi/2)
+        *                              2·sin²(psi/2) = 1-cos(psi)
+        *      2 <= ml² (1-cos(psi))
+        *
+        *                              in Â· out = |in| |out| cos (psi)
+        *
+        * in and out are both unit vectors, so:
+        *
+        *                              in Â· out = cos (psi)
+        *
+        *      2 <= ml² (1 - in Â· out)
+        *
+        */
+       if (2 <= ml * ml * (1 - in_dot_out)) {
+           double              x1, y1, x2, y2;
+           double              mx, my;
+           double              dx1, dx2, dy1, dy2;
+           cairo_point_t       outer;
+           cairo_point_t       quad[4];
+           double              ix, iy;
+           double              fdx1, fdy1, fdx2, fdy2;
+           double              mdx, mdy;
+
+           /*
+            * we've got the points already transformed to device
+            * space, but need to do some computation with them and
+            * also need to transform the slope from user space to
+            * device space
+            */
+           /* outer point of incoming line face */
+           x1 = _cairo_fixed_to_double (inpt->x);
+           y1 = _cairo_fixed_to_double (inpt->y);
+           dx1 = in->usr_vector.x;
+           dy1 = in->usr_vector.y;
+           cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
+
+           /* outer point of outgoing line face */
+           x2 = _cairo_fixed_to_double (outpt->x);
+           y2 = _cairo_fixed_to_double (outpt->y);
+           dx2 = out->usr_vector.x;
+           dy2 = out->usr_vector.y;
+           cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+
+           /*
+            * Compute the location of the outer corner of the miter.
+            * That's pretty easy -- just the intersection of the two
+            * outer edges.  We've got slopes and points on each
+            * of those edges.  Compute my directly, then compute
+            * mx by using the edge with the larger dy; that avoids
+            * dividing by values close to zero.
+            */
+           my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
+                 (dx1 * dy2 - dx2 * dy1));
+           if (fabs (dy1) >= fabs (dy2))
+               mx = (my - y1) * dx1 / dy1 + x1;
+           else
+               mx = (my - y2) * dx2 / dy2 + x2;
+
+           /*
+            * When the two outer edges are nearly parallel, slight
+            * perturbations in the position of the outer points of the lines
+            * caused by representing them in fixed point form can cause the
+            * intersection point of the miter to move a large amount. If
+            * that moves the miter intersection from between the two faces,
+            * then draw a bevel instead.
+            */
+
+           ix = _cairo_fixed_to_double (in->point.x);
+           iy = _cairo_fixed_to_double (in->point.y);
+
+           /* slope of one face */
+           fdx1 = x1 - ix; fdy1 = y1 - iy;
+
+           /* slope of the other face */
+           fdx2 = x2 - ix; fdy2 = y2 - iy;
+
+           /* slope from the intersection to the miter point */
+           mdx = mx - ix; mdy = my - iy;
+
+           /*
+            * Make sure the miter point line lies between the two
+            * faces by comparing the slopes
+            */
+           if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
+               slope_compare_sgn (fdx2, fdy2, mdx, mdy))
+           {
+               /*
+                * Draw the quadrilateral
+                */
+               outer.x = _cairo_fixed_from_double (mx);
+               outer.y = _cairo_fixed_from_double (my);
+
+               quad[0] = in->point;
+               quad[1] = *inpt;
+               quad[2] = outer;
+               quad[3] = *outpt;
+
+               _cairo_traps_tessellate_convex_quad (stroker->traps, quad);
+               break;
+           }
+       }
+       /* fall through ... */
+    }
+
+    case CAIRO_LINE_JOIN_BEVEL: {
+       cairo_point_t tri[3];
+       tri[0] = in->point;
+       tri[1] = *inpt;
+       tri[2] = *outpt;
+
+       _cairo_traps_tessellate_triangle (stroker->traps, tri);
+       break;
+    }
+    }
+}
+
+static void
+add_cap (struct stroker *stroker, cairo_stroke_face_t *f)
+{
+    switch (stroker->style->line_cap) {
+    case CAIRO_LINE_CAP_ROUND: {
+       int start, stop;
+       cairo_slope_t in_slope, out_slope;
+       cairo_point_t tri[3];
+       cairo_pen_t *pen = &stroker->pen;
+
+       in_slope = f->dev_vector;
+       out_slope.dx = -in_slope.dx;
+       out_slope.dy = -in_slope.dy;
+       _cairo_pen_find_active_cw_vertices (pen, &in_slope, &out_slope,
+                                           &start, &stop);
+       tri[0] = f->point;
+       tri[1] = f->cw;
+       while (start != stop) {
+           tri[2] = f->point;
+           translate_point (&tri[2], &pen->vertices[start].point);
+           _cairo_traps_tessellate_triangle (stroker->traps, tri);
+
+           tri[1] = tri[2];
+           if (++start == pen->num_vertices)
+               start = 0;
+       }
+       tri[2] = f->ccw;
+       _cairo_traps_tessellate_triangle (stroker->traps, tri);
+       break;
+    }
+
+    case CAIRO_LINE_CAP_SQUARE: {
+       double dx, dy;
+       cairo_slope_t fvector;
+       cairo_point_t quad[4];
+
+       dx = f->usr_vector.x;
+       dy = f->usr_vector.y;
+       dx *= stroker->half_line_width;
+       dy *= stroker->half_line_width;
+       cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
+       fvector.dx = _cairo_fixed_from_double (dx);
+       fvector.dy = _cairo_fixed_from_double (dy);
+
+       quad[0] = f->cw;
+       quad[1].x = f->cw.x + fvector.dx;
+       quad[1].y = f->cw.y + fvector.dy;
+       quad[2].x = f->ccw.x + fvector.dx;
+       quad[2].y = f->ccw.y + fvector.dy;
+       quad[3] = f->ccw;
+
+       _cairo_traps_tessellate_convex_quad (stroker->traps, quad);
+       break;
+    }
+
+    case CAIRO_LINE_CAP_BUTT:
+    default:
+       break;
+    }
+}
+
+static void
+add_leading_cap (struct stroker     *stroker,
+                cairo_stroke_face_t *face)
+{
+    cairo_stroke_face_t reversed;
+    cairo_point_t t;
+
+    reversed = *face;
+
+    /* The initial cap needs an outward facing vector. Reverse everything */
+    reversed.usr_vector.x = -reversed.usr_vector.x;
+    reversed.usr_vector.y = -reversed.usr_vector.y;
+    reversed.dev_vector.dx = -reversed.dev_vector.dx;
+    reversed.dev_vector.dy = -reversed.dev_vector.dy;
+    t = reversed.cw;
+    reversed.cw = reversed.ccw;
+    reversed.ccw = t;
+
+    add_cap (stroker, &reversed);
+}
+
+static void
+add_trailing_cap (struct stroker *stroker, cairo_stroke_face_t *face)
+{
+    add_cap (stroker, face);
+}
+
+static inline double
+normalize_slope (double *dx, double *dy)
+{
+    double dx0 = *dx, dy0 = *dy;
+
+    if (dx0 == 0.0 && dy0 == 0.0)
+       return 0;
+
+    if (dx0 == 0.0) {
+       *dx = 0.0;
+       if (dy0 > 0.0) {
+           *dy = 1.0;
+           return dy0;
+       } else {
+           *dy = -1.0;
+           return -dy0;
+       }
+    } else if (dy0 == 0.0) {
+       *dy = 0.0;
+       if (dx0 > 0.0) {
+           *dx = 1.0;
+           return dx0;
+       } else {
+           *dx = -1.0;
+           return -dx0;
+       }
+    } else {
+       double mag = hypot (dx0, dy0);
+       *dx = dx0 / mag;
+       *dy = dy0 / mag;
+       return mag;
+    }
+}
+
+static void
+compute_face (const cairo_point_t *point,
+             const cairo_slope_t *dev_slope,
+             struct stroker *stroker,
+             cairo_stroke_face_t *face)
+{
+    double face_dx, face_dy;
+    cairo_point_t offset_ccw, offset_cw;
+    double slope_dx, slope_dy;
+
+    slope_dx = _cairo_fixed_to_double (dev_slope->dx);
+    slope_dy = _cairo_fixed_to_double (dev_slope->dy);
+    face->length = normalize_slope (&slope_dx, &slope_dy);
+    face->dev_slope.x = slope_dx;
+    face->dev_slope.y = slope_dy;
+
+    /*
+     * rotate to get a line_width/2 vector along the face, note that
+     * the vector must be rotated the right direction in device space,
+     * but by 90° in user space. So, the rotation depends on
+     * whether the ctm reflects or not, and that can be determined
+     * by looking at the determinant of the matrix.
+     */
+    if (stroker->ctm_inverse) {
+       cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy);
+       normalize_slope (&slope_dx, &slope_dy);
+
+       if (stroker->ctm_det_positive) {
+           face_dx = - slope_dy * stroker->half_line_width;
+           face_dy = slope_dx * stroker->half_line_width;
+       } else {
+           face_dx = slope_dy * stroker->half_line_width;
+           face_dy = - slope_dx * stroker->half_line_width;
+       }
+
+       /* back to device space */
+       cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
+    } else {
+       face_dx = - slope_dy * stroker->half_line_width;
+       face_dy = slope_dx * stroker->half_line_width;
+    }
+
+    offset_ccw.x = _cairo_fixed_from_double (face_dx);
+    offset_ccw.y = _cairo_fixed_from_double (face_dy);
+    offset_cw.x = -offset_ccw.x;
+    offset_cw.y = -offset_ccw.y;
+
+    face->ccw = *point;
+    translate_point (&face->ccw, &offset_ccw);
+
+    face->point = *point;
+
+    face->cw = *point;
+    translate_point (&face->cw, &offset_cw);
+
+    face->usr_vector.x = slope_dx;
+    face->usr_vector.y = slope_dy;
+
+    face->dev_vector = *dev_slope;
+}
+
+static void
+add_caps (struct stroker *stroker)
+{
+    /* check for a degenerative sub_path */
+    if (stroker->has_initial_sub_path &&
+       !stroker->has_first_face &&
+       !stroker->has_current_face &&
+       stroker->style->line_cap == CAIRO_LINE_CAP_ROUND)
+    {
+       /* pick an arbitrary slope to use */
+       cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
+       cairo_stroke_face_t face;
+
+       /* arbitrarily choose first_point
+        * first_point and current_point should be the same */
+       compute_face (&stroker->first_point, &slope, stroker, &face);
+
+       add_leading_cap (stroker, &face);
+       add_trailing_cap (stroker, &face);
+    }
+
+    if (stroker->has_first_face)
+       add_leading_cap (stroker, &stroker->first_face);
+
+    if (stroker->has_current_face)
+       add_trailing_cap (stroker, &stroker->current_face);
+}
+
+static cairo_bool_t
+stroker_intersects_edge (const struct stroker *stroker,
+                        const cairo_stroke_face_t *start,
+                        const cairo_stroke_face_t *end)
+{
+    cairo_box_t box;
+
+    if (! stroker->has_bounds)
+       return TRUE;
+
+    if (_cairo_box_contains_point (&stroker->tight_bounds, &start->cw))
+       return TRUE;
+    box.p2 = box.p1 = start->cw;
+
+    if (_cairo_box_contains_point (&stroker->tight_bounds, &start->ccw))
+       return TRUE;
+    _cairo_box_add_point (&box, &start->ccw);
+
+    if (_cairo_box_contains_point (&stroker->tight_bounds, &end->cw))
+       return TRUE;
+    _cairo_box_add_point (&box, &end->cw);
+
+    if (_cairo_box_contains_point (&stroker->tight_bounds, &end->ccw))
+       return TRUE;
+    _cairo_box_add_point (&box, &end->ccw);
+
+    return (box.p2.x > stroker->tight_bounds.p1.x &&
+           box.p1.x < stroker->tight_bounds.p2.x &&
+           box.p2.y > stroker->tight_bounds.p1.y &&
+           box.p1.y < stroker->tight_bounds.p2.y);
+}
+
+static void
+add_sub_edge (struct stroker *stroker,
+             const cairo_point_t *p1, const cairo_point_t *p2,
+             const cairo_slope_t *dev_slope,
+             cairo_stroke_face_t *start, cairo_stroke_face_t *end)
+{
+    cairo_point_t rectangle[4];
+
+    compute_face (p1, dev_slope, stroker, start);
+
+    *end = *start;
+    end->point = *p2;
+    rectangle[0].x = p2->x - p1->x;
+    rectangle[0].y = p2->y - p1->y;
+    translate_point (&end->ccw, &rectangle[0]);
+    translate_point (&end->cw, &rectangle[0]);
+
+    if (p1->x == p2->x && p1->y == p2->y)
+       return;
+
+    if (! stroker_intersects_edge (stroker, start, end))
+       return;
+
+    rectangle[0] = start->cw;
+    rectangle[1] = start->ccw;
+    rectangle[2] = end->ccw;
+    rectangle[3] = end->cw;
+
+    _cairo_traps_tessellate_convex_quad (stroker->traps, rectangle);
+}
+
+static cairo_status_t
+move_to (void *closure, const cairo_point_t *point)
+{
+    struct stroker *stroker = closure;
+
+    /* Cap the start and end of the previous sub path as needed */
+    add_caps (stroker);
+
+    stroker->first_point = *point;
+    stroker->current_face.point = *point;
+
+    stroker->has_first_face = FALSE;
+    stroker->has_current_face = FALSE;
+    stroker->has_initial_sub_path = FALSE;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+move_to_dashed (void *closure, const cairo_point_t *point)
+{
+    /* reset the dash pattern for new sub paths */
+    struct stroker *stroker = closure;
+
+    _cairo_stroker_dash_start (&stroker->dash);
+    return move_to (closure, point);
+}
+
+static cairo_status_t
+line_to (void *closure, const cairo_point_t *point)
+{
+    struct stroker *stroker = closure;
+    cairo_stroke_face_t start, end;
+    const cairo_point_t *p1 = &stroker->current_face.point;
+    const cairo_point_t *p2 = point;
+    cairo_slope_t dev_slope;
+
+    stroker->has_initial_sub_path = TRUE;
+
+    if (p1->x == p2->x && p1->y == p2->y)
+       return CAIRO_STATUS_SUCCESS;
+
+    _cairo_slope_init (&dev_slope, p1, p2);
+    add_sub_edge (stroker, p1, p2, &dev_slope, &start, &end);
+
+    if (stroker->has_current_face) {
+       /* Join with final face from previous segment */
+       join (stroker, &stroker->current_face, &start);
+    } else if (!stroker->has_first_face) {
+       /* Save sub path's first face in case needed for closing join */
+       stroker->first_face = start;
+       stroker->has_first_face = TRUE;
+    }
+    stroker->current_face = end;
+    stroker->has_current_face = TRUE;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/*
+ * Dashed lines.  Cap each dash end, join around turns when on
+ */
+static cairo_status_t
+line_to_dashed (void *closure, const cairo_point_t *point)
+{
+    struct stroker *stroker = closure;
+    double mag, remain, step_length = 0;
+    double slope_dx, slope_dy;
+    double dx2, dy2;
+    cairo_stroke_face_t sub_start, sub_end;
+    const cairo_point_t *p1 = &stroker->current_face.point;
+    const cairo_point_t *p2 = point;
+    cairo_slope_t dev_slope;
+    cairo_line_t segment;
+    cairo_bool_t fully_in_bounds;
+
+    stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
+
+    if (p1->x == p2->x && p1->y == p2->y)
+       return CAIRO_STATUS_SUCCESS;
+
+    fully_in_bounds = TRUE;
+    if (stroker->has_bounds &&
+       (! _cairo_box_contains_point (&stroker->join_bounds, p1) ||
+        ! _cairo_box_contains_point (&stroker->join_bounds, p2)))
+    {
+       fully_in_bounds = FALSE;
+    }
+
+    _cairo_slope_init (&dev_slope, p1, p2);
+
+    slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
+    slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
+
+    if (stroker->ctm_inverse)
+       cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy);
+    mag = normalize_slope (&slope_dx, &slope_dy);
+    if (mag <= DBL_EPSILON)
+       return CAIRO_STATUS_SUCCESS;
+
+    remain = mag;
+    segment.p1 = *p1;
+    while (remain) {
+       step_length = MIN (stroker->dash.dash_remain, remain);
+       remain -= step_length;
+       dx2 = slope_dx * (mag - remain);
+       dy2 = slope_dy * (mag - remain);
+       cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+       segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
+       segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;
+
+       if (stroker->dash.dash_on &&
+           (fully_in_bounds ||
+            (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
+            _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment)))
+       {
+           add_sub_edge (stroker,
+                         &segment.p1, &segment.p2,
+                         &dev_slope,
+                         &sub_start, &sub_end);
+
+           if (stroker->has_current_face) {
+               /* Join with final face from previous segment */
+               join (stroker, &stroker->current_face, &sub_start);
+
+               stroker->has_current_face = FALSE;
+           } else if (! stroker->has_first_face && stroker->dash.dash_starts_on) {
+               /* Save sub path's first face in case needed for closing join */
+               stroker->first_face = sub_start;
+               stroker->has_first_face = TRUE;
+           } else {
+               /* Cap dash start if not connecting to a previous segment */
+               add_leading_cap (stroker, &sub_start);
+           }
+
+           if (remain) {
+               /* Cap dash end if not at end of segment */
+               add_trailing_cap (stroker, &sub_end);
+           } else {
+               stroker->current_face = sub_end;
+               stroker->has_current_face = TRUE;
+           }
+       } else {
+           if (stroker->has_current_face) {
+               /* Cap final face from previous segment */
+               add_trailing_cap (stroker, &stroker->current_face);
+
+               stroker->has_current_face = FALSE;
+           }
+       }
+
+       _cairo_stroker_dash_step (&stroker->dash, step_length);
+       segment.p1 = segment.p2;
+    }
+
+    if (stroker->dash.dash_on && ! stroker->has_current_face) {
+       /* This segment ends on a transition to dash_on, compute a new face
+        * and add cap for the beginning of the next dash_on step.
+        *
+        * Note: this will create a degenerate cap if this is not the last line
+        * in the path. Whether this behaviour is desirable or not is debatable.
+        * On one side these degenerate caps can not be reproduced with regular
+        * path stroking.
+        * On the other hand, Acroread 7 also produces the degenerate caps.
+        */
+       compute_face (point, &dev_slope, stroker, &stroker->current_face);
+
+       add_leading_cap (stroker, &stroker->current_face);
+
+       stroker->has_current_face = TRUE;
+    } else
+       stroker->current_face.point = *point;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+spline_to (void *closure,
+          const cairo_point_t *point,
+          const cairo_slope_t *tangent)
+{
+    struct stroker *stroker = closure;
+    cairo_stroke_face_t face;
+
+    if ((tangent->dx | tangent->dy) == 0) {
+       cairo_point_t t;
+
+       face = stroker->current_face;
+
+       face.usr_vector.x = -face.usr_vector.x;
+       face.usr_vector.y = -face.usr_vector.y;
+       face.dev_slope.x = -face.dev_slope.x;
+       face.dev_slope.y = -face.dev_slope.y;
+       face.dev_vector.dx = -face.dev_vector.dx;
+       face.dev_vector.dy = -face.dev_vector.dy;
+
+       t = face.cw;
+       face.cw = face.ccw;
+       face.ccw = t;
+
+       join (stroker, &stroker->current_face, &face);
+    } else {
+       cairo_point_t rectangle[4];
+
+       compute_face (&stroker->current_face.point, tangent, stroker, &face);
+
+       join (stroker, &stroker->current_face, &face);
+
+       rectangle[0] = face.cw;
+       rectangle[1] = face.ccw;
+
+       rectangle[2].x = point->x - face.point.x;
+       rectangle[2].y = point->y - face.point.y;
+       face.point = *point;
+       translate_point (&face.ccw, &rectangle[2]);
+       translate_point (&face.cw, &rectangle[2]);
+
+       rectangle[2] = face.ccw;
+       rectangle[3] = face.cw;
+
+       _cairo_traps_tessellate_convex_quad (stroker->traps, rectangle);
+    }
+
+    stroker->current_face = face;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+curve_to (void *closure,
+         const cairo_point_t *b,
+         const cairo_point_t *c,
+         const cairo_point_t *d)
+{
+    struct stroker *stroker = closure;
+    cairo_line_join_t line_join_save;
+    cairo_spline_t spline;
+    cairo_stroke_face_t face;
+    cairo_status_t status;
+
+    if (stroker->has_bounds &&
+       ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
+                                   &stroker->line_bounds))
+       return line_to (closure, d);
+
+    if (! _cairo_spline_init (&spline, spline_to, stroker,
+                             &stroker->current_face.point, b, c, d))
+       return line_to (closure, d);
+
+    compute_face (&stroker->current_face.point, &spline.initial_slope,
+                 stroker, &face);
+
+    if (stroker->has_current_face) {
+       /* Join with final face from previous segment */
+       join (stroker, &stroker->current_face, &face);
+    } else {
+       if (! stroker->has_first_face) {
+           /* Save sub path's first face in case needed for closing join */
+           stroker->first_face = face;
+           stroker->has_first_face = TRUE;
+       }
+       stroker->has_current_face = TRUE;
+    }
+    stroker->current_face = face;
+
+    /* Temporarily modify the stroker to use round joins to guarantee
+     * smooth stroked curves. */
+    line_join_save = stroker->line_join;
+    stroker->line_join = CAIRO_LINE_JOIN_ROUND;
+
+    status = _cairo_spline_decompose (&spline, stroker->tolerance);
+
+    stroker->line_join = line_join_save;
+
+    return status;
+}
+
+static cairo_status_t
+curve_to_dashed (void *closure,
+                const cairo_point_t *b,
+                const cairo_point_t *c,
+                const cairo_point_t *d)
+{
+    struct stroker *stroker = closure;
+    cairo_spline_t spline;
+    cairo_line_join_t line_join_save;
+    cairo_spline_add_point_func_t func;
+    cairo_status_t status;
+
+    func = (cairo_spline_add_point_func_t)line_to_dashed;
+
+    if (stroker->has_bounds &&
+       ! _cairo_spline_intersects (&stroker->current_face.point, b, c, b,
+                                   &stroker->line_bounds))
+       return func (closure, d, NULL);
+
+    if (! _cairo_spline_init (&spline, func, stroker,
+                             &stroker->current_face.point, b, c, d))
+       return func (closure, d, NULL);
+
+    /* Temporarily modify the stroker to use round joins to guarantee
+     * smooth stroked curves. */
+    line_join_save = stroker->line_join;
+    stroker->line_join = CAIRO_LINE_JOIN_ROUND;
+
+    status = _cairo_spline_decompose (&spline, stroker->tolerance);
+
+    stroker->line_join = line_join_save;
+
+    return status;
+}
+
+static cairo_status_t
+_close_path (struct stroker *stroker)
+{
+    if (stroker->has_first_face && stroker->has_current_face) {
+       /* Join first and final faces of sub path */
+       join (stroker, &stroker->current_face, &stroker->first_face);
+    } else {
+       /* Cap the start and end of the sub path as needed */
+       add_caps (stroker);
+    }
+
+    stroker->has_initial_sub_path = FALSE;
+    stroker->has_first_face = FALSE;
+    stroker->has_current_face = FALSE;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+close_path (void *closure)
+{
+    struct stroker *stroker = closure;
+    cairo_status_t status;
+
+    status = line_to (stroker, &stroker->first_point);
+    if (unlikely (status))
+       return status;
+
+    return _close_path (stroker);
+}
+
+static cairo_status_t
+close_path_dashed (void *closure)
+{
+    struct stroker *stroker = closure;
+    cairo_status_t status;
+
+    status = line_to_dashed (stroker, &stroker->first_point);
+    if (unlikely (status))
+       return status;
+
+    return _close_path (stroker);
+}
+
+cairo_int_status_t
+_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t    *path,
+                                  const cairo_stroke_style_t   *style,
+                                  const cairo_matrix_t         *ctm,
+                                  const cairo_matrix_t         *ctm_inverse,
+                                  double                        tolerance,
+                                  cairo_traps_t                *traps)
+{
+    struct stroker stroker;
+    cairo_status_t status;
+
+    status = stroker_init (&stroker, path, style,
+                          ctm, ctm_inverse, tolerance,
+                          traps);
+    if (unlikely (status))
+       return status;
+
+    if (stroker.dash.dashed)
+       status = _cairo_path_fixed_interpret (path,
+                                             move_to_dashed,
+                                             line_to_dashed,
+                                             curve_to_dashed,
+                                             close_path_dashed,
+                                             &stroker);
+    else
+       status = _cairo_path_fixed_interpret (path,
+                                             move_to,
+                                             line_to,
+                                             curve_to,
+                                             close_path,
+                                             &stroker);
+    assert(status == CAIRO_STATUS_SUCCESS);
+    add_caps (&stroker);
+
+    stroker_fini (&stroker);
+
+    return traps->status;
+}
index dab5de8..0d7679d 100644 (file)
@@ -52,6 +52,7 @@ typedef struct cairo_stroker {
 
     const cairo_matrix_t *ctm;
     const cairo_matrix_t *ctm_inverse;
+    double half_line_width;
     double tolerance;
     double ctm_determinant;
     cairo_bool_t ctm_det_positive;
@@ -88,6 +89,46 @@ typedef struct cairo_stroker {
     cairo_box_t bounds;
 } cairo_stroker_t;
 
+static cairo_bool_t
+_cairo_stroke_segment_intersect (cairo_point_t *p1, cairo_point_t *p2,
+                 cairo_point_t *p3, cairo_point_t *p4,
+                                 cairo_point_t *p)
+{
+    double x1, y1, x2, y2, x3, y3, x4, y4;
+    double pre, post;
+    double x, y, d;
+
+    x1 = _cairo_fixed_to_double (p1->x);
+    y1 = _cairo_fixed_to_double (p1->y);
+    x2 = _cairo_fixed_to_double (p2->x);
+    y2 = _cairo_fixed_to_double (p2->y);
+    x3 = _cairo_fixed_to_double (p3->x);
+    y3 = _cairo_fixed_to_double (p3->y);
+    x4 = _cairo_fixed_to_double (p4->x);
+    y4 = _cairo_fixed_to_double (p4->y);
+
+    d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
+    if (d == 0)
+        return FALSE;
+
+    pre = x1 * y2 - y1 * x2;
+    post = x3 * y4 - y3 * x4;
+    x = (pre * (x3 - x4) - (x1 - x2) * post) / d;
+    y = (pre * (y3 - y4) - (y1 - y2) * post) / d;
+
+    /* check if x, y are within both segments */
+    if (x < MIN (x1, x2) || x > MAX (x1, x2) ||
+        x < MIN (x3, x4) || x > MAX (x3, x4))
+    return FALSE;
+    if (y < MIN (y1, y2) || y > MAX (y1, y2) ||
+        y < MIN (y1, y2) || y > MAX (y3, y4))
+    return FALSE;
+
+    p->x = _cairo_fixed_from_double (x);
+    p->y = _cairo_fixed_from_double (y);
+    return TRUE;
+}
+
 static void
 _cairo_stroker_limit (cairo_stroker_t *stroker,
                      const cairo_path_fixed_t *path,
@@ -134,13 +175,13 @@ _cairo_stroker_init (cairo_stroker_t              *stroker,
     stroker->ctm = ctm;
     stroker->ctm_inverse = ctm_inverse;
     stroker->tolerance = tolerance;
+    stroker->half_line_width = stroke_style->line_width / 2.0;
 
     stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
     stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
 
     status = _cairo_pen_init (&stroker->pen,
-                             stroke_style->line_width / 2.0,
-                             tolerance, ctm);
+                             stroker->half_line_width, tolerance, ctm);
     if (unlikely (status))
        return status;
 
@@ -637,8 +678,8 @@ _cairo_stroker_add_cap (cairo_stroker_t *stroker,
 
        dx = f->usr_vector.x;
        dy = f->usr_vector.y;
-       dx *= stroker->style.line_width / 2.0;
-       dy *= stroker->style.line_width / 2.0;
+       dx *= stroker->half_line_width;
+       dy *= stroker->half_line_width;
        cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
        fvector.dx = _cairo_fixed_from_double (dx);
        fvector.dy = _cairo_fixed_from_double (dy);
@@ -779,13 +820,13 @@ _compute_face (const cairo_point_t *point,
      */
     if (stroker->ctm_det_positive)
     {
-       face_dx = - slope_dy * (stroker->style.line_width / 2.0);
-       face_dy = slope_dx * (stroker->style.line_width / 2.0);
+       face_dx = - slope_dy * stroker->half_line_width;
+       face_dy = slope_dx * stroker->half_line_width;
     }
     else
     {
-       face_dx = slope_dy * (stroker->style.line_width / 2.0);
-       face_dy = - slope_dx * (stroker->style.line_width / 2.0);
+       face_dx = slope_dy * stroker->half_line_width;
+       face_dy = - slope_dx * stroker->half_line_width;
     }
 
     /* back to device space */
@@ -990,6 +1031,7 @@ _cairo_stroker_spline_to (void *closure,
     cairo_stroke_face_t new_face;
     double slope_dx, slope_dy;
     cairo_point_t points[3];
+    cairo_point_t intersect_point;
 
     stroker->has_initial_sub_path = TRUE;
 
@@ -1009,8 +1051,24 @@ _cairo_stroker_spline_to (void *closure,
                   stroker, &new_face);
 
     assert(stroker->has_current_face);
+
+    if (_cairo_stroke_segment_intersect (&stroker->current_face.cw,
+                     &stroker->current_face.ccw,
+                                         &new_face.cw,
+                                         &new_face.ccw,
+                                         &intersect_point)) {
+    points[0] = stroker->current_face.ccw;
+    points[1] = new_face.ccw;
+    points[2] = intersect_point;
+    stroker->add_triangle (stroker->closure, points);
+
     points[0] = stroker->current_face.cw;
-    points[1] = stroker->current_face.ccw;
+    points[1] = new_face.cw;
+    stroker->add_triangle (stroker->closure, points);
+    }
+    else {
+    points[0] = stroker->current_face.ccw;
+    points[1] = stroker->current_face.cw;
     points[2] = new_face.cw;
     stroker->add_triangle (stroker->closure, points);
 
@@ -1018,6 +1076,7 @@ _cairo_stroker_spline_to (void *closure,
     points[1] = new_face.cw;
     points[2] = new_face.ccw;
     stroker->add_triangle (stroker->closure, points);
+    }
 
     stroker->current_face = new_face;
     stroker->has_current_face = TRUE;
@@ -1396,12 +1455,12 @@ BAIL:
 }
 
 cairo_int_status_t
-_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t    *path,
-                                  const cairo_stroke_style_t   *stroke_style,
-                                  const cairo_matrix_t *ctm,
-                                  const cairo_matrix_t *ctm_inverse,
-                                  double                tolerance,
-                                  cairo_traps_t        *traps)
+_cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t    *path,
+                                           const cairo_stroke_style_t  *stroke_style,
+                                           const cairo_matrix_t        *ctm,
+                                           const cairo_matrix_t        *ctm_inverse,
+                                           double               tolerance,
+                                           cairo_traps_t       *traps)
 {
     cairo_int_status_t status;
     cairo_polygon_t polygon;
index cf441c4..61be0e8 100644 (file)
@@ -284,7 +284,7 @@ _cairo_pen_vertices_needed (double      tolerance,
                                                                     radius);
     int num_vertices;
 
-    if (tolerance >= 2*major_axis) {
+    if (tolerance >= 4*major_axis) { /* XXX relaxed from 2*major for inkscape */
        num_vertices = 1;
     } else if (tolerance >= major_axis) {
        num_vertices = 4;
@@ -412,21 +412,23 @@ _cairo_pen_find_active_cw_vertices (const cairo_pen_t *pen,
            i = 0;
     *start = i;
 
-    lo = i;
-    hi = i + pen->num_vertices;
-    i = (lo + hi) >> 1;
-    do {
-       int j = i;
-       if (j >= pen->num_vertices)
-           j -= pen->num_vertices;
-       if (_cairo_slope_compare (&pen->vertices[j].slope_cw, out) > 0)
-           hi = i;
-       else
-           lo = i;
+    if (_cairo_slope_compare (out, &pen->vertices[i].slope_ccw) >= 0) {
+       lo = i;
+       hi = i + pen->num_vertices;
        i = (lo + hi) >> 1;
-    } while (hi - lo > 1);
-    if (i >= pen->num_vertices)
-       i -= pen->num_vertices;
+       do {
+           int j = i;
+           if (j >= pen->num_vertices)
+               j -= pen->num_vertices;
+           if (_cairo_slope_compare (&pen->vertices[j].slope_cw, out) > 0)
+               hi = i;
+           else
+               lo = i;
+           i = (lo + hi) >> 1;
+       } while (hi - lo > 1);
+       if (i >= pen->num_vertices)
+           i -= pen->num_vertices;
+    }
     *stop = i;
 }
 
@@ -452,20 +454,22 @@ _cairo_pen_find_active_ccw_vertices (const cairo_pen_t *pen,
            i = 0;
     *start = i;
 
-    lo = i;
-    hi = i + pen->num_vertices;
-    i = (lo + hi) >> 1;
-    do {
-       int j = i;
-       if (j >= pen->num_vertices)
-           j -= pen->num_vertices;
-       if (_cairo_slope_compare (out, &pen->vertices[j].slope_ccw) > 0)
-           hi = i;
-       else
-           lo = i;
+    if (_cairo_slope_compare (&pen->vertices[i].slope_cw, out) <= 0) {
+       lo = i;
+       hi = i + pen->num_vertices;
        i = (lo + hi) >> 1;
-    } while (hi - lo > 1);
-    if (i >= pen->num_vertices)
-       i -= pen->num_vertices;
+       do {
+           int j = i;
+           if (j >= pen->num_vertices)
+               j -= pen->num_vertices;
+           if (_cairo_slope_compare (out, &pen->vertices[j].slope_ccw) > 0)
+               hi = i;
+           else
+               lo = i;
+           i = (lo + hi) >> 1;
+       } while (hi - lo > 1);
+       if (i >= pen->num_vertices)
+           i -= pen->num_vertices;
+    }
     *stop = i;
 }
index ce7c760..edbeed7 100755 (executable)
@@ -210,7 +210,10 @@ bbtree_add (struct bbtree *bbt,
     if (box->p1.x == bbt->extents.p1.x && box->p1.y == bbt->extents.p1.y &&
        box->p2.x == bbt->extents.p2.x && box->p2.y == bbt->extents.p2.y)
     {
-       header->chain = bbt->chain;
+       cairo_command_header_t *last = header;
+       while (last->chain) /* expected to be infrequent */
+           last = last->chain;
+       last->chain = bbt->chain;
        bbt->chain = header;
        return CAIRO_STATUS_SUCCESS;
     }
@@ -1536,12 +1539,12 @@ _cairo_recording_surface_get_path (cairo_surface_t    *abstract_surface,
            _cairo_traps_init (&traps);
 
            /* XXX call cairo_stroke_to_path() when that is implemented */
-           status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
-                                                       &command->stroke.style,
-                                                       &command->stroke.ctm,
-                                                       &command->stroke.ctm_inverse,
-                                                       command->stroke.tolerance,
-                                                       &traps);
+           status = _cairo_path_fixed_stroke_polygon_to_traps (&command->stroke.path,
+                                                               &command->stroke.style,
+                                                               &command->stroke.ctm,
+                                                               &command->stroke.ctm_inverse,
+                                                               command->stroke.tolerance,
+                                                               &traps);
 
            if (status == CAIRO_INT_STATUS_SUCCESS)
                status = _cairo_traps_path (&traps, path);
index 47f2837..2d51d7b 100644 (file)
@@ -189,7 +189,7 @@ _cairo_rectangle_union (cairo_rectangle_int_t *dst,
  */
 
 cairo_bool_t
-_cairo_box_intersects_line_segment (cairo_box_t *box, cairo_line_t *line)
+_cairo_box_intersects_line_segment (const cairo_box_t *box, cairo_line_t *line)
 {
     cairo_fixed_t t1=0, t2=0, t3=0, t4=0;
     cairo_int64_t t1y, t2y, t3x, t4x;
index f622a53..0405253 100644 (file)
@@ -451,16 +451,16 @@ _cairo_scaled_font_map_destroy (void)
  CLEANUP_MUTEX_LOCK:
     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
 }
+
 static void
-_cairo_scaled_glyph_page_destroy (void *closure)
+_cairo_scaled_glyph_page_destroy (cairo_scaled_font_t *scaled_font,
+                                 cairo_scaled_glyph_page_t *page)
 {
-    cairo_scaled_glyph_page_t *page = closure;
-    cairo_scaled_font_t *scaled_font;
     unsigned int n;
 
-    assert (! cairo_list_is_empty (&page->link));
+    assert (!scaled_font->cache_frozen);
+    assert (!scaled_font->global_cache_frozen);
 
-    scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
     for (n = 0; n < page->num_glyphs; n++) {
        _cairo_hash_table_remove (scaled_font->glyphs,
                                  &page->glyphs[n].hash_entry);
@@ -468,10 +468,24 @@ _cairo_scaled_glyph_page_destroy (void *closure)
     }
 
     cairo_list_del (&page->link);
-
     free (page);
 }
 
+static void
+_cairo_scaled_glyph_page_pluck (void *closure)
+{
+    cairo_scaled_glyph_page_t *page = closure;
+    cairo_scaled_font_t *scaled_font;
+
+    assert (! cairo_list_is_empty (&page->link));
+
+    scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
+
+    CAIRO_MUTEX_LOCK (scaled_font->mutex);
+    _cairo_scaled_glyph_page_destroy (scaled_font, page);
+    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
+}
+
 /* If a scaled font wants to unlock the font map while still being
  * created (needed for user-fonts), we need to take extra care not
  * ending up with multiple identical scaled fonts being created.
@@ -790,32 +804,40 @@ _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
 void
 _cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
 {
-    scaled_font->cache_frozen = FALSE;
+    assert (scaled_font->cache_frozen);
 
     if (scaled_font->global_cache_frozen) {
        CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
        _cairo_cache_thaw (&cairo_scaled_glyph_page_cache);
        CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
-
        scaled_font->global_cache_frozen = FALSE;
     }
 
+    scaled_font->cache_frozen = FALSE;
     CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
 }
 
 void
 _cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
 {
+    CAIRO_MUTEX_LOCK (scaled_font->mutex);
     assert (! scaled_font->cache_frozen);
-
+    assert (! scaled_font->global_cache_frozen);
     CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
     while (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
-       _cairo_cache_remove (&cairo_scaled_glyph_page_cache,
-                             &cairo_list_first_entry (&scaled_font->glyph_pages,
-                                                      cairo_scaled_glyph_page_t,
-                                                      link)->cache_entry);
+       cairo_scaled_glyph_page_t *page =
+           cairo_list_first_entry (&scaled_font->glyph_pages,
+                                   cairo_scaled_glyph_page_t,
+                                   link);
+
+       cairo_scaled_glyph_page_cache.size -= page->cache_entry.size;
+       _cairo_hash_table_remove (cairo_scaled_glyph_page_cache.hash_table,
+                                 (cairo_hash_entry_t *) &page->cache_entry);
+
+       _cairo_scaled_glyph_page_destroy (scaled_font, page);
     }
     CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
+    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
 }
 
 cairo_status_t
@@ -850,6 +872,8 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t     *scaled_font,
 static void
 _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
 {
+    assert (! scaled_font->cache_frozen);
+    assert (! scaled_font->global_cache_frozen);
     scaled_font->finished = TRUE;
 
     _cairo_scaled_font_reset_cache (scaled_font);
@@ -1141,6 +1165,8 @@ cairo_scaled_font_create (cairo_font_face_t          *font_face,
      * ft-font-faces
      */
     assert (scaled_font->font_face == font_face);
+    assert (! scaled_font->cache_frozen);
+    assert (! scaled_font->global_cache_frozen);
 
     scaled_font->original_font_face =
        cairo_font_face_reference (original_font_face);
@@ -1290,6 +1316,9 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
     if (! _cairo_reference_count_dec_and_test (&scaled_font->ref_count))
        return;
 
+    assert (! scaled_font->cache_frozen);
+    assert (! scaled_font->global_cache_frozen);
+
     font_map = _cairo_scaled_font_map_lock ();
     assert (font_map != NULL);
 
@@ -2156,36 +2185,37 @@ _cairo_scaled_font_single_glyph_device_extents (cairo_scaled_font_t      *scaled_fon
                                                const cairo_glyph_t      *glyph,
                                                cairo_rectangle_int_t   *extents)
 {
-    cairo_round_glyph_positions_t round_xy;
     cairo_scaled_glyph_t *scaled_glyph;
     cairo_status_t status;
-    cairo_box_t box;
-    cairo_fixed_t v;
 
+    _cairo_scaled_font_freeze_cache (scaled_font);
     status = _cairo_scaled_glyph_lookup (scaled_font,
                                         glyph->index,
                                         CAIRO_SCALED_GLYPH_INFO_METRICS,
                                         &scaled_glyph);
-    if (unlikely (status))
-       return status;
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+       cairo_bool_t round_xy = _cairo_font_options_get_round_glyph_positions (&scaled_font->options) == CAIRO_ROUND_GLYPH_POS_ON;
+       cairo_box_t box;
+       cairo_fixed_t v;
 
-    round_xy = _cairo_font_options_get_round_glyph_positions (&scaled_font->options);
-    if (round_xy == CAIRO_ROUND_GLYPH_POS_ON)
-       v = _cairo_fixed_from_int (_cairo_lround (glyph->x));
-    else
-       v = _cairo_fixed_from_double (glyph->x);
-    box.p1.x = v + scaled_glyph->bbox.p1.x;
-    box.p2.x = v + scaled_glyph->bbox.p2.x;
+       if (round_xy)
+           v = _cairo_fixed_from_int (_cairo_lround (glyph->x));
+       else
+           v = _cairo_fixed_from_double (glyph->x);
+       box.p1.x = v + scaled_glyph->bbox.p1.x;
+       box.p2.x = v + scaled_glyph->bbox.p2.x;
 
-    if (round_xy == CAIRO_ROUND_GLYPH_POS_ON)
-       v = _cairo_fixed_from_int (_cairo_lround (glyph->y));
-    else
-       v = _cairo_fixed_from_double (glyph->y);
-    box.p1.y = v + scaled_glyph->bbox.p1.y;
-    box.p2.y = v + scaled_glyph->bbox.p2.y;
+       if (round_xy)
+           v = _cairo_fixed_from_int (_cairo_lround (glyph->y));
+       else
+           v = _cairo_fixed_from_double (glyph->y);
+       box.p1.y = v + scaled_glyph->bbox.p1.y;
+       box.p2.y = v + scaled_glyph->bbox.p2.y;
 
-    _cairo_box_round_to_rectangle (&box, extents);
-    return CAIRO_STATUS_SUCCESS;
+       _cairo_box_round_to_rectangle (&box, extents);
+    }
+    _cairo_scaled_font_thaw_cache (scaled_font);
+    return status;
 }
 
 /*
@@ -2841,6 +2871,8 @@ _cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font,
     cairo_scaled_glyph_page_t *page;
     cairo_status_t status;
 
+    assert (scaled_font->cache_frozen);
+
     /* only the first page in the list may contain available slots */
     if (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
         page = cairo_list_last_entry (&scaled_font->glyph_pages,
@@ -2866,7 +2898,7 @@ _cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font,
            status = _cairo_cache_init (&cairo_scaled_glyph_page_cache,
                                        NULL,
                                        _cairo_scaled_glyph_page_can_remove,
-                                       _cairo_scaled_glyph_page_destroy,
+                                       _cairo_scaled_glyph_page_pluck,
                                        MAX_GLYPH_PAGES_CACHED);
            if (unlikely (status)) {
                CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
@@ -2958,6 +2990,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
        return scaled_font->status;
 
     assert (CAIRO_MUTEX_IS_LOCKED(scaled_font->mutex));
+    assert (scaled_font->cache_frozen);
 
     if (CAIRO_INJECT_FAULT ())
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -3040,7 +3073,8 @@ _cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
  * hold true for all possible cases.
  *
  * Return value: The #cairo_font_face_t with which @scaled_font was
- * created.
+ * created.  This object is owned by cairo. To keep a reference to it,
+ * you must call cairo_scaled_font_reference().
  *
  * Since: 1.2
  **/
index 2149e7e..b84aed9 100644 (file)
@@ -3390,8 +3390,10 @@ _cairo_script_surface_show_text_glyphs (void                         *abstract_surface,
                                             glyphs[n].index,
                                             CAIRO_SCALED_GLYPH_INFO_METRICS,
                                             &scaled_glyph);
-       if (unlikely (status))
+       if (unlikely (status)) {
+           _cairo_scaled_font_thaw_cache (scaled_font);
            goto BAIL;
+       }
 
        if (fabs (glyphs[n].x - x) > 1e-5 || fabs (glyphs[n].y - y) > 1e-5) {
            if (fabs (glyphs[n].y - y) < 1e-5) {
index d8b94fb..0babebd 100644 (file)
@@ -46,7 +46,7 @@ CAIRO_BEGIN_DECLS
 
 typedef struct _cairo_abstract_span_renderer {
     cairo_span_renderer_t base;
-    char data[2048];
+    char data[4096];
 } cairo_abstract_span_renderer_t;
 
 struct cairo_spans_compositor {
index ffbf56f..cb3e973 100644 (file)
@@ -557,8 +557,10 @@ composite_aligned_boxes (const cairo_spans_compositor_t            *compositor,
 
     TRACE ((stderr, "%s: need_clip_mask=%d, is-bounded=%d\n",
            __FUNCTION__, need_clip_mask, extents->is_bounded));
-    if (need_clip_mask && ! extents->is_bounded)
+    if (need_clip_mask && ! extents->is_bounded) {
+       TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
        return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
 
     no_mask = extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
        CAIRO_COLOR_IS_OPAQUE (&extents->mask_pattern.solid.color);
@@ -570,8 +572,10 @@ composite_aligned_boxes (const cairo_spans_compositor_t            *compositor,
 
     if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) {
        /* SOURCE with a mask is actually a LERP in cairo semantics */
-       if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0)
+       if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0) {
+           TRACE ((stderr, "%s: unsupported lerp\n", __FUNCTION__));
            return CAIRO_INT_STATUS_UNSUPPORTED;
+       }
     }
 
     /* Are we just copying a recording surface? */
@@ -700,8 +704,10 @@ composite_boxes (const cairo_spans_compositor_t *compositor,
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
     _cairo_box_from_rectangle (&box, &extents->unbounded);
-    if (composite_needs_clip (extents, &box))
+    if (composite_needs_clip (extents, &box)) {
+       TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
        return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
 
     _cairo_rectangular_scan_converter_init (&converter, &extents->unbounded);
     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
@@ -738,10 +744,13 @@ composite_polygon (const cairo_spans_compositor_t *compositor,
     cairo_bool_t needs_clip;
     cairo_int_status_t status;
 
-    needs_clip = ! extents->is_bounded &&
-       (! _clip_is_region (extents->clip) || extents->clip->num_boxes > 1);
+    if (extents->is_bounded)
+       needs_clip = extents->clip->path != NULL;
+    else
+       needs_clip = !_clip_is_region (extents->clip) || extents->clip->num_boxes > 1;
     TRACE ((stderr, "%s - needs_clip=%d\n", __FUNCTION__, needs_clip));
     if (needs_clip) {
+       TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
        return CAIRO_INT_STATUS_UNSUPPORTED;
        converter = _cairo_clip_tor_scan_converter_create (extents->clip,
                                                           polygon,
@@ -992,7 +1001,9 @@ _cairo_spans_compositor_stroke (const cairo_compositor_t   *_compositor,
     const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
     cairo_int_status_t status;
 
+    TRACE ((stderr, "%s\n", __FUNCTION__));
     TRACE_ (_cairo_debug_print_path (stderr, path));
+    TRACE_ (_cairo_debug_print_clip (stderr, extents->clip));
 
     status = CAIRO_INT_STATUS_UNSUPPORTED;
     if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
index 3ebaf01..51c9414 100644 (file)
@@ -127,6 +127,45 @@ _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
     }
 }
 
+void
+_cairo_stroke_style_max_line_distance_from_path (const cairo_stroke_style_t *style,
+                                                const cairo_path_fixed_t *path,
+                                                const cairo_matrix_t *ctm,
+                                                double *dx, double *dy)
+{
+    double style_expansion = 0.5 * style->line_width;
+    if (_cairo_matrix_has_unity_scale (ctm)) {
+       *dx = *dy = style_expansion;
+    } else {
+       *dx = style_expansion * hypot (ctm->xx, ctm->xy);
+       *dy = style_expansion * hypot (ctm->yy, ctm->yx);
+    }
+}
+
+void
+_cairo_stroke_style_max_join_distance_from_path (const cairo_stroke_style_t *style,
+                                                const cairo_path_fixed_t *path,
+                                                const cairo_matrix_t *ctm,
+                                                double *dx, double *dy)
+{
+    double style_expansion = 0.5;
+
+    if (style->line_join == CAIRO_LINE_JOIN_MITER &&
+       ! path->stroke_is_rectilinear &&
+       style_expansion < M_SQRT2 * style->miter_limit)
+    {
+       style_expansion = M_SQRT2 * style->miter_limit;
+    }
+
+    style_expansion *= style->line_width;
+
+    if (_cairo_matrix_has_unity_scale (ctm)) {
+       *dx = *dy = style_expansion;
+    } else {
+       *dx = style_expansion * hypot (ctm->xx, ctm->xy);
+       *dy = style_expansion * hypot (ctm->yy, ctm->yx);
+    }
+}
 /*
  * Computes the period of a dashed stroke style.
  * Returns 0 for non-dashed styles.
index 57e560c..6b4140d 100644 (file)
@@ -1279,7 +1279,8 @@ _cairo_mime_data_destroy (void *ptr)
  * memory and disk space.
  *
  * The recognized MIME types are the following: %CAIRO_MIME_TYPE_JPEG,
- * %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI.
+ * %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI,
+ * %CAIRO_MIME_TYPE_UNIQUE_ID.
  *
  * See corresponding backend surface docs for details about which MIME
  * types it can handle. Caution: the associated MIME data will be
index eeee20c..6dccb51 100644 (file)
@@ -1570,7 +1570,7 @@ clip_and_composite_polygon (const cairo_traps_compositor_t *compositor,
         * The clip will trim that overestimate to our expectations.
         */
        if (! extents->is_bounded)
-               flags |= FORCE_CLIP_REGION;
+           flags |= FORCE_CLIP_REGION;
 
        traps.antialias = antialias;
        status = clip_and_composite (compositor, extents,
@@ -1791,7 +1791,8 @@ composite_traps_as_boxes (const cairo_traps_compositor_t *compositor,
 static cairo_int_status_t
 clip_and_composite_traps (const cairo_traps_compositor_t *compositor,
                          cairo_composite_rectangles_t *extents,
-                         composite_traps_info_t *info)
+                         composite_traps_info_t *info,
+                         unsigned flags)
 {
     cairo_int_status_t status;
 
@@ -1801,10 +1802,10 @@ clip_and_composite_traps (const cairo_traps_compositor_t *compositor,
     if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
        return status;
 
-    status = composite_traps_as_boxes (compositor, extents, info);
+    status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if ((flags & FORCE_CLIP_REGION) == 0)
+       status = composite_traps_as_boxes (compositor, extents, info);
     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-       unsigned int flags = 0;
-
        /* For unbounded operations, the X11 server will estimate the
         * affected rectangle and apply the operation to that. However,
         * there are cases where this is an overestimate (e.g. the
@@ -2152,16 +2153,32 @@ _cairo_traps_compositor_stroke (const cairo_compositor_t *_compositor,
     }
 
     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+       cairo_int_status_t (*func) (const cairo_path_fixed_t    *path,
+                                   const cairo_stroke_style_t  *stroke_style,
+                                   const cairo_matrix_t        *ctm,
+                                   const cairo_matrix_t        *ctm_inverse,
+                                   double                       tolerance,
+                                   cairo_traps_t               *traps);
        composite_traps_info_t info;
+       unsigned flags = 0;
+
+       if (antialias == CAIRO_ANTIALIAS_BEST || antialias == CAIRO_ANTIALIAS_GOOD) {
+           func = _cairo_path_fixed_stroke_polygon_to_traps;
+       } else {
+           func = _cairo_path_fixed_stroke_to_traps;
+           if (extents->clip->num_boxes > 1 ||
+               extents->mask.width  > extents->unbounded.width ||
+               extents->mask.height > extents->unbounded.height)
+           {
+               flags = NEED_CLIP_REGION | FORCE_CLIP_REGION;
+           }
+       }
 
        info.antialias = antialias;
        _cairo_traps_init_with_clip (&info.traps, extents->clip);
-       status = _cairo_path_fixed_stroke_to_traps (path, style,
-                                                   ctm, ctm_inverse,
-                                                   tolerance,
-                                                   &info.traps);
+       status = func (path, style, ctm, ctm_inverse, tolerance, &info.traps);
        if (likely (status == CAIRO_INT_STATUS_SUCCESS))
-           status = clip_and_composite_traps (compositor, extents, &info);
+           status = clip_and_composite_traps (compositor, extents, &info, flags);
        _cairo_traps_fini (&info.traps);
     }
 
@@ -2276,7 +2293,6 @@ _cairo_traps_compositor_glyphs (const cairo_compositor_t  *_compositor,
     if (unlikely (status))
        return status;
 
-    _cairo_scaled_font_freeze_cache (scaled_font);
     status = compositor->check_composite_glyphs (extents,
                                                 scaled_font, glyphs,
                                                 &num_glyphs);
@@ -2301,7 +2317,6 @@ _cairo_traps_compositor_glyphs (const cairo_compositor_t  *_compositor,
                                     need_bounded_clip (extents) |
                                     flags);
     }
-    _cairo_scaled_font_thaw_cache (scaled_font);
 
     return status;
 }
index 62c0fe7..7fef062 100644 (file)
@@ -47,6 +47,7 @@ CAIRO_BEGIN_DECLS
 struct _cairo_traps {
     cairo_status_t status;
 
+    cairo_box_t bounds;
     const cairo_box_t *limits;
     int num_limits;
 
@@ -89,6 +90,14 @@ _cairo_traps_fini (cairo_traps_t *traps);
 cairo_private void
 _cairo_traps_translate (cairo_traps_t *traps, int x, int y);
 
+cairo_private void
+_cairo_traps_tessellate_triangle (cairo_traps_t *traps,
+                                 const cairo_point_t t[3]);
+
+cairo_private void
+_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps,
+                                    const cairo_point_t q[4]);
+
 cairo_private cairo_status_t
 _cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
                                   const cairo_point_t *top_left,
index 48eaf98..9f1d4a7 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "cairoint.h"
 
+#include "cairo-box-inline.h"
 #include "cairo-boxes-private.h"
 #include "cairo-error-private.h"
 #include "cairo-region-private.h"
@@ -73,8 +74,14 @@ _cairo_traps_limit (cairo_traps_t    *traps,
                    const cairo_box_t   *limits,
                    int                  num_limits)
 {
+    int i;
+
     traps->limits = limits;
     traps->num_limits = num_limits;
+
+    traps->bounds = limits[0];
+    for (i = 1; i < num_limits; i++)
+       _cairo_box_add_box (&traps->bounds, &limits[i]);
 }
 
 void
@@ -158,6 +165,245 @@ _cairo_traps_add_trap (cairo_traps_t *traps,
     trap->right = *right;
 }
 
+static void
+_cairo_traps_add_clipped_trap (cairo_traps_t *traps,
+                              cairo_fixed_t _top, cairo_fixed_t _bottom,
+                              cairo_line_t *_left, cairo_line_t *_right)
+{
+    /* Note: With the goofy trapezoid specification, (where an
+     * arbitrary two points on the lines can specified for the left
+     * and right edges), these limit checks would not work in
+     * general. For example, one can imagine a trapezoid entirely
+     * within the limits, but with two points used to specify the left
+     * edge entirely to the right of the limits.  Fortunately, for our
+     * purposes, cairo will never generate such a crazy
+     * trapezoid. Instead, cairo always uses for its points the
+     * extreme positions of the edge that are visible on at least some
+     * trapezoid. With this constraint, it's impossible for both
+     * points to be outside the limits while the relevant edge is
+     * entirely inside the limits.
+     */
+    if (traps->num_limits) {
+       const cairo_box_t *b = &traps->bounds;
+       cairo_fixed_t top = _top, bottom = _bottom;
+       cairo_line_t left = *_left, right = *_right;
+
+       /* Trivially reject if trapezoid is entirely to the right or
+        * to the left of the limits. */
+       if (left.p1.x >= b->p2.x && left.p2.x >= b->p2.x)
+           return;
+
+       if (right.p1.x <= b->p1.x && right.p2.x <= b->p1.x)
+           return;
+
+       /* And reject if the trapezoid is entirely above or below */
+       if (top >= b->p2.y || bottom <= b->p1.y)
+           return;
+
+       /* Otherwise, clip the trapezoid to the limits. We only clip
+        * where an edge is entirely outside the limits. If we wanted
+        * to be more clever, we could handle cases where a trapezoid
+        * edge intersects the edge of the limits, but that would
+        * require slicing this trapezoid into multiple trapezoids,
+        * and I'm not sure the effort would be worth it. */
+       if (top < b->p1.y)
+           top = b->p1.y;
+
+       if (bottom > b->p2.y)
+           bottom = b->p2.y;
+
+       if (left.p1.x <= b->p1.x && left.p2.x <= b->p1.x)
+           left.p1.x = left.p2.x = b->p1.x;
+
+       if (right.p1.x >= b->p2.x && right.p2.x >= b->p2.x)
+           right.p1.x = right.p2.x = b->p2.x;
+
+       /* Trivial discards for empty trapezoids that are likely to
+        * be produced by our tessellators (most notably convex_quad
+        * when given a simple rectangle).
+        */
+       if (top >= bottom)
+           return;
+
+       /* cheap colinearity check */
+       if (right.p1.x <= left.p1.x && right.p1.y == left.p1.y &&
+           right.p2.x <= left.p2.x && right.p2.y == left.p2.y)
+           return;
+
+       _cairo_traps_add_trap (traps, top, bottom, &left, &right);
+    } else
+       _cairo_traps_add_trap (traps, _top, _bottom, _left, _right);
+}
+
+static int
+_compare_point_fixed_by_y (const void *av, const void *bv)
+{
+    const cairo_point_t        *a = av, *b = bv;
+    int ret = a->y - b->y;
+    if (ret == 0)
+       ret = a->x - b->x;
+    return ret;
+}
+
+void
+_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps,
+                                    const cairo_point_t q[4])
+{
+    int a, b, c, d;
+    int i;
+    cairo_slope_t ab, ad;
+    cairo_bool_t b_left_of_d;
+    cairo_line_t left;
+    cairo_line_t right;
+
+    /* Choose a as a point with minimal y */
+    a = 0;
+    for (i = 1; i < 4; i++)
+       if (_compare_point_fixed_by_y (&q[i], &q[a]) < 0)
+           a = i;
+
+    /* b and d are adjacent to a, while c is opposite */
+    b = (a + 1) % 4;
+    c = (a + 2) % 4;
+    d = (a + 3) % 4;
+
+    /* Choose between b and d so that b.y is less than d.y */
+    if (_compare_point_fixed_by_y (&q[d], &q[b]) < 0) {
+       b = (a + 3) % 4;
+       d = (a + 1) % 4;
+    }
+
+    /* Without freedom left to choose anything else, we have four
+     * cases to tessellate.
+     *
+     * First, we have to determine the Y-axis sort of the four
+     * vertices, (either abcd or abdc). After that we need to detemine
+     * which edges will be "left" and which will be "right" in the
+     * resulting trapezoids. This can be determined by computing a
+     * slope comparison of ab and ad to determine if b is left of d or
+     * not.
+     *
+     * Note that "left of" here is in the sense of which edges should
+     * be the left vs. right edges of the trapezoid. In particular, b
+     * left of d does *not* mean that b.x is less than d.x.
+     *
+     * This should hopefully be made clear in the lame ASCII art
+     * below. Since the same slope comparison is used in all cases, we
+     * compute it before testing for the Y-value sort. */
+
+    /* Note: If a == b then the ab slope doesn't give us any
+     * information. In that case, we can replace it with the ac (or
+     * equivalenly the bc) slope which gives us exactly the same
+     * information we need. At worst the names of the identifiers ab
+     * and b_left_of_d are inaccurate in this case, (would be ac, and
+     * c_left_of_d). */
+    if (q[a].x == q[b].x && q[a].y == q[b].y)
+       _cairo_slope_init (&ab, &q[a], &q[c]);
+    else
+       _cairo_slope_init (&ab, &q[a], &q[b]);
+
+    _cairo_slope_init (&ad, &q[a], &q[d]);
+
+    b_left_of_d = _cairo_slope_compare (&ab, &ad) > 0;
+
+    if (q[c].y <= q[d].y) {
+       if (b_left_of_d) {
+           /* Y-sort is abcd and b is left of d, (slope(ab) > slope (ad))
+            *
+            *                      top bot left right
+            *        _a  a  a
+            *      / /  /|  |\      a.y b.y  ab   ad
+            *     b /  b |  b \
+            *    / /   | |   \ \    b.y c.y  bc   ad
+            *   c /    c |    c \
+            *  | /      \|     \ \  c.y d.y  cd   ad
+            *  d         d       d
+            */
+           left.p1  = q[a]; left.p2  = q[b];
+           right.p1 = q[a]; right.p2 = q[d];
+           _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+           left.p1  = q[b]; left.p2  = q[c];
+           _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
+           left.p1  = q[c]; left.p2  = q[d];
+           _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
+       } else {
+           /* Y-sort is abcd and b is right of d, (slope(ab) <= slope (ad))
+            *
+            *       a  a  a_
+            *      /|  |\  \ \     a.y b.y  ad  ab
+            *     / b  | b  \ b
+            *    / /   | |   \ \   b.y c.y  ad  bc
+            *   / c    | c    \ c
+            *  / /     |/      \ | c.y d.y  ad  cd
+            *  d       d         d
+            */
+           left.p1  = q[a]; left.p2  = q[d];
+           right.p1 = q[a]; right.p2 = q[b];
+           _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+           right.p1 = q[b]; right.p2 = q[c];
+           _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
+           right.p1 = q[c]; right.p2 = q[d];
+           _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
+       }
+    } else {
+       if (b_left_of_d) {
+           /* Y-sort is abdc and b is left of d, (slope (ab) > slope (ad))
+            *
+            *        a   a     a
+            *       //  / \    |\     a.y b.y  ab  ad
+            *     /b/  b   \   b \
+            *    / /    \   \   \ \   b.y d.y  bc  ad
+            *   /d/      \   d   \ d
+            *  //         \ /     \|  d.y c.y  bc  dc
+            *  c           c       c
+            */
+           left.p1  = q[a]; left.p2  = q[b];
+           right.p1 = q[a]; right.p2 = q[d];
+           _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+           left.p1  = q[b]; left.p2  = q[c];
+           _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
+           right.p1 = q[d]; right.p2 = q[c];
+           _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
+       } else {
+           /* Y-sort is abdc and b is right of d, (slope (ab) <= slope (ad))
+            *
+            *      a     a   a
+            *     /|    / \  \\       a.y b.y  ad  ab
+            *    / b   /   b  \b\
+            *   / /   /   /    \ \    b.y d.y  ad  bc
+            *  d /   d   /      \d\
+            *  |/     \ /         \\  d.y c.y  dc  bc
+            *  c       c          c
+            */
+           left.p1  = q[a]; left.p2  = q[d];
+           right.p1 = q[a]; right.p2 = q[b];
+           _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+           right.p1 = q[b]; right.p2 = q[c];
+           _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
+           left.p1  = q[d]; left.p2  = q[c];
+           _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
+       }
+    }
+}
+
+/* A triangle is simply a degenerate case of a convex
+ * quadrilateral. We would not benefit from having any distinct
+ * implementation of triangle vs. quadrilateral tessellation here. */
+void
+_cairo_traps_tessellate_triangle (cairo_traps_t *traps,
+                                 const cairo_point_t t[3])
+{
+    cairo_point_t quad[4];
+
+    quad[0] = t[0];
+    quad[1] = t[0];
+    quad[2] = t[1];
+    quad[3] = t[2];
+
+    _cairo_traps_tessellate_convex_quad (traps, quad);
+}
+
+
 /**
  * _cairo_traps_init_boxes:
  * @traps: a #cairo_traps_t
@@ -240,6 +486,9 @@ _cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
        cairo_bool_t reversed;
        int n;
 
+       if (top >= traps->bounds.p2.y || bottom <= traps->bounds.p1.y)
+           return CAIRO_STATUS_SUCCESS;
+
        /* support counter-clockwise winding for rectangular tessellation */
        reversed = top_left->x > bottom_right->x;
        if (reversed) {
@@ -247,6 +496,9 @@ _cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
            left.p1.x = left.p2.x = bottom_right->x;
        }
 
+       if (left.p1.x >= traps->bounds.p2.x || right.p1.x <= traps->bounds.p1.x)
+           return CAIRO_STATUS_SUCCESS;
+
        for (n = 0; n < traps->num_limits; n++) {
            const cairo_box_t *limits = &traps->limits[n];
            cairo_line_t _left, _right;
index c19773d..e87ed46 100644 (file)
@@ -53,6 +53,7 @@
 #include "cairo-output-stream-private.h"
 
 #include <ctype.h>
+#include <locale.h>
 
 #define TYPE1_STACKSIZE 24 /* Defined in Type 1 Font Format */
 
@@ -114,6 +115,8 @@ typedef struct _cairo_type1_font_subset {
 
     const char *rd, *nd, *np;
 
+    int lenIV;
+
     char *type1_data;
     unsigned int type1_length;
     char *type1_end;
@@ -134,11 +137,13 @@ typedef struct _cairo_type1_font_subset {
     int hex_column;
 
     struct {
-       int stack[TYPE1_STACKSIZE], sp, top_value;
+       double stack[TYPE1_STACKSIZE];
+       int sp;
     } build_stack;
 
     struct {
-       int other_subr_args[TYPE1_STACKSIZE], num_other_subr_args, cur_other_subr_arg;
+       int stack[TYPE1_STACKSIZE];
+       int sp;
     } ps_stack;
 
 
@@ -302,8 +307,17 @@ cairo_type1_font_subset_get_matrix (cairo_type1_font_subset_t *font,
                                    double                    *d)
 {
     const char *start, *end, *segment_end;
-    int ret;
+    int ret, s_max, i, j;
     char *s;
+    struct lconv *locale_data;
+    const char *decimal_point;
+    int decimal_point_len;
+
+    locale_data = localeconv ();
+    decimal_point = locale_data->decimal_point;
+    decimal_point_len = strlen (decimal_point);
+
+    assert (decimal_point_len != 0);
 
     segment_end = font->header_segment + font->header_segment_size;
     start = find_token (font->header_segment, segment_end, name);
@@ -314,12 +328,23 @@ cairo_type1_font_subset_get_matrix (cairo_type1_font_subset_t *font,
     if (end == NULL)
        return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    s = malloc (end - start + 1);
+    s_max = end - start + 5*decimal_point_len + 1;
+    s = malloc (s_max);
     if (unlikely (s == NULL))
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    strncpy (s, start, end - start);
-    s[end - start] = 0;
+    i = 0;
+    j = 0;
+    while (i < end - start && j < s_max - decimal_point_len) {
+       if (start[i] == '.') {
+           strncpy(s + j, decimal_point, decimal_point_len);
+           i++;
+           j += decimal_point_len;
+       } else {
+           s[j++] = start[i++];
+       }
+    }
+    s[j] = 0;
 
     start = strpbrk (s, "{[");
     if (!start) {
@@ -719,17 +744,37 @@ use_standard_encoding_glyph (cairo_type1_font_subset_t *font, int index)
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
 
-#define TYPE1_CHARSTRING_COMMAND_ESCAPE                0x0c
-#define TYPE1_CHARSTRING_COMMAND_SEAC          0x0c06
-#define TYPE1_CHARSTRING_COMMAND_SBW           0x0c07
-#define TYPE1_CHARSTRING_COMMAND_HSBW          0x0d
-#define TYPE1_CHARSTRING_COMMAND_CALLSUBR      0x0a
-#define TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR  0x0c10
-#define TYPE1_CHARSTRING_COMMAND_POP           0x0c11
 
-
-
-/* Get glyph width and look for seac operatorParse charstring */
+#define TYPE1_CHARSTRING_COMMAND_HSTEM          0x01
+#define TYPE1_CHARSTRING_COMMAND_VSTEM          0x03
+#define TYPE1_CHARSTRING_COMMAND_VMOVETO        0x04
+#define TYPE1_CHARSTRING_COMMAND_RLINETO        0x05
+#define TYPE1_CHARSTRING_COMMAND_HLINETO        0x06
+#define TYPE1_CHARSTRING_COMMAND_VLINETO        0x07
+#define TYPE1_CHARSTRING_COMMAND_RRCURVETO      0x08
+#define TYPE1_CHARSTRING_COMMAND_CLOSEPATH      0x09
+#define TYPE1_CHARSTRING_COMMAND_CALLSUBR       0x0a
+#define TYPE1_CHARSTRING_COMMAND_RETURN                 0x0b
+#define TYPE1_CHARSTRING_COMMAND_ESCAPE                 0x0c
+#define TYPE1_CHARSTRING_COMMAND_HSBW           0x0d
+#define TYPE1_CHARSTRING_COMMAND_ENDCHAR        0x0e
+#define TYPE1_CHARSTRING_COMMAND_RMOVETO        0x15
+#define TYPE1_CHARSTRING_COMMAND_HMOVETO        0x16
+#define TYPE1_CHARSTRING_COMMAND_VHCURVETO      0x1e
+#define TYPE1_CHARSTRING_COMMAND_HVCURVETO      0x1f
+#define TYPE1_CHARSTRING_COMMAND_DOTSECTION     0x0c00
+#define TYPE1_CHARSTRING_COMMAND_VSTEM3                 0x0c01
+#define TYPE1_CHARSTRING_COMMAND_HSTEM3                 0x0c02
+#define TYPE1_CHARSTRING_COMMAND_SEAC           0x0c06
+#define TYPE1_CHARSTRING_COMMAND_SBW            0x0c07
+#define TYPE1_CHARSTRING_COMMAND_DIV            0x0c0c
+#define TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR   0x0c10
+#define TYPE1_CHARSTRING_COMMAND_POP            0x0c11
+#define TYPE1_CHARSTRING_COMMAND_SETCURRENTPOINT 0x0c21
+
+/* Parse the charstring, including recursing into subroutines. Find
+ * the glyph width, subroutines called, and glyphs required by the
+ * SEAC operator. */
 static cairo_status_t
 cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font,
                                          int                        glyph,
@@ -740,9 +785,7 @@ cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font,
     unsigned char *charstring;
     const unsigned char *end;
     const unsigned char *p;
-    cairo_bool_t last_op_was_integer;
     int command;
-    int subr_num, i;
 
     charstring = malloc (encrypted_charstring_length);
     if (unlikely (charstring == NULL))
@@ -753,45 +796,72 @@ cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font,
                                                encrypted_charstring_length,
                                                charstring);
     end = charstring + encrypted_charstring_length;
-
-    p = charstring + 4;
-
-    last_op_was_integer = FALSE;
-
+    p = charstring + font->lenIV;
+    status = CAIRO_STATUS_SUCCESS;
     while (p < end) {
         if (*p < 32) {
            command = *p++;
            switch (command) {
-           case TYPE1_CHARSTRING_COMMAND_HSBW:
-               if (! last_op_was_integer)
-                   return CAIRO_INT_STATUS_UNSUPPORTED;
-
-               font->glyphs[glyph].width = font->build_stack.stack[1]/font->base.units_per_em;
+           case TYPE1_CHARSTRING_COMMAND_HSTEM:
+           case TYPE1_CHARSTRING_COMMAND_VSTEM:
+           case TYPE1_CHARSTRING_COMMAND_VMOVETO:
+           case TYPE1_CHARSTRING_COMMAND_RLINETO:
+           case TYPE1_CHARSTRING_COMMAND_HLINETO:
+           case TYPE1_CHARSTRING_COMMAND_VLINETO:
+           case TYPE1_CHARSTRING_COMMAND_RRCURVETO:
+           case TYPE1_CHARSTRING_COMMAND_CLOSEPATH:
+           case TYPE1_CHARSTRING_COMMAND_RMOVETO:
+           case TYPE1_CHARSTRING_COMMAND_HMOVETO:
+           case TYPE1_CHARSTRING_COMMAND_VHCURVETO:
+           case TYPE1_CHARSTRING_COMMAND_HVCURVETO:
+           case TYPE1_CHARSTRING_COMMAND_RETURN:
+           case TYPE1_CHARSTRING_COMMAND_ENDCHAR:
+           default:
+               /* stack clearing operator */
                font->build_stack.sp = 0;
-               last_op_was_integer = FALSE;
                break;
 
            case TYPE1_CHARSTRING_COMMAND_CALLSUBR:
-               if (font->subset_subrs  &&
-                   last_op_was_integer &&
-                   font->build_stack.top_value >= 0    &&
-                   font->build_stack.top_value < font->num_subrs)
-               {
-                   subr_num = font->build_stack.top_value;
-                   font->subrs[subr_num].used = TRUE;
-                   last_op_was_integer = FALSE;
-                   status = cairo_type1_font_subset_parse_charstring (font,
-                                                                      glyph,
-                                                                      font->subrs[subr_num].subr_string,
-                                                                      font->subrs[subr_num].subr_length);
-               } else {
-                   font->subset_subrs = FALSE;
+               if (font->subset_subrs && font->build_stack.sp > 0) {
+                   double int_val;
+                   if (modf(font->build_stack.stack[--font->build_stack.sp], &int_val) == 0.0) {
+                       int subr_num = int_val;
+                       if (subr_num >= 0 && subr_num < font->num_subrs) {
+                           font->subrs[subr_num].used = TRUE;
+                           status = cairo_type1_font_subset_parse_charstring (
+                               font,
+                               glyph,
+                               font->subrs[subr_num].subr_string,
+                               font->subrs[subr_num].subr_length);
+                           break;
+                       }
+                   }
                }
+               font->subset_subrs = FALSE;
+               break;
+
+           case TYPE1_CHARSTRING_COMMAND_HSBW:
+               if (font->build_stack.sp < 2) {
+                   status = CAIRO_INT_STATUS_UNSUPPORTED;
+                   goto cleanup;
+               }
+
+               font->glyphs[glyph].width = font->build_stack.stack[1]/font->base.units_per_em;
+               font->build_stack.sp = 0;
                break;
 
            case TYPE1_CHARSTRING_COMMAND_ESCAPE:
                command = command << 8 | *p++;
                switch (command) {
+               case TYPE1_CHARSTRING_COMMAND_DOTSECTION:
+               case TYPE1_CHARSTRING_COMMAND_VSTEM3:
+               case TYPE1_CHARSTRING_COMMAND_HSTEM3:
+               case TYPE1_CHARSTRING_COMMAND_SETCURRENTPOINT:
+               default:
+                   /* stack clearing operator */
+                   font->build_stack.sp = 0;
+                   break;
+
                case TYPE1_CHARSTRING_COMMAND_SEAC:
                    /* The seac command takes five integer arguments.  The
                     * last two are glyph indices into the PS standard
@@ -799,69 +869,92 @@ cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font,
                     * glyph is composed from.  All we need to do is to
                     * make sure those glyphs are present in the subset
                     * under their standard names. */
+                   if (font->build_stack.sp < 5) {
+                       status = CAIRO_INT_STATUS_UNSUPPORTED;
+                       goto cleanup;
+                   }
+
                    status = use_standard_encoding_glyph (font, font->build_stack.stack[3]);
                    if (unlikely (status))
-                       return status;
+                       goto cleanup;
 
                    status = use_standard_encoding_glyph (font, font->build_stack.stack[4]);
                    if (unlikely (status))
-                       return status;
+                       goto cleanup;
 
                    font->build_stack.sp = 0;
-                   last_op_was_integer = FALSE;
                    break;
 
                case TYPE1_CHARSTRING_COMMAND_SBW:
-                   if (! last_op_was_integer)
-                       return CAIRO_INT_STATUS_UNSUPPORTED;
+                   if (font->build_stack.sp < 4) {
+                       status = CAIRO_INT_STATUS_UNSUPPORTED;
+                       goto cleanup;
+                   }
 
                    font->glyphs[glyph].width = font->build_stack.stack[2]/font->base.units_per_em;
                    font->build_stack.sp = 0;
-                   last_op_was_integer = FALSE;
                    break;
 
-               case TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR:
-                   for (i = 0; i < font->build_stack.sp; i++)
-                       font->ps_stack.other_subr_args[i] = font->build_stack.stack[i];
-                   font->ps_stack.num_other_subr_args = font->build_stack.sp;
-                   font->ps_stack.cur_other_subr_arg = 0;
-                   font->build_stack.sp = 0;
-                   last_op_was_integer = FALSE;
+               case TYPE1_CHARSTRING_COMMAND_DIV:
+                   if (font->build_stack.sp < 2) {
+                       status = CAIRO_INT_STATUS_UNSUPPORTED;
+                       goto cleanup;
+                   } else {
+                       double num1 = font->build_stack.stack[font->build_stack.sp - 2];
+                       double num2 = font->build_stack.stack[font->build_stack.sp - 1];
+                       font->build_stack.sp--;
+                       if (num2 == 0.0) {
+                           status = CAIRO_INT_STATUS_UNSUPPORTED;
+                           goto cleanup;
+                       }
+                       font->build_stack.stack[font->build_stack.sp - 1] = num1/num2;
+                   }
                    break;
 
+               case TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR:
+                   if (font->build_stack.sp < 1) {
+                       status = CAIRO_INT_STATUS_UNSUPPORTED;
+                       goto cleanup;
+                   }
+
+                   font->build_stack.sp--;
+                   font->ps_stack.sp = 0;
+                   while (font->build_stack.sp)
+                       font->ps_stack.stack[font->ps_stack.sp++] = font->build_stack.stack[--font->build_stack.sp];
+
+                    break;
+
                case TYPE1_CHARSTRING_COMMAND_POP:
-                   if (font->ps_stack.num_other_subr_args > font->ps_stack.cur_other_subr_arg) {
-                       font->build_stack.top_value = font->ps_stack.other_subr_args[font->ps_stack.cur_other_subr_arg++];
-                       last_op_was_integer = TRUE;
-                   } else {
-                       font->subset_subrs = FALSE;
+                   if (font->ps_stack.sp < 1) {
+                       status = CAIRO_INT_STATUS_UNSUPPORTED;
+                       goto cleanup;
                    }
-                   break;
 
-               default:
-                   font->build_stack.sp = 0;
-                   last_op_was_integer = FALSE;
+                   /* T1 spec states that if the interpreter does not
+                    * support executing the callothersub, the results
+                    * must be taken from the callothersub arguments. */
+                   font->build_stack.stack[font->build_stack.sp++] = font->ps_stack.stack[--font->ps_stack.sp];
                    break;
                }
                break;
-
-           default:
-               font->build_stack.sp = 0;
-               last_op_was_integer = FALSE;
-               break;
            }
-        } else {
+       } else {
             /* integer argument */
-           p = cairo_type1_font_subset_decode_integer (p, &font->build_stack.top_value);
-           last_op_was_integer = TRUE;
-           if (font->build_stack.sp < TYPE1_STACKSIZE)
-               font->build_stack.stack[font->build_stack.sp++] = font->build_stack.top_value;
-        }
+           if (font->build_stack.sp < TYPE1_STACKSIZE) {
+               int val;
+               p = cairo_type1_font_subset_decode_integer (p, &val);
+               font->build_stack.stack[font->build_stack.sp++] = val;
+           } else {
+               status = CAIRO_INT_STATUS_UNSUPPORTED;
+               goto cleanup;
+           }
+       }
     }
 
+cleanup:
     free (charstring);
 
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 static cairo_status_t
@@ -1137,9 +1230,9 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
 {
     cairo_status_t status;
     const char *p, *subrs, *charstrings, *array_start, *array_end, *dict_start, *dict_end;
-    const char *closefile_token;
-    char buffer[32], *subr_count_end, *glyph_count_end;
-    int length;
+    const char *lenIV_start, *lenIV_end, *closefile_token;
+    char buffer[32], *lenIV_str, *subr_count_end, *glyph_count_end;
+    int ret, lenIV, length;
     const cairo_scaled_font_backend_t *backend;
     unsigned int i;
     int glyph, j;
@@ -1161,6 +1254,38 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
      * subroutines and charstrings not required.
      */
 
+    /* Determine lenIV, the number of random characters at the start of
+       each encrypted charstring. The defaults is 4, but this can be
+       overridden in the private dict. */
+    font->lenIV = 4;
+    if ((lenIV_start = find_token (font->cleartext, font->cleartext_end, "/lenIV")) != NULL) {
+        lenIV_start += 6;
+        lenIV_end = find_token (lenIV_start, font->cleartext_end, "def");
+        if (lenIV_end == NULL)
+           return CAIRO_INT_STATUS_UNSUPPORTED;
+
+        lenIV_str = malloc (lenIV_end - lenIV_start + 1);
+        if (unlikely (lenIV_str == NULL))
+           return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+        strncpy (lenIV_str, lenIV_start, lenIV_end - lenIV_start);
+        lenIV_str[lenIV_end - lenIV_start] = 0;
+
+        ret = sscanf(lenIV_str, "%d", &lenIV);
+        free(lenIV_str);
+
+        if (unlikely (ret <= 0))
+           return CAIRO_INT_STATUS_UNSUPPORTED;
+
+        /* Apparently some fonts signal unencrypted charstrings with a negative lenIV,
+           though this is not part of the Type 1 Font Format specification.  See, e.g.
+           http://lists.gnu.org/archive/html/freetype-devel/2000-06/msg00064.html. */
+        if (unlikely (lenIV < 0))
+           return CAIRO_INT_STATUS_UNSUPPORTED;
+
+        font->lenIV = lenIV;
+    }
+
     /* Find start of Subrs */
     subrs = find_token (font->cleartext, font->cleartext_end, "/Subrs");
     if (subrs == NULL) {
@@ -1265,7 +1390,7 @@ skip_subrs:
     for (j = 0; j < font->num_glyphs; j++) {
        glyph = font->subset_index_to_glyphs[j];
        font->build_stack.sp = 0;
-       font->ps_stack.num_other_subr_args = 0;
+       font->ps_stack.sp = 0;
        status = cairo_type1_font_subset_parse_charstring (font,
                                                           glyph,
                                                           font->glyphs[glyph].encrypted_charstring,
@@ -1274,6 +1399,12 @@ skip_subrs:
            return status;
     }
 
+    /* Always include the first five subroutines in case the Flex/hint mechanism is
+     * being used. */
+    for (j = 0; j < MIN (font->num_subrs, 5); j++) {
+       font->subrs[j].used = TRUE;
+    }
+
     closefile_token = find_token (dict_end, font->cleartext_end, "closefile");
     if (closefile_token == NULL)
        return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1549,6 +1680,8 @@ _cairo_type1_font_subset_fini (cairo_type1_font_subset_t *font)
 
     free (font->subset_index_to_glyphs);
 
+    free (font->cleartext);
+
     return status;
 }
 
index 0eb2b84..ae7c023 100644 (file)
@@ -159,20 +159,20 @@ _cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
     }
 }
 
-void
-_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
-                                   xcb_drawable_t dst,
-                                   xcb_gcontext_t gc,
-                                   int16_t src_x,
-                                   int16_t src_y,
-                                   uint16_t width,
-                                   uint16_t height,
-                                   uint16_t cpp,
-                                   int stride,
-                                   int16_t dst_x,
-                                   int16_t dst_y,
-                                   uint8_t depth,
-                                   void *_data)
+static void
+_cairo_xcb_connection_do_put_subimage (cairo_xcb_connection_t *connection,
+                                      xcb_drawable_t dst,
+                                      xcb_gcontext_t gc,
+                                      int16_t src_x,
+                                      int16_t src_y,
+                                      uint16_t width,
+                                      uint16_t height,
+                                      uint16_t cpp,
+                                      int stride,
+                                      int16_t dst_x,
+                                      int16_t dst_y,
+                                      uint8_t depth,
+                                      void *_data)
 {
     xcb_protocol_request_t xcb_req = {
        0 /* count */,
@@ -239,6 +239,50 @@ _cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
        free (vec);
 }
 
+void
+_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
+                                   xcb_drawable_t dst,
+                                   xcb_gcontext_t gc,
+                                   int16_t src_x,
+                                   int16_t src_y,
+                                   uint16_t width,
+                                   uint16_t height,
+                                   uint16_t cpp,
+                                   int stride,
+                                   int16_t dst_x,
+                                   int16_t dst_y,
+                                   uint8_t depth,
+                                   void *_data)
+{
+    const uint32_t req_size = sizeof(xcb_put_image_request_t);
+    uint32_t length = height * cpp * width;
+    uint32_t len = (req_size + length) >> 2;
+
+    if (len < connection->maximum_request_length) {
+       _cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
+                       width, height, cpp, stride, dst_x, dst_y, depth, _data);
+    } else {
+       int rows = (connection->maximum_request_length - req_size - 4) / (cpp * width);
+       if (rows > 0) {
+           do {
+               if (rows > height)
+                   rows = height;
+
+               length = rows * cpp * width;
+
+               _cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
+                       width, rows, cpp, stride, dst_x, dst_y, depth, _data);
+
+               height -= rows;
+               dst_y += rows;
+               _data = (char *) _data + stride * rows;
+           } while (height);
+       } else {
+           ASSERT_NOT_REACHED;
+       }
+    }
+}
+
 cairo_status_t
 _cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
                                 xcb_drawable_t src,
index 7c2a675..2be2dac 100644 (file)
@@ -63,6 +63,7 @@ typedef enum {
 struct _cairo_xcb_shm_mem_pool {
     int shmid;
     uint32_t shmseg;
+    void *shm;
 
     cairo_mempool_t mem;
 
@@ -74,7 +75,7 @@ _cairo_xcb_shm_mem_pool_destroy (cairo_xcb_shm_mem_pool_t *pool)
 {
     cairo_list_del (&pool->link);
 
-    shmdt (pool->mem.base);
+    shmdt (pool->shm);
     _cairo_mempool_fini (&pool->mem);
 
     free (pool);
@@ -160,7 +161,6 @@ _cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection,
     size_t shm_allocated = 0;
     void *mem = NULL;
     cairo_status_t status;
-    void *base;
 
     assert (connection->flags & CAIRO_XCB_HAS_SHM);
 
@@ -240,18 +240,18 @@ _cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection,
        return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    base = shmat (pool->shmid, NULL, 0);
-    if (unlikely (base == (char *) -1)) {
+    pool->shm = shmat (pool->shmid, NULL, 0);
+    if (unlikely (pool->shm == (char *) -1)) {
        shmctl (pool->shmid, IPC_RMID, NULL);
        free (pool);
        CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
 
-    status = _cairo_mempool_init (&pool->mem, base, bytes,
+    status = _cairo_mempool_init (&pool->mem, pool->shm, bytes,
                                  minbits, maxbits - minbits + 1);
     if (unlikely (status)) {
-       shmdt (base);
+       shmdt (pool->shm);
        free (pool);
        CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
        return status;
@@ -275,7 +275,7 @@ _cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection,
     shm_info->pool = pool;
     shm_info->shm = pool->shmseg;
     shm_info->size = size;
-    shm_info->offset = (char *) mem - (char *) pool->mem.base;
+    shm_info->offset = (char *) mem - (char *) pool->shm;
     shm_info->mem = mem;
     shm_info->sync.sequence = XCB_NONE;
 
diff --git a/src/cairo-xcb-surface-cairo.c b/src/cairo-xcb-surface-cairo.c
deleted file mode 100644 (file)
index 338a616..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright Â© 2009 Intel Corporation
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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.
- *
- * Contributor(s):
- *     Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#include "cairoint.h"
-
-#include "cairo-clip-private.h"
-#include "cairo-xcb-private.h"
-
-cairo_int_status_t
-_cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t    *surface,
-                               cairo_operator_t         op,
-                               const cairo_pattern_t   *source,
-                               const cairo_clip_t      *clip)
-{
-    return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_int_status_t
-_cairo_xcb_surface_cairo_mask (cairo_xcb_surface_t     *surface,
-                              cairo_operator_t          op,
-                              const cairo_pattern_t    *source,
-                              const cairo_pattern_t    *mask,
-                              const cairo_clip_t       *clip)
-{
-    return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_int_status_t
-_cairo_xcb_surface_cairo_stroke (cairo_xcb_surface_t   *surface,
-                                cairo_operator_t        op,
-                                const cairo_pattern_t  *source,
-                                const cairo_path_fixed_t       *path,
-                                const cairo_stroke_style_t     *style,
-                                const cairo_matrix_t           *ctm,
-                                const cairo_matrix_t           *ctm_inverse,
-                                double                  tolerance,
-                                cairo_antialias_t       antialias,
-                                const cairo_clip_t             *clip)
-{
-    return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_int_status_t
-_cairo_xcb_surface_cairo_fill (cairo_xcb_surface_t     *surface,
-                              cairo_operator_t          op,
-                              const cairo_pattern_t    *source,
-                              const cairo_path_fixed_t *path,
-                              cairo_fill_rule_t         fill_rule,
-                              double                    tolerance,
-                              cairo_antialias_t         antialias,
-                              const cairo_clip_t               *clip)
-{
-    return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_int_status_t
-_cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t   *surface,
-                                cairo_operator_t                op,
-                                const cairo_pattern_t  *source,
-                                cairo_scaled_font_t    *scaled_font,
-                                cairo_glyph_t          *glyphs,
-                                int                     num_glyphs,
-                                const cairo_clip_t     *clip)
-{
-    return CAIRO_INT_STATUS_UNSUPPORTED;
-}
index dff62af..cce95a1 100644 (file)
@@ -3617,14 +3617,6 @@ _cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t *dst,
     return status;
 }
 
-static void
-_clear_image (cairo_surface_t *surface)
-{
-    cairo_image_surface_t *image = (cairo_image_surface_t *) surface;
-    memset (image->data, 0, image->stride * image->height);
-    surface->is_clear = TRUE;
-}
-
 static cairo_status_t
 _cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t         *dst,
                                           cairo_operator_t              op,
@@ -3650,8 +3642,6 @@ _cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t            *dst,
     if (unlikely (image->status))
        return image->status;
 
-    _clear_image (image);
-
     clip = _cairo_clip_copy_region (extents->clip);
     status = _cairo_surface_offset_stroke (image, x, y,
                                           CAIRO_OPERATOR_ADD,
@@ -3792,8 +3782,6 @@ _cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t      *dst,
     if (unlikely (image->status))
        return image->status;
 
-    _clear_image (image);
-
     clip = _cairo_clip_copy_region (extents->clip);
     status = _cairo_surface_offset_fill (image, x, y,
                                         CAIRO_OPERATOR_ADD,
@@ -3904,8 +3892,6 @@ _cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t            *dst,
     if (unlikely (image->status))
        return image->status;
 
-    _clear_image (image);
-
     clip = _cairo_clip_copy_region (extents->clip);
     status = _cairo_surface_offset_glyphs (image, x, y,
                                           CAIRO_OPERATOR_ADD,
@@ -4179,10 +4165,8 @@ _cairo_xcb_font_close (cairo_xcb_font_t *font)
 
     scaled_font = font->scaled_font;
 
-    CAIRO_MUTEX_LOCK (scaled_font->mutex);
     //scaled_font->surface_private = NULL;
     _cairo_scaled_font_reset_cache (scaled_font);
-    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
 
     _cairo_xcb_font_destroy (font);
 }
index bde03ff..746fb45 100644 (file)
@@ -190,6 +190,11 @@ _cairo_xcb_surface_create_similar_image (void                      *abstract_other,
     if (unlikely (status))
        return _cairo_surface_create_in_error (status);
 
+    if (! image->base.is_clear) {
+       memset (image->data, 0, image->stride * image->height);
+       image->base.is_clear = TRUE;
+    }
+
     return &image->base;
 }
 
index aaa71d5..9398079 100644 (file)
@@ -83,6 +83,7 @@ struct _fill_box {
     Display *dpy;
     Drawable drawable;
     GC gc;
+    //cairo_surface_t *dither = NULL;
 };
 
 static cairo_bool_t fill_box (cairo_box_t *box, void *closure)
@@ -128,27 +129,25 @@ color_to_pixel (cairo_xlib_surface_t    *dst,
 }
 
 static cairo_int_status_t
-fill_boxes (cairo_xlib_surface_t    *dst,
-           const cairo_color_t     *color,
-           cairo_boxes_t           *boxes)
+_fill_box_init (struct _fill_box *fb,
+               cairo_xlib_surface_t *dst,
+               const cairo_color_t *color)
 {
-    cairo_surface_t *dither = NULL;
-    cairo_status_t status;
-    struct _fill_box fb;
+    cairo_int_status_t status;
 
-    status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb.gc);
+    status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb->gc);
     if (unlikely (status))
         return status;
 
-    fb.dpy = dst->display->display;
-    fb.drawable = dst->drawable;
+    fb->dpy = dst->display->display;
+    fb->drawable = dst->drawable;
 
     if (dst->visual && dst->visual->class != TrueColor && 0) {
+#if 0
        cairo_solid_pattern_t solid;
        cairo_surface_attributes_t attrs;
 
        _cairo_pattern_init_solid (&solid, color);
-#if 0
        status = _cairo_pattern_acquire_surface (&solid.base, &dst->base,
                                                 0, 0,
                                                 ARRAY_LENGTH (dither_pattern[0]),
@@ -160,27 +159,70 @@ fill_boxes (cairo_xlib_surface_t    *dst,
            _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
            return status;
        }
-#endif
 
-       XSetTSOrigin (fb.dpy, fb.gc,
+       XSetTSOrigin (fb->dpy, fb->gc,
                      - (dst->base.device_transform.x0 + attrs.x_offset),
                      - (dst->base.device_transform.y0 + attrs.y_offset));
-       XSetTile (fb.dpy, fb.gc, ((cairo_xlib_surface_t *) dither)->drawable);
+       XSetTile (fb->dpy, fb->gc, ((cairo_xlib_surface_t *) dither)->drawable);
+#endif
     } else {
        XGCValues gcv;
 
        gcv.foreground = color_to_pixel (dst, color);
        gcv.fill_style = FillSolid;
 
-       XChangeGC (fb.dpy, fb.gc, GCFillStyle | GCForeground, &gcv);
+       XChangeGC (fb->dpy, fb->gc, GCFillStyle | GCForeground, &gcv);
     }
 
+    return CAIRO_INT_STATUS_SUCCESS;
+}
+
+static void
+_fill_box_fini (struct _fill_box *fb,
+               cairo_xlib_surface_t *dst)
+{
+    _cairo_xlib_surface_put_gc (dst->display, dst, fb->gc);
+    //cairo_surface_destroy (fb->dither);
+}
+
+cairo_int_status_t
+_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t    *dst,
+                            const cairo_color_t     *color,
+                            cairo_boxes_t          *boxes)
+{
+    cairo_int_status_t status;
+    struct _fill_box fb;
+
+    status = _fill_box_init (&fb, dst, color);
+    if (unlikely (status))
+        return status;
+
     _cairo_boxes_for_each_box (boxes, fill_box, &fb);
 
-    _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
+    _fill_box_fini (&fb, dst);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_int_status_t
+_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t    *dst,
+                                 const cairo_color_t     *color,
+                                 int num_rects,
+                                 cairo_rectangle_int_t *rects)
+{
+    cairo_int_status_t status;
+    struct _fill_box fb;
+    int i;
+
+    status = _fill_box_init (&fb, dst, color);
+    if (unlikely (status))
+        return status;
 
-    cairo_surface_destroy (dither);
+    for (i = 0; i < num_rects; i++)
+       XFillRectangle (fb.dpy, fb.drawable, fb.gc,
+                       rects[i].x, rects[i].y,
+                       rects[i].width, rects[i].height);
 
+    _fill_box_fini (&fb, dst);
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -495,9 +537,8 @@ draw_boxes (cairo_composite_rectangles_t *extents,
        return status;
 
     if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
-       status = fill_boxes (dst,
-                            &((cairo_solid_pattern_t *) src)->color,
-                            boxes);
+       status = _cairo_xlib_core_fill_boxes
+           (dst, &((cairo_solid_pattern_t *) src)->color, boxes);
     } else {
        status = upload_image_inplace (dst, src, boxes);
        if (status == CAIRO_INT_STATUS_UNSUPPORTED)
index f23a655..04c89b2 100644 (file)
@@ -213,6 +213,13 @@ _cairo_xlib_device_create (Display *dpy)
        goto UNLOCK;
     }
 
+    _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
+
+    display->display = dpy;
+    cairo_list_init (&display->screens);
+    cairo_list_init (&display->fonts);
+    display->closed = FALSE;
+
     /* Xlib calls out to the extension close_display hooks in LIFO
      * order. So we have to ensure that all extensions that we depend
      * on in our close_display hook are properly initialized before we
@@ -240,23 +247,6 @@ _cairo_xlib_device_create (Display *dpy)
 
     _cairo_xlib_display_select_compositor (display);
 
-    codes = XAddExtension (dpy);
-    if (unlikely (codes == NULL)) {
-       device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
-       free (display);
-       goto UNLOCK;
-    }
-
-    _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
-
-    XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
-
-    cairo_device_reference (&display->base); /* add one for the CloseDisplay */
-    display->display = dpy;
-    cairo_list_init (&display->screens);
-    cairo_list_init (&display->fonts);
-    display->closed = FALSE;
-
     display->white = NULL;
     memset (display->alpha, 0, sizeof (display->alpha));
     memset (display->solid, 0, sizeof (display->solid));
@@ -325,7 +315,7 @@ _cairo_xlib_device_create (Display *dpy)
      *    safest to just blacklist all old-versioning-scheme X servers,
      *    (just using VendorRelease < 70000000), as buggy_repeat=TRUE.
      */
-    if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
+    if (_cairo_xlib_vendor_is_xorg (dpy)) {
        if (VendorRelease (dpy) >= 60700000) {
            if (VendorRelease (dpy) < 70000000)
                display->buggy_repeat = TRUE;
@@ -352,6 +342,16 @@ _cairo_xlib_device_create (Display *dpy)
        display->buggy_pad_reflect = TRUE;
     }
 
+    codes = XAddExtension (dpy);
+    if (unlikely (codes == NULL)) {
+       device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+       free (display);
+       goto UNLOCK;
+    }
+
+    XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
+    cairo_device_reference (&display->base); /* add one for the CloseDisplay */
+
     display->next = _cairo_xlib_display_list;
     _cairo_xlib_display_list = display;
 
index d2bd588..4fd725f 100644 (file)
@@ -50,6 +50,7 @@
 #include "cairo-surface-private.h"
 
 #include <pixman.h>
+#include <string.h>
 
 typedef struct _cairo_xlib_display cairo_xlib_display_t;
 typedef struct _cairo_xlib_shm_display cairo_xlib_shm_display_t;
@@ -170,6 +171,7 @@ struct _cairo_xlib_surface {
     cairo_surface_t base;
 
     Picture picture;
+    Drawable drawable;
 
     const cairo_compositor_t *compositor;
     cairo_surface_t *shm;
@@ -180,7 +182,6 @@ struct _cairo_xlib_surface {
     cairo_list_t link;
 
     Display *dpy; /* only valid between acquire/release */
-    Drawable drawable;
     cairo_bool_t owns_pixmap;
     Visual *visual;
 
@@ -202,6 +203,7 @@ struct _cairo_xlib_surface {
        cairo_surface_t base;
 
        Picture picture;
+       Pixmap pixmap;
        Display *dpy;
 
        unsigned int filter:3;
@@ -216,6 +218,13 @@ struct _cairo_xlib_proxy {
     cairo_surface_t *owner;
 };
 
+inline static cairo_bool_t
+_cairo_xlib_vendor_is_xorg (Display *dpy)
+{
+    const char *const vendor = ServerVendor (dpy);
+    return strstr (vendor, "X.Org") || strstr (vendor, "Xorg");
+}
+
 cairo_private cairo_status_t
 _cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
                             cairo_xlib_surface_t *surface,
@@ -387,6 +396,17 @@ _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
     return dst->screen == src->screen;
 }
 
+cairo_private cairo_int_status_t
+_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t    *dst,
+                            const cairo_color_t     *color,
+                            cairo_boxes_t          *boxes);
+
+cairo_private cairo_int_status_t
+_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t    *dst,
+                                 const cairo_color_t     *color,
+                                 int num_rects,
+                                 cairo_rectangle_int_t *rects);
+
 static inline void
 _cairo_xlib_surface_put_gc (cairo_xlib_display_t *display,
                             cairo_xlib_surface_t *surface,
@@ -445,5 +465,4 @@ _cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface);
 cairo_private pixman_format_code_t
 _pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface);
 
-
 #endif /* CAIRO_XLIB_PRIVATE_H */
index e325382..12f357d 100644 (file)
 #include "cairo-tristrip-private.h"
 
 static cairo_int_status_t
+check_composite (const cairo_composite_rectangles_t *extents)
+{
+    cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
+
+    if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
+       return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
 acquire (void *abstract_dst)
 {
     cairo_xlib_surface_t *dst = abstract_dst;
@@ -157,6 +168,7 @@ copy_image_boxes (void *_dst,
        int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
        int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
 
+       _cairo_xlib_shm_surface_mark_active (&image->base);
        XCopyArea (dst->dpy, src, dst->drawable, gc,
                   x1 + dx, y1 + dy,
                   x2 - x1, y2 - y1,
@@ -179,29 +191,26 @@ copy_image_boxes (void *_dst,
                int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
                int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
 
-               rects[j].x = x1;
-               rects[j].y = y1;
-               rects[j].width  = x2 - x1;
-               rects[j].height = y2 - y1;
-               j++;
+               if (x2 > x1 && y2 > y1) {
+                   rects[j].x = x1;
+                   rects[j].y = y1;
+                   rects[j].width  = x2 - x1;
+                   rects[j].height = y2 - y1;
+                   j++;
+               }
            }
        }
-       assert (j == boxes->num_boxes);
 
        XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
-
+       _cairo_xlib_shm_surface_mark_active (&image->base);
        XCopyArea (dst->dpy, src, dst->drawable, gc,
-                  dx, dy,
-                  image->width,  image->height,
-                  0,      0);
-
+                  0, 0, image->width, image->height, -dx, -dy);
        XSetClipMask (dst->dpy, gc, None);
 
        if (rects != stack_rects)
            free (rects);
     }
 
-    _cairo_xlib_shm_surface_mark_active (&image->base);
     _cairo_xlib_surface_put_gc (dst->display, dst, gc);
     release (dst);
     return CAIRO_STATUS_SUCCESS;
@@ -237,16 +246,20 @@ draw_image_boxes (void *_dst,
 {
     cairo_xlib_surface_t *dst = _dst;
     struct _cairo_boxes_chunk *chunk;
-    cairo_image_surface_t *shm;
+    cairo_image_surface_t *shm = NULL;
     cairo_int_status_t status;
     int i;
 
-    if (image->base.device == dst->base.device &&
-       image->depth == dst->depth &&
-       _cairo_xlib_shm_surface_get_pixmap (&image->base))
+    if (image->base.device == dst->base.device) {
+       if (image->depth != dst->depth)
+           return CAIRO_INT_STATUS_UNSUPPORTED;
+
+       if (_cairo_xlib_shm_surface_get_pixmap (&image->base))
            return copy_image_boxes (dst, image, boxes, dx, dy);
 
-    shm = NULL;
+       goto draw_image_boxes;
+    }
+
     if (boxes_cover_surface (boxes, dst))
        shm = (cairo_image_surface_t *) _cairo_xlib_surface_get_shm (dst, TRUE);
     if (shm) {
@@ -337,11 +350,13 @@ draw_image_boxes (void *_dst,
 
            if (_cairo_xlib_shm_surface_get_pixmap (&image->base)) {
                status = copy_image_boxes (dst, image, boxes, dx, dy);
-               goto out;
+               if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+                   goto out;
            }
        }
     }
 
+draw_image_boxes:
     status = CAIRO_STATUS_SUCCESS;
     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
        for (i = 0; i < chunk->count; i++) {
@@ -350,10 +365,10 @@ draw_image_boxes (void *_dst,
            int y1 = _cairo_fixed_integer_part (b->p1.y);
            int x2 = _cairo_fixed_integer_part (b->p2.x);
            int y2 = _cairo_fixed_integer_part (b->p2.y);
-           if ( _cairo_xlib_surface_draw_image (dst, image,
-                                                x1 + dx, y1 + dy,
-                                                x2 - x1, y2 - y1,
-                                                x1, y1)) {
+           if (_cairo_xlib_surface_draw_image (dst, image,
+                                               x1 + dx, y1 + dy,
+                                               x2 - x1, y2 - y1,
+                                               x1, y1)) {
                status = CAIRO_INT_STATUS_UNSUPPORTED;
                goto out;
            }
@@ -599,14 +614,23 @@ fill_rectangles (void                             *abstract_surface,
 
     //X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
 
+    if (fill_reduces_to_source (op, color, dst))
+       op = CAIRO_OPERATOR_SOURCE;
+
+    if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+       cairo_int_status_t status;
+
+       status = CAIRO_INT_STATUS_UNSUPPORTED;
+       if (op == CAIRO_OPERATOR_SOURCE)
+           status = _cairo_xlib_core_fill_rectangles (dst, color, num_rects, rects);
+       return status;
+    }
+
     render_color.red   = color->red_short;
     render_color.green = color->green_short;
     render_color.blue  = color->blue_short;
     render_color.alpha = color->alpha_short;
 
-    if (fill_reduces_to_source (op, color, dst))
-       op = CAIRO_OPERATOR_SOURCE;
-
     _cairo_xlib_surface_ensure_picture (dst);
     if (num_rects == 1) {
        /* Take advantage of the protocol compaction that libXrender performs
@@ -656,14 +680,23 @@ fill_boxes (void          *abstract_surface,
     cairo_xlib_surface_t *dst = abstract_surface;
     XRenderColor render_color;
 
+    if (fill_reduces_to_source (op, color, dst))
+       op = CAIRO_OPERATOR_SOURCE;
+
+    if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+       cairo_int_status_t status;
+
+       status = CAIRO_INT_STATUS_UNSUPPORTED;
+       if (op == CAIRO_OPERATOR_SOURCE)
+           status = _cairo_xlib_core_fill_boxes (dst, color, boxes);
+       return status;
+    }
+
     render_color.red   = color->red_short;
     render_color.green = color->green_short;
     render_color.blue  = color->blue_short;
     render_color.alpha = color->alpha_short;
 
-    if (fill_reduces_to_source (op, color, dst))
-       op = CAIRO_OPERATOR_SOURCE;
-
     _cairo_xlib_surface_ensure_picture (dst);
     if (boxes->num_boxes == 1) {
        int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
@@ -1491,6 +1524,8 @@ check_composite_glyphs (const cairo_composite_rectangles_t *extents,
     cairo_xlib_display_t *display = dst->display;
     int max_request_size, size;
 
+    TRACE ((stderr, "%s\n", __FUNCTION__));
+
     if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
        return CAIRO_INT_STATUS_UNSUPPORTED;
 
@@ -1697,7 +1732,7 @@ _cairo_xlib_mask_compositor_get (void)
        compositor.fill_rectangles = fill_rectangles;
        compositor.fill_boxes = fill_boxes;
        compositor.copy_boxes = copy_boxes;
-       //compositor.check_composite = check_composite;
+       compositor.check_composite = check_composite;
        compositor.composite = composite;
        //compositor.check_composite_boxes = check_composite_boxes;
        compositor.composite_boxes = composite_boxes;
@@ -1928,17 +1963,6 @@ composite_tristrip (void         *abstract_dst,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_int_status_t
-check_composite (const cairo_composite_rectangles_t *extents)
-{
-    cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
-
-    if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
-       return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
 const cairo_compositor_t *
 _cairo_xlib_traps_compositor_get (void)
 {
index 42fc46a..56dff65 100644 (file)
@@ -46,7 +46,7 @@
 #include "cairo-xlib-surface-private.h"
 
 #include "cairo-error-private.h"
-#include "cairo-image-surface-private.h"
+#include "cairo-image-surface-inline.h"
 #include "cairo-paginated-private.h"
 #include "cairo-pattern-inline.h"
 #include "cairo-recording-surface-private.h"
@@ -71,6 +71,8 @@ _cairo_xlib_source_finish (void *abstract_surface)
     cairo_xlib_source_t *source = abstract_surface;
 
     XRenderFreePicture (source->dpy, source->picture);
+    if (source->pixmap)
+           XFreePixmap (source->dpy, source->pixmap);
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -85,8 +87,10 @@ _cairo_xlib_proxy_finish (void *abstract_surface)
 {
     cairo_xlib_proxy_t *proxy = abstract_surface;
 
-    XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
     _cairo_xlib_shm_surface_mark_active (proxy->owner);
+    XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
+    if (proxy->source.pixmap)
+           XFreePixmap (proxy->source.dpy, proxy->source.pixmap);
     cairo_surface_destroy (proxy->owner);
     return CAIRO_STATUS_SUCCESS;
 }
@@ -98,16 +102,18 @@ static const cairo_surface_backend_t cairo_xlib_proxy_backend = {
 };
 
 static cairo_surface_t *
-source (cairo_xlib_surface_t *dst, Picture picture)
+source (cairo_xlib_surface_t *dst, Picture picture, Pixmap pixmap)
 {
     cairo_xlib_source_t *source;
 
     if (picture == None)
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    source = malloc (sizeof (cairo_image_surface_t));
+    source = malloc (sizeof (*source));
     if (unlikely (source == NULL)) {
        XRenderFreePicture (dst->display->display, picture);
+       if (pixmap)
+               XFreePixmap (dst->display->display, pixmap);
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     }
 
@@ -118,6 +124,7 @@ source (cairo_xlib_surface_t *dst, Picture picture)
 
     /* The source exists only within an operation */
     source->picture = picture;
+    source->pixmap = pixmap;
     source->dpy = dst->display->display;
 
     return &source->base;
@@ -433,22 +440,65 @@ gradient_source (cairo_xlib_surface_t *dst,
        return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
     }
 
-    return source (dst, picture);
+    return source (dst, picture, None);
 }
 
 static cairo_surface_t *
 color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
 {
-    XRenderColor xrender_color;
+    Display *dpy = dst->display->display;
+    XRenderColor xcolor;
+    Picture picture;
+    Pixmap pixmap = None;
+
+    xcolor.red   = color->red_short;
+    xcolor.green = color->green_short;
+    xcolor.blue  = color->blue_short;
+    xcolor.alpha = color->alpha_short;
 
-    xrender_color.red   = color->red_short;
-    xrender_color.green = color->green_short;
-    xrender_color.blue  = color->blue_short;
-    xrender_color.alpha = color->alpha_short;
+    if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) {
+       picture = XRenderCreateSolidFill (dpy, &xcolor);
+    } else {
+       XRenderPictureAttributes pa;
+       int mask = 0;
+
+       pa.repeat = RepeatNormal;
+       mask |= CPRepeat;
 
-    return source (dst,
-                  XRenderCreateSolidFill (dst->display->display,
-                                          &xrender_color));
+       pixmap = XCreatePixmap (dpy, dst->drawable, 1, 1, 32);
+       picture = XRenderCreatePicture (dpy, pixmap,
+                                       _cairo_xlib_display_get_xrender_format (dst->display, CAIRO_FORMAT_ARGB32),
+                                       mask, &pa);
+
+       if (CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+           XRectangle r = { 0, 0, 1, 1};
+           XRenderFillRectangles (dpy, PictOpSrc, picture, &xcolor, &r, 1);
+       } else {
+           XGCValues gcv;
+           GC gc;
+
+           gc = _cairo_xlib_screen_get_gc (dst->display, dst->screen,
+                                           32, pixmap);
+           if (unlikely (gc == NULL)) {
+               XFreePixmap (dpy, pixmap);
+               return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+           }
+
+           gcv.foreground = 0;
+           gcv.foreground |= color->alpha_short >> 8 << 24;
+           gcv.foreground |= color->red_short   >> 8 << 16;
+           gcv.foreground |= color->green_short >> 8 << 8;
+           gcv.foreground |= color->blue_short  >> 8 << 0;
+           gcv.fill_style = FillSolid;
+
+           XChangeGC (dpy, gc, GCFillStyle | GCForeground, &gcv);
+           XFillRectangle (dpy, pixmap, gc, 0, 0, 1, 1);
+
+           _cairo_xlib_screen_put_gc (dst->display, dst->screen, 32, gc);
+       }
+    }
+
+    return source (dst, picture, pixmap);
 }
 
 static cairo_surface_t *
@@ -897,8 +947,7 @@ surface_source (cairo_xlib_surface_t *dst,
     cairo_xlib_surface_t *xsrc;
     cairo_surface_pattern_t local_pattern;
     cairo_status_t status;
-    cairo_rectangle_int_t upload, limit, map_extents;
-    cairo_matrix_t m;
+    cairo_rectangle_int_t upload, limit;
 
     src = pattern->surface;
     if (src->type == CAIRO_SURFACE_TYPE_IMAGE &&
@@ -906,31 +955,27 @@ surface_source (cairo_xlib_surface_t *dst,
        _cairo_xlib_shm_surface_get_pixmap (src)) {
        cairo_xlib_proxy_t *proxy;
 
-       cairo_surface_reference (src);
-
-prepare_shm_image:
        proxy = malloc (sizeof(*proxy));
-       if (unlikely (proxy == NULL)) {
-           cairo_surface_destroy (src);
+       if (unlikely (proxy == NULL))
            return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
-       }
 
        _cairo_surface_init (&proxy->source.base,
                             &cairo_xlib_proxy_backend,
                             dst->base.device,
-                            CAIRO_CONTENT_COLOR_ALPHA);
+                            src->content);
 
        proxy->source.dpy = dst->display->display;
        proxy->source.picture = XRenderCreatePicture (proxy->source.dpy,
                                                      _cairo_xlib_shm_surface_get_pixmap (src),
                                                      _cairo_xlib_shm_surface_get_xrender_format (src),
                                                      0, NULL);
+       proxy->source.pixmap = None;
 
        proxy->source.has_component_alpha = 0;
        proxy->source.has_matrix = 0;
        proxy->source.filter = CAIRO_FILTER_NEAREST;
        proxy->source.extend = CAIRO_EXTEND_NONE;
-       proxy->owner = src;
+       proxy->owner = cairo_surface_reference (src);
 
        return embedded_source (dst, pattern, extents, src_x, src_y,
                                &proxy->source);
@@ -952,31 +997,54 @@ prepare_shm_image:
        }
     }
 
-    src = _cairo_xlib_surface_create_similar_shm (&dst->base,
-                                                 _cairo_format_from_content (pattern->surface->content),
-                                                 upload.width,
-                                                 upload.height);
+    xsrc = (cairo_xlib_surface_t *)
+           _cairo_surface_create_similar_scratch (&dst->base,
+                                                  src->content,
+                                                  upload.width,
+                                                  upload.height);
+    if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+       cairo_surface_destroy (src);
+       cairo_surface_destroy (&xsrc->base);
+       return None;
+    }
 
-    _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
-    cairo_matrix_init_translate (&local_pattern.base.matrix,
-                                upload.x, upload.y);
+    if (_cairo_surface_is_image (src)) {
+       status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
+                                                upload.x, upload.y,
+                                                upload.width, upload.height,
+                                                0, 0);
+    } else {
+       cairo_image_surface_t *image;
+       cairo_rectangle_int_t map_extents = { 0,0, upload.width,upload.height };
 
-    map_extents = upload;
-    map_extents.x = map_extents.y = 0;
+       image = _cairo_surface_map_to_image (&xsrc->base, &map_extents);
 
-    status = _cairo_surface_paint (src,
-                                  CAIRO_OPERATOR_SOURCE,
-                                  &local_pattern.base,
-                                  NULL);
-    _cairo_pattern_fini (&local_pattern.base);
+       _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
+       cairo_matrix_init_translate (&local_pattern.base.matrix,
+                                    upload.x, upload.y);
 
-    if (unlikely (status)) {
-       cairo_surface_destroy (src);
-       return _cairo_surface_create_in_error (status);
+       status = _cairo_surface_paint (&image->base,
+                                      CAIRO_OPERATOR_SOURCE,
+                                      &local_pattern.base,
+                                      NULL);
+       _cairo_pattern_fini (&local_pattern.base);
+
+       status = _cairo_surface_unmap_image (&xsrc->base, image);
+       if (unlikely (status)) {
+           cairo_surface_destroy (&xsrc->base);
+           return _cairo_surface_create_in_error (status);
+       }
+
+       status = _cairo_xlib_surface_put_shm (xsrc);
+       if (unlikely (status)) {
+           cairo_surface_destroy (&xsrc->base);
+           return _cairo_surface_create_in_error (status);
+       }
     }
 
     _cairo_pattern_init_static_copy (&local_pattern.base, &pattern->base);
     if (upload.x | upload.y) {
+       cairo_matrix_t m;
        cairo_matrix_init_translate (&m, -upload.x, -upload.y);
        cairo_matrix_multiply (&local_pattern.base.matrix,
                               &local_pattern.base.matrix,
@@ -984,29 +1052,6 @@ prepare_shm_image:
     }
 
     *src_x = *src_y = 0;
-    if (src->device == dst->base.device &&
-       _cairo_xlib_shm_surface_get_pixmap (src)) {
-           pattern = &local_pattern;
-           goto prepare_shm_image;
-    }
-
-    xsrc = (cairo_xlib_surface_t *)
-           _cairo_surface_create_similar_scratch (&dst->base,
-                                                  src->content,
-                                                  upload.width,
-                                                  upload.height);
-    if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
-       cairo_surface_destroy (src);
-       cairo_surface_destroy (&xsrc->base);
-       return None;
-    }
-
-    status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
-                                            0, 0,
-                                            upload.width, upload.height,
-                                            0, 0);
-    cairo_surface_destroy (src);
-
     _cairo_xlib_surface_ensure_picture (xsrc);
     if (! picture_set_properties (xsrc->display,
                                  xsrc->picture,
index 08169f2..fa7d3eb 100644 (file)
 
 #include "cairo-xlib-private.h"
 #include "cairo-xlib-surface-private.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-mempool-private.h"
+
+#if !HAVE_X11_EXTENSIONS_XSHM_H || !(HAVE_X11_EXTENSIONS_SHMPROTO_H || HAVE_X11_EXTENSIONS_SHMSTR_H)
+void _cairo_xlib_display_init_shm (cairo_xlib_display_t *display) {}
+
+cairo_surface_t *
+_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface,
+                            cairo_bool_t overwrite)
+{
+    return NULL;
+}
+
+cairo_int_status_t
+_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
+{
+    assert (!surface->fallback);
+    return CAIRO_INT_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other,
+                               pixman_format_code_t format,
+                               int width, int height)
+{
+    return NULL;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface,
+                                      pixman_format_code_t format,
+                                      int width, int height)
+{
+    return NULL;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_similar_shm (void *other,
+                                       cairo_format_t format,
+                                       int width, int height)
+{
+    return cairo_image_surface_create (format, width, height);
+}
+
+void
+_cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm)
+{
+    ASSERT_NOT_REACHED;
+}
+
+void
+_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
+                                   XImage *ximage)
+{
+    ASSERT_NOT_REACHED;
+}
+
+void *
+_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
+{
+    ASSERT_NOT_REACHED;
+    return NULL;
+}
+
+Pixmap
+_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface)
+{
+    ASSERT_NOT_REACHED;
+    return 0;
+}
+
+XRenderPictFormat *
+_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface)
+{
+    ASSERT_NOT_REACHED;
+    return NULL;
+}
+
+cairo_bool_t
+_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface)
+{
+    ASSERT_NOT_REACHED;
+    return FALSE;
+}
+
+cairo_bool_t
+_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
+{
+    ASSERT_NOT_REACHED;
+    return TRUE;
+}
+
+void _cairo_xlib_display_fini_shm (cairo_xlib_display_t *display) {}
+
+#else
 
 #include "cairo-damage-private.h"
 #include "cairo-default-context-private.h"
+#include "cairo-image-surface-private.h"
 #include "cairo-list-inline.h"
+#include "cairo-mempool-private.h"
 
 #include <X11/Xlibint.h>
 #include <X11/Xproto.h>
 #include <X11/extensions/XShm.h>
+#if HAVE_X11_EXTENSIONS_SHMPROTO_H
 #include <X11/extensions/shmproto.h>
+#elif HAVE_X11_EXTENSIONS_SHMSTR_H
+#include <X11/extensions/shmstr.h>
+#endif
 #include <sys/ipc.h>
 #include <sys/shm.h>
 
@@ -109,6 +206,8 @@ struct _cairo_xlib_shm_display {
     int event;
 
     Window window;
+    unsigned long last_request;
+    unsigned long last_event;
 
     cairo_list_t surfaces;
 
@@ -119,9 +218,21 @@ struct _cairo_xlib_shm_display {
 static inline cairo_bool_t
 seqno_passed (unsigned long a, unsigned long b)
 {
+    return (long)(b - a) >= 0;
+}
+
+static inline cairo_bool_t
+seqno_before (unsigned long a, unsigned long b)
+{
     return (long)(b - a) > 0;
 }
 
+static inline cairo_bool_t
+seqno_after (unsigned long a, unsigned long b)
+{
+    return (long)(a - b) > 0;
+}
+
 static inline cairo_status_t
 _pqueue_init (struct pqueue *pq)
 {
@@ -305,11 +416,6 @@ peek_processed (cairo_device_t *device)
     return LastKnownRequestProcessed (peek_display(device));
 }
 
-static unsigned next_request (cairo_device_t *device)
-{
-    return NextRequest (peek_display (device));
-}
-
 static void
 _cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t *display,
                                      cairo_xlib_shm_t *pool)
@@ -324,6 +430,43 @@ _cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t *display,
     free (pool);
 }
 
+static void send_event(cairo_xlib_display_t *display,
+                      cairo_xlib_shm_info_t *info,
+                      unsigned long seqno)
+{
+    XShmCompletionEvent ev;
+
+    if (! seqno_after (seqno, display->shm->last_event))
+       return;
+
+    ev.type = display->shm->event;
+    ev.send_event = 1; /* XXX or lie? */
+    ev.serial = NextRequest (display->display);
+    ev.drawable = display->shm->window;
+    ev.major_code = display->shm->opcode;
+    ev.minor_code = X_ShmPutImage;
+    ev.shmseg = info->pool->shm.shmid;
+    ev.offset = (char *)info->mem - (char *)info->pool->shm.shmaddr;
+
+    XSendEvent (display->display, ev.drawable, False, 0, (XEvent *)&ev);
+
+    display->shm->last_event = ev.serial;
+}
+
+static void sync (cairo_xlib_display_t *display)
+{
+    cairo_xlib_shm_info_t *info;
+    struct pqueue *pq = &display->shm->info;
+
+    XSync (display->display, False);
+
+    while ((info = PQ_TOP(pq))) {
+       _cairo_mempool_free (&info->pool->mem, info->mem);
+       _pqueue_pop (&display->shm->info);
+       free (info);
+    }
+}
+
 static void
 _cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
 {
@@ -340,8 +483,10 @@ _cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
 
     info = PQ_TOP(pq);
     do {
-       if (! seqno_passed (info->last_request, processed))
-           break;
+       if (! seqno_passed (info->last_request, processed)) {
+           send_event (display, info, display->shm->last_request);
+           return;
+       }
 
        _cairo_mempool_free (&info->pool->mem, info->mem);
        _pqueue_pop (&display->shm->info);
@@ -349,9 +494,9 @@ _cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
     } while ((info = PQ_TOP(pq)));
 }
 
-static cairo_xlib_shm_info_t *
-_cairo_xlib_shm_info_find (cairo_xlib_display_t *display,
-                          size_t size, unsigned long *last_request)
+static cairo_xlib_shm_t *
+_cairo_xlib_shm_info_find (cairo_xlib_display_t *display, size_t size,
+                          void **ptr, unsigned long *last_request)
 {
     cairo_xlib_shm_info_t *info;
     struct pqueue *pq = &display->shm->info;
@@ -361,14 +506,21 @@ _cairo_xlib_shm_info_find (cairo_xlib_display_t *display,
 
     info = PQ_TOP(pq);
     do {
-       _pqueue_pop (&display->shm->info);
-
-       if (info->size >= size && size <= 2*info->size)
-           return info;
+       cairo_xlib_shm_t *pool = info->pool;
 
        *last_request = info->last_request;
-       _cairo_mempool_free (&info->pool->mem, info->mem);
+
+       _pqueue_pop (&display->shm->info);
+       _cairo_mempool_free (&pool->mem, info->mem);
        free (info);
+
+       if (pool->mem.free_bytes >= size) {
+           void *mem = _cairo_mempool_alloc (&pool->mem, size);
+           if (mem != NULL) {
+               *ptr = mem;
+               return pool;
+           }
+       }
     } while ((info = PQ_TOP(pq)));
 
     return NULL;
@@ -449,6 +601,9 @@ _cairo_xlib_shm_pool_create(cairo_xlib_display_t *display,
 
     pool->attached = NextRequest (dpy);
     success = XShmAttach (dpy, &pool->shm);
+#if !IPC_RMID_DEFERRED_RELEASE
+    XSync (dpy, FALSE);
+#endif
     shmctl (pool->shm.shmid, IPC_RMID, NULL);
 
     if (! success)
@@ -482,15 +637,12 @@ _cairo_xlib_shm_info_create (cairo_xlib_display_t *display,
     unsigned long last_request = 0;
     void *mem = NULL;
 
-    if (will_sync) {
-       info = _cairo_xlib_shm_info_find (display, size, &last_request);
-       if (info)
-           return info;
-    }
-
     _cairo_xlib_shm_info_cleanup (display);
     pool = _cairo_xlib_shm_pool_find (display, size, &mem);
     _cairo_xlib_shm_pool_cleanup (display);
+
+    if (pool == NULL && will_sync)
+       pool = _cairo_xlib_shm_info_find (display, size, &mem, &last_request);
     if (pool == NULL)
        pool = _cairo_xlib_shm_pool_create (display, size, &mem);
     if (pool == NULL)
@@ -517,6 +669,7 @@ _cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags)
 {
     cairo_xlib_shm_surface_t *shm = abstract_surface;
     cairo_xlib_display_t *display;
+    Display *dpy;
     cairo_status_t status;
 
     if (shm->active == 0)
@@ -534,10 +687,15 @@ _cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags)
     if (unlikely (status))
        return status;
 
-    XEventsQueued (display->display, QueuedAfterReading);
-    if (!seqno_passed (shm->active,
-                      LastKnownRequestProcessed (display->display)))
-       XSync (display->display, False);
+    send_event (display, shm->info, shm->active);
+
+    dpy = display->display;
+    XEventsQueued (dpy, QueuedAfterReading);
+    while (! seqno_passed (shm->active, LastKnownRequestProcessed (dpy))) {
+       LockDisplay(dpy);
+       _XReadEvents(dpy);
+       UnlockDisplay(dpy);
+    }
 
     cairo_device_release (&display->base);
     shm->active = 0;
@@ -549,7 +707,7 @@ static inline cairo_bool_t
 active (cairo_xlib_shm_surface_t *shm, Display *dpy)
 {
     return (shm->active &&
-           !seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
+           ! seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
 }
 
 static cairo_status_t
@@ -559,6 +717,11 @@ _cairo_xlib_shm_surface_finish (void *abstract_surface)
     cairo_xlib_display_t *display;
     cairo_status_t status;
 
+    if (shm->image.base.damage) {
+       _cairo_damage_destroy (shm->image.base.damage);
+       shm->image.base.damage = _cairo_damage_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
+    }
+
     status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
     if (unlikely (status))
        return status;
@@ -569,6 +732,8 @@ _cairo_xlib_shm_surface_finish (void *abstract_surface)
     if (active (shm, display->display)) {
        shm->info->last_request = shm->active;
        _pqueue_push (&display->shm->info, shm->info);
+       if (seqno_before (display->shm->last_request, shm->active))
+           display->shm->last_request = shm->active;
     } else {
        _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
        free (shm->info);
@@ -579,7 +744,7 @@ _cairo_xlib_shm_surface_finish (void *abstract_surface)
     cairo_list_del (&shm->link);
 
     cairo_device_release (&display->base);
-    return CAIRO_STATUS_SUCCESS;
+    return _cairo_image_surface_finish (abstract_surface);
 }
 
 static const cairo_surface_backend_t cairo_xlib_shm_surface_backend = {
@@ -720,6 +885,13 @@ _cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface)
     if (_cairo_xlib_surface_get_gc (display, surface, &gc))
        goto cleanup_display;
 
+    if (! surface->owns_pixmap) {
+       XGCValues gcv;
+
+       gcv.subwindow_mode = IncludeInferiors;
+       XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
+    }
+
     if (damage->region) {
        XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
        XRectangle *rects = stack_rects;
@@ -770,7 +942,14 @@ _cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface)
                   0, 0);
     }
 
-    XSync (display->display, False);
+    if (! surface->owns_pixmap) {
+       XGCValues gcv;
+
+       gcv.subwindow_mode = ClipByChildren;
+       XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
+    }
+
+    sync (display);
     shm->active = 0;
     shm->idle--;
 
@@ -899,10 +1078,6 @@ _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
        damage = _cairo_damage_reduce (shm->image.base.damage);
        shm->image.base.damage = _cairo_damage_create ();
 
-       status = _cairo_xlib_surface_get_gc (display, surface, &gc);
-       if (unlikely (status))
-           goto out;
-
        TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__,
                damage->region ? cairo_region_num_rectangles (damage->region) : 0));
        if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) {
@@ -912,9 +1087,16 @@ _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
            int n_rects, i;
 
            n_rects = cairo_region_num_rectangles (damage->region);
-           if (n_rects == 0) {
-           } else if (n_rects == 1) {
+           if (n_rects == 0)
+               goto out;
+
+           status = _cairo_xlib_surface_get_gc (display, surface, &gc);
+           if (unlikely (status))
+               goto out;
+
+           if (n_rects == 1) {
                cairo_region_get_rectangle (damage->region, 0, &r);
+               _cairo_xlib_shm_surface_mark_active (surface->shm);
                XCopyArea (display->display,
                           shm->pixmap, surface->drawable, gc,
                           r.x, r.y,
@@ -925,6 +1107,7 @@ _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
                    rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
                    if (unlikely (rects == NULL)) {
                        status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+                       _cairo_xlib_surface_put_gc (display, surface, gc);
                        goto out;
                    }
                }
@@ -938,6 +1121,7 @@ _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
                }
                XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
 
+               _cairo_xlib_shm_surface_mark_active (surface->shm);
                XCopyArea (display->display,
                           shm->pixmap, surface->drawable, gc,
                           0, 0,
@@ -947,12 +1131,12 @@ _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
                if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
                    XSetClipMask (display->display, gc, None);
            }
+
+           _cairo_xlib_surface_put_gc (display, surface, gc);
        }
-       _cairo_damage_destroy (damage);
 
-       _cairo_xlib_shm_surface_mark_active (surface->shm);
-       _cairo_xlib_surface_put_gc (display, surface, gc);
 out:
+       _cairo_damage_destroy (damage);
        cairo_device_release (&display->base);
     }
 
@@ -968,9 +1152,8 @@ _cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other,
 
     surface = NULL;
     if (has_shm (other))
-       surface = &_cairo_xlib_shm_surface_create (other, format,
-                                                  width, height, FALSE,
-                                                  has_shm_pixmaps (other))->image.base;
+       surface = &_cairo_xlib_shm_surface_create (other, format, width, height,
+                                                  FALSE, has_shm_pixmaps (other))->image.base;
 
     return surface;
 }
@@ -983,9 +1166,8 @@ _cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface,
     if (! has_shm(surface))
        return NULL;
 
-    return &_cairo_xlib_shm_surface_create (surface, format,
-                                           surface->width, surface->height,
-                                           TRUE, 0)->image.base;
+    return &_cairo_xlib_shm_surface_create (surface, format, width, height,
+                                           FALSE, 0)->image.base;
 }
 
 cairo_surface_t *
@@ -1016,17 +1198,8 @@ _cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm)
 {
     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) _shm;
     cairo_xlib_display_t *display = (cairo_xlib_display_t *) _shm->device;
-    XShmCompletionEvent ev;
-
-    ev.type = display->shm->event;
-    ev.drawable = display->shm->window;
-    ev.major_code = display->shm->opcode;
-    ev.minor_code = X_ShmPutImage;
-    ev.shmseg = shm->info->pool->shm.shmid;
-    ev.offset = (char *)shm->info->mem - (char *)shm->info->pool->shm.shmaddr;
 
     shm->active = NextRequest (display->display);
-    XSendEvent (display->display, ev.drawable, False, 0, (XEvent *)&ev);
 }
 
 void
@@ -1065,10 +1238,10 @@ _cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
 void *
 _cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
 {
-    cairo_xlib_shm_surface_t *shm;
+    cairo_xlib_display_t *display = (cairo_xlib_display_t *) surface->device;
+    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
 
-    shm = (cairo_xlib_shm_surface_t *) surface;
-    shm->active = next_request (surface->device);
+    display->shm->last_event = shm->active = NextRequest (display->display);
     return &shm->info->pool->shm;
 }
 
@@ -1121,6 +1294,85 @@ _cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
     return shm->idle > 0;
 }
 
+#define XORG_VERSION_ENCODE(major,minor,patch,snap) \
+    (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
+
+static cairo_bool_t
+has_broken_send_shm_event (cairo_xlib_display_t *display,
+                          cairo_xlib_shm_display_t *shm)
+{
+    Display *dpy = display->display;
+    int (*old_handler) (Display *display, XErrorEvent *event);
+    XShmCompletionEvent ev;
+    XShmSegmentInfo info;
+
+    info.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
+    if (info.shmid == -1)
+       return TRUE;
+
+    info.readOnly = FALSE;
+    info.shmaddr = shmat (info.shmid, NULL, 0);
+    if (info.shmaddr == (char *) -1) {
+       shmctl (info.shmid, IPC_RMID, NULL);
+       return TRUE;
+    }
+
+    ev.type = shm->event;
+    ev.send_event = 1;
+    ev.serial = 1;
+    ev.drawable = shm->window;
+    ev.major_code = shm->opcode;
+    ev.minor_code = X_ShmPutImage;
+
+    ev.shmseg = info.shmid;
+    ev.offset = 0;
+
+    assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex));
+    _x_error_occurred = FALSE;
+
+    XLockDisplay (dpy);
+    XSync (dpy, False);
+    old_handler = XSetErrorHandler (_check_error_handler);
+
+    XShmAttach (dpy, &info);
+    XSendEvent (dpy, ev.drawable, False, 0, (XEvent *)&ev);
+    XShmDetach (dpy, &info);
+
+    XSync (dpy, False);
+    XSetErrorHandler (old_handler);
+    XUnlockDisplay (dpy);
+
+    shmctl (info.shmid, IPC_RMID, NULL);
+    shmdt (info.shmaddr);
+
+    return _x_error_occurred;
+}
+
+static cairo_bool_t
+xorg_has_buggy_send_shm_completion_event(cairo_xlib_display_t *display,
+                                        cairo_xlib_shm_display_t *shm)
+{
+    Display *dpy = display->display;
+
+    /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent,
+     * the Xserver may crash if it does not take care when processing
+     * the event type. For instance versions of Xorg prior to 1.11.1
+     * exhibited this bug, and was fixed by:
+     *
+     * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39
+     * Author: Sam Spilsbury <sam.spilsbury@canonical.com>
+     * Date:   Wed Sep 14 09:58:34 2011 +0800
+     *
+     * Remove the SendEvent bit (0x80) before doing range checks on event type.
+     */
+    if (_cairo_xlib_vendor_is_xorg (dpy) &&
+       VendorRelease (dpy) < XORG_VERSION_ENCODE(1,11,0,1))
+       return TRUE;
+
+    /* For everyone else check that no error is generated */
+    return has_broken_send_shm_event (display, shm);
+}
+
 void
 _cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
 {
@@ -1138,6 +1390,15 @@ _cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
     if (unlikely (shm == NULL))
        return;
 
+    codes = XInitExtension (display->display, SHMNAME);
+    if (codes == NULL) {
+       free (shm);
+       return;
+    }
+
+    shm->opcode = codes ->major_opcode;
+    shm->event = codes->first_event;
+
     if (unlikely (_pqueue_init (&shm->info))) {
        free (shm);
        return;
@@ -1152,14 +1413,15 @@ _cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
                                 InputOutput,
                                 DefaultVisual (display->display, scr),
                                 CWOverrideRedirect, &attr);
+    shm->last_event = 0;
+    shm->last_request = 0;
+
+    if (xorg_has_buggy_send_shm_completion_event(display, shm))
+       has_pixmap = 0;
 
     shm->has_pixmaps = has_pixmap ? MIN_PIXMAP_SIZE : 0;
     cairo_list_init (&shm->pool);
 
-    codes = XInitExtension (display->display, SHMNAME);
-    shm->opcode = codes ->major_opcode;
-    shm->event = codes->first_event;
-
     cairo_list_init (&shm->surfaces);
 
     display->shm = shm;
@@ -1193,5 +1455,5 @@ _cairo_xlib_display_fini_shm (cairo_xlib_display_t *display)
     free (shm);
     display->shm = NULL;
 }
-
+#endif
 #endif
index e9e647a..96ba3ad 100644 (file)
@@ -1090,9 +1090,10 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t   *surface,
     XImage ximage;
     cairo_format_masks_t image_masks;
     int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
+    cairo_surface_t *shm_image = NULL;
     pixman_image_t *pixman_image = NULL;
     cairo_status_t status;
-    cairo_bool_t own_data;
+    cairo_bool_t own_data = FALSE;
     cairo_bool_t is_rgb_image;
     GC gc;
 
@@ -1127,9 +1128,39 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t   *surface,
        ximage.bits_per_pixel = image_masks.bpp;
        ximage.bytes_per_line = image->stride;
        ximage.data = (char *)image->data;
-       if (image->base.device == surface->base.device)
+       if (image->base.device != surface->base.device) {
+           /* If PutImage will break the image up into chunks, prefer to
+            * send it all in one pass with ShmPutImage.  For larger images,
+            * it is further advantageous to reduce the number of copies,
+            * albeit at the expense of more SHM bookkeeping.
+            */
+           int max_request_size = XExtendedMaxRequestSize (display->display);
+           if (max_request_size == 0)
+               max_request_size = XMaxRequestSize (display->display);
+           if (max_request_size > 8192)
+               max_request_size = 8192;
+           if (width * height * 4 > max_request_size) {
+               shm_image = _cairo_xlib_surface_create_shm__image (surface,
+                                                                  image->pixman_format,
+                                                                  width, height);
+               if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) {
+                   cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image;
+                   pixman_image_composite32 (PIXMAN_OP_SRC,
+                                             image->pixman_image, NULL, clone->pixman_image,
+                                             src_x, src_y,
+                                             0, 0,
+                                             0, 0,
+                                             width, height);
+                   ximage.obdata = _cairo_xlib_shm_surface_get_obdata (shm_image);
+                   ximage.data = (char *)clone->data;
+                   ximage.bytes_per_line = clone->stride;
+                   ximage.width = width;
+                   ximage.height = height;
+                   src_x = src_y = 0;
+               }
+           }
+       } else
            ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&image->base);
-       own_data = FALSE;
 
        ret = XInitImage (&ximage);
        assert (ret != 0);
@@ -1147,29 +1178,48 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t   *surface,
         ret = _pixman_format_from_masks (&image_masks, &intermediate_format);
         assert (ret);
 
-       own_data = FALSE;
-
-        pixman_image = pixman_image_create_bits (intermediate_format,
-                                                 width, height, NULL, 0);
-        if (pixman_image == NULL) {
-           status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-            goto BAIL;
-        }
+       shm_image = _cairo_xlib_surface_create_shm__image (surface,
+                                                          intermediate_format,
+                                                          width, height);
+       if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) {
+           cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image;
+
+           pixman_image_composite32 (PIXMAN_OP_SRC,
+                                     image->pixman_image,
+                                     NULL,
+                                     clone->pixman_image,
+                                     src_x, src_y,
+                                     0, 0,
+                                     0, 0,
+                                     width, height);
+
+           ximage.data = (char *) clone->data;
+           ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&clone->base);
+           ximage.bytes_per_line = clone->stride;
+       } else {
+           pixman_image = pixman_image_create_bits (intermediate_format,
+                                                    width, height, NULL, 0);
+           if (pixman_image == NULL) {
+               status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+               goto BAIL;
+           }
 
-        pixman_image_composite32 (PIXMAN_OP_SRC,
-                                  image->pixman_image,
-                                  NULL,
-                                  pixman_image,
-                                  src_x, src_y,
-                                  0, 0,
-                                  0, 0,
-                                  width, height);
+           pixman_image_composite32 (PIXMAN_OP_SRC,
+                                     image->pixman_image,
+                                     NULL,
+                                     pixman_image,
+                                     src_x, src_y,
+                                     0, 0,
+                                     0, 0,
+                                     width, height);
+
+           ximage.data = (char *) pixman_image_get_data (pixman_image);
+           ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
+       }
 
        ximage.width = width;
        ximage.height = height;
        ximage.bits_per_pixel = image_masks.bpp;
-       ximage.data = (char *) pixman_image_get_data (pixman_image);
-       ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
 
        ret = XInitImage (&ximage);
        assert (ret != 0);
@@ -1195,7 +1245,6 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t   *surface,
        ximage.bytes_per_line = stride;
        ximage.data = _cairo_malloc_ab (stride, ximage.height);
        if (unlikely (ximage.data == NULL)) {
-            own_data = FALSE;
            status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
             goto BAIL;
         }
@@ -1296,7 +1345,7 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t   *surface,
 
     if (ximage.obdata)
        XShmPutImage (display->display, surface->drawable, gc, &ximage,
-                     src_x, src_y, dst_x, dst_y, width, height, TRUE);
+                     src_x, src_y, dst_x, dst_y, width, height, True);
     else
        XPutImage (display->display, surface->drawable, gc, &ximage,
                   src_x, src_y, dst_x, dst_y, width, height);
@@ -1308,6 +1357,8 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t   *surface,
 
     if (own_data)
        free (ximage.data);
+    if (shm_image)
+       cairo_surface_destroy (shm_image);
     if (pixman_image)
         pixman_image_unref (pixman_image);
 
index a2f5aa3..7dee792 100644 (file)
@@ -2382,7 +2382,7 @@ typedef enum _cairo_surface_type {
     CAIRO_SURFACE_TYPE_XML,
     CAIRO_SURFACE_TYPE_SKIA,
     CAIRO_SURFACE_TYPE_SUBSURFACE,
-    CAIRO_SURFACE_TYPE_COGL
+    CAIRO_SURFACE_TYPE_COGL,
 } cairo_surface_type_t;
 
 cairo_public cairo_surface_type_t
index 1381bc1..4fe89e6 100644 (file)
@@ -337,7 +337,7 @@ _cairo_rectangle_union (cairo_rectangle_int_t *dst,
                        const cairo_rectangle_int_t *src);
 
 cairo_private cairo_bool_t
-_cairo_box_intersects_line_segment (cairo_box_t *box,
+_cairo_box_intersects_line_segment (const cairo_box_t *box,
                                    cairo_line_t *line) cairo_pure;
 
 cairo_private cairo_bool_t
@@ -1052,12 +1052,6 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t   *path,
                                 double                      tolerance,
                                 cairo_traps_t              *traps);
 
-cairo_private cairo_status_t
-_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
-                                            cairo_fill_rule_t        fill_rule,
-                                            cairo_antialias_t        antialias,
-                                            cairo_traps_t                *traps);
-
 /* cairo-path-stroke.c */
 cairo_private cairo_status_t
 _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t  *path,
@@ -1098,6 +1092,14 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t      *path,
                                   double                tolerance,
                                   cairo_traps_t        *traps);
 
+cairo_private cairo_int_status_t
+_cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t    *path,
+                                          const cairo_stroke_style_t   *stroke_style,
+                                          const cairo_matrix_t *ctm,
+                                          const cairo_matrix_t *ctm_inverse,
+                                          double                tolerance,
+                                          cairo_traps_t        *traps);
+
 cairo_private cairo_status_t
 _cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path,
                                   const cairo_stroke_style_t   *stroke_style,
@@ -1244,6 +1246,17 @@ _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
                                            const cairo_path_fixed_t *path,
                                             const cairo_matrix_t *ctm,
                                             double *dx, double *dy);
+cairo_private void
+_cairo_stroke_style_max_line_distance_from_path (const cairo_stroke_style_t *style,
+                                                const cairo_path_fixed_t *path,
+                                                const cairo_matrix_t *ctm,
+                                                double *dx, double *dy);
+
+cairo_private void
+_cairo_stroke_style_max_join_distance_from_path (const cairo_stroke_style_t *style,
+                                                const cairo_path_fixed_t *path,
+                                                const cairo_matrix_t *ctm,
+                                                double *dx, double *dy);
 
 cairo_private double
 _cairo_stroke_style_dash_period (const cairo_stroke_style_t *style);
@@ -1915,6 +1928,7 @@ slim_hidden_proto (cairo_pattern_set_matrix);
 slim_hidden_proto (cairo_pop_group);
 slim_hidden_proto (cairo_push_group_with_content);
 slim_hidden_proto_no_warn (cairo_path_destroy);
+slim_hidden_proto (cairo_recording_surface_create);
 slim_hidden_proto (cairo_rel_line_to);
 slim_hidden_proto (cairo_restore);
 slim_hidden_proto (cairo_save);
@@ -2050,7 +2064,7 @@ cairo_private void
 _cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip);
 
 #if 0
-#define TRACE(x) fprintf x
+#define TRACE(x) fprintf (stderr, "%s: ", __FILE__), fprintf x
 #define TRACE_(x) x
 #else
 #define TRACE(x)
index f8fa517..ff84b10 100644 (file)
@@ -662,10 +662,10 @@ base_compositor_stroke (const cairo_compositor_t *_compositor,
 
     info.antialias = antialias;
     _cairo_traps_init_with_clip (&info.traps, extents->clip);
-    status = _cairo_path_fixed_stroke_to_traps (path, style,
-                                               ctm, ctm_inverse,
-                                               tolerance,
-                                               &info.traps);
+    status = _cairo_path_fixed_stroke_polygon_to_traps (path, style,
+                                                       ctm, ctm_inverse,
+                                                       tolerance,
+                                                       &info.traps);
     if (likely (status == CAIRO_INT_STATUS_SUCCESS))
        status = trim_extents_to_traps (extents, &info.traps);
     if (likely (status == CAIRO_INT_STATUS_SUCCESS))
index 2c5374c..b0c2f90 100644 (file)
@@ -497,6 +497,7 @@ _cairo_win32_display_surface_unmap_image (void                    *abstract_surf
                __FUNCTION__, r.x, r.y, r.width, r.height));
        surface->fallback->damage =
            _cairo_damage_add_rectangle (surface->fallback->damage, &r);
+       surface = to_win32_display_surface (surface->fallback);
     }
 
     return _cairo_surface_unmap_image (surface->image, image);
index 8fee54a..1f03885 100644 (file)
@@ -290,6 +290,7 @@ test_sources = \
        scale-source-surface-paint.c                    \
        scaled-font-zero-matrix.c                       \
        stroke-ctm-caps.c                               \
+       stroke-clipped.c                                \
        stroke-image.c                                  \
        stroke-open-box.c                               \
        select-font-face.c                              \
@@ -366,6 +367,7 @@ test_sources = \
        world-map.c                                     \
        white-in-noop.c                                 \
        xcb-huge-image-shm.c                            \
+       xcb-huge-subimage.c                             \
        xcb-stress-cache.c                              \
        xcb-snapshot-assert.c                           \
        xcomposite-projection.c                         \
index 3f37147..076b014 100644 (file)
@@ -35,9 +35,6 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <ctype.h>
-#if HAVE_FEENABLEEXCEPT
-#include <fenv.h>
-#endif
 #include <assert.h>
 #if HAVE_UNISTD_H
 #include <unistd.h>
index d41cd29..87ba7df 100644 (file)
@@ -62,6 +62,26 @@ typedef unsigned __int64 uint64_t;
 
 #endif
 
+#if HAVE_FENV_H
+# include <fenv.h>
+#endif
+/* The following are optional in C99, so define them if they aren't yet */
+#ifndef FE_DIVBYZERO
+#define FE_DIVBYZERO 0
+#endif
+#ifndef FE_INEXACT
+#define FE_INEXACT 0
+#endif
+#ifndef FE_INVALID
+#define FE_INVALID 0
+#endif
+#ifndef FE_OVERFLOW
+#define FE_OVERFLOW 0
+#endif
+#ifndef FE_UNDERFLOW
+#define FE_UNDERFLOW 0
+#endif
+
 #include <math.h>
 
 static inline double
index 6cfaedf..9bb26be 100644 (file)
 #define INFINITY HUGE_VAL
 #endif
 
-#if HAVE_FENV_H
-# include <fenv.h>
-#endif
-
 static cairo_test_status_t
 draw (cairo_t *cr, int width, int height)
 {
diff --git a/test/mime-surface.c b/test/mime-surface.c
deleted file mode 100644 (file)
index d59112f..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright Â© 2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Author: Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#include "cairo-test.h"
-
-#include <stdio.h>
-#include <errno.h>
-
-/* Basic test to exercise the new mime-surface callback. */
-
-#define WIDTH 200
-#define HEIGHT 80
-
-/* Lazy way of determining PNG dimensions... */
-static void
-png_dimensions (const char *filename,
-               cairo_content_t *content, int *width, int *height)
-{
-    cairo_surface_t *surface;
-
-    surface = cairo_image_surface_create_from_png (filename);
-    *content = cairo_surface_get_content (surface);
-    *width = cairo_image_surface_get_width (surface);
-    *height = cairo_image_surface_get_height (surface);
-    cairo_surface_destroy (surface);
-}
-
-static cairo_surface_t *
-png_acquire (cairo_surface_t *mime_surface, void *closure,
-            cairo_surface_t *target, const cairo_rectangle_int_t *roi,
-            cairo_rectangle_int_t *extents)
-{
-    cairo_surface_t *image;
-
-    image = cairo_image_surface_create_from_png (closure);
-    extents->x = extents->y = 0;
-    extents->width = cairo_image_surface_get_width (image);
-    extents->height = cairo_image_surface_get_height (image);
-    return image;
-}
-
-static cairo_surface_t *
-red_acquire (cairo_surface_t *mime_surface, void *closure,
-            cairo_surface_t *target, const cairo_rectangle_int_t *roi,
-            cairo_rectangle_int_t *extents)
-{
-    cairo_surface_t *image;
-    cairo_t *cr;
-
-    image = cairo_surface_create_similar_image (target,
-                                               CAIRO_FORMAT_RGB24,
-                                               roi->width, roi->height);
-    cr = cairo_create (image);
-    cairo_set_source_rgb (cr, 1, 0, 0);
-    cairo_paint (cr);
-    cairo_destroy (cr);
-
-    *extents = *roi;
-    return image;
-}
-
-static void
-release (cairo_surface_t *mime_surface, void *closure, cairo_surface_t *image)
-{
-    cairo_surface_destroy (image);
-}
-
-static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
-{
-    const char *png_filename = "png.png";
-    cairo_surface_t *png, *red;
-    cairo_content_t content;
-    int png_width, png_height;
-    int i, j;
-
-    png_dimensions (png_filename, &content, &png_width, &png_height);
-
-    png = cairo_mime_surface_create ((void*)png_filename, content, png_width, png_height);
-    cairo_mime_surface_set_acquire (png, png_acquire, release);
-
-    red = cairo_mime_surface_create (NULL, CAIRO_CONTENT_COLOR, WIDTH, HEIGHT);
-    cairo_mime_surface_set_acquire (red, red_acquire, release);
-
-    cairo_set_source_rgb (cr, 0, 0, 1);
-    cairo_paint (cr);
-
-    cairo_translate (cr, 0, (HEIGHT-png_height)/2);
-    for (i = 0; i < 4; i++) {
-       for (j = 0; j < 4; j++) {
-           cairo_surface_t *source;
-           if ((i ^ j) & 1)
-               source = red;
-           else
-               source = png;
-           cairo_set_source_surface (cr, source, 0, 0);
-           cairo_rectangle (cr, i * WIDTH/4, j * png_height/4, WIDTH/4, png_height/4);
-           cairo_fill (cr);
-       }
-    }
-
-    cairo_surface_destroy (red);
-    cairo_surface_destroy (png);
-
-    return CAIRO_TEST_SUCCESS;
-}
-
-static cairo_test_status_t
-check_status (const cairo_test_context_t *ctx,
-             cairo_status_t status,
-             cairo_status_t expected)
-{
-    if (status == expected)
-       return CAIRO_TEST_SUCCESS;
-
-    cairo_test_log (ctx,
-                   "Error: Expected status value %d (%s), received %d (%s)\n",
-                   expected,
-                   cairo_status_to_string (expected),
-                   status,
-                   cairo_status_to_string (status));
-    return CAIRO_TEST_FAILURE;
-}
-
-static cairo_test_status_t
-preamble (cairo_test_context_t *ctx)
-{
-    cairo_surface_t *mime;
-    cairo_status_t status;
-    cairo_t *cr;
-
-    /* drawing to a mime-surface is verboten */
-
-    mime = cairo_mime_surface_create (NULL, CAIRO_CONTENT_COLOR, 0, 0);
-    cr = cairo_create (mime);
-    cairo_surface_destroy (mime);
-    status = cairo_status (cr);
-    cairo_destroy (cr);
-    status = check_status (ctx, status, CAIRO_STATUS_WRITE_ERROR);
-    if (status)
-       return status;
-
-    return CAIRO_TEST_SUCCESS;
-}
-
-CAIRO_TEST (mime_surface,
-           "Check that the mime-surface embedding works",
-           "api", /* keywords */
-           NULL, /* requirements */
-           WIDTH, HEIGHT,
-           preamble, draw)
index 6d0c5cf..516e66c 100644 (file)
Binary files a/test/reference/arc-looping-dash.ref.png and b/test/reference/arc-looping-dash.ref.png differ
index 6cf2b1a..9f2f52c 100644 (file)
Binary files a/test/reference/bug-source-cu.rgb24.ref.png and b/test/reference/bug-source-cu.rgb24.ref.png differ
index f23d5dc..ac97c82 100644 (file)
Binary files a/test/reference/caps-tails-curve.ref.png and b/test/reference/caps-tails-curve.ref.png differ
index 5247843..c62bf29 100644 (file)
Binary files a/test/reference/clip-nesting.rgb24.ref.png and b/test/reference/clip-nesting.rgb24.ref.png differ
index 8bf64c1..316cc36 100644 (file)
Binary files a/test/reference/clip-stroke-unbounded.argb32.ref.png and b/test/reference/clip-stroke-unbounded.argb32.ref.png differ
index 2dbe36b..ee4bec4 100644 (file)
Binary files a/test/reference/clip-stroke-unbounded.rgb24.ref.png and b/test/reference/clip-stroke-unbounded.rgb24.ref.png differ
index 396da65..23ef735 100644 (file)
Binary files a/test/reference/image-bug-710072-unaligned.egl.argb32.ref.png and b/test/reference/image-bug-710072-unaligned.egl.argb32.ref.png differ
index d965468..2d740d4 100644 (file)
Binary files a/test/reference/mask.argb32.ref.png and b/test/reference/mask.argb32.ref.png differ
index 0617ec2..12114a7 100644 (file)
Binary files a/test/reference/mask.rgb24.ref.png and b/test/reference/mask.rgb24.ref.png differ
index faab9d3..34279c8 100644 (file)
Binary files a/test/reference/pthread-same-source.egl.argb32.ref.png and b/test/reference/pthread-same-source.egl.argb32.ref.png differ
index 630c024..06a4d55 100644 (file)
Binary files a/test/reference/record-fill-alpha.ref.png and b/test/reference/record-fill-alpha.ref.png differ
index 3bc8cd5..34d3aa6 100644 (file)
Binary files a/test/reference/record-paint-alpha-clip-mask.ref.png and b/test/reference/record-paint-alpha-clip-mask.ref.png differ
index 5727f35..ef3c967 100644 (file)
Binary files a/test/reference/record1414x-text-transform.ref.png and b/test/reference/record1414x-text-transform.ref.png differ
index 6c21785..ff521ab 100644 (file)
Binary files a/test/reference/record2x-text-transform.ref.png and b/test/reference/record2x-text-transform.ref.png differ
diff --git a/test/reference/record90-paint-alpha-clip-mask.ref.png b/test/reference/record90-paint-alpha-clip-mask.ref.png
new file mode 100644 (file)
index 0000000..03cf805
Binary files /dev/null and b/test/reference/record90-paint-alpha-clip-mask.ref.png differ
diff --git a/test/reference/record90-paint-alpha-clip.ref.png b/test/reference/record90-paint-alpha-clip.ref.png
new file mode 100644 (file)
index 0000000..ab1fe3c
Binary files /dev/null and b/test/reference/record90-paint-alpha-clip.ref.png differ
diff --git a/test/reference/record90-text-transform.ref.png b/test/reference/record90-text-transform.ref.png
new file mode 100644 (file)
index 0000000..e8fa722
Binary files /dev/null and b/test/reference/record90-text-transform.ref.png differ
index c8040da..d69cdc9 100644 (file)
Binary files a/test/reference/recording-surface-extend-none.argb32.ref.png and b/test/reference/recording-surface-extend-none.argb32.ref.png differ
index bd84338..48401f9 100644 (file)
Binary files a/test/reference/recording-surface-extend-none.rgb24.ref.png and b/test/reference/recording-surface-extend-none.rgb24.ref.png differ
index f1c3d23..31b7005 100644 (file)
Binary files a/test/reference/recording-surface-extend-pad.argb32.ref.png and b/test/reference/recording-surface-extend-pad.argb32.ref.png differ
index 4906c8f..06a6ce2 100644 (file)
Binary files a/test/reference/recording-surface-extend-pad.rgb24.ref.png and b/test/reference/recording-surface-extend-pad.rgb24.ref.png differ
index 016bf39..bc1d70f 100644 (file)
Binary files a/test/reference/recording-surface-extend-reflect.argb32.ref.png and b/test/reference/recording-surface-extend-reflect.argb32.ref.png differ
index 59b58e9..f6f52e7 100644 (file)
Binary files a/test/reference/recording-surface-extend-reflect.rgb24.ref.png and b/test/reference/recording-surface-extend-reflect.rgb24.ref.png differ
index 960bfd2..d95245b 100644 (file)
Binary files a/test/reference/recording-surface-extend-repeat.argb32.ref.png and b/test/reference/recording-surface-extend-repeat.argb32.ref.png differ
index d49fd12..2d77522 100644 (file)
Binary files a/test/reference/recording-surface-extend-repeat.rgb24.ref.png and b/test/reference/recording-surface-extend-repeat.rgb24.ref.png differ
diff --git a/test/reference/recording-surface-over.argb32.ref.png b/test/reference/recording-surface-over.argb32.ref.png
new file mode 100644 (file)
index 0000000..d69cdc9
Binary files /dev/null and b/test/reference/recording-surface-over.argb32.ref.png differ
index bd84338..48401f9 100644 (file)
Binary files a/test/reference/recording-surface-over.rgb24.ref.png and b/test/reference/recording-surface-over.rgb24.ref.png differ
index 22c612b..bc6930f 100644 (file)
Binary files a/test/reference/recording-surface-source.argb32.ref.png and b/test/reference/recording-surface-source.argb32.ref.png differ
index 3481673..b77d6dc 100644 (file)
Binary files a/test/reference/recording-surface-source.rgb24.ref.png and b/test/reference/recording-surface-source.rgb24.ref.png differ
index 1318806..c05eb96 100644 (file)
Binary files a/test/reference/reflected-stroke.ref.png and b/test/reference/reflected-stroke.ref.png differ
index 78d8a08..0301ed2 100644 (file)
Binary files a/test/reference/rel-path.rgb24.ref.png and b/test/reference/rel-path.rgb24.ref.png differ
diff --git a/test/reference/stroke-clipped.ref.png b/test/reference/stroke-clipped.ref.png
new file mode 100644 (file)
index 0000000..2d4c5d1
Binary files /dev/null and b/test/reference/stroke-clipped.ref.png differ
diff --git a/test/reference/xcb-huge-subimage.ref.png b/test/reference/xcb-huge-subimage.ref.png
new file mode 100644 (file)
index 0000000..a0b24c8
Binary files /dev/null and b/test/reference/xcb-huge-subimage.ref.png differ
diff --git a/test/stroke-clipped.c b/test/stroke-clipped.c
new file mode 100644 (file)
index 0000000..4b80794
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "cairo-test.h"
+
+#define SIZE 200
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    int row;
+
+    cairo_set_source_rgb(cr, 1, 1, 1);
+    cairo_paint(cr);
+
+    cairo_set_source_rgb(cr, 1, 0, 0);
+    for(row = 0; row < SIZE; row++) {
+       cairo_rectangle(cr, 0, row, SIZE, 1);
+       cairo_clip(cr);
+
+       cairo_arc(cr, SIZE/2, SIZE/2, SIZE/2-8, 0, 2*M_PI);
+       cairo_stroke(cr);
+
+       cairo_reset_clip(cr);
+    }
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (stroke_clipped,
+           "Check that the stroke is accurately drawn through smaller clips",
+           "stroke", /* keywords */
+           NULL, /* requirements */
+           SIZE, SIZE,
+           NULL, draw)
diff --git a/test/xcb-huge-subimage.c b/test/xcb-huge-subimage.c
new file mode 100644 (file)
index 0000000..fc8e278
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright Â© 2012 Uli Schlachter
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Uli Schlachter <psychon@znc.in>
+ */
+
+#include "cairo-test.h"
+
+#define WIDTH 6000
+#define HEIGHT 6000
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *surface;
+    cairo_surface_t *image;
+    cairo_surface_t *subimage;
+    cairo_rectangle_int_t extents;
+    cairo_t *cr2;
+
+    extents.x = extents.y = 10;
+    extents.width = WIDTH - 20;
+    extents.height = HEIGHT - 20;
+
+    /* We use a similar surface to have way smaller ref images */
+    surface = cairo_surface_create_similar (cairo_get_target (cr),
+                                           CAIRO_CONTENT_COLOR_ALPHA,
+                                           WIDTH, HEIGHT);
+
+    /* First we have to defeat xcb's deferred clear */
+    cr2 = cairo_create (surface);
+    cairo_test_paint_checkered (cr2);
+    cairo_destroy (cr2);
+
+    /* Get us an image surface with a non-natural stride */
+    image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                       WIDTH, HEIGHT);
+    subimage = cairo_surface_map_to_image (image, &extents);
+
+    /* Paint the subimage to the similar surface and trigger the big upload */
+    cr2 = cairo_create (surface);
+    cairo_set_source_surface (cr2, subimage, 0, 0);
+    cairo_paint (cr2);
+    cairo_destroy (cr2);
+
+    /* Finally we make sure that errors aren't lost. */
+    cairo_surface_unmap_image (image, subimage);
+    cairo_set_source_surface (cr, surface, 0, 0);
+    cairo_paint (cr);
+    cairo_surface_destroy (image);
+    cairo_surface_destroy (surface);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (xcb_huge_subimage,
+           "Test if the maximum request size is honored",
+           "xcb", /* keywords */
+           NULL, /* requirements */
+           2, 2,
+           NULL, draw)
index 5cd5798..34215a6 100644 (file)
@@ -10,4 +10,6 @@ cairo_fdr_la_SOURCES = fdr.c
 cairo_fdr_la_CPPFLAGS = $(AM_CPPFLAGS)
 cairo_fdr_la_CFLAGS = $(CAIRO_CFLAGS)
 cairo_fdr_la_LDFLAGS = -module -no-undefined
+if CAIRO_HAS_DL
 cairo_fdr_la_LIBADD = -ldl
+endif
index f43a6d0..e82cbc0 100644 (file)
@@ -117,7 +117,7 @@ cairo_gobject_line_cap_get_type (void);
 cairo_public GType
 cairo_gobject_line_join_get_type (void);
 
-#define CAIRO_GOBJECT_TYPE_CLUSTER_FLAGS cairo_gobject_cluster_flags_get_type ()
+#define CAIRO_GOBJECT_TYPE_TEXT_CLUSTER_FLAGS cairo_gobject_text_cluster_flags_get_type ()
 cairo_public GType
 cairo_gobject_text_cluster_flags_get_type (void);
 
@@ -137,7 +137,9 @@ cairo_gobject_subpixel_order_get_type (void);
 cairo_public GType
 cairo_gobject_hint_style_get_type (void);
 
+/* historical accident */
 #define CAIRO_GOBJECT_TYPE_HNT_METRICS cairo_gobject_hint_metrics_get_type ()
+#define CAIRO_GOBJECT_TYPE_HINT_METRICS cairo_gobject_hint_metrics_get_type ()
 cairo_public GType
 cairo_gobject_hint_metrics_get_type (void);
 
index c2f55a3..d5c2998 100644 (file)
@@ -15,7 +15,7 @@ libcairo_script_interpreter_la_SOURCES = \
        $(NULL)
 libcairo_script_interpreter_la_CFLAGS = $(CAIRO_CFLAGS)
 libcairo_script_interpreter_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_INFO) -no-undefined $(export_symbols)
-libcairo_script_interpreter_la_LIBADD = $(top_builddir)/src/libcairo.la $(CAIRO_LIBS) -lz
+libcairo_script_interpreter_la_LIBADD = $(top_builddir)/src/libcairo.la $(CAIRO_LIBS) $(lzo_LIBS) -lz
 
 csi_replay_SOURCES = csi-replay.c
 csi_replay_CFLAGS = $(CAIRO_CFLAGS)
index 34f2964..85d292c 100644 (file)
 #include <string.h>
 #include <zlib.h>
 
+#if HAVE_LZO
+#include <lzo/lzo2a.h>
+#endif
+
 #define CHUNK_SIZE 32768
 
 #define OWN_STREAM 0x1
@@ -166,12 +170,32 @@ csi_file_new_from_string (csi_t *ctx,
            return status;
 
        tmp_str = tmp_obj.datum.string;
-       if (uncompress ((Bytef *) tmp_str->string, &len,
-                       (Bytef *) src->string, src->len) != Z_OK)
-       {
+       switch (src->method) {
+       case NONE:
+       default:
+           status = _csi_error (CAIRO_STATUS_NO_MEMORY);
+           break;
+
+#if HAVE_ZLIB
+       case ZLIB:
+           if (uncompress ((Bytef *) tmp_str->string, &len,
+                           (Bytef *) src->string, src->len) != Z_OK)
+               status = _csi_error (CAIRO_STATUS_NO_MEMORY);
+           break;
+#endif
+#if HAVE_LZO
+       case LZO:
+           if (lzo2a_decompress ((lzo_bytep) src->string, src->len,
+                                 (lzo_bytep) tmp_str->string, &len,
+                                 NULL))
+               status = _csi_error (CAIRO_STATUS_NO_MEMORY);
+           break;
+#endif
+       }
+       if (_csi_unlikely (status)) {
            csi_string_free (ctx, tmp_str);
            _csi_slab_free (ctx, file, sizeof (csi_file_t));
-           return _csi_error (CAIRO_STATUS_NO_MEMORY);
+           return status;
        }
 
        file->src  = tmp_str;
index bbdd15d..27fb986 100644 (file)
@@ -65,6 +65,12 @@ typedef void
 (*csi_copy_page_func_t) (void *closure,
                         cairo_t *cr);
 
+typedef cairo_surface_t *
+(*csi_create_source_image_t) (void *closure,
+                             cairo_format_t format,
+                             int width, int height,
+                             long uid);
+
 typedef struct _cairo_script_interpreter_hooks {
     void *closure;
     csi_surface_create_func_t surface_create;
@@ -73,6 +79,7 @@ typedef struct _cairo_script_interpreter_hooks {
     csi_destroy_func_t context_destroy;
     csi_show_page_func_t show_page;
     csi_copy_page_func_t copy_page;
+    csi_create_source_image_t create_source_image;
 } cairo_script_interpreter_hooks_t;
 
 cairo_public cairo_script_interpreter_t *
index adf6160..a625489 100644 (file)
@@ -508,6 +508,7 @@ csi_string_new (csi_t *ctx,
     }
     string->len = len;
     string->deflate = 0;
+    string->method = NONE;
 
     string->base.type = CSI_OBJECT_TYPE_STRING;
     string->base.ref = 1;
@@ -534,6 +535,7 @@ csi_string_deflate_new (csi_t *ctx,
 
     string = obj->datum.string;
     string->deflate = out_len;
+    string->method = ZLIB;
 
     return CSI_STATUS_SUCCESS;
 }
@@ -556,6 +558,7 @@ csi_string_new_from_bytes (csi_t *ctx,
     string->string = bytes;
     string->len = len;
     string->deflate = 0;
+    string->method = NONE;
 
     string->base.type = CSI_OBJECT_TYPE_STRING;
     string->base.ref = 1;
index 42f5296..d423fe5 100644 (file)
 #include <math.h>
 #include <limits.h> /* INT_MAX */
 #include <assert.h>
+
+#if HAVE_ZLIB
 #include <zlib.h>
+#endif
+
+#if HAVE_LZO
+#include <lzo/lzo2a.h>
+#endif
 
 #ifdef HAVE_MMAP
 # ifdef HAVE_UNISTD_H
@@ -1756,17 +1763,37 @@ inflate_string (csi_t *ctx, csi_string_t *src)
     if (bytes == NULL)
        return NULL;
 
-    if (uncompress ((Bytef *) bytes, &len,
-                   (Bytef *) src->string, src->len) != Z_OK)
-    {
-       _csi_free (ctx, bytes);
-       bytes = NULL;
-    }
-    else
-    {
-       bytes[len] = '\0';
+    switch (src->method) {
+    default:
+    case NONE:
+       free (bytes);
+       return NULL;
+
+#if HAVE_ZLIB
+    case ZLIB:
+       if (uncompress ((Bytef *) bytes, &len,
+                       (Bytef *) src->string, src->len) != Z_OK)
+       {
+           _csi_free (ctx, bytes);
+           return NULL;
+       }
+       break;
+#endif
+
+#if HAVE_LZO
+    case LZO:
+       if (lzo2a_decompress ((Bytef *) src->string, src->len,
+                             (Bytef *) bytes, &len,
+                             NULL))
+       {
+           _csi_free (ctx, bytes);
+           return NULL;
+       }
+       break;
+#endif
     }
 
+    bytes[len] = '\0';
     return bytes;
 }
 
@@ -2865,7 +2892,8 @@ _ifelse (csi_t *ctx)
 }
 
 static csi_status_t
-_image_read_raw (csi_file_t *src,
+_image_read_raw (csi_t *ctx,
+                csi_object_t *src,
                 cairo_format_t format,
                 int width, int height,
                 cairo_surface_t **image_out)
@@ -2875,20 +2903,34 @@ _image_read_raw (csi_file_t *src,
     int rem, len, ret, x, rowlen, instride, stride;
     cairo_status_t status;
 
-    stride = cairo_format_stride_for_width (format, width);
-    data = malloc (stride * height);
-    if (data == NULL)
-       return CAIRO_STATUS_NO_MEMORY;
+    if (width == 0 || height == 0) {
+       *image_out = cairo_image_surface_create (format, 0, 0);
+       return CSI_STATUS_SUCCESS;
+    }
 
-    image = cairo_image_surface_create_for_data (data, format,
-                                                width, height, stride);
-    status = cairo_surface_set_user_data (image,
-                                         (const cairo_user_data_key_t *) image,
-                                         data, free);
-    if (status) {
-       cairo_surface_destroy (image);
-       free (image);
-       return status;
+    if (ctx->hooks.create_source_image != NULL) {
+       image = ctx->hooks.create_source_image (ctx->hooks.closure,
+                                               format, width, height,
+                                               0);
+
+       stride = cairo_image_surface_get_stride (image);
+       data = cairo_image_surface_get_data (image);
+    } else {
+       stride = cairo_format_stride_for_width (format, width);
+       data = malloc (stride * height);
+       if (data == NULL)
+           return CAIRO_STATUS_NO_MEMORY;
+
+       image = cairo_image_surface_create_for_data (data, format,
+                                                    width, height, stride);
+       status = cairo_surface_set_user_data (image,
+                                             (const cairo_user_data_key_t *) image,
+                                             data, free);
+       if (status) {
+           cairo_surface_destroy (image);
+           free (image);
+           return status;
+       }
     }
 
     switch (format) {
@@ -2914,192 +2956,236 @@ _image_read_raw (csi_file_t *src,
     }
     len = rowlen * height;
 
-    bp = data;
-    rem = len;
-    while (rem) {
-       ret = csi_file_read (src, bp, rem);
-       if (_csi_unlikely (ret == 0)) {
+    if (rowlen == instride &&
+       src->type == CSI_OBJECT_TYPE_STRING &&
+       len == src->datum.string->deflate)
+    {
+       csi_string_t *s = src->datum.string;
+       unsigned long out = s->deflate;
+
+       switch (s->method) {
+       default:
+       case NONE:
+err_decompress:
            cairo_surface_destroy (image);
            return _csi_error (CSI_STATUS_READ_ERROR);
+
+#if HAVE_ZLIB
+       case ZLIB:
+           if (uncompress ((Bytef *) data, &out,
+                           (Bytef *) s->string, s->len) != Z_OK)
+               goto err_decompress;
+           break;
+#endif
+
+#if HAVE_LZO
+       case LZO:
+           if (lzo2a_decompress ((Bytef *) s->string, s->len,
+                                 (Bytef *) data, &out,
+                                 NULL))
+               goto err_decompress;
+           break;
+#endif
        }
-       rem -= ret;
-       bp += ret;
     }
+    else
+    {
+       csi_object_t file;
+
+       status = csi_object_as_file (ctx, src, &file);
+       if (_csi_unlikely (status)) {
+           cairo_surface_destroy (image);
+           return status;
+       }
+
+       bp = data;
+       rem = len;
+       while (rem) {
+           ret = csi_file_read (file.datum.file, bp, rem);
+           if (_csi_unlikely (ret == 0)) {
+               cairo_surface_destroy (image);
+               return _csi_error (CSI_STATUS_READ_ERROR);
+           }
+           rem -= ret;
+           bp += ret;
+       }
+
+       if (len != height * stride) {
+           while (--height) {
+               uint8_t *row = data + height * stride;
+
+               /* XXX pixel conversion */
+               switch (format) {
+               case CAIRO_FORMAT_A1:
+                   for (x = rowlen; x--; ) {
+                       uint8_t byte = *--bp;
+                       row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
+                   }
+                   break;
+               case CAIRO_FORMAT_A8:
+                   for (x = width; x--; )
+                       row[x] = *--bp;
+                   break;
+               case CAIRO_FORMAT_RGB16_565:
+                   for (x = width; x--; ) {
+#ifdef WORDS_BIGENDIAN
+                       row[2*x + 1] = *--bp;
+                       row[2*x + 0] = *--bp;
+#else
+                       row[2*x + 0] = *--bp;
+                       row[2*x + 1] = *--bp;
+#endif
+                   }
+                   break;
+               case CAIRO_FORMAT_RGB24:
+                   for (x = width; x--; ) {
+#ifdef WORDS_BIGENDIAN
+                       row[4*x + 3] = *--bp;
+                       row[4*x + 2] = *--bp;
+                       row[4*x + 1] = *--bp;
+                       row[4*x + 0] = 0xff;
+#else
+                       row[4*x + 0] = *--bp;
+                       row[4*x + 1] = *--bp;
+                       row[4*x + 2] = *--bp;
+                       row[4*x + 3] = 0xff;
+#endif
+                   }
+                   break;
+               case CAIRO_FORMAT_RGB30:
+               case CAIRO_FORMAT_INVALID:
+               case CAIRO_FORMAT_ARGB32:
+                   /* stride == width */
+                   break;
+               }
 
-    if (len != height * stride) {
-       while (--height) {
-           uint8_t *row = data + height * stride;
+               memset (row + instride, 0, stride - instride);
+           }
 
-           /* XXX pixel conversion */
+           /* need to treat last row carefully */
            switch (format) {
            case CAIRO_FORMAT_A1:
                for (x = rowlen; x--; ) {
                    uint8_t byte = *--bp;
-                   row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
+                   data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
                }
                break;
            case CAIRO_FORMAT_A8:
                for (x = width; x--; )
-                   row[x] = *--bp;
+                   data[x] = *--bp;
                break;
            case CAIRO_FORMAT_RGB16_565:
                for (x = width; x--; ) {
 #ifdef WORDS_BIGENDIAN
-                   row[2*x + 1] = *--bp;
-                   row[2*x + 0] = *--bp;
+                   data[2*x + 1] = *--bp;
+                   data[2*x + 0] = *--bp;
 #else
-                   row[2*x + 0] = *--bp;
-                   row[2*x + 1] = *--bp;
+                   data[2*x + 0] = *--bp;
+                   data[2*x + 1] = *--bp;
 #endif
                }
                break;
            case CAIRO_FORMAT_RGB24:
-               for (x = width; x--; ) {
+               for (x = width; --x>1; ) {
 #ifdef WORDS_BIGENDIAN
-                   row[4*x + 3] = *--bp;
-                   row[4*x + 2] = *--bp;
-                   row[4*x + 1] = *--bp;
-                   row[4*x + 0] = 0xff;
+                   data[4*x + 3] = *--bp;
+                   data[4*x + 2] = *--bp;
+                   data[4*x + 1] = *--bp;
+                   data[4*x + 0] = 0xff;
 #else
-                   row[4*x + 0] = *--bp;
-                   row[4*x + 1] = *--bp;
-                   row[4*x + 2] = *--bp;
-                   row[4*x + 3] = 0xff;
+                   data[4*x + 0] = *--bp;
+                   data[4*x + 1] = *--bp;
+                   data[4*x + 2] = *--bp;
+                   data[4*x + 3] = 0xff;
 #endif
                }
-               break;
-           case CAIRO_FORMAT_RGB30:
-           case CAIRO_FORMAT_INVALID:
-           case CAIRO_FORMAT_ARGB32:
-               /* stride == width */
-               break;
-           }
-
-           memset (row + instride, 0, stride - instride);
-       }
-
-       /* need to treat last row carefully */
-       switch (format) {
-       case CAIRO_FORMAT_A1:
-           for (x = rowlen; x--; ) {
-               uint8_t byte = *--bp;
-               data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
-           }
-           break;
-       case CAIRO_FORMAT_A8:
-           for (x = width; x--; )
-               data[x] = *--bp;
-           break;
-       case CAIRO_FORMAT_RGB16_565:
-           for (x = width; x--; ) {
-#ifdef WORDS_BIGENDIAN
-               data[2*x + 1] = *--bp;
-               data[2*x + 0] = *--bp;
-#else
-               data[2*x + 0] = *--bp;
-               data[2*x + 1] = *--bp;
-#endif
-           }
-           break;
-       case CAIRO_FORMAT_RGB24:
-           for (x = width; --x>1; ) {
-#ifdef WORDS_BIGENDIAN
-               data[4*x + 3] = *--bp;
-               data[4*x + 2] = *--bp;
-               data[4*x + 1] = *--bp;
-               data[4*x + 0] = 0xff;
-#else
-               data[4*x + 0] = *--bp;
-               data[4*x + 1] = *--bp;
-               data[4*x + 2] = *--bp;
-               data[4*x + 3] = 0xff;
-#endif
-           }
-           if (width > 1) {
-               uint8_t rgb[2][3];
-               /* shuffle the last couple of overlapping pixels */
-               rgb[1][0] = data[5];
-               rgb[1][1] = data[4];
-               rgb[1][2] = data[3];
-               rgb[0][0] = data[2];
-               rgb[0][1] = data[1];
-               rgb[0][2] = data[0];
+               if (width > 1) {
+                   uint8_t rgb[2][3];
+                   /* shuffle the last couple of overlapping pixels */
+                   rgb[1][0] = data[5];
+                   rgb[1][1] = data[4];
+                   rgb[1][2] = data[3];
+                   rgb[0][0] = data[2];
+                   rgb[0][1] = data[1];
+                   rgb[0][2] = data[0];
 #ifdef WORDS_BIGENDIAN
-               data[4] = 0xff;
-               data[5] = rgb[1][2];
-               data[6] = rgb[1][1];
-               data[7] = rgb[1][0];
-               data[0] = 0xff;
-               data[1] = rgb[0][2];
-               data[2] = rgb[0][1];
-               data[3] = rgb[0][0];
+                   data[4] = 0xff;
+                   data[5] = rgb[1][2];
+                   data[6] = rgb[1][1];
+                   data[7] = rgb[1][0];
+                   data[0] = 0xff;
+                   data[1] = rgb[0][2];
+                   data[2] = rgb[0][1];
+                   data[3] = rgb[0][0];
 #else
-               data[7] = 0xff;
-               data[6] = rgb[1][2];
-               data[5] = rgb[1][1];
-               data[4] = rgb[1][0];
-               data[3] = 0xff;
-               data[2] = rgb[0][2];
-               data[1] = rgb[0][1];
-               data[0] = rgb[0][0];
+                   data[7] = 0xff;
+                   data[6] = rgb[1][2];
+                   data[5] = rgb[1][1];
+                   data[4] = rgb[1][0];
+                   data[3] = 0xff;
+                   data[2] = rgb[0][2];
+                   data[1] = rgb[0][1];
+                   data[0] = rgb[0][0];
 #endif
-           } else {
+               } else {
 #ifdef WORDS_BIGENDIAN
-               data[0] = 0xff;
-               data[1] = data[0];
-               data[2] = data[1];
-               data[3] = data[2];
+                   data[0] = 0xff;
+                   data[1] = data[0];
+                   data[2] = data[1];
+                   data[3] = data[2];
 #else
-               data[3] = data[0];
-               data[0] = data[2];
-               data[2] = data[3];
-               data[3] = 0xff;
+                   data[3] = data[0];
+                   data[0] = data[2];
+                   data[2] = data[3];
+                   data[3] = 0xff;
 #endif
+               }
+               break;
+           case CAIRO_FORMAT_RGB30:
+           case CAIRO_FORMAT_INVALID:
+           case CAIRO_FORMAT_ARGB32:
+               /* stride == width */
+               break;
            }
-           break;
-       case CAIRO_FORMAT_RGB30:
-       case CAIRO_FORMAT_INVALID:
-       case CAIRO_FORMAT_ARGB32:
-           /* stride == width */
-           break;
-       }
-       memset (data + instride, 0, stride - instride);
-    } else {
+           memset (data + instride, 0, stride - instride);
+       } else {
 #ifndef WORDS_BIGENDIAN
-       switch (format) {
-       case CAIRO_FORMAT_A1:
-           for (x = 0; x < len; x++) {
-               uint8_t byte = data[x];
-               data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
-           }
-           break;
-       case CAIRO_FORMAT_RGB16_565:
-           {
-               uint32_t *rgba = (uint32_t *) data;
-               for (x = len/2; x--; rgba++) {
-                   *rgba = bswap_16 (*rgba);
+           switch (format) {
+           case CAIRO_FORMAT_A1:
+               for (x = 0; x < len; x++) {
+                   uint8_t byte = data[x];
+                   data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
                }
-           }
-           break;
-       case CAIRO_FORMAT_ARGB32:
-           {
-               uint32_t *rgba = (uint32_t *) data;
-               for (x = len/4; x--; rgba++) {
-                   *rgba = bswap_32 (*rgba);
+               break;
+           case CAIRO_FORMAT_RGB16_565:
+               {
+                   uint32_t *rgba = (uint32_t *) data;
+                   for (x = len/2; x--; rgba++) {
+                       *rgba = bswap_16 (*rgba);
+                   }
                }
-           }
-           break;
+               break;
+           case CAIRO_FORMAT_ARGB32:
+               {
+                   uint32_t *rgba = (uint32_t *) data;
+                   for (x = len/4; x--; rgba++) {
+                       *rgba = bswap_32 (*rgba);
+                   }
+               }
+               break;
 
-       case CAIRO_FORMAT_A8:
-           break;
+           case CAIRO_FORMAT_A8:
+               break;
 
-       case CAIRO_FORMAT_RGB30:
-       case CAIRO_FORMAT_RGB24:
-       case CAIRO_FORMAT_INVALID:
-       default:
-           break;
-       }
+           case CAIRO_FORMAT_RGB30:
+           case CAIRO_FORMAT_RGB24:
+           case CAIRO_FORMAT_INVALID:
+           default:
+               break;
+           }
 #endif
+       }
+       csi_object_free (ctx, &file);
     }
 
     cairo_surface_mark_dirty (image);
@@ -3276,22 +3362,22 @@ _image_load_from_dictionary (csi_t *ctx,
                mime_type = MIME_TYPE_PNG;
        }
 
-       status = csi_object_as_file (ctx, &obj, &file);
-       if (_csi_unlikely (status))
-           return status;
 
        /* XXX hook for general mime-type decoder */
 
        switch (mime_type) {
        case MIME_TYPE_NONE:
-           status = _image_read_raw (file.datum.file,
-                                     format, width, height, &image);
+           status = _image_read_raw (ctx, &obj, format, width, height, &image);
            break;
        case MIME_TYPE_PNG:
+           status = csi_object_as_file (ctx, &obj, &file);
+           if (_csi_unlikely (status))
+               return status;
+
            status = _image_read_png (file.datum.file, &image);
+           csi_object_free (ctx, &file);
            break;
        }
-       csi_object_free (ctx, &file);
        if (_csi_unlikely (status))
            return status;
 
@@ -3690,8 +3776,8 @@ _map_to_image (csi_t *ctx)
     }
 
     obj.type = CSI_OBJECT_TYPE_SURFACE;
-    obj.datum.surface = cairo_surface_map_to_image (surface, r);
-    pop (2);
+    obj.datum.surface = cairo_surface_reference (cairo_surface_map_to_image (surface, r));
+    pop (1);
     return push (&obj);
 }
 
@@ -3712,7 +3798,7 @@ _unmap_image (csi_t *ctx)
 
     cairo_surface_unmap_image (surface, image);
 
-    pop (2);
+    pop (1);
     return CSI_STATUS_SUCCESS;
 }
 
@@ -5270,11 +5356,20 @@ _set_source_image (csi_t *ctx)
      * principally to remove the pixman ops from the profiles.
      */
     if (_csi_likely (_matching_images (surface, source))) {
-       cairo_surface_flush (surface);
-       memcpy (cairo_image_surface_get_data (surface),
-               cairo_image_surface_get_data (source),
-               cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source));
-       cairo_surface_mark_dirty (surface);
+       if (cairo_surface_get_reference_count (surface) == 1 &&
+           cairo_surface_get_reference_count (source) == 1)
+       {
+           _csi_peek_ostack (ctx, 0)->datum.surface = surface;
+           _csi_peek_ostack (ctx, 1)->datum.surface = source;
+       }
+       else
+       {
+           cairo_surface_flush (surface);
+           memcpy (cairo_image_surface_get_data (surface),
+                   cairo_image_surface_get_data (source),
+                   cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source));
+           cairo_surface_mark_dirty (surface);
+       }
     } else {
        cairo_t *cr;
 
index 3286bb4..6bf41b4 100644 (file)
@@ -392,6 +392,11 @@ struct _csi_string {
     csi_compound_object_t base;
     csi_integer_t len;
     csi_integer_t deflate;
+    enum {
+       NONE,
+       ZLIB,
+       LZO,
+    } method;
     char *string;
 };
 
index eeec686..4254aa0 100644 (file)
 #include <math.h> /* pow */
 #include <stdio.h> /* EOF */
 #include <stdint.h> /* for {INT,UINT}*_{MIN,MAX} */
+#include <stdlib.h> /* malloc/free */
 #include <string.h> /* memset */
 #include <assert.h>
 #include <zlib.h>
 
+#if HAVE_LZO
+#include <lzo/lzo2a.h>
+#endif
+
 #define DEBUG_SCAN 0
 
 #if WORDS_BIGENDIAN
@@ -124,7 +129,8 @@ fprintf_obj (FILE *stream, csi_t *ctx, const csi_object_t *obj)
                    obj->datum.matrix->matrix.y0);
            break;
        case CSI_OBJECT_TYPE_STRING:
-           fprintf (stream, "string: len=%ld\n", obj->datum.string->len);
+           fprintf (stream, "string: len=%ld, defate=%ld, method=%d\n",
+                    obj->datum.string->len, obj->datum.string->deflate, obj->datum.string->method);
            break;
 
            /* cairo */
@@ -799,6 +805,7 @@ string_read (csi_t *ctx,
        uint32_t u32;
        scan_read (scan, src, &u32, 4);
        obj->datum.string->deflate = be32 (u32);
+       obj->datum.string->method = compressed;
     }
 
     if (_csi_likely (len))
@@ -994,8 +1001,13 @@ scan_none:
            obj.type &= ~CSI_OBJECT_ATTR_EXECUTABLE;
            break;
 
+#define STRING_LZO 154
+       case STRING_LZO:
+           scan_read (scan, src, &u.u32, 4);
+           string_read (ctx, scan, src, be32 (u.u32), LZO, &obj);
+           break;
+
            /* unassigned */
-       case 154:
        case 155:
        case 156:
        case 157:
@@ -1569,51 +1581,139 @@ _translate_string (csi_t *ctx,
        uint16_t u16;
        uint32_t u32;
     } u;
-    int len;
+    void *buf;
+    unsigned long hdr_len, buf_len, deflate;
+    int method;
+
+    buf = string->string;
+    buf_len = string->len;
+    deflate = string->deflate;
+    method = string->method;
+
+#if HAVE_LZO
+    if (method == NONE && buf_len > 16) {
+       unsigned long mem_len = 2*string->len > LZO2A_999_MEM_COMPRESS ? 2*string->len : LZO2A_999_MEM_COMPRESS;
+       void *mem = malloc (mem_len);
+       void *work = malloc(LZO2A_999_MEM_COMPRESS);
+
+       if (lzo2a_999_compress ((lzo_bytep) buf, buf_len,
+                               (lzo_bytep) mem, &mem_len,
+                               work) == 0 &&
+           8+2*mem_len < buf_len)
+       {
+           method = LZO;
+           deflate = buf_len;
+           buf_len = mem_len;
+           buf = mem;
+       }
+       else
+       {
+           free (mem);
+       }
 
-#if WORDS_BIGENDIAN
-    if (string->len <= UINT8_MAX) {
-       hdr = STRING_1;
-       u.u8 = string->len;
-       len = 1;
-    } else if (string->len <= UINT16_MAX) {
-       hdr = STRING_2_MSB;
-       u.u16 = string->len;
-       len = 2;
-    } else {
-       hdr = STRING_4_MSB;
-       u.u32 = string->len;
-       len = 4;
+       free (work);
     }
-#else
-    if (string->len <= UINT8_MAX) {
-       hdr = STRING_1;
-       u.u8 = string->len;
-       len = 1;
-    } else if (string->len <= UINT16_MAX) {
-       hdr = STRING_2_LSB;
-       u.u16 = string->len;
-       len = 2;
-    } else {
-       hdr = STRING_4_LSB;
-       u.u32 = string->len;
-       len = 4;
+#if HAVE_ZLIB
+    if (method == ZLIB) {
+       buf_len = string->deflate;
+       buf = malloc (string->deflate);
+       if (uncompress ((Bytef *) buf, &buf_len,
+                       (Bytef *) string->string, string->len) == Z_OK)
+       {
+           if (buf_len <= 8 + 2*string->len) {
+               method = NONE;
+               deflate = 0;
+           } else {
+               unsigned long mem_len = 2*string->deflate;
+               void *mem = malloc (mem_len);
+               void *work = malloc(LZO2A_999_MEM_COMPRESS);
+
+               if (lzo2a_999_compress ((lzo_bytep) buf, buf_len,
+                                       (lzo_bytep) mem, &mem_len,
+                                       work) == 0)
+               {
+                   if (8 + mem_len > buf_len) {
+                       method = NONE;
+                       deflate = 0;
+                   } else {
+                       free (buf);
+                       method = LZO;
+                       deflate = buf_len;
+                       buf_len = mem_len;
+                       buf = mem;
+                       assert(deflate);
+                   }
+               }
+               else
+               {
+                   free (buf);
+                   buf = string->string;
+                   buf_len = string->len;
+               }
+
+               free (work);
+           }
+       }
+       else
+       {
+           free (buf);
+           buf = string->string;
+           buf_len = string->len;
+       }
     }
 #endif
-    if (string->deflate)
-       hdr |= STRING_DEFLATE;
-
-    closure->write_func (closure->closure,
-                        (unsigned char *) &hdr, 1);
-    closure->write_func (closure->closure,
-                        (unsigned char *) &u, len);
-    if (string->deflate) {
-       uint32_t u32 = to_be32 (string->deflate);
-       closure->write_func (closure->closure,
-                            (unsigned char *) &u32, 4);
+#endif
+
+    if (method == LZO) {
+       hdr = STRING_LZO;
+       u.u32 = to_be32 (buf_len);
+       hdr_len = 4;
+    } else {
+#if WORDS_BIGENDIAN
+       if (buf_len <= UINT8_MAX) {
+           hdr = STRING_1;
+           u.u8 = buf_len;
+           hdr_len = 1;
+       } else if (buf_len <= UINT16_MAX) {
+           hdr = STRING_2_MSB;
+           u.u16 = buf_len;
+           hdr_len = 2;
+       } else {
+           hdr = STRING_4_MSB;
+           u.u32 = buf_len;
+           hdr_len = 4;
+       }
+#else
+       if (buf_len <= UINT8_MAX) {
+           hdr = STRING_1;
+           u.u8 = buf_len;
+           hdr_len = 1;
+       } else if (buf_len <= UINT16_MAX) {
+           hdr = STRING_2_LSB;
+           u.u16 = buf_len;
+           hdr_len = 2;
+       } else {
+           hdr = STRING_4_LSB;
+           u.u32 = buf_len;
+           hdr_len = 4;
+       }
+#endif
+       if (deflate) {
+           assert (method == ZLIB);
+           hdr |= STRING_DEFLATE;
+       }
     }
-    closure->write_func (closure->closure,
-                        (unsigned char *) string->string, string->len);
+
+    closure->write_func (closure->closure, (unsigned char *) &hdr, 1);
+    closure->write_func (closure->closure, (unsigned char *) &u, hdr_len);
+    if (deflate) {
+       uint32_t u32 = to_be32 (deflate);
+       closure->write_func (closure->closure, (unsigned char *) &u32, 4);
+    }
+    closure->write_func (closure->closure, (unsigned char *) buf, buf_len);
+
+    if (buf != string->string)
+       free (buf);
 
     return CSI_STATUS_SUCCESS;
 }
index b25bd23..10bc10c 100644 (file)
@@ -12,7 +12,9 @@ cairo_sphinx_la_SOURCES = fdr.c
 cairo_sphinx_la_CPPFLAGS = $(AM_CPPFLAGS)
 cairo_sphinx_la_CFLAGS = $(CAIRO_CFLAGS)
 cairo_sphinx_la_LDFLAGS = -module -no-undefined
+if CAIRO_HAS_DL
 cairo_sphinx_la_LIBADD = -ldl
+endif
 
 cairo_sphinx_SOURCES = sphinx.c
 cairo_sphinx_CPPFLAGS = $(AM_CPPFLAGS) -DLIBDIR="\"$(cairolibdir)\""
index f7945e7..ead48a6 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <dlfcn.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
@@ -163,6 +164,7 @@ struct _object {
     int width, height;
     cairo_bool_t foreign;
     cairo_bool_t defined;
+    cairo_bool_t unknown;
     int operand;
     void *data;
     void (*destroy)(void *);
@@ -937,13 +939,13 @@ ensure_operands (int num_operands)
 }
 
 static void
-_consume_operand (void)
+_consume_operand (bool discard)
 {
     Object *obj;
 
     ensure_operands (1);
     obj = current_object[--current_stack_depth];
-    if (! obj->defined) {
+    if (!discard && ! obj->defined) {
        _trace_printf ("dup /%s%ld exch def\n",
                       obj->type->op_code,
                       obj->token);
@@ -967,24 +969,18 @@ _exch_operands (void)
 }
 
 static cairo_bool_t
-_pop_operands_to_object (Object *obj)
+_pop_operands_to_depth (int depth)
 {
-    if (obj->operand == -1)
-       return FALSE;
-
-    if (obj->operand == current_stack_depth - 2) {
-       _exch_operands ();
-       _trace_printf ("exch ");
-       return TRUE;
-    }
-
-    while (current_stack_depth > obj->operand + 1) {
+    while (current_stack_depth > depth) {
        Object *c_obj;
 
        ensure_operands (1);
        c_obj = current_object[--current_stack_depth];
        c_obj->operand = -1;
        if (! c_obj->defined) {
+           if (c_obj->unknown)
+               return FALSE;
+
            _trace_printf ("/%s%ld exch def\n",
                     c_obj->type->op_code,
                     c_obj->token);
@@ -999,6 +995,23 @@ _pop_operands_to_object (Object *obj)
 }
 
 static cairo_bool_t
+_pop_operands_to_object (Object *obj)
+{
+    if (obj->operand == -1)
+       return FALSE;
+
+    if (obj->operand == current_stack_depth - 1)
+       return TRUE;
+
+    if (! _pop_operands_to_depth (obj->operand + 2))
+       return FALSE;
+
+    _exch_operands ();
+    _trace_printf ("exch ");
+    return TRUE;
+}
+
+static cairo_bool_t
 _pop_operands_to (enum operand_type t, const void *ptr)
 {
     return _pop_operands_to_object (_get_object (t, ptr));
@@ -1935,7 +1948,7 @@ cairo_create (cairo_surface_t *target)
 
            /* we presume that we will continue to use the context */
            if (_pop_operands_to (SURFACE, target)){
-               _consume_operand ();
+               _consume_operand (false);
            } else {
                _trace_printf ("s%ld ", surface_id);
            }
@@ -2168,14 +2181,14 @@ cairo_set_source_surface (cairo_t *cr, cairo_surface_t *surface, double x, doubl
        if (_is_current (SURFACE, surface, 0) &&
            _is_current (CONTEXT, cr, 1))
        {
-           _consume_operand ();
+           _consume_operand (false);
        }
        else if (_is_current (SURFACE, surface, 1) &&
                 _is_current (CONTEXT, cr, 0))
        {
            _trace_printf ("exch ");
            _exch_operands ();
-           _consume_operand ();
+           _consume_operand (false);
        } else if (obj->defined) {
            _emit_context (cr);
            _trace_printf ("s%ld ", obj->token);
@@ -2213,7 +2226,7 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source)
            _is_current (CONTEXT, cr, 1))
        {
            if (obj->defined) {
-               _consume_operand ();
+               _consume_operand (false);
                need_context_and_pattern = FALSE;
            }
        }
@@ -2223,7 +2236,7 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source)
            if (obj->defined) {
                _trace_printf ("exch ");
                _exch_operands ();
-               _consume_operand ();
+               _consume_operand (false);
                need_context_and_pattern = FALSE;
            }
        }
@@ -2675,7 +2688,7 @@ cairo_mask (cairo_t *cr, cairo_pattern_t *pattern)
            _is_current (CONTEXT, cr, 1))
        {
            if (obj->defined) {
-               _consume_operand ();
+               _consume_operand (false);
                need_context_and_pattern = FALSE;
            }
        }
@@ -2685,7 +2698,7 @@ cairo_mask (cairo_t *cr, cairo_pattern_t *pattern)
            if (obj->defined) {
                _trace_printf ("exch ");
                _exch_operands ();
-               _consume_operand ();
+               _consume_operand (false);
                need_context_and_pattern = FALSE;
            }
        }
@@ -2712,14 +2725,14 @@ cairo_mask_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y)
        if (_is_current (SURFACE, surface, 0) &&
            _is_current (CONTEXT, cr, 1))
        {
-           _consume_operand ();
+           _consume_operand (false);
        }
        else if (_is_current (SURFACE, surface, 1) &&
                 _is_current (CONTEXT, cr, 0))
        {
            _trace_printf ("exch ");
            _exch_operands ();
-           _consume_operand ();
+           _consume_operand (false);
        } else if (obj->defined){
            _emit_context (cr);
            _trace_printf ("s%ld ", obj->token);
@@ -2901,14 +2914,14 @@ cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face)
        if (_is_current (FONT_FACE, font_face, 0) &&
            _is_current (CONTEXT, cr, 1))
        {
-           _consume_operand ();
+           _consume_operand (false);
        }
        else if (_is_current (FONT_FACE, font_face, 1) &&
                 _is_current (CONTEXT, cr, 0))
        {
            _trace_printf ("exch ");
            _exch_operands ();
-           _consume_operand ();
+           _consume_operand (false);
        }
        else
        {
@@ -3071,14 +3084,14 @@ cairo_set_scaled_font (cairo_t *cr, const cairo_scaled_font_t *scaled_font)
        if (_pop_operands_to (SCALED_FONT, scaled_font)) {
            if (_is_current (CONTEXT, cr, 1)) {
                if (_write_lock ()) {
-                   _consume_operand ();
+                   _consume_operand (false);
                    _trace_printf ("set-scaled-font\n");
                    _write_unlock ();
                }
            } else {
                if (_get_object (CONTEXT, cr)->defined) {
                    if (_write_lock ()) {
-                       _consume_operand ();
+                       _consume_operand (false);
                        _trace_printf ("c%ld exch set-scaled-font pop\n",
                                       _get_context_id (cr));
                        _write_unlock ();
@@ -3135,7 +3148,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
        && _write_lock ())
     {
        if (_pop_operands_to (FONT_FACE, font_face))
-           _consume_operand ();
+           _consume_operand (false);
        else
            _trace_printf ("f%ld ", _get_font_face_id (font_face));
 
@@ -3662,15 +3675,19 @@ cairo_surface_map_to_image (cairo_surface_t *surface,
     if (_write_lock ()) {
        Object *obj = _create_surface (ret);
 
+       _emit_surface (surface);
        if (extents) {
-           _trace_printf ("[%d %d %d %d] map-to-image\n",
+           _trace_printf ("[%d %d %d %d] map-to-image %% s%ld\n",
                           extents->x, extents->y,
-                          extents->width, extents->height);
+                          extents->width, extents->height,
+                          obj->token);
            obj->width  = extents->width;
            obj->height = extents->height;
        } else {
-           _trace_printf ("[ ] map-to-image\n");
+           _trace_printf ("[ ] map-to-image %% s%ld\n", obj->token);
        }
+
+       obj->unknown = TRUE;
        _push_object (obj);
        _write_unlock ();
     }
@@ -3687,10 +3704,17 @@ cairo_surface_unmap_image (cairo_surface_t *surface,
 
     _emit_line_info ();
     if (_write_lock ()) {
-       _trace_printf ("/s%ld /s%ld  unmap-image\n",
-                      _get_surface_id (surface),
-                      _get_surface_id (image));
-       _consume_operand ();
+       Object *s = _get_object (SURFACE, surface);
+       Object *i = _get_object (SURFACE, image);
+       if (!(s->operand == current_stack_depth - 2 &&
+             i->operand == current_stack_depth - 1)) {
+           if (i->operand != s->operand + 1 || ! _pop_operands_to_depth (i->operand + 1)) {
+               _emit_surface (surface);
+               _emit_surface (image);
+           }
+       }
+       _trace_printf ("unmap-image\n");
+       _consume_operand (true);
        _write_unlock ();
     }
 
@@ -4020,7 +4044,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface)
        surface_id = _get_surface_id (surface);
 
        if (_pop_operands_to (SURFACE, surface)) {
-           _consume_operand ();
+           _consume_operand (false);
        } else {
            _trace_printf ("s%ld ", surface_id);
        }
index fc1444d..35c0014 100644 (file)
@@ -55,17 +55,35 @@ static void draw_edges (cairo_t *cr, polygon_t *p, gdouble sf, int dir)
 {
     int n;
 
+    if (dir < 0)
+       cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
+    else
+       cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
+
     for (n = 0; n < p->num_edges; n++) {
        const edge_t *e = &p->edges[n];
+       double dx, dy;
+       double x1, x2;
 
        if (e->dir != dir)
            continue;
 
-       cairo_arc (cr, e->p1.x, e->p1.y, 2/sf, 0, 2*M_PI);
-       cairo_arc (cr, e->p2.x, e->p2.y, 2/sf, 0, 2*M_PI);
+       dx = e->p2.x - e->p1.x;
+       dy = e->p2.y - e->p1.y;
+
+       x1 = e->p1.x + (e->top - e->p1.y) / dy * dx;
+       x2 = e->p1.x + (e->bot - e->p1.y) / dy * dx;
+
+       cairo_arc (cr, x1, e->top, 2/sf, 0, 2*M_PI);
+       cairo_arc (cr, x2, e->bot, 2/sf, 0, 2*M_PI);
        cairo_fill (cr);
     }
 
+    if (dir < 0)
+       cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.5);
+    else
+       cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
+
     for (n = 0; n < p->num_edges; n++) {
        const edge_t *e = &p->edges[n];
 
@@ -80,14 +98,40 @@ static void draw_edges (cairo_t *cr, polygon_t *p, gdouble sf, int dir)
        cairo_set_line_width (cr, 1.);
        cairo_stroke (cr);
     } cairo_restore (cr);
+
+    if (dir < 0)
+       cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
+    else
+       cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
+
+    for (n = 0; n < p->num_edges; n++) {
+       const edge_t *e = &p->edges[n];
+       double dx, dy;
+       double x1, x2;
+
+       if (e->dir != dir)
+           continue;
+
+       dx = e->p2.x - e->p1.x;
+       dy = e->p2.y - e->p1.y;
+
+       x1 = e->p1.x + (e->top - e->p1.y) / dy * dx;
+       x2 = e->p1.x + (e->bot - e->p1.y) / dy * dx;
+
+       cairo_move_to (cr, x1, e->top);
+       cairo_line_to (cr, x2, e->bot);
+    }
+    cairo_save (cr); {
+       cairo_identity_matrix (cr);
+       cairo_set_line_width (cr, 1.);
+       cairo_stroke (cr);
+    } cairo_restore (cr);
 }
 
 static void draw_polygon (cairo_t *cr, polygon_t *p, gdouble sf)
 {
-    cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
     draw_edges (cr, p, sf, -1);
 
-    cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
     draw_edges (cr, p, sf, +1);
 }