Imported Upstream version 1.12.14 upstream/1.12.14
authorAnas Nashif <anas.nashif@intel.com>
Mon, 11 Feb 2013 15:02:05 +0000 (07:02 -0800)
committerAnas Nashif <anas.nashif@intel.com>
Mon, 11 Feb 2013 15:02:05 +0000 (07:02 -0800)
174 files changed:
ChangeLog
Makefile.in
NEWS
boilerplate/Makefile.in
boilerplate/cairo-boilerplate-glx.c
boilerplate/cairo-boilerplate-xcb.c
build/aclocal.pkg.m4
build/configure.ac.warnings
cairo-version.h
config.h.in
configure
configure.ac
doc/Makefile.in
doc/public/Makefile.in
doc/public/html/cairo-cairo-scaled-font-t.html
doc/public/html/cairo-cairo-surface-t.html
doc/public/html/index.html
doc/public/version.xml
doc/public/xml/cairo-scaled-font.xml
doc/public/xml/cairo-surface.xml
perf/Makefile.in
perf/cairo-perf-chart.c
perf/cairo-perf-trace.c
perf/cairo-perf.c
perf/micro/Makefile.in
src/Makefile.in
src/Makefile.sources
src/cairo-cff-subset.c
src/cairo-cogl-surface.c
src/cairo-composite-rectangles.c
src/cairo-compositor-private.h
src/cairo-damage-private.h
src/cairo-damage.c
src/cairo-default-context.c
src/cairo-egl-context.c
src/cairo-ft-font.c
src/cairo-gl-composite.c
src/cairo-gl-device.c
src/cairo-gl-dispatch-private.h
src/cairo-gl-dispatch.c
src/cairo-gl-glyphs.c
src/cairo-gl-gradient.c
src/cairo-gl-msaa-compositor.c
src/cairo-gl-operand.c
src/cairo-gl-private.h
src/cairo-gl-shaders.c
src/cairo-gl-source.c
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-private.h
src/cairo-image-surface.c
src/cairo-mask-compositor.c
src/cairo-mempool.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-polygon.c
src/cairo-qt-surface.cpp
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-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/cairoint.h
src/test-base-compositor-surface.c
src/win32/cairo-win32-device.c
src/win32/cairo-win32-display-surface.c
test/Makefile.in
test/Makefile.sources
test/cairo-test-constructors.c
test/cairo-test.c
test/cairo-test.h
test/gl-device-release.c [new file with mode: 0644]
test/invalid-matrix.c
test/pdiff/Makefile.in
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/mask.argb32.ref.png
test/reference/mask.rgb24.ref.png
test/reference/record-fill-alpha.argb32.ref.png [deleted file]
test/reference/record-fill-alpha.ref.png
test/reference/record-fill-alpha.rgb24.ref.png [deleted file]
test/reference/record-paint-alpha-clip-mask.argb32.ref.png [deleted file]
test/reference/record-paint-alpha-clip-mask.ref.png
test/reference/record-paint-alpha-clip-mask.rgb24.ref.png [deleted file]
test/reference/record-text-transform.argb32.ref.png [deleted file]
test/reference/record-text-transform.rgb24.ref.png [deleted file]
test/reference/record1414x-fill-alpha.argb32.ref.png [deleted file]
test/reference/record1414x-fill-alpha.ref.png [new file with mode: 0644]
test/reference/record1414x-fill-alpha.rgb24.ref.png [deleted file]
test/reference/record1414x-text-transform.ref.png
test/reference/record2x-fill-alpha.argb32.ref.png [deleted file]
test/reference/record2x-fill-alpha.ref.png [new file with mode: 0644]
test/reference/record2x-fill-alpha.rgb24.ref.png [deleted file]
test/reference/record2x-text-transform.ref.png
test/reference/record90-fill-alpha.argb32.ref.png [deleted file]
test/reference/record90-fill-alpha.ref.png [new file with mode: 0644]
test/reference/record90-fill-alpha.rgb24.ref.png [deleted file]
test/reference/record90-paint-alpha-clip-mask.argb32.ref.png [deleted file]
test/reference/record90-paint-alpha-clip-mask.ref.png [new file with mode: 0644]
test/reference/record90-paint-alpha-clip-mask.rgb24.ref.png [deleted file]
test/reference/record90-paint-alpha-clip.argb32.ref.png [deleted file]
test/reference/record90-paint-alpha-clip.ref.png [new file with mode: 0644]
test/reference/record90-paint-alpha-clip.rgb24.ref.png [deleted file]
test/reference/record90-text-transform.argb32.ref.png [deleted file]
test/reference/record90-text-transform.ref.png [new file with mode: 0644]
test/reference/record90-text-transform.rgb24.ref.png [deleted file]
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/Makefile.in
util/cairo-fdr/Makefile.am
util/cairo-fdr/Makefile.in
util/cairo-gobject/Makefile.in
util/cairo-gobject/cairo-gobject.h
util/cairo-missing/Makefile.in
util/cairo-script/Makefile.am
util/cairo-script/Makefile.in
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-script/examples/Makefile.in
util/cairo-sphinx/Makefile.am
util/cairo-sphinx/Makefile.in
util/cairo-trace/Makefile.in
util/cairo-trace/trace.c
util/show-polygon.c

index 558648e..cfad1b9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 # Generated by configure.  Do not edit.
 
+commit 0dac37c41473deafa4a2f154187c5c3d08b07c91
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Feb 10 13:38:28 2013 +0000
+
+    1.12.14 release
+
+ NEWS            |   32 ++++++++++++++++++++++++++++++++
+ cairo-version.h |    2 +-
+ 2 files changed, 33 insertions(+), 1 deletion(-)
+
+commit 93ddc3a28308bcd9e062178ceb453f26e9228fc4
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Feb 10 13:13:31 2013 +0000
+
+    tests: Update reference images after adjustments to polygon line clipping
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ test/reference/clip-nesting.rgb24.ref.png            |  Bin 937 -> 936 bytes
+ test/reference/record-fill-alpha.argb32.ref.png      |  Bin 2736 -> 0 bytes
+ test/reference/record-fill-alpha.ref.png             |  Bin 2839 -> 2812 bytes
+ test/reference/record-fill-alpha.rgb24.ref.png       |  Bin 2736 -> 0 bytes
+ test/reference/record1414x-fill-alpha.argb32.ref.png |  Bin 4129 -> 0 bytes
+ test/reference/record1414x-fill-alpha.rgb24.ref.png  |  Bin 4129 -> 0 bytes
+ test/reference/record2x-fill-alpha.argb32.ref.png    |  Bin 5715 -> 0 bytes
+ test/reference/record2x-fill-alpha.rgb24.ref.png     |  Bin 5715 -> 0 bytes
+ test/reference/record90-fill-alpha.argb32.ref.png    |  Bin 2651 -> 0 bytes
+ test/reference/record90-fill-alpha.rgb24.ref.png     |  Bin 2651 -> 0 bytes
+ test/reference/rel-path.rgb24.ref.png                |  Bin 216 -> 216 bytes
+ 11 files changed, 0 insertions(+), 0 deletions(-)
+
+commit d4651676e1496f0354acb0ef045e8b65601edf6d
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Feb 8 22:17:13 2013 +0000
+
+    win32: Clear the similar-image before returning to the user
+    
+    Our userspace API mandates that surfaces created for the user are
+    cleared before they are returned. Make it so for the win32 similar image
+    constructor.
+    
+    Reported-by: Michael Henning <drawoc@darkrefraction.com>
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=60519
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/win32/cairo-win32-display-surface.c |   10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+commit 2d7ac9e737f37daf8490c27e6a04c65bba642645
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Feb 8 15:19:14 2013 +0000
+
+    xlib: Only apply the dst offset to the glyph strings once
+    
+    The elts offset is a delta from the previous glyph coordinate. So by
+    subtracting the dst origin everytime, we were accumulating a glyph
+    position error. Instead we just want to offset the starting coordinate
+    and then always use relative positions.
+    
+    Reported-by: Theo Veenker <T.J.G.Veenker@uu.nl>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-render-compositor.c |   12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+commit ea16302e45ced56e6f12b8520e9f530e1ffc68c4
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Feb 8 13:22:01 2013 +0000
+
+    polygon: Avoid computing the unused intersection coordinates
+    
+    If we only ignore the result of the computed boundary intersection,
+    because the edge is inside that boundary, then we can simply forgo the
+    calculation.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-polygon.c |   13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+commit 8cfbdf2f02ba01d5638a91c9f3f7fc228b402caa
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Feb 8 13:10:25 2013 +0000
+
+    polygon: Only rely on the computed boundary intersections for crossing edges
+    
+    If we need to extrapolate the edge to the boundary, then we run the risk
+    of an overflow for an immaterial result. So if the edge does not cross
+    the boundary, we can simply use the corresponding end-point and not emit
+    the boundary segment.
+    
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=60489
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-polygon.c |   35 +++++++++++++++++++++++++----------
+ 1 file changed, 25 insertions(+), 10 deletions(-)
+
+commit 607a15db5df04d10e5be6d06599ec4e9d98d2446
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Feb 7 21:40:30 2013 +0000
+
+    gl: Mark up _cairo_gl_composite_set_operator* as private
+    
+    Add the cairo_private markup to hide the PLT entries and to keep make
+    check happy.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-gl-private.h |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 562cc8227feb99b75fb53df7800df66887be129d
+Author: Ravi Nanjundappa <ravi.nanjundappa@gmail.com>
+Date:   Mon Feb 6 10:56:55 2012 +0530
+
+    gl/spans: Handle SOURCE operations with opaque sources.
+    
+    SOURCE operations with an opaque are equivalent to OVER.
+    This can prevent us from falling back in certain cases.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-gl-spans-compositor.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit 4b6b28b5e8b9020c72a60b01ff3340a70dd59478
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Feb 7 10:00:47 2013 +0000
+
+    win32: Fix is_win98()
+    
+    Since the translation into a separate function, its condition was
+    reversed: that is almost everybody thought they were on a win98 machine
+    and so had no working AlphaBlend().
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/win32/cairo-win32-device.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 4b54c09c056e5dee65f2cf4e87835eb9127e5b1c
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Feb 6 22:16:12 2013 +0000
+
+    image: Substitute OVER spans for SOURCE with an opaque pattern
+    
+    Based on an idea from Ravi Nanjundappa
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-image-compositor.c |   12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+commit 400ea9c2905461067df9e6d27c2e961d47f04676
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Wed Feb 6 12:53:14 2013 -0800
+
+    gl/msaa: Properly fall back when using CLEAR operator
+    
+    There are some situations that the MSAA compositor doesn't support using
+    the CLEAR operator. We should properly fall back in those cases.
+
+ src/cairo-gl-msaa-compositor.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit 7bee1962f601009c507f987838de1a9dec3d9334
+Author: Adrian Johnson <ajohnson@redneon.com>
+Date:   Tue Feb 5 21:57:52 2013 +1030
+
+    type1-subset: in latin subsets replace glyph names with standard names
+    
+    When using WinAnsiEncoding in PDF the glyphs are keyed by glyph
+    name. We need to ensure the correct names are used and can't assume
+    the glyph names in the font are correct.
+    
+    Bug 60248
+
+ src/cairo-type1-subset.c |   19 +++++++++++++++++--
+ 1 file changed, 17 insertions(+), 2 deletions(-)
+
+commit 4cb181d985adbbf79e80ff695adc908810b41544
+Author: Henry Song <henry.song@samsung.com>
+Date:   Tue Jan 29 17:53:38 2013 +0000
+
+    gl: do not force flush everytime uploading a glyph image to glyph cache
+    
+    In normal cases, we want to flush pending operations reading from the
+    texture before modifying its contents.  However during uploading of
+    glyphs into the glyph cache, we repeatedly modify the texture as we
+    construct the vbo (whilst referencing it for that operation). We track
+    unused areas in the glyph cache so that if we run out of space, we can
+    explicitly flush the pending glyphs and start afresh and avoid having to
+    flush the operation in common case.
+
+ src/cairo-gl-glyphs.c           |    2 +-
+ src/cairo-gl-private.h          |    3 ++-
+ src/cairo-gl-spans-compositor.c |    2 +-
+ src/cairo-gl-surface-legacy.c   |    7 ++++---
+ src/cairo-gl-surface.c          |   16 ++++++++++------
+ src/cairo-gl-traps-compositor.c |    9 ++++++---
+ 6 files changed, 24 insertions(+), 15 deletions(-)
+
+commit 260c16331a2c7bedbcf35d7f2cbab2f1f4098c87
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Mon Feb 4 10:43:13 2013 +0000
+
+    gl: Include the vertex ident in the shader cache hash
+    
+    As we may specialise the vertex program depending upon details of the
+    fragment shader, and may have more than one program for the same
+    combination of fragment sources, we need to include the vertex tag in
+    the cache entry.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-gl-shaders.c |   49 +++++++++++++++++++++++++++++-------------------
+ 1 file changed, 30 insertions(+), 19 deletions(-)
+
+commit 05ad89f91241b386f72f5b9bac3ebe62faff1d1b
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Feb 3 16:51:35 2013 +0000
+
+    gl: Replace manual vertex transformation with VS computation of texcoords
+    
+    Not only is our point transformation code is quite slow (well at least
+    compared to a real GPU), but by deriving the texture coordinates from
+    the vertex position we can elide the multiple arrays that we need to
+    construct and pass to GL - improving performance by eliminating CPU
+    overhead from needless transforms and data shovelling.
+    
+    However, not all vertex emission is suitable. For instance, for glyphs
+    we need to emit discontiguous texture coordinates for each glyph, but
+    span generation is suitable - which fortuitously also has the largest
+    vertex density and so benefits the most.
+    
+    The only real concern is for hardware without true vertex shader support
+    (e.g. i915) but there we are already invoking the VS to transform the
+    vertex into the viewport. We would need to eliminate that transform as
+    well as manually compute the texture coordinates in order to eliminate
+    the vertex recomputation pass.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-gl-composite.c        |   70 +++++++++++++++++++++++++++++----------
+ src/cairo-gl-msaa-compositor.c  |   21 ++++++++----
+ src/cairo-gl-operand.c          |   67 +++++++++++++++++++++++++++----------
+ src/cairo-gl-private.h          |   24 +++++++++-----
+ src/cairo-gl-shaders.c          |   31 ++++++++++++-----
+ src/cairo-gl-source.c           |    3 +-
+ src/cairo-gl-spans-compositor.c |    6 ++--
+ src/cairo-gl-traps-compositor.c |    3 +-
+ 8 files changed, 162 insertions(+), 63 deletions(-)
+
+commit d15a71f128c73ce1da19e6ff5a4e2fe044b58749
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Feb 3 12:51:13 2013 +0000
+
+    qt: Update for fallback compositor
+    
+    We now need to explicitly manage fallbacks and to provide an
+    implementation for map-to-image/unmap-image.
+
+ src/cairo-qt-surface.cpp |  210 ++++++++++++++++++++++++++++++----------------
+ 1 file changed, 140 insertions(+), 70 deletions(-)
+
+commit 10110d58cee179cded8e4c4ff8a8d02c477585bd
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sat Feb 2 08:47:26 2013 +0000
+
+    surface: Prevent reads from the user-data arrays during teardown
+    
+    In a similar fashion to the previous commit, we also need to be wary of
+    users simply trying to read from a potentially freed user-data array.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-surface.c |    8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+commit 18cff63e3d288bf2d7773760f2ab25c80a4a2bc1
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sat Feb 2 08:47:26 2013 +0000
+
+    surface: Prevent writes to the user-data arrays during teardown
+    
+    As we cleanup the user-data arrays, we call the user provided destroy
+    notifier callbacks. These callbacks are at liberty to write back into
+    the parent surface, and in particular try to write into the arrays that
+    we have just freed. This causes hard to control and fairly unpredictable
+    use-after-frees in the client, so lets just rule out the dangerous
+    behaviour.
+    
+    References:https://bugzilla.mozilla.org/show_bug.cgi?id=722975
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-surface.c |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+commit c391093f40472c2300f38d0e5857858f85586b60
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Feb 1 16:31:49 2013 +0000
+
+    image: Add a convenience function for creating an image from another's data
+    
+    The GL backend would like to extract a rectangle from another surface
+    and convert it to a different pixel format. The
+    _cairo_image_surface_create_from_image() does that by returning a new
+    image that has the contents of the specified rectangle in the source
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-image-surface-private.h |    7 +++++
+ src/cairo-image-surface.c         |   55 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 62 insertions(+)
+
+commit 15830fdb1087f18dcd6351de1034a5025b8ed343
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Jan 31 18:50:39 2013 +0000
+
+    NEWS: fix a couple of typos
+    
+    Reported-by: Thierry Vignaud
+
+ NEWS |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 28dbafd5643fcf637a556fc196b5b984d44d151d
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Jan 31 16:23:24 2013 +0000
+
+    Post release version bump to 1.12.13
+
+ cairo-version.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a201a1169f472e822a66275b7dffe62f241d8ec0
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Jan 31 15:24:33 2013 +0000
+
+    1.12.12 release
+
+ NEWS            |   24 ++++++++++++++++++++++++
+ cairo-version.h |    2 +-
+ 2 files changed, 25 insertions(+), 1 deletion(-)
+
+commit 350f9fb5366079113eb8bca947d480362c3ae6be
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Jan 31 15:15:03 2013 +0000
+
+    test: Refresh refs for aa noise following reduction of the 2-stage compositing
+    
+    A side effect of
+    
+    commit c986a7310bb06582b7d8a566d5f007ba4e5e75bf
+    Author: Chris Wilson <chris@chris-wilson.co.uk>
+    Date:   Thu Jan 24 08:55:54 2013 +0000
+    
+        image: Enable inplace compositing with opacities for general routines
+    
+    is that we should in theory be reducing the rounding errors when
+    compositing coverage.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ test/reference/bug-source-cu.rgb24.ref.png                     |  Bin 3211 -> 3211 bytes
+ test/reference/clip-stroke-unbounded.argb32.ref.png            |  Bin 4128 -> 4127 bytes
+ test/reference/clip-stroke-unbounded.rgb24.ref.png             |  Bin 3546 -> 3566 bytes
+ test/reference/mask.argb32.ref.png                             |  Bin 8579 -> 8565 bytes
+ test/reference/mask.rgb24.ref.png                              |  Bin 7127 -> 7135 bytes
+ test/reference/record-paint-alpha-clip-mask.argb32.ref.png     |  Bin 340 -> 0 bytes
+ test/reference/record-paint-alpha-clip-mask.ref.png            |  Bin 333 -> 318 bytes
+ test/reference/record-paint-alpha-clip-mask.rgb24.ref.png      |  Bin 340 -> 0 bytes
+ test/reference/record-text-transform.argb32.ref.png            |  Bin 5579 -> 0 bytes
+ test/reference/record-text-transform.rgb24.ref.png             |  Bin 5579 -> 0 bytes
+ test/reference/record1414x-text-transform.ref.png              |  Bin 8706 -> 8365 bytes
+ test/reference/record2x-text-transform.ref.png                 |  Bin 13476 -> 13072 bytes
+ test/reference/record90-paint-alpha-clip-mask.argb32.ref.png   |  Bin 343 -> 0 bytes
+ test/reference/record90-paint-alpha-clip-mask.ref.png          |  Bin 0 -> 316 bytes
+ test/reference/record90-paint-alpha-clip-mask.rgb24.ref.png    |  Bin 343 -> 0 bytes
+ test/reference/record90-paint-alpha-clip.argb32.ref.png        |  Bin 296 -> 0 bytes
+ test/reference/record90-paint-alpha-clip.ref.png               |  Bin 0 -> 320 bytes
+ test/reference/record90-paint-alpha-clip.rgb24.ref.png         |  Bin 296 -> 0 bytes
+ test/reference/record90-text-transform.argb32.ref.png          |  Bin 5811 -> 0 bytes
+ test/reference/record90-text-transform.ref.png                 |  Bin 0 -> 5481 bytes
+ test/reference/record90-text-transform.rgb24.ref.png           |  Bin 5811 -> 0 bytes
+ test/reference/recording-surface-extend-none.argb32.ref.png    |  Bin 3051 -> 3153 bytes
+ test/reference/recording-surface-extend-none.rgb24.ref.png     |  Bin 3128 -> 3145 bytes
+ test/reference/recording-surface-extend-pad.argb32.ref.png     |  Bin 10822 -> 11200 bytes
+ test/reference/recording-surface-extend-pad.rgb24.ref.png      |  Bin 12582 -> 12586 bytes
+ test/reference/recording-surface-extend-reflect.argb32.ref.png |  Bin 23518 -> 23967 bytes
+ test/reference/recording-surface-extend-reflect.rgb24.ref.png  |  Bin 23881 -> 23930 bytes
+ test/reference/recording-surface-extend-repeat.argb32.ref.png  |  Bin 24047 -> 24091 bytes
+ test/reference/recording-surface-extend-repeat.rgb24.ref.png   |  Bin 24038 -> 24075 bytes
+ test/reference/recording-surface-over.argb32.ref.png           |  Bin 0 -> 3153 bytes
+ test/reference/recording-surface-over.rgb24.ref.png            |  Bin 3128 -> 3145 bytes
+ test/reference/recording-surface-source.argb32.ref.png         |  Bin 3044 -> 3153 bytes
+ test/reference/recording-surface-source.rgb24.ref.png          |  Bin 3133 -> 3146 bytes
+ test/reference/stroke-clipped.ref.png                          |  Bin 5886 -> 5790 bytes
+ 34 files changed, 0 insertions(+), 0 deletions(-)
+
+commit 22b7fae0368ba6cff23b2ebdf58bd7d1bfdfbd6f
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Jan 31 14:19:53 2013 +0000
+
+    image: Add a reference for the clone's parent image
+    
+    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.
+    
+    Unlike other users of the parent pointer, there is no resource sharing
+    between the two surfaces.
+    
+    Reported-by: Henry Song <henry.song@samsung.com>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-image-surface.c |    9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+commit ec58fde294afd52c89fa5ed21ba2611edfdbd550
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Jan 31 14:06:48 2013 +0000
+
+    perf: Synchronize before stopping the timers
+    
+    Fixes a regression from
+    
+    commit 2855ff4666922f2c38505414270d47f659b0d499
+    Author: Andrea Canciani <ranma42@gmail.com>
+    Date:   Wed Aug 31 16:42:03 2011 +0200
+    
+        perf: Reuse cairo-time
+    
+    which dropped the essential call to synchronize when refactoring the
+    code.
+    
+    Reported-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ perf/cairo-perf.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+commit 2560c0b6577a6380ef175cf18bb804913784632c
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 29 23:51:44 2013 +0000
+
+    xlib/shm: More clarification of seqno required
+    
+    Everytime I read the predicate wrong, but hopefully, this time I have it
+    right!
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit 91834fbdee40f46e18d071fd2671a7a642e6aa86
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 29 22:12:00 2013 +0000
+
+    xlib/shm: Clarify testing of seqno
+    
+    Rename the seqno tests into seqno_passed(), seqno_before() and
+    seqno_after() in order to clarify their semantics.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-source.c      |    2 +-
+ src/cairo-xlib-surface-shm.c |   20 ++++++++++++++++----
+ 2 files changed, 17 insertions(+), 5 deletions(-)
+
+commit 89092b97b50a7740058d0f72f94dfc6defe15ed6
+Author: Henry Song <henry.song@samsung.com>
+Date:   Tue Jan 29 13:21:00 2013 -0800
+
+    gl/msaa: Don't emit alpha when emitting vertices
+    
+    The color attribute is disabled when not in spans mode, so the emitted
+    alpha is simply overwritten by the next vertex. Additionally, this can
+    potentially cause the alpha to be written past the end of the buffer.
+
+ src/cairo-gl-composite.c |   24 +++++++++++-------------
+ 1 file changed, 11 insertions(+), 13 deletions(-)
+
+commit 74a19c527c1fa07ade2042a8d2acecbb5f6ccab1
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 29 10:31:05 2013 +0000
+
+    configure: Include X11.h before testing for usability of Xrender.h
+    
+    On Solaris at least, the Xrender.h header is not standalone and requires
+    X11/X.h to be included first to define the essential types.
+    
+    Reported-by: Andreas F. Borchert <bugzilla@andreas-borchert.de>
+    Bugzilla; https://bugs.freedesktop.org/show_bug.cgi?id=58199
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ configure.ac |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 41ae904461e344fbfa3be3d276a7102bb4304b19
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 29 03:52:02 2013 +0000
+
+    xlib/shm: Appease the compiler for a 'maybe used uninitialised' variable
+    
+    Initialise shm during its declaration so that it is indeed initialised
+    for the cleanup after every path.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-render-compositor.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+commit 9b92625151ca75a6ee10f231f83b53f67a371947
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 29 03:49:56 2013 +0000
+
+    xlib/shm: Simplify uploading of SHM image data
+    
+    Make sure that we simply copy from the SHM segment into the target
+    drawable, and not inadvertently stage it through another SHM buffer.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-render-compositor.c |   22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+commit c006b886d28a772d7a62cec52ab7e0c8196c36f6
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 29 03:01:31 2013 +0000
+
+    xlib/shm: Force synchronisation for scratch SHM image buffers
+    
+    The scratch image buffers are used for uploads to the xserver and so we
+    must be careful not to overwrite active SHM segments. Unfortunately we
+    told the core SHM allocator that we would sync before using the images,
+    which was a lie.
+    
+    Reported-by: Michael Natterer <mitch@gimp.org>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit fd59e6d86a3a1fc6720316f20deb8a0bd6f7b767
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 29 03:00:46 2013 +0000
+
+    xlib/shm: Always request a CompletionEvent from ShmPutImage
+    
+    ...and treat is as an expected event for synchronisation.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |   11 +++--------
+ src/cairo-xlib-surface.c     |    3 +--
+ 2 files changed, 4 insertions(+), 10 deletions(-)
+
+commit a364a106b257c4493ba7b3badacc63599ba6064a
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 29 02:52:10 2013 +0000
+
+    xlib/shm: Tidy up destroying the mempool for a shm block
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 02a2baa8dcf49ad2d9766d43578ba216fab0d464
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 29 02:51:25 2013 +0000
+
+    xlib/shm: Tidy creation of the proxy source for ShmPixmaps
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-source.c |   10 +++-------
+ 1 file changed, 3 insertions(+), 7 deletions(-)
+
+commit 30e950515171b25d9bc3da8d535cfe05d8be69c8
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 29 02:49:26 2013 +0000
+
+    xlib/shm: Skip creating new SHM segments if the data is already in the xserver
+    
+    If the image is already inside a SHM segment, but the image format does
+    not match the surface, fallback to the XRender paths in order to perform
+    colorspace conversion on the data already inside the Xserver.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-render-compositor.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit 1d1af825bb4fcfd7c4a54b65292734ba244e096d
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 29 02:47:48 2013 +0000
+
+    xlib/shm: Tighten mark-active to the actual CopyArea on the ShmPixmap
+    
+    Along the draw_image_boxes() upload path, we were actually marking the
+    ShmPixmap as still active for the subsequent drawing operation - which
+    could in theory never be submitted...
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-render-compositor.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 3c18bae20ee2fea24d75f6986390ef8157d0207d
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Mon Jan 28 10:03:54 2013 +0000
+
+    perf; Do not allow the backends to optimize away the clear before sync
+    
+    The importance of writing to the scratch surface before retrieving an
+    image is that it makes that the write lands in the server queue, as well
+    as the GetImage, in order to serialise the timer against all the
+    operations.
+    
+    Reported-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ perf/cairo-perf-trace.c |   10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+commit d9d5adec256b3935e4f261d81c37c77a2649248b
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Jan 27 16:51:52 2013 +0000
+
+    image: And more fallout from c986a73, restore the absent short runs
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-image-compositor.c |   34 ++++++++++++++++------------------
+ 1 file changed, 16 insertions(+), 18 deletions(-)
+
+commit 1ba9fb6fadcc1cb619af0ef974dffb0ff8672244
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Jan 27 16:15:35 2013 +0000
+
+    Mark _cairo_path_is_simple_quad as private
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-path-fixed-private.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 1d105f215a9c62f5b60541da209bf71182a2e9df
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Jan 27 16:29:44 2013 +0000
+
+    image: Fix opaque span fills
+    
+    I should have realised the previous result was too good to be true!
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-image-compositor.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit c986a7310bb06582b7d8a566d5f007ba4e5e75bf
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Jan 24 08:55:54 2013 +0000
+
+    image: Enable inplace compositing with opacities for general routines
+    
+    On a SNB i5-2500:
+    
+    Speedups
+    ========
+             firefox-chalkboard  34284.16 -> 19637.40:  1.74x speedup
+             swfdec-giant-steps    778.35 ->   665.37:  1.17x speedup
+                      ocitysmap    485.64 ->   431.94:  1.12x speedup
+    
+    Slowdowns
+    =========
+               firefox-fishbowl  46878.98 -> 54407.14:  1.16x slowdown
+    
+    That slow down is due to overhead of the increased number of calls to
+    pixman_image_composite32() (pixman_transform_point for analyzing the
+    source extents in particular) outweighing any advantage gained by
+    performing the rasterisation in a single pass and eliding gaps. The
+    solution that has been floated in the past is for an interface into
+    pixman to only perform the analysis once and then to return a kernel to
+    use for all spans.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-image-compositor.c         |  190 ++++++++++++++++++++++++++++------
+ src/cairo-spans-compositor-private.h |    2 +-
+ 2 files changed, 162 insertions(+), 30 deletions(-)
+
+commit cfe0e59663c71a6ecd0c976797ac32339e363af2
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Tue Jan 22 20:09:01 2013 -0800
+
+    gl/msaa: Add a fast path for fills that are simple quads
+    
+    Instead of invoking Bentley-Ottman for fills that are simple
+    quadrilaterals, just pass the geometry straight to OpenGL.
+
+ src/cairo-gl-msaa-compositor.c |   45 +++++++++++--
+ src/cairo-path-fixed-private.h |   17 +++++
+ src/cairo-path-fixed.c         |  136 ++++++++++++++++++++++++++++++----------
+ 3 files changed, 158 insertions(+), 40 deletions(-)
+
+commit 1e3424cfd1fea3f9aa2b1c8af4bb72239a94f365
+Author: Henry Song <henry.song@samsung.com>
+Date:   Tue Jan 22 14:54:38 2013 -0800
+
+    gl: Use GL_ALPHA textures for CAIRO_CONTENT_ALPHA glyph caching
+    
+    It's safe to us GL_ALPHA for glyph caching surfaces, since Cairo only
+    uses them for texture uploading. This saves a little bit of memory.
+
+ src/cairo-gl-glyphs.c  |   16 ++++++++--------
+ src/cairo-gl-private.h |    6 ++++++
+ src/cairo-gl-surface.c |   38 +++++++++++++++++++++++++++++++-------
+ 3 files changed, 45 insertions(+), 15 deletions(-)
+
+commit a44b8bd70683a92d862b11c2d7359ce2b0a6a968
+Author: Henry Song <henry.song@samsung.com>
+Date:   Fri Jan 25 12:45:10 2013 -0800
+
+    gl: Fix typos in multisampling detection
+    
+    Instead of looking for the EXT_framebuffer_multisample, this code should
+    look for GL_EXT_framebuffer_multisample. GL_ARB_framebuffer_object also
+    contains all necessary API for using multisampling, so we don't need to
+    check for both it and the GL_EXT_framebuffer_blit and
+    GL_EXT_framebuffer_multisample pair.
+
+ src/cairo-gl-device.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit bb4072046016610a510373df3b67cdeb2ac1b583
+Author: Henry Song <henry.song@samsung.com>
+Date:   Fri Jan 25 11:55:10 2013 -0800
+
+    gl/msaa: Fix a memory leak in _clip_to_traps
+    
+    We need to clean up the polygon we create when decomposing a path into
+    trapezoids.
+
+ src/cairo-gl-msaa-compositor.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 7054c9969cb0e41845635d6658935da223899f08
+Author: Henry Song <henry.song@samsung.com>
+Date:   Wed Jan 16 15:32:32 2013 +0100
+
+    gl: Don't query the display when checking if the context changed
+    
+    If display has changed, the associated context must change. A
+    context is tied a display so we can avoid this check, eliminating
+    unnecessary work during context acquisition and release.
+
+ src/cairo-egl-context.c |   13 ++++---------
+ src/cairo-glx-context.c |   13 ++++---------
+ 2 files changed, 8 insertions(+), 18 deletions(-)
+
+commit fa4f48cccb6c7f4e1afb2ff4b98b906b7d8d4afc
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Jan 23 15:04:26 2013 +0000
+
+    xlib: Do not upload the whole image just because we want an entire row
+    
+    Fixes regression exposed by
+    
+    commit a73e7ff0186176bc82cd3ae1432c054c1fd3aebd
+    Author: Chris Wilson <chris@chris-wilson.co.uk>
+    Date:   Sun Jan 6 11:29:27 2013 +0000
+    
+        xlib: Simplify source creation by use of map-to-image
+    
+    but ultimately from
+    
+    commit 74941f822015cc50cd8477d0cf97f1a70dbff60b
+    Author: Chris Wilson <chris@chris-wilson.co.uk>
+    Date:   Wed Jan 2 22:27:55 2013 +0000
+    
+        xlib: Use SHM transport for ordinary image uploads
+    
+    Reported-by: Gökçen Eraslan <gokcen.eraslan@gmail.com>
+    Reported-by: Guillaume Ayoub <guillaume.ayoub@kozea.fr>
+    Reported-by: Emmanuel Benisty <benisty.e@gmail.com>
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=59635
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-source.c  |    8 +++++++-
+ src/cairo-xlib-surface.c |   24 +++++++++++-------------
+ 2 files changed, 18 insertions(+), 14 deletions(-)
+
+commit ed2fa6b16b03fccc3e21598cdb9157cbcebd1d37
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Jan 16 20:58:46 2013 +0000
+
+    version: Post-release bump to 1.12.11
+
+ cairo-version.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2d6204c67d4d0d9c5d03087c4c1609a81ef1fdb7
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Jan 16 20:22:38 2013 +0000
+
+    1.12.10 release
+
+ NEWS            |   49 +++++++++++++++++++++++++++++++++++++++++++++++++
+ cairo-version.h |    2 +-
+ 2 files changed, 50 insertions(+), 1 deletion(-)
+
+commit 1dfea39841fc6d545e45420b1999239f29556c05
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Tue Jan 15 17:12:23 2013 -0800
+
+    gl: Follow up fix for the previous commit
+    
+    Handle "fake" surfaces created by _cairo_gl_pattern_to_source which just
+    embed a GL backend operand. These surfaces do not have a backend, so we
+    should not fall back if a surface without a backend is not a texture
+    surface.
+
+ src/cairo-gl-operand.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 769ea3b2c757adc9f8f348fdc93bb46f35c2f6b8
+Author: Henry Song <henry.song@samsung.com>
+Date:   Wed May 2 21:54:55 2012 +0200
+
+    gl: Support for non-texture sources and masks
+    
+    If a GL surface is not a texture and is used as source or mask,
+    fall back to using an image surface as an intermediary.
+    
+    Fixes subsurface-image-repeat, subsurface-modify-child,
+    subsurface-modify-parent, subsurface-outside-target, subsurface-pad,
+    subsurface-reflect, subsurface-repeat, and subsurface-scale.
+
+ src/cairo-gl-operand.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+commit d01a502710296c9b15755f445f6fdda289a2df0b
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Tue Jan 15 12:07:33 2013 -0800
+
+    gl/msaa: Check for more extensions before using MSAA
+    
+    The MSAA compositor is implicitly relying on the existence of several
+    OpenGL extensions. This change makes those dependencies explicit.
+
+ src/cairo-gl-device.c |   33 +++++++++++++++++----------------
+ 1 file changed, 17 insertions(+), 16 deletions(-)
+
+commit 768b81b78eabbebb1bb443355441cac567739035
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Mon Jan 14 03:27:11 2013 +0000
+
+    script: Set decompression length prior to calling decompressors
+    
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=59224
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ util/cairo-script/cairo-script-operators.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 6639c1231072d71d33eb0952bae5f95e7480cd0d
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Jan 13 22:48:30 2013 +0000
+
+    xlib: Initialise Pixmap for proxy sources
+    
+    So that we do not try to tell X to free a garbage pixmap and promptly
+    kill us.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-source.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit fd34f420ec3ba02eb39f22f6551705ab23ebfc28
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Jan 13 18:16:17 2013 +0000
+
+    compositor: Pass back the internal failure
+    
+    In order to pass back a CAIRO_INT_STATUS_UNSUPPORTED, we need to use the
+    internal error surface creation functions as they do not assert on
+    private error codes.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-mask-compositor.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 14c32ee1cf6bfcaeb07d50a80b6d5a388a1f2885
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Jan 13 18:11:31 2013 +0000
+
+    compositor: Convert image surface into backend source
+    
+    Before passing a surface to the backend composite functions, they expect
+    them to be a native source. The copy'n'paste code for the mask
+    compositor forgot to perform the conversion upon the clip surfaces,
+    which originally were native to the backend and are now images.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-mask-compositor.c |   61 ++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 46 insertions(+), 15 deletions(-)
+
+commit 7012334ebb424b619312e1fa397cc3b8a3ffd770
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Jan 13 17:20:24 2013 +0000
+
+    xlib: Handle lack of XRenderFillRectangles
+    
+    Remember to check for a supported render version before making a
+    FillRectangle request, and fallback to the core protocol where possible
+    instead.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-core-compositor.c   |   79 +++++++++++++++++++++++++++---------
+ src/cairo-xlib-private.h           |   15 ++++++-
+ src/cairo-xlib-render-compositor.c |   30 +++++++++++---
+ src/cairo-xlib-source.c            |   70 +++++++++++++++++++++++++++-----
+ 4 files changed, 157 insertions(+), 37 deletions(-)
+
+commit 503b6b9e2ea65805a77d527c00cf242ec86d479b
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Jan 11 13:10:56 2013 +0000
+
+    xlib: Only fallback through the mask intermediate if we can composite the mask
+    
+    Before rendering into the mask, we should first check whether the
+    subsequent call to composite the mask will trigger a fallback. In that
+    case, we should fallback earlier and do the operation in place.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-compositor-private.h     |    3 +++
+ src/cairo-mask-compositor.c        |   27 +++++++++++++++++++++++----
+ src/cairo-xlib-render-compositor.c |   24 ++++++++++++------------
+ 3 files changed, 38 insertions(+), 16 deletions(-)
+
+commit 1bcd59ef4c9dceaefa51ec6db1f5240d75940724
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Wed Jan 9 14:16:59 2013 -0800
+
+    gl/msaa: Rely on the stencil buffer to cache the clip
+    
+    When using a texture surface the depth/stencil buffer is private to
+    cairo so we can rely on the fact that any previously painted clip is
+    still valid.
+    
+    We also only scissor when there's a previously painted clip on the
+    stencil buffer, otherwise we disable the scissor test. This fixes a few
+    test cases.
+
+ src/cairo-gl-composite.c       |   58 ++++++++++++++++++++++++++++------------
+ src/cairo-gl-msaa-compositor.c |    4 +++
+ src/cairo-gl-private.h         |    1 +
+ 3 files changed, 46 insertions(+), 17 deletions(-)
+
+commit d524697ede85d36e4f88fa44d6a8b884685d804b
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Tue Jan 8 17:08:52 2013 -0800
+
+    gl/msaa: No need to set the clip when masking
+    
+    After 5e9083f882859201c5df18fc870577a224f88cbb there's no need to set a
+    clip on the cairo_gl_composite_t when masking. Clips are converted to
+    traps and rendered directly when masking now.
+
+ src/cairo-gl-msaa-compositor.c |    1 -
+ 1 file changed, 1 deletion(-)
+
+commit 17418371b6755ef22b6d0c5787f71de3005e0730
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Jan 9 15:06:28 2013 +0000
+
+    xcb: _cairo_scaled_font_reset_cache does it own locking
+    
+    So we can drop ours.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xcb-surface-render.c |    2 --
+ 1 file changed, 2 deletions(-)
+
+commit dd20c1f4d6419238bbb37fb93a48986f83c6e6c2
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Jan 9 12:38:09 2013 +0000
+
+    xlib: map-to-image requires an extents
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-source.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 351a9e756d0863ae7408c6d43a622620daa0c354
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Jan 9 12:31:10 2013 +0000
+
+    stroke: Flip the dev slope as well for computing the cusp on a degeneracy
+    
+    Otherwise, the join think it starts and end in exactly the same
+    direction and elimiates the round capping.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-path-stroke-traps.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 14720cd0dbc325a2140fbd5b2a7ce4b257ae5f5e
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Jan 9 12:11:25 2013 +0000
+
+    gstate: Use the polygon intermediate for geometry queries
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-gstate.c |   24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+commit a942938e90a219a0b88153f9fa96c606ce644ef1
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Jan 9 00:36:13 2013 +0000
+
+    scaled-font: Fix use after free when clearing the glyph cache
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-scaled-font.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+commit c5b353c3725a1a8c116b790df4206f060d64eb5c
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 22:56:28 2013 +0000
+
+    scaled-font: Make reset-font-cache threadsafe
+    
+    Stop trying to workaround the destroy-callback requiring the font mutex
+    as we already hold the mutex whilst cleaning up the font caches.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-scaled-font.c |   66 ++++++++++++++++++++++-------------------------
+ 1 file changed, 31 insertions(+), 35 deletions(-)
+
+commit d1184b69e8871180b7b357a02d1a0bed3e68d897
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Thu Feb 2 20:38:51 2012 -0800
+
+    gl: Do less work when acquiring and releasing devices
+    
+    After acquiring a GL device and the same GL context, surface, and
+    display combination is already active outside of Cairo, do not ask EGL
+    or GLX to change the current context as that may cause a flush on some
+    drivers. Also do not unset the context when releasing the device for the
+    same reason.
+
+ src/cairo-egl-context.c  |   64 +++++++++++++---
+ src/cairo-glx-context.c  |   78 ++++++++++++++++----
+ test/Makefile.sources    |    1 +
+ test/gl-device-release.c |  182 ++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 301 insertions(+), 24 deletions(-)
+
+commit 7401455cb4136473521b9f33b09944aa0bc66971
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 17:52:04 2013 +0000
+
+    image: Allocate a temporary buffer for inline span composition
+    
+    Allow the inpline span compositor to operate on wider images than its
+    temporary buffer by allocating a scanline mask.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-image-compositor.c |   24 ++++++++++++++++++++----
+ 1 file changed, 20 insertions(+), 4 deletions(-)
+
+commit 0d38518c38fec68a1fa8cf9d3ae946faa08d6c42
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 18:52:08 2013 +0000
+
+    scaled-font: Remove a non-threadsafe double-freeze assert
+    
+    Sadly we cannot check ahead of acquiring the lock whether we hold the
+    lock. Just have to rely on lockdep.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-scaled-font.c |    1 -
+ 1 file changed, 1 deletion(-)
+
+commit e4acba6d1ddfe1c6d27b5a77edccea9d69b178f8
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 16:38:11 2013 +0000
+
+    xlib/shm: Only destroy an existing damage
+    
+    _cairo_damage_destroy() does not like to be passed a NULL.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 2ed484817ef3a5084dc65a2ae1acdef551acd107
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 16:06:02 2013 +0000
+
+    xlib/shm: Discard damage upon shm finish
+    
+    Both to make sure we do not leak the memory, but to also prevent
+    _cairo_xlib_surface_put_shm() from operating upon the finished shm
+    surface after the display is closed.
+    
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=58253
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-damage-private.h   |    3 +++
+ src/cairo-damage.c           |    7 +++++++
+ src/cairo-xlib-surface-shm.c |    3 +++
+ 3 files changed, 13 insertions(+)
+
+commit b5dcc8ce4450de1e48fd0586fddb5ed658719b28
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 11:20:08 2013 +0000
+
+    scaled-font: Hold the scaled font mutex whilst reaping from the global cache
+    
+    If we need to reap the global cache, this will call back into the scaled
+    font to free the glyph page. We therefore need to be careful not to run
+    concurrently with a user adding to the glyph page, ergo we need locking.
+    To complicate matters we need to be wary of a lock-inversion as we hold
+    the scaled_font lock whilst thawing the global cache. We prevent the
+    deadlock by careful ordering of the thaw-unlock and by inspecting the
+    current frozen state of the scaled-font before releasing the glyph
+    page.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-scaled-font.c |    9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+commit c4ea7b13b406bf0ea1dc9b337010131d3704bc4a
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 13:35:43 2013 +0000
+
+    scaled-font: Assert if attempting to finish a frozen font
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-scaled-font.c |   12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+commit 4d4bf8fddff49d349e03282ffa827f6f4659e3fe
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 14:56:07 2013 +0000
+
+    scaled-font: Free the cached glyphs from the font before taking the global lock
+    
+    In the case of a recording surface we may recurse into the global glyph
+    cache so we need to be careful and stage the ordering of how we free the
+    glyphs. So first we finish any information and surfaces from the scaled
+    font glyph cache (and so triggering recursion into other scaled fonts)
+    and then take the global cache and remove our pages.
+    
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=54950
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-scaled-font.c |   21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+commit 44a093eb95c950b0e8f2d7d1cdb9719cb8a550f7
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 14:58:41 2013 +0000
+
+    scaled-font: Always hold the mutex even for single glyph probes
+    
+    The freeze/thaw routines have a side-effect of managing the global glyph
+    cache in addition to taking the mutex on the font. If we don't call
+    them, we may end up indefinitely keeping the global glyph cache frozen
+    (effectively leaking glyphs to the maximum of all open fonts) and
+    triggering asserts.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-scaled-font.c |   41 +++++++++++++++++++++--------------------
+ 1 file changed, 21 insertions(+), 20 deletions(-)
+
+commit 80cc532271d7e94ad02732841fbcdc811cce8754
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 13:47:23 2013 +0000
+
+    script: Thaw the scaled font cache on the error path
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-script-surface.c |    4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+commit e1307da8616027004dd6c901017a667b1503781d
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 12:53:24 2013 +0000
+
+    script: Simply exchange source/dest images for _set_source_image
+    
+    But note we can only do the exchange if they do indeed match and
+    there are no other references (the objects are only on the stack).
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ util/cairo-script/cairo-script-operators.c |   19 ++++++++++++++-----
+ 1 file changed, 14 insertions(+), 5 deletions(-)
+
+commit 146da77d85b304651949a819bc8b0a74819f0416
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Jan 8 12:19:33 2013 +0000
+
+    script: Attempt to decompress images in place
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ perf/cairo-perf-trace.c                      |   16 +-
+ util/cairo-script/cairo-script-interpreter.h |    7 +
+ util/cairo-script/cairo-script-operators.c   |  391 +++++++++++++++-----------
+ 3 files changed, 247 insertions(+), 167 deletions(-)
+
+commit 5f2e89660d5e38d8e2682945962521958f150825
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Mon Jan 7 13:11:06 2013 +0000
+
+    image: Call pixman without a mask for opaque regions of inplace_spans
+    
+    Speedups
+    ========
+    firefox-paintball  59462.09 -> 40928.76:  1.45x speedup
+     firefox-fishtank  43687.33 -> 34627.78:  1.26x speedup
+         firefox-tron  52526.00 -> 45754.73:  1.15x speedup
+    
+    However in order to avoid a regression with firefox-talos-svg we need to
+    prevent splitting up the scanline when using a gradient source.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-image-compositor.c |   57 ++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 47 insertions(+), 10 deletions(-)
+
+commit a73e7ff0186176bc82cd3ae1432c054c1fd3aebd
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Jan 6 11:29:27 2013 +0000
+
+    xlib: Simplify source creation by use of map-to-image
+    
+    We were open-coding the functionality of map-to-image inside the source
+    creation routines. so refactor to actually use map-to-image instead.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-source.c |   92 +++++++++++++++++------------------------------
+ 1 file changed, 33 insertions(+), 59 deletions(-)
+
+commit 4f142f3a7bf24b659c5caccab3a1aedd6b680909
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Jan 6 10:32:25 2013 +0000
+
+    xlib/shm: Only mark the shm pixmap as active if we upload into it
+    
+    Be more strict with when we mark the pixmap as active so that we only
+    wait for the actual XCopyArea involving the pixmap to complete.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |   23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+commit 45a4b42a361eb791c571b201e11c3505a0a1a396
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Jan 4 17:32:46 2013 +0000
+
+    script: Recompress strings using LZO whilst binding traces
+    
+    Try using the lighter-weight LZO decompressor in an effort to speed up
+    replays (at the cost of making the bound traces slightly larger).
+    Presuming that with the slight increase in file size (from -1% to +10%),
+    the file data remains in the readahead buffer cache, replays see a
+    performance improvement of between 5-10%.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ configure.ac                               |   12 ++
+ util/cairo-script/Makefile.am              |    2 +-
+ util/cairo-script/cairo-script-file.c      |   32 ++++-
+ util/cairo-script/cairo-script-objects.c   |    3 +
+ util/cairo-script/cairo-script-operators.c |   45 +++++--
+ util/cairo-script/cairo-script-private.h   |    5 +
+ util/cairo-script/cairo-script-scanner.c   |  184 +++++++++++++++++++++-------
+ 7 files changed, 227 insertions(+), 56 deletions(-)
+
+commit 9194904fa838a115b4dc58e5bff7a235cc2a9a7a
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Fri Jan 4 16:31:01 2013 -0800
+
+    gl: Better handling of clear surfaces
+    
+    When clearing a GL surface, set is_clear to true, and when mapping to an
+    image, handle is_clear like surfaces without modification. Additionally,
+    explicitly clear surfaces created via cairo_surface_create_similar.
+
+ src/cairo-gl-surface.c |   43 +++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 37 insertions(+), 6 deletions(-)
+
+commit 9bff4508443abe002fcb0ffdb9b1897272f1c588
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Fri Jan 4 15:47:13 2013 -0800
+
+    boilerplate/glx: Add a target with multisampling and stencil support
+    
+    Add a gl-window target that supports multisampling. This is useful for
+    testing the MSAA backend on the default framebuffer.
+
+ boilerplate/cairo-boilerplate-glx.c |  170 ++++++++++++++++++++---------------
+ 1 file changed, 96 insertions(+), 74 deletions(-)
+
+commit 8cd604e18adc1dbe22303d5c57dae374d7e8cd2b
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Jan 4 14:03:40 2013 +0000
+
+    gobject: Fix my typo s/TEST/TEXT/ in the previous commit
+    
+    Again reported by Kouhei Sutou, who I am grateful for his deligence.
+
+ util/cairo-gobject/cairo-gobject.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit a4f221498c20bd9bd6178fddc1ba481ff3fd6cb3
+Author: Kouhei Sutou <kou@clear-code.com>
+Date:   Fri Jan 4 12:18:29 2013 +0000
+
+    gobject: Fix "text_cluster_flags_get_type" typo
+    
+    The macro missed the text from the name, rendering it useless.
+
+ util/cairo-gobject/cairo-gobject.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 9dde964553f74ccbc037b13ca83d0abb46adb194
+Author: Henry Song <henry.song@samsung.com>
+Date:   Thu Jan 3 16:03:55 2013 -0800
+
+    gl/msaa: Only clear parts of the stencil buffer we will use
+    
+    Writing to the stencil buffer can be expensive, so when using the
+    stencil buffer for clipping only clear the clip extent. When using the
+    stencil buffer to prevent overlapping rendering during stroking, only
+    clear the approximate stroke extents.
+
+ src/cairo-gl-composite.c       |   17 ++++++++++-------
+ src/cairo-gl-msaa-compositor.c |   34 ++++++++++++++++++++++++++++++----
+ src/cairo-gl-private.h         |    4 ++++
+ 3 files changed, 44 insertions(+), 11 deletions(-)
+
+commit 5e9083f882859201c5df18fc870577a224f88cbb
+Author: Alejandro G. Castro <alex@igalia.com>
+Date:   Wed Mar 7 14:38:52 2012 +0100
+
+    gl/msaa: Avoid the stencil buffer when possible during masking
+    
+    In this case we can draw the clip path and avoid the stencil buffer,
+    which can be expensive.
+
+ src/cairo-gl-msaa-compositor.c |   68 +++++++++++++++++++++++++++++++---------
+ 1 file changed, 53 insertions(+), 15 deletions(-)
+
+commit dd850583a7f57a666da6af218841bb10b536df46
+Author: Henry Song <henry.song@samsung.com>
+Date:   Tue Mar 13 08:43:24 2012 -0700
+
+    gl/msaa: Add full support for masking with the SOURCE operator
+    
+    Since OpenGL does not have a means to represent a masking SOURCE
+    operation in one step, we use two steps combined with the ADD
+    operator.
+
+ src/cairo-gl-composite.c       |  108 ++++++++++++++++++++++++----------------
+ src/cairo-gl-msaa-compositor.c |   84 ++++++++++++++++++++++++++++---
+ src/cairo-gl-private.h         |    9 ++++
+ 3 files changed, 152 insertions(+), 49 deletions(-)
+
+commit c743e93451f467782b861c67a6894df26082d5c6
+Author: Chuanbo Weng <chuanbo.weng@intel.com>
+Date:   Wed Jan 2 18:03:44 2013 +0100
+
+    gl: Support the GL_IMG_texture_npot extension
+    
+    This extension, used by older PowerVR drivers, is functionally
+    equivalent to the GL_OES_TEXTURE_NPOT extension.
+
+ src/cairo-gl-device.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit ae1724ced98b86aaf97c7be9c4294fa3823d7350
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Jan 3 13:46:20 2013 +0000
+
+    Add missing local slim proto for cairo_recording_surface_create
+    
+    Dependency introduced in 749ef6be4d11b95d666b0e5fe06df926b828d655
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairoint.h |    1 +
+ 1 file changed, 1 insertion(+)
+
+commit 872a92b874270ac3b83b0e206fb5b15a7405502a
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Jan 3 13:30:13 2013 +0000
+
+    scaled-font: Mention ownership of returned object from get_font_face()
+    
+    As suggested by Simon Sapin.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-scaled-font.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 734a541dc34565f40fe0ae4e93c81c4849198a79
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Jan 3 13:01:34 2013 +0000
+
+    xlib: Avoid copying the source twice if it is an image
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-source.c |   37 +++++++++++++++++++++++++++----------
+ 1 file changed, 27 insertions(+), 10 deletions(-)
+
+commit ecc8c28b24cb5fcd85aee5d4c82b9ad72c87fa69
+Author: Kouhei Sutou <kou@clear-code.com>
+Date:   Thu Jan 3 12:37:43 2013 +0000
+
+    gobject: Add the correct macro name for the hint-metrics type
+    
+    s/CAIRO_GOBJECT_TYPE_HNT_METRICS/CAIRO_GOBJECT_TYPE_HINT_METRICS/
+    
+    However, as we have already released the broken headers, we need to
+    preserve that mistake in case applications are already using. Since it
+    is just a #define, there is little associated cost with carrying both
+    the incorrect spelling and the corrected define.
+
+ util/cairo-gobject/cairo-gobject.h |    2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 5bc1b1f6aac108d9a3963352ad774bb4fcd69e28
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Aug 24 17:22:34 2012 +0100
+
+    stroke: Make the incremental trapezoid stroker optionally available again
+    
+    Whilst it cannot handle self-intersecting strokes (which includes the
+    antialias region of neighbouring lines and joints), it is about 3x
+    faster to use than the more robust algorithm. As some backends delegate
+    the rendering, the quality may still be preserved and so they should be
+    responsible for choosing the appropriate method for generation of the
+    stroke geometry.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/Makefile.sources               |    1 +
+ src/cairo-cogl-surface.c           |    6 +-
+ src/cairo-path-stroke-traps.c      | 1120 ++++++++++++++++++++++++++++++++++++
+ src/cairo-path-stroke.c            |   12 +-
+ src/cairo-recording-surface.c      |   12 +-
+ src/cairo-rectangle.c              |    2 +-
+ src/cairo-stroke-style.c           |   39 ++
+ src/cairo-traps-compositor.c       |   37 +-
+ src/cairo-traps-private.h          |    9 +
+ src/cairo-traps.c                  |  252 ++++++++
+ src/cairoint.h                     |   21 +-
+ src/test-base-compositor-surface.c |    8 +-
+ 12 files changed, 1489 insertions(+), 30 deletions(-)
+
+commit 74941f822015cc50cd8477d0cf97f1a70dbff60b
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Jan 2 22:27:55 2013 +0000
+
+    xlib: Use SHM transport for ordinary image uploads
+    
+    In theory this should just save a single copy, however PutImage will
+    break up requests into a series of scanlines requests which is less
+    efficient than the single-shot transfer provided by ShmPutImage.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface.c |  100 +++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 77 insertions(+), 23 deletions(-)
+
+commit bf2a04c5ab91c93d4d188afd030b3004c67a180f
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Jan 3 12:24:14 2013 +0000
+
+    xlib/shm: Fix typo in creation of a SHM image
+    
+    Pass along the size the caller requests, not the size of the related
+    drawable.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |    8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+commit c29ab389fb2b3b91c895f2df684b0e9af8225d12
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Dec 30 12:32:45 2012 +0000
+
+    gl: Provide a fast emitter for solid spans
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-gl-composite.c |   55 +++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 50 insertions(+), 5 deletions(-)
+
+commit d3848521c497dbcd3d9ae0fab34fa70c72752e60
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Dec 30 12:32:45 2012 +0000
+
+    gl: Provide a fast emitter for solid glyphs
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-gl-composite.c |   62 ++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 49 insertions(+), 13 deletions(-)
+
+commit 127dd466695dcb05e6178e4ed2471dba1b229d17
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Dec 30 12:21:11 2012 +0000
+
+    gl: Use vfunc for vertex emission
+    
+    In order to overload the emitters in future to provide specialised
+    routines for the common types of operands, begin by switching the
+    current users over to a vfunc interface.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-gl-composite.c        |  107 +++++++++++++++++++++++++++---------
+ src/cairo-gl-glyphs.c           |   11 ++--
+ src/cairo-gl-private.h          |   48 +++++++++-------
+ src/cairo-gl-spans-compositor.c |  115 +++++++++++++++++++++------------------
+ src/cairo-gl-surface.c          |    2 +-
+ src/cairo-gl-traps-compositor.c |   21 +++----
+ 6 files changed, 190 insertions(+), 114 deletions(-)
+
+commit 9558cb62c6a3ed59a53f00f740a261251b9b64b2
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sat Dec 29 18:30:48 2012 +0000
+
+    perf/chart: Contract the default output filenames
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ perf/cairo-perf-chart.c |    4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+commit fbd4864995e261a4cfc5e53273b53ce8a22d72db
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sat Dec 29 18:30:48 2012 +0000
+
+    perf/chart: Show the geometric average as an extra column
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ perf/cairo-perf-chart.c |  112 ++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 111 insertions(+), 1 deletion(-)
+
+commit 71028865fae38bf26c45aae72e0a6773a19a640d
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sat Dec 29 15:05:53 2012 +0000
+
+    Revert "xlib/shm: Do not trigger a surplus event from XShmPutImage"
+    
+    This reverts commit c97f2d4acd5c4a1a4b839c72626f84e242e60b23.
+    
+    Testing suggests that keeping that event is a win; so do so.
+
+ src/cairo-xlib-surface.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit c97f2d4acd5c4a1a4b839c72626f84e242e60b23
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sat Dec 29 14:56:24 2012 +0000
+
+    xlib/shm: Do not trigger a surplus event from XShmPutImage
+    
+    As our lazy event mechanism is sufficient for tracking when to reuse shm
+    memory, and the events are not necessary for ShmPut/ShmGetImage paths.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 0c84a5474d4e90fc9361ccbb0ebc3d0580bad82b
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sat Dec 29 11:41:17 2012 +0000
+
+    xlib/shm: Rate-limit events and only use as necessary
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-render-compositor.c |    4 +-
+ src/cairo-xlib-surface-shm.c       |  110 +++++++++++++++++++++++++-----------
+ 2 files changed, 79 insertions(+), 35 deletions(-)
+
+commit 21db1c99108dc84166cbd9641f3256b22f571ee3
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Fri Dec 28 14:10:29 2012 -0800
+
+    gl: Cleanup selection of multisampling mode
+    
+    Fold the choice of multisampling mode into the cairo_gl_composite_t
+    structure itself. This makes it more similar to other settings.
+
+ src/cairo-gl-composite.c       |   20 +++++++++-----------
+ src/cairo-gl-msaa-compositor.c |   14 +++++++++-----
+ src/cairo-gl-private.h         |    9 ++++-----
+ 3 files changed, 22 insertions(+), 21 deletions(-)
+
+commit 7d02e2d62d1d2d2852f256905af60f418216b9ea
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Dec 23 11:12:21 2012 +0000
+
+    xlib/shm: Populate send_event and serial
+    
+    Hopefully this random choice is more meaningful than random junk.
+    
+    Bugzilla; https://bugs.freedesktop.org/show_bug.cgi?id=58672
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+commit e748c122435c1047894f73c14266bc81ad2edecd
+Author: Adrian Johnson <ajohnson@redneon.com>
+Date:   Sat Dec 22 18:34:43 2012 +1030
+
+    doc: Add CAIRO_MIME_TYPE_UNIQUE_ID to list of supported mime types
+
+ src/cairo-surface.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit 4e751fcb031557e6ad720f5bf5f14e181564ab9b
+Author: David Maxwell <damaxwell@alaska.edu>
+Date:   Thu Oct 11 08:52:36 2012 -0800
+
+    type1-subset: always include subroutine 4 (hint replacement idiom)
+    
+    http://lists.cairographics.org/archives/cairo/2012-December/023846.html
+
+ src/cairo-type1-subset.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit b94a519aad3d5b50aa6de47ee16ee6a099de9791
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 21 18:40:08 2012 -0500
+
+    [ft] Fix resizing of bitmap fonts
+    
+    Say, you were asking cairo for a font at 200px.  For bitmap-only fonts,
+    cairo was finding the closes strike size and using it.  If the strike
+    was at 20px, well, that's what you were getting.  We now scale that 20px
+    strike by a factor of 10 to get the correct size rendering.
+    
+    Note that by itself this patch doesn't change much on the Linux desktop.
+    The reason is that the size you are interested in (eg. 200px) is lost by
+    fontconfig.  When you request a font at 200px, fontconfig returns a font
+    pattern that says 20px, and so the next layers thing you want a font at
+    20px.  To address that, one also needs a piece of fontconfig config that
+    puts the 200 back into the pixelsize.  Something like this:
+    
+    <match target="font">
+      <test name="scalable" mode="eq">
+        <bool>false</bool>
+      </test>
+      <edit name="pixelsize" mode="assign">
+        <times>
+          <name>size</name>
+          <name>dpi</name>
+          <double>0.0138888888888</double> <!--1/72.-->
+        </times>
+      </edit>
+    </match>
+    
+    I'm going to try to upstream this config so it will be enabled by
+    default.  The config can be a bit smarter.  For example, if
+    metricshinting is enabled and the size difference is small, we may as
+    well not scale.
+    
+    The nice thing about this is that the configuration of whether and when
+    to scale bitmaps will be done in fontconfig, not cairo / Qt / ... code.
+
+ src/cairo-ft-font.c |   66 ++++++++++++++++++++++++++-------------------------
+ 1 file changed, 34 insertions(+), 32 deletions(-)
+
+commit 1404ed9692af1958b4090c46d1a27e0fe4a5616e
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Fri Dec 21 18:35:41 2012 -0500
+
+    [ft] Remove ancient check for FT_Bitmap_Size.y_ppem
+    
+    That member is available in the version of FreeType we require.
+
+ configure.ac        |    7 -------
+ src/cairo-ft-font.c |   11 +----------
+ 2 files changed, 1 insertion(+), 17 deletions(-)
+
+commit 867c876b0e7ce3dcc8afc7227ef6317701a6dda0
+Author: Behdad Esfahbod <behdad@behdad.org>
+Date:   Wed Nov 7 14:30:35 2012 -0800
+
+    [Minor] Improve logging
+
+ src/cairo-xlib-render-compositor.c |    2 ++
+ src/cairoint.h                     |    2 +-
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+commit 5d21c9e224617110678a5b854a6a41049a02fca2
+Author: Adam Jackson <ajax@redhat.com>
+Date:   Tue Dec 18 13:33:13 2012 -0500
+
+    xlib/shm: Fix memory leak
+    
+    Despite subclassing image surfaces, we never called down to the image
+    surface destructor, so we leaked a pixman_image_t every time.
+    
+    Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=882976
+    Signed-off-by: Adam Jackson <ajax@redhat.com>
+
+ src/cairo-xlib-surface-shm.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 51435eeb0c4d9e53d76dae8b5af279ad518a05f8
+Author: Uli Schlachter <psychon@znc.in>
+Date:   Mon Dec 17 18:33:22 2012 +0100
+
+    xcb: Fix xcb-huge-subimage
+    
+    This teaches the xcb backend how to split up a PutImage request for a subimage
+    into multiple requests. The backend already does the same for "normal" PutImage
+    where it doesn't have to assemble the image from various rows.
+    
+    Signed-off-by: Uli Schlachter <psychon@znc.in>
+
+ src/cairo-xcb-connection-core.c |   72 +++++++++++++++++++++++++++++++--------
+ 1 file changed, 58 insertions(+), 14 deletions(-)
+
+commit 5fb364287f96e4457d8df107ba3d0dc3f99f6f04
+Author: Uli Schlachter <psychon@znc.in>
+Date:   Mon Dec 17 18:29:21 2012 +0100
+
+    test: Add xcb-huge-subimage
+    
+    This creates an image surface with a non-natural stride and paints it to a
+    similar surface.
+    
+    In the xcb backend, this causes a call to _cairo_xcb_connection_put_subimage()
+    which tries to send a huge PutImage request. As a result, xcb kills the X11
+    connection.
+    
+    Signed-off-by: Uli Schlachter <psychon@znc.in>
+
+ test/Makefile.sources                    |    1 +
+ test/reference/xcb-huge-subimage.ref.png |  Bin 0 -> 97 bytes
+ test/xcb-huge-subimage.c                 |   81 ++++++++++++++++++++++++++++++
+ 3 files changed, 82 insertions(+)
+
+commit 749ef6be4d11b95d666b0e5fe06df926b828d655
+Author: Uli Schlachter <psychon@znc.in>
+Date:   Mon Dec 17 17:45:25 2012 +0100
+
+    context: Use recording surfaces for unbounded groups
+    
+    The old code uses an uninitialized variable for the extents of the group that is
+    created. This patch makes it use an unbounded recording surface instead.
+    
+    This has the implicit assumption that everything that is unbounded smells like a
+    recording surface. Let's see when this assumption breaks. :-)
+    
+    http://lists.cairographics.org/archives/cairo/2012-October/023585.html
+    
+    Signed-off-by: Uli Schlachter <psychon@znc.in>
+
+ src/cairo-default-context.c |   23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+commit 433a5829d7c38a9301346fc5a643e623565c1625
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Mon Dec 17 17:53:33 2012 +0100
+
+    Revert "gl/msaa: Share the depth/stencil buffer among all surfaces"
+    
+    This was pushed mistakenly. Sorry.
+    
+    This reverts commit a7d684e6fe4bbeea2262276aaa57bb2a47c401df.
+
+ src/cairo-gl-device.c  |  118 ++++++++++++++----------------------------------
+ src/cairo-gl-private.h |   13 ------
+ src/cairo-gl-surface.c |   31 ++-----------
+ 3 files changed, 38 insertions(+), 124 deletions(-)
+
+commit 000a137a6554cfc350407f3b719fb4aa3a1c33c6
+Author: Uli Schlachter <psychon@znc.in>
+Date:   Mon Dec 17 17:12:59 2012 +0100
+
+    boilerplate-xcb: Ignore MappingNotify events
+    
+    The boilerplate code makes sure that our tests didn't cause any X11 errors or
+    X11 events, because those might confuse API users.
+    
+    However, when the keyboard layout changes, every connection gets a MappingNotify
+    event. This means that the test and performance test suites failed when the
+    keyboard layout was changed while they are running.
+    
+    Fix this by ignoring MappingNotifies.
+    
+    Reported by Arthur Huillet on IRC.
+    
+    Signed-off-by: Uli Schlachter <psychon@znc.in>
+
+ boilerplate/cairo-boilerplate-xcb.c |   10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+commit 9d9aa04b60e24542b6b2a4c6bf87115db7736c2f
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Mon Dec 3 16:08:23 2012 -0800
+
+    gl: Add BGRA download support for GLES2
+    
+    Some OpenGLES2 drivers support downloading BGRA data. On little-endian
+    systems BGRA and GL_UNSIGNED_BYTe is equivalent to the typical
+    cairo_image_t format, so this can prevent CPU bit swizzling for
+    operations that involve images.
+
+ src/cairo-gl-device.c  |   18 +++++++++++++++++
+ src/cairo-gl-private.h |    1 +
+ src/cairo-gl-surface.c |   51 ++++++++++++++++++++++++------------------------
+ 3 files changed, 44 insertions(+), 26 deletions(-)
+
+commit a7d684e6fe4bbeea2262276aaa57bb2a47c401df
+Author: Martin Robinson <mrobinson@igalia.com>
+Date:   Mon Mar 5 23:11:19 2012 -0800
+
+    gl/msaa: Share the depth/stencil buffer among all surfaces
+    
+    Instead of allocating a depth/stencil buffer for all surfaces, share a
+    common buffer that's the size of the largest surface. This reduces
+    video memory usage when there are many GL surfaces.
+
+ src/cairo-gl-device.c  |  118 ++++++++++++++++++++++++++++++++++--------------
+ src/cairo-gl-private.h |   13 ++++++
+ src/cairo-gl-surface.c |   31 +++++++++++--
+ 3 files changed, 124 insertions(+), 38 deletions(-)
+
+commit ba4a4eae051cd932e59e3092ef36d4f6cded0159
+Author: Chuanbo Weng <chuanbo.weng@intel.com>
+Date:   Tue Oct 2 13:58:49 2012 +0200
+
+    gl/msaa: Use GL_IMG_multisampled_render_to_texture when available
+    
+    Some OpenGLES platforms support GL_IMG_multisampled_render_to_texture
+    instead of GL_EXT_multisampled_render_to_texture.
+
+ src/cairo-gl-device.c           |    8 ++++++++
+ src/cairo-gl-dispatch-private.h |   10 +++++++---
+ src/cairo-gl-dispatch.c         |   26 ++++++++++++++++++++++++++
+ 3 files changed, 41 insertions(+), 3 deletions(-)
+
+commit 3bedff0c009e645fff2d6f40976b4483871e73e1
+Author: Henry Song <henry.song@samsung.com>
+Date:   Tue May 15 20:32:44 2012 +0200
+
+    gl: Properly disable ctx->spans when necessary
+    
+    When compositing starts, if we are not using the spans compositor, we
+    should set the spans member of the context to false.
+
+ src/cairo-gl-composite.c |   14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+commit 18e7234c7e56ca26d7d7a2e29b1da2bb6944bb34
+Author: Henry Song <henry.song@samsung.com>
+Date:   Wed May 23 15:12:16 2012 +0200
+
+    gl/msaa: Also setmsaa_active to true for non-texture surfaces
+    
+    This is important because there are places in the code where msaa_active
+    is used to decide whether or not to complete an operation with
+    multisampling or not.
+
+ src/cairo-gl-device.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+commit 9f43f096b22a13f02d638b86b4460c7ed66d3c96
+Author: Henry Song <henry.song@samsung.com>
+Date:   Sat Dec 1 17:08:56 2012 +0000
+
+    gl: Flush context upon evicting a gradient
+    
+    As the random selection of a gradient can possible destroy the currently
+    active gradient, we need to flush the context in order to flush any
+    references to the texture before deletion.
+
+ src/cairo-gl-gradient.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+commit a0fb1391315033de54368715a8855aedea258e67
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sat Dec 1 09:21:15 2012 +0000
+
+    mempool: Reduce the assertion into an alignment adjustment for the base
+    
+    Instead of asserting that the caller passed in a chunk-aligned base
+    pointer, just perform the fixup whilst initialising the mempool. This
+    means that the caller (xcb!) cannot assume that the mempool->base is
+    then the same base pointer as passed in and so needs to store it
+    separately for use in computing SHM offsets.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-mempool.c |    9 +++++++++
+ src/cairo-xcb-shm.c |   14 +++++++-------
+ 2 files changed, 16 insertions(+), 7 deletions(-)
+
+commit 153b11612f34294241429b53722839984f367f2e
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Nov 28 09:57:29 2012 +0000
+
+    script: Fix map-to-image/unmap stack manipulations
+    
+    The idiom (and expectation) for surface operators is that it leaves the
+    surface on the stack for the next operation. Also we need to hold onto a
+    surface reference for objects put onto the stack, yet for the
+    map-to-image return we did not own one.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ util/cairo-script/cairo-script-operators.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+commit dfbf80a57d161707d105d1b5711c85890fe18a6d
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Nov 27 12:25:56 2012 +0000
+
+    trace: Do not forcibly add surfaces to the dictionary
+    
+    Adjust the stack manipulation to avoid moving an unknown surface to
+    the dictionary.
+    
+    Reported-by: Dongyeon Kim <dy5.kim@samsung.com>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ util/cairo-trace/trace.c |   50 +++++++++++++++++++++++++++++-----------------
+ 1 file changed, 32 insertions(+), 18 deletions(-)
+
+commit 376d39121c0d4eba8f0a22be71f782ce18e50923
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Nov 27 12:25:56 2012 +0000
+
+    trace: Fix operand emission for map-to-image and unmap-image
+    
+    Reported-by: Dongyeon Kim <dy5.kim@samsung.com>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ util/cairo-trace/trace.c |   58 +++++++++++++++++++++++++++-------------------
+ 1 file changed, 34 insertions(+), 24 deletions(-)
+
+commit 62b795fe52c73ad58101c101aa77449f4b61a576
+Author: Zozó Teki <teknos@gmail.com>
+Date:   Sat Nov 10 08:35:33 2012 +0000
+
+    recording: Append new elements to the end of the bbtree chain
+    
+    I have noticed that some of my objects were lost when drawing them on
+    a recording surface and playing them back. Later elements with the same
+    extents as a prior one tend to disappear from the chain of headers
+    having similar extents. After doing some debugging, I found that they
+    are not properly added to the bbtree during playback, and were instead
+    clobbering the existing chain.
+
+ src/cairo-recording-surface.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+commit 6ed1da67b5814c5ff062831f17621a585f81d704
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Nov 4 15:34:34 2012 +0000
+
+    version: Post-release bump to 1.12.9
+
+ cairo-version.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit cc162915a55cc67587677352bd9e389f16117853
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Nov 4 14:23:09 2012 +0000
+
+    1.12.8 release
+
+ NEWS            |   42 ++++++++++++++++++++++++++++++++++++++++++
+ cairo-version.h |    2 +-
+ 2 files changed, 43 insertions(+), 1 deletion(-)
+
+commit cf07bd866dc3fdbfaf3d7e7fdc83cc2a4ef5698c
+Author: Adrian Johnson <ajohnson@redneon.com>
+Date:   Sat Nov 3 11:08:01 2012 +1030
+
+    type1-subset: remove unused variable
+
+ src/cairo-type1-subset.c |    4 ----
+ 1 file changed, 4 deletions(-)
+
+commit 9f537156adcab5e7a9b21cd2bb5cc7676db52713
+Author: Adrian Johnson <ajohnson@redneon.com>
+Date:   Sat Nov 3 11:07:02 2012 +1030
+
+    type1-subset: fix memory leak
+
+ src/cairo-type1-subset.c |   52 +++++++++++++++++++++++++++++-----------------
+ 1 file changed, 33 insertions(+), 19 deletions(-)
+
+commit 724c6dfa9521e887682029add879c2fcdd518b14
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Nov 2 16:54:46 2012 +0000
+
+    xlib/shm: Need IncludeInferiors when creating the source fallback
+    
+    Reported-by: Benjamin Otte <otte@redhat.com>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |   14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+commit 1f4d05b55c96347aa4240190fda27f951b00c539
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Nov 2 14:52:03 2012 +0000
+
+    stroke: Fix calling '_cairo_spline_intersect' for in-bounds checking of splines
+    
+    Fixes stroke-clipped, within reason. There still remains some
+    antialiasing noise (between rendering the circle piecewise and wholly)
+    worth investigating - but that is probably an artefact of switching
+    between analytical rendering modes in the scanline
+    rasterisation.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-path-stroke-polygon.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 2dd4ff32064c3c564e0902ae07330272e6676c22
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Nov 2 14:48:40 2012 +0000
+
+    test: Add stroke-clipped
+    
+    Exercise a bug in the determine of clip-bounds when stroking, as
+    reported by ed44.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ test/Makefile.sources                 |    1 +
+ test/reference/stroke-clipped.ref.png |  Bin 0 -> 5886 bytes
+ test/stroke-clipped.c                 |   54 +++++++++++++++++++++++++++++++++
+ 3 files changed, 55 insertions(+)
+
+commit e9d45705844f67f4c8342d68fe35ad08ea008e30
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Nov 1 11:42:46 2012 +0000
+
+    pen: Tighten checking for bevel (start==stop) joins
+    
+    From commit d7f5a1bec421d6c7b92d16daae681fa31ac7c212
+    Author: Chris Wilson <chris@chris-wilson.co.uk>
+    Date:   Wed Oct 31 09:27:52 2012 +0000
+    
+        pen: First check whether the in/out edges lie within the single pen vertex
+    
+    makes a couple of tests much happier.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-pen.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+commit 90860241bb8f8eff3c1ab40641b1bfca0798b238
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Nov 1 09:47:00 2012 +0000
+
+    gl: Tune the default VBO size to reduce overhead on embedded devices
+    
+    Henry Song found that the 256k buffers were disadvantageous on his
+    embedded hardware. As there is no obvious right value for the default
+    VBO size, we can tune for the more obvious constraints.
+    
+    Based on a patch by Henry Song <henry.song@samsung.com>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-gl-private.h |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+commit 0c1ff1572f1fc4c11b429e39f7de798030530740
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Nov 1 08:45:37 2012 +0000
+
+    xlib: Fixup standalone header compilation for 'make check'
+    
+    Missing include of string.h
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-private.h |    1 +
+ 1 file changed, 1 insertion(+)
+
+commit b6daf47fa08c74d9672040b2b98ac6dd1f841429
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Nov 1 08:39:01 2012 +0000
+
+    spans: Do not assume that we manage to perform the clip geometrically
+    
+    Even for bounded masks, we may fail to perform the clipping
+    geometrically for a variety of reasons, the prime one being that the
+    clip has a mixture of antialias settings. So when compositing the
+    polygon, we need to check whether a clip path still remains and so
+    requires a clipmask.
+    
+    Fixes regression from
+    
+    commit cd1004ce19c7ea28c7fedb6464562a08416586c0
+    Author: Chris Wilson <chris@chris-wilson.co.uk>
+    Date:   Fri May 11 21:20:35 2012 +0100
+    
+        traps,spans-compositor: Avoid mistreating unaligned clips as aligned
+    
+    and
+    
+    commit 4ea3ace6c810ba090464e48795fac5456f6cdc24
+    Author: Chris Wilson <chris@chris-wilson.co.uk>
+    Date:   Fri May 11 21:51:44 2012 +0100
+    
+        spans: Only fallback for a clipmask if unbounded
+    
+    Reported-by: Dominik Röttsches <dominik.rottsches@intel.com>
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=56574
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-spans-compositor.c |    8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+commit 5844dead01db9ddab7f10a4d685bc5ee874d0eba
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Nov 1 08:37:58 2012 +0000
+
+    util/show-polygon: Show the limited range of each edge
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ util/show-polygon.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 48 insertions(+), 4 deletions(-)
+
+commit 03adea2f50aa10d49ff578389927e7b37e265918
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Nov 1 08:37:01 2012 +0000
+
+    stroke: Precompute the line half-width
+    
+    As we regularly recompute stroke->line_width/2 we may as compute it once
+    during initialisation.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-path-stroke.c |   17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+commit dbc0d83f2a7a0e6658f3b97b5f9921c44ef6a11f
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Oct 31 15:18:21 2012 +0000
+
+    image: Add a couple of tracepoints for spans fallbacks
+    
+    References: https://bugs.freedesktop.org/show_bug.cgi?id=56574
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-image-compositor.c |    3 ++-
+ src/cairo-spans-compositor.c |   13 ++++++++++---
+ 2 files changed, 12 insertions(+), 4 deletions(-)
+
+commit 9b7ed9b2cd6c9ee4dfab71aed9b7d97b720fceb0
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Oct 31 13:15:07 2012 +0000
+
+    xlib/shm: Fix bogus assertion without shm available
+    
+    In particular note that _cairo_xlib_surface_put_shm is indeed called and
+    is expected to be a no-op when shm is not available.
+    
+    Reported-by: Thomas Klausner <wiz@NetBSD.org>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit d7f5a1bec421d6c7b92d16daae681fa31ac7c212
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Wed Oct 31 09:27:52 2012 +0000
+
+    pen: First check whether the in/out edges lie within the single pen vertex
+    
+    In order to prevent underflow when searching for the closing pen vertex,
+    we first need to be sure that it does not simply lie next to the opening
+    pen vertex. As a result we were missing many cases that should have been
+    a bevel (in == out) and generating almost complete round caps instead.
+    
+    Reported-by: Dominik Röttsches <dominik.rottsches@intel.com>
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=56432
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-pen.c                         |   60 ++++++++++++++++---------------
+ test/reference/arc-looping-dash.ref.png |  Bin 502 -> 464 bytes
+ test/reference/caps-tails-curve.ref.png |  Bin 54750 -> 54314 bytes
+ test/reference/reflected-stroke.ref.png |  Bin 5139 -> 5116 bytes
+ 4 files changed, 32 insertions(+), 28 deletions(-)
+
+commit 66625cb46c985321c46b79d2163a4d676d6700ba
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Oct 30 12:40:41 2012 +0000
+
+    xlib: Apply the image offsets to the destination rather the source
+    
+    So that we can specify the entire source surface as the region to copy
+    and not introduce clipping errors.
+    
+    Fixes regression from
+    commit c068691ff57c2f6cd750a54db17393c0e132cb00
+    Author: Chris Wilson <chris@chris-wilson.co.uk>
+    Date:   Fri Aug 17 21:33:54 2012 +0100
+    
+        xlib/shm: Use an impromptu upload ShmSegment
+    
+    Reported-by: John Lindgren <john.lindgren@aol.com>
+    Reported-by: Kalev Lember <kalevlember@gmail.com>
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=56547
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-render-compositor.c |   22 ++++++++++------------
+ 1 file changed, 10 insertions(+), 12 deletions(-)
+
+commit 65176b7380f0d633da514be1febe16f17b99d876
+Author: Kevin Tardif <kiyoka@gmail.com>
+Date:   Tue Oct 30 00:27:27 2012 -0400
+
+    type1-subset, cff-subset: Plugged 2 memory leaks
+    
+    - _cairo_type1_font_subset_fini doesn't free font->cleartext
+    - _cairo_cff_font_create can exit without freeing font->font_name and/or
+      font->data; _cairo_cff_font_load_opentype_cff is called to allocate
+      font_name, then _cairo_cff_font_load_cff is called to allocate
+      font->data, then _cairo_cff_font_load_cff's return status is checked
+      and if it failed, it jumps to fail1. This can cause font_name to leak
+      since the fail1 target only frees the font variable. In addition,
+      _cairo_cff_font_load_cff can fail -after- allocating data, and then
+      data won't be freed either.
+    
+    Bug 56566
+
+ src/cairo-cff-subset.c   |    6 +++---
+ src/cairo-type1-subset.c |    2 ++
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+commit 0c800dc3f64ee030df1cd0a6a1dcd6df71502dea
+Author: Adrian Johnson <ajohnson@redneon.com>
+Date:   Tue Oct 30 19:23:30 2012 +1030
+
+    type1-subset: ensure subroutine numnber is an integer
+
+ src/cairo-type1-subset.c |   21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+commit 5a6e1d680a5bf1c4091e74f999abd611abd92334
+Author: Adrian Johnson <ajohnson@redneon.com>
+Date:   Sun Oct 28 20:58:52 2012 +1030
+
+    type1-subset: restore correct callothersub behavior
+    
+    that was removed in d57e652f. Without this subsetting of subroutines
+    won't work for some fonts.
+
+ src/cairo-type1-subset.c |   35 +++++++++++++++++++++++++++++------
+ 1 file changed, 29 insertions(+), 6 deletions(-)
+
+commit 0e2458697848cf8c89c9d57fa9b64f0ea7bd0877
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Oct 28 10:08:39 2012 +0000
+
+    xlib/shm: Use shmstr.h instead of shmproto.h if available
+    
+    Before it was known as shmproto.h, the wire protocol definition was to
+    be found in shmstr.h, so if we don't have the current version of libXext
+    try to use the older includes.
+    
+    Reported-by: Sebastian Haas <sehaas@gmail.com>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ configure.ac                 |    2 +-
+ src/cairo-xlib-surface-shm.c |    6 +++++-
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+commit f18199fcfb3b052c198041fc05156ae3d9e6aee7
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sun Oct 28 10:04:12 2012 +0000
+
+    xlib/shm: Check for XShm headers
+    
+    Not all version of libXext ship the same set of headers, so play safe
+    and check during configure that we have the headers we depend upon in
+    the code.
+    
+    Reported-by: Sebastian Haas <sehaas@gmail.com>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ configure.ac                 |    4 ++
+ src/cairo-xlib-surface-shm.c |   99 ++++++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 100 insertions(+), 3 deletions(-)
+
+commit d57e652f08f5ff7c334d01bc071962e6a131928f
+Author: Adrian Johnson <ajohnson@redneon.com>
+Date:   Fri Oct 26 23:00:01 2012 +1030
+
+    type1-subset: parse all operators
+    
+    The PDF at bug 56265 contained a Type 1 font that used the "div"
+    operator to compute the glyph width. As the "div" operator was
+    not handled by the charstring parser this resulted in an incorrect
+    glyph width in the PDF output.
+    
+    Fix this by upgrading the charstring parsing to handle all Type 1
+    operators.
+
+ src/cairo-type1-subset.c |  167 +++++++++++++++++++++++++++-------------------
+ 1 file changed, 100 insertions(+), 67 deletions(-)
+
+commit fdd2082f923012a1354be7086d03f78fb166695b
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Oct 26 10:51:31 2012 +0100
+
+    xlib: Check for both X.org and Xorg ServerVendors
+    
+    Martin Husemann reported that on his NetBSD machine the vendor was being
+    reported as "The Xorg Foundation", a non-conformist separatist split of
+    the Peoples' Liberation Army^W^W^W "The X.Org Foundation". Simply check
+    for both during initialisation.
+    
+    Reported-by: Martin Husemann <martin@duskware.de>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-display.c     |    2 +-
+ src/cairo-xlib-private.h     |    7 +++++++
+ src/cairo-xlib-surface-shm.c |    2 +-
+ 3 files changed, 9 insertions(+), 2 deletions(-)
+
+commit 00feb8ce530a472abbde445b52d9ae8c99ec97f0
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Oct 26 10:51:31 2012 +0100
+
+    xlib/shm: Sanity check that the server handles XSendEvent with ShmCompletion
+    
+    Uli Schlachter suggested it would be wiser to complement our blacklist
+    of known broken X/libXext with an explicit roundtrip to check for a
+    BadValue error return when we try to use XSendEvent.
+    
+    Suggested-by: Uli Schlachter <psychon@znc.in>
+    Reported-by: Martin Husemann <martin@duskware.de>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |   77 +++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 69 insertions(+), 8 deletions(-)
+
+commit e43f53bf7f3d371116f31f22ab9754b08b5abe7f
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Mon Oct 22 13:47:11 2012 +0100
+
+    version: Post release bump to 1.12.7
+
+ cairo-version.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit fab6958eff35a94cf46e38f19a7e75e10aa2b182
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Mon Oct 22 11:07:15 2012 +0100
+
+    1.12.6 release
+
+ NEWS            |   35 +++++++++++++++++++++++++++++++++++
+ cairo-version.h |    2 +-
+ 2 files changed, 36 insertions(+), 1 deletion(-)
+
+commit d49b2284b505e93cd415af4da3cd2cc2d3d168d3
+Author: Gilles Espinasse <g.esp@free.fr>
+Date:   Sat Oct 20 20:22:51 2012 +0200
+
+    configure: fix unrecognized -Wno option
+    
+    gcc-4.4 and later accept every -Wno option. So we can test for the
+    option without no in the name to check if the option is supported.
+    
+    Each time a warning is emitted and without this fix, on gcc-4.4 that will
+    add this warning:
+       cc1: warning: unrecognized command line option "-Wno-unused-but-set-variable"
+    
+    bugs.freedesktop.org #51633, rediffed after 1.12.4
+    
+    Of course this assumes that all compilers will behave like gcc, which is
+    reasonably implicit in the set of warning flags.
+    
+    Signed-off-by: Gilles Espinasse <g.esp@free.fr>
+    [ickle: slight modification to test both -W and -Wno variants to ideally
+    preserve compatability with non-GCC compilers sharing GCC options!]
+
+ build/configure.ac.warnings |   11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+commit b12a94b98306d87689bad23dad4c0ec033037046
+Author: Gilles Espinasse <g.esp@free.fr>
+Date:   Sat Oct 20 20:22:50 2012 +0200
+
+    configure: fix PKG_CHECK_MODULES tests displaying no no
+    
+    Inside PKG_CHECK_MODULES, AC_MSG_RESULT(no) is already displayed, so the
+    caller should not use another AC_MSG_RESULT(no).
+    
+    Add a comment that empty ACTION-IF-NOT-FOUND is not allowed for
+    PKG_CHECK_MODULES, but a simple : is enough.
+    
+    This is bugs.freedesktop.org #51628, rediffed after 1.12.4
+    
+    Signed-off-by: Gilles Espinasse <g.esp@free.fr>
+
+ build/aclocal.pkg.m4 |    2 ++
+ configure.ac         |   41 +++++++++++++++++------------------------
+ 2 files changed, 19 insertions(+), 24 deletions(-)
+
+commit 813143c2205c12923519ce6dcf3c8e10f63f1085
+Author: Gilles Espinasse <g.esp@free.fr>
+Date:   Sat Oct 20 23:06:44 2012 +0200
+
+    ft: Fix compilation on 1.12 without FT_Get_X11_Font_Format
+    
+    Signed-off-by: Gilles Espinasse <g.esp@free.fr>
+
+ configure.ac        |    2 +-
+ src/cairo-ft-font.c |   23 +++++++++++++++++------
+ 2 files changed, 18 insertions(+), 7 deletions(-)
+
+commit c565bad8901dbe66e1402cdc2418986e96e698e3
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Oct 19 12:22:58 2012 +0100
+
+    pen: Relax invisibility criteria from half-tolerance to quarter-tolerance
+    
+    Inkscape is one user who sets geometric tolerance to 1.25 pixels when
+    stroking sub-pixel lines. Whilst we wait for inkscape to set sensible
+    values for their tolerance, we have to allow through the current values
+    in order to prevent the fine strokes from disappearing.
+    
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=56099
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-pen.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5041b462d084de8552336275914d30c23bf5dd35
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Oct 19 12:04:50 2012 +0100
+
+    xlib/shm: Sync the XShmAttach before removing the ShmSegment id
+    
+    Whilst reading through other users of XShm, it became apparent that
+    IPC_RMID behaves differently across the platforms. Linux allows
+    processes to attach to an existing ShmSegment id after a IPC_RMID, but
+    for others the IPC_RMID takes immediate effect. On those platforms
+    without a "deferred" IPC_RMID, we then need to perform the XShmAttach
+    synchronously before perfomring the IPC_RMID.
+    
+    Reported-by: Thomas Klausner <wiz@NetBSD.org>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ configure.ac                 |   32 ++++++++++++++++++++++++++++++++
+ src/cairo-xlib-surface-shm.c |    3 +++
+ 2 files changed, 35 insertions(+)
+
+commit d5f9c694b9145f0464c8bd58d844bddedcb77d5e
+Author: Uli Schlachter <psychon@znc.in>
+Date:   Tue Oct 16 17:09:42 2012 +0200
+
+    test: Define optional exception classes
+    
+    According to musl libc author:
+    
+    "C99 requires the FE_ macros to be defined if and only if the exception they
+    correspond to is supported"
+    
+    So we define these macros to 0 if they are not supported. Support for these FPU
+    exceptions is not necessary for correct functionality, but makes some tests less
+    effective.
+    
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55771
+    Signed-off-by: Uli Schlachter <psychon@znc.in>
+
+ test/cairo-test.c     |    3 ---
+ test/cairo-test.h     |   20 ++++++++++++++++++++
+ test/invalid-matrix.c |    4 ----
+ 3 files changed, 20 insertions(+), 7 deletions(-)
+
+commit db488a1703d4ef3bcbd54138b51c01600a2f4d3a
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Oct 11 17:00:57 2012 +0100
+
+    recording: Copy across the is-clear? during snapshotting
+    
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55799
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-recording-surface.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit ed720007ba6be17434eb68b604fd36bd91c0d894
+Author: Henry Song <henry.song@samsung.com>
+Date:   Thu Oct 11 16:57:57 2012 +0100
+
+    recording: copy reverses its dst and src parameters
+    
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55799
+
+ src/cairo-recording-surface.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 26c8accd41163d86711ba900bec7d9cd6591d8a3
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Thu Oct 11 16:52:07 2012 +0100
+
+    xlib: Reorder CloseDisplay hooks
+    
+    As we may utilize X extensions as we shutdown and release resources
+    during CloseDisplay, we need to run our own callback first. If we run
+    last, than we reinstantiate the extensions which often have the
+    unfortunate habit of then persisting with stale data across the next
+    Display connection, causing invalid requests to be generated and raise
+    XErrors.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-display.c |   34 +++++++++++++++++-----------------
+ 1 file changed, 17 insertions(+), 17 deletions(-)
+
+commit fbf528f46deaebc7d8cf38fc61be9e016f207575
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Tue Oct 9 17:37:53 2012 +0100
+
+    compositor: Reduce glyph "overlap" if the inked pixels are opaque
+    
+    We can ignore the issue of overdraw if when we paint the glyphs, the
+    result is opaque.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-composite-rectangles.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+commit 66500ef29fea41ccda554f85d82a6aa3de774903
+Author: Henry Song <henry.song@samsung.com>
+Date:   Thu Sep 27 19:22:23 2012 +0000
+
+    gl/traps: ensure RGBA surface before upload image to texture for GLES2
+    
+    As GLESv2 may only use an RGBA surface as its source for texture
+    uploads, we therefore need to perform a conversion.
+
+ src/cairo-gl-traps-compositor.c |   32 ++++++++++++++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+
+commit 188c34b40d6f08851b4076ad11aefe69d4a78a25
+Author: Henry Song <henry.song@samsung.com>
+Date:   Thu Sep 27 18:25:52 2012 +0000
+
+    gl: gles2 only supports GL_DEPTH24_STENCIL8_OES
+    
+    Patch also provided by U. Artie Eoff <ullysses.a.eoff@intel.com>
+    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=50355
+
+ src/cairo-gl-device.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f78a9269228f2f48e8eb496e341ef990db39c6c3
+Author: Alexis Ballier <aballier@gentoo.org>
+Date:   Fri Sep 21 08:22:55 2012 -0300
+
+    cairo-sphinx: protect -ldl link with CAIRO_HAS_DL like in cairo-trace.
+    
+    Signed-off-by: Uli Schlachter <psychon@znc.in>
+
+ util/cairo-sphinx/Makefile.am |    2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 3d2712d56a22f2a86fb80da94c3e55be8d26a330
+Author: Alexis Ballier <aballier@gentoo.org>
+Date:   Fri Sep 21 08:22:54 2012 -0300
+
+    cairo-fdr: protect -ldl link with CAIRO_HAS_DL like in cairo-trace.
+    
+    Signed-off-by: Uli Schlachter <psychon@znc.in>
+
+ util/cairo-fdr/Makefile.am |    2 ++
+ 1 file changed, 2 insertions(+)
+
+commit 9ab9916114db9917108198111d3232a18ae505ed
+Author: Adrian Johnson <ajohnson@redneon.com>
+Date:   Sun Oct 7 23:54:20 2012 +1030
+
+    remove debug code
+
+ src/cairo-type1-subset.c |    2 --
+ 1 file changed, 2 deletions(-)
+
+commit 9c2a92c70836b8534ef8c26d943fa17f891da105
+Author: Adrian Johnson <ajohnson@redneon.com>
+Date:   Sun Oct 7 23:50:54 2012 +1030
+
+    type1: convert '.' to locale specific decimal point before using sscanf
+
+ src/cairo-type1-subset.c |   31 +++++++++++++++++++++++++++----
+ 1 file changed, 27 insertions(+), 4 deletions(-)
+
+commit 0d5f63755e7ceb1bb5678fcf1f4661f3435470fb
+Author: David Maxwell <damaxwell@alaska.edu>
+Date:   Sun Oct 7 00:01:53 2012 -0800
+
+    type1-subset: always subset subroutines 0-3 (Flex/hint replacement)
+    
+    http://lists.cairographics.org/archives/cairo/2012-October/023576.html
+
+ src/cairo-type1-subset.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+commit 599e78ea2ee146c74fc7ffcee32a055dabbefdda
+Author: David Maxwell <damaxwell@alaska.edu>
+Date:   Tue Oct 2 16:16:28 2012 -0800
+
+    type1: lenIV support
+    
+    http://lists.cairographics.org/archives/cairo/2012-October/023557.html
+
+ src/cairo-type1-subset.c |   42 ++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 38 insertions(+), 4 deletions(-)
+
+commit cffbdf50ce0117d62d6e157369c60e4a8572fd21
+Author: David Maxwell <damaxwell@alaska.edu>
+Date:   Tue Oct 2 16:16:28 2012 -0800
+
+    type1: buildchar stack fix
+    
+    http://lists.cairographics.org/archives/cairo/2012-October/023557.html
+
+ src/cairo-type1-subset.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+commit e29bb5f295d055068a24b629fa1bd5f06a93431b
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Sat Oct 6 18:53:41 2012 +0100
+
+    win32: Use the image surface below the fallback when unmapping an HDC
+    
+    As for a native window, the surface does not have an image delegate
+    itself but instead installs a fallback surface during map_to_image. So
+    during unmap_image, we then need to unmap from the fallback surface
+    instead.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/win32/cairo-win32-display-surface.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+commit 0251f0951d8dcdd198912326c11489823989a3eb
+Author: Uli Schlachter <psychon@znc.in>
+Date:   Sat Oct 6 15:00:51 2012 +0200
+
+    xcb: Clear the result of create_similar_image
+    
+    The documentation of cairo_surface_create_similar_image() states that the
+    image's contents are initially all 0. However, the implementation didn't live up
+    to the documentation.
+    
+    This was found via the corresponding assert in
+    cairo_surface_create_similar_image().
+    
+    There are some cairo-xcb-internal users of this function which cleared the image
+    right after creating it. Obviously, this isn't needed anymore.
+    
+    Fixes: Nothing. The existing call in the testsuite to
+    cairo_surface_create_similar_image() doesn't hit this issue, since it creates a
+    too small image to hit the SHM-case.
+    
+    Signed-off-by: Uli Schlachter <psychon@znc.in>
+
+ src/cairo-xcb-surface-render.c |   14 --------------
+ src/cairo-xcb-surface.c        |    5 +++++
+ 2 files changed, 5 insertions(+), 14 deletions(-)
+
+commit 15ef4a3248bbf32d05da7ed2480a2ce58c26d9bc
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Oct 5 19:46:41 2012 +0100
+
+    xlib/shm: Note the bug is an interaction between libXext and xorg
+    
+    Søren thought it was bit harsh to lay the blame solely on xorg for it
+    crashing due to an unexpected input value, and that we should mention
+    libXext was also partly to blame for incorrectly setting the SEND_EVENT
+    bit in the ShmCompletionEvent.
+    
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |    9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+commit b1532f465e05d566f6d160c5ca916a5a12614067
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Oct 5 19:20:18 2012 +0100
+
+    xlib/shm: Avoid using XSendEvent with old versions of Xorg
+    
+    Søren Sandmann Pedersen pointed out that all versions of Xorg prior to
+    and including xorg-1.11.0 contained a bug that would cause them to crash
+    if they ever processed an event sent by XSendEvent. This was fixed in
+    
+    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.
+    
+    so make sure we do not use XSendEvent prior to that commit, which
+    fortuitously is quite easy as we only do so along the ShmPixmap path.
+    
+    Reported-by: Søren Sandmann Pedersen <ssp@redhat.com>
+    Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+
+ src/cairo-xlib-surface-shm.c |   21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+commit dba46f4eab716c0148d278ba7cae0cb075b5df01
+Author: Chris Wilson <chris@chris-wilson.co.uk>
+Date:   Fri Oct 5 17:24:56 2012 +0100
+
+    version: Post release bump to 1.12.5
+
+ cairo-version.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
 commit 117abd85ac7ff41e484fe0d98f16704ec30abd09
 Author: Chris Wilson <chris@chris-wilson.co.uk>
 Date:   Fri Oct 5 16:44:00 2012 +0100
index a2d85be..994c5c8 100644 (file)
@@ -373,6 +373,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
diff --git a/NEWS b/NEWS
index f14a51e..368d293 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,185 @@
+Release 1.12.14 (2013-02-10 Chris Wilson <chris@chris-wilson.co.uk>)
+===================================================================
+In the last week we had a few more bugs reported and promptly resolved.
+As these are a combination of regressions and stability issues, it is
+time for a prompt update and release. Many thanks to everyone for
+testing and reporting issues, and helping to make Cairo better.
+
+Bug fixes
+---------
+
+  Prevent user callbacks accessing user-data during destroy to prevent
+  use-after-free bugs.
+  https://bugzilla.mozilla.org/show_bug.cgi?id=722975
+
+  Use standard names for glyphs in subset fonts (PDF).
+  https://bugs.freedesktop.org/show_bug.cgi?id=60248
+
+  Fix detection of Win98. The logic for detecting Win98 (and its broken
+  AlphaBlend()) was inverted, disabling AlphaBlend() for everyone.
+
+  Prevent numeric overflow from extrapolating polygon edges to the clip
+  boundary and causing severe render artifacts.
+  https://bugs.freedesktop.org/show_bug.cgi?id=60489
+
+  Fix computation of glyph string coordinates when breaking up runs
+  for xlib.
+
+  Fix an assertion in the win32 backend for failing to clear its
+  similar-images.
+  https://bugs.freedesktop.org/show_bug.cgi?id=60519
+
+
+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 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?id=58253
+
+  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
index d9fee2c..db0d57a 100644 (file)
@@ -615,6 +615,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
index 28026dc..52cd99f 100644 (file)
@@ -144,32 +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 };
     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);
 
@@ -219,13 +208,75 @@ _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 (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,
+                          GLX_ALPHA_SIZE, 1,
+                          GLX_DOUBLEBUFFER,
+                          None };
+
+    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,
+                          GLX_ALPHA_SIZE, 1,
+                          GLX_STENCIL_SIZE, 1,
+                          GLX_SAMPLES, 4,
+                          GLX_SAMPLE_BUFFERS, 1,
+                          GLX_DOUBLEBUFFER,
+                          None };
+
+    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_db (const char               *name,
                                        cairo_content_t            content,
                                        double                     width,
@@ -235,6 +286,10 @@ _cairo_boilerplate_gl_create_window_db (const char           *name,
                                        cairo_boilerplate_mode_t   mode,
                                        void                     **closure)
 {
+    cairo_status_t status;
+    cairo_surface_t *surface;
+    gl_target_closure_t *gltc;
+
     int rgba_attribs[] = { GLX_RGBA,
                           GLX_RED_SIZE, 1,
                           GLX_GREEN_SIZE, 1,
@@ -242,66 +297,18 @@ _cairo_boilerplate_gl_create_window_db (const char                  *name,
                           GLX_ALPHA_SIZE, 1,
                           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;
 
-    width = ceil (width);
-    height = ceil (height);
-
-    if (width == 0)
-       width = 1;
-    if (height == 0)
-       height = 1;
+    surface = _cairo_boilerplate_gl_create_window_common (rgba_attribs, content,
+                                                         width, height,
+                                                         max_width, max_height,
+                                                         mode, gltc);
 
-    dpy = XOpenDisplay (NULL);
-    gltc->dpy = dpy;
-    if (!gltc->dpy) {
-       fprintf (stderr, "Failed to open display: %s\n", XDisplayName(0));
-       free (gltc);
-       return NULL;
-    }
-
-    if (mode == CAIRO_BOILERPLATE_MODE_TEST)
-       XSynchronize (gltc->dpy, 1);
-
-    vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
-    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)
@@ -414,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 74306ce..cf90a96 100644 (file)
@@ -92,6 +92,8 @@ fi[]dnl
 # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
 # [ACTION-IF-NOT-FOUND])
 #
+# ACTION-IF-NOT-FOUND is not allowed to be empty, that trigger PKG_CONFIG_PATH error message.
+# Use : or set a dummy variable to avoid that behavior.
 #
 # Note that if there is a possibility the first call to
 # PKG_CHECK_MODULES might not happen, you should be sure to include an
index 9b9c742..f984eb2 100644 (file)
@@ -21,8 +21,11 @@ MAYBE_WARN="-Wall -Wextra \
 -Wno-missing-field-initializers -Wno-unused-parameter \
 -Wno-attributes -Wno-long-long -Winline"
 
+# New -Wno options should be added here
+# gcc-4.4 and later accept every -Wno- option but may complain later that this
+# option is unknow each time another warning happen.
 # -Wunused-but-set-variable is too noisy at present
-NO_WARN="-Wno-unused-but-set-variable"
+NO_WARN="unused-but-set-variable"
 
 dnl Sun Studio 12 likes to rag at us for abusing enums like
 dnl having cairo_status_t variables hold cairo_int_status_t
@@ -48,8 +51,6 @@ MAYBE_WARN="$MAYBE_WARN -fno-strict-aliasing -fno-common"
 dnl Also to turn various gcc/glibc-specific preprocessor checks
 MAYBE_WARN="$MAYBE_WARN -Wp,-D_FORTIFY_SOURCE=2"
 
-MAYBE_WARN="$MAYBE_WARN $NO_WARN"
-
 # invalidate cached value if MAYBE_WARN has changed
 if test "x$cairo_cv_warn_maybe" != "x$MAYBE_WARN"; then
        unset cairo_cv_warn_cflags
@@ -72,7 +73,9 @@ AC_CACHE_CHECK([for supported warning flags], cairo_cv_warn_cflags, [
        for W in $MAYBE_WARN; do
                CAIRO_CC_TRY_FLAG([$W],, [WARN_CFLAGS="$WARN_CFLAGS $W"])
        done
-
+       for W in $NO_WARN; do
+               CAIRO_CC_TRY_FLAG([-W$W -Wno-$W],, [WARN_CFLAGS="$WARN_CFLAGS -Wno-$W"])
+       done
        cairo_cv_warn_cflags=$WARN_CFLAGS
        cairo_cv_warn_maybe=$MAYBE_WARN
 
index 1c43907..9cda383 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 14
 
 #endif
index 05503bf..6b0e1e7 100644 (file)
 /* Define to 1 if you have the `fork' function. */
 #undef HAVE_FORK
 
-/* FT_Bitmap_Size structure includes y_ppem field */
-#undef HAVE_FT_BITMAP_SIZE_Y_PPEM
+/* Define to 1 if you have the `FT_Get_X11_Font_Format' function. */
+#undef HAVE_FT_GET_X11_FONT_FORMAT
 
 /* Define to 1 if you have the `FT_GlyphSlot_Embolden' function. */
 #undef HAVE_FT_GLYPHSLOT_EMBOLDEN
 /* Define to 1 if you have the Valgrind lockdep tool */
 #undef HAVE_LOCKDEP
 
+/* Define to 1 if you have lzo available */
+#undef HAVE_LZO
+
 /* Define to 1 if you have the Valgrind memfault tool */
 #undef HAVE_MEMFAULT
 
 /* Define to 1 if you have the <windows.h> header file. */
 #undef HAVE_WINDOWS_H
 
+/* Define to 1 if you have the <X11/extensions/shmproto.h> header file. */
+#undef HAVE_X11_EXTENSIONS_SHMPROTO_H
+
+/* Define to 1 if you have the <X11/extensions/shmstr.h> header file. */
+#undef HAVE_X11_EXTENSIONS_SHMSTR_H
+
+/* Define to 1 if you have the <X11/extensions/XShm.h> header file. */
+#undef HAVE_X11_EXTENSIONS_XSHM_H
+
 /* Define to 1 if you have the `XRenderCreateConicalGradient' function. */
 #undef HAVE_XRENDERCREATECONICALGRADIENT
 
 /* Define to 1 if the system has the type `__uint128_t'. */
 #undef HAVE___UINT128_T
 
+/* Define to 1 if shared memory segments are released deferred. */
+#undef IPC_RMID_DEFERRED_RELEASE
+
 /* Define to the sub-directory in which libtool stores uninstalled libraries.
    */
 #undef LT_OBJDIR
index 7b4e91d..0ceb5bf 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for cairo 1.12.4.
+# Generated by GNU Autoconf 2.69 for cairo 1.12.14.
 #
 # Report bugs to <http://bugs.freedesktop.org/enter_bug.cgi?product=cairo>.
 #
@@ -591,8 +591,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='cairo'
 PACKAGE_TARNAME='cairo'
-PACKAGE_VERSION='1.12.4'
-PACKAGE_STRING='cairo 1.12.4'
+PACKAGE_VERSION='1.12.14'
+PACKAGE_STRING='cairo 1.12.14'
 PACKAGE_BUGREPORT='http://bugs.freedesktop.org/enter_bug.cgi?product=cairo'
 PACKAGE_URL='http://cairographics.org/'
 
@@ -808,6 +808,7 @@ CAIRO_HAS_DLSYM_FALSE
 CAIRO_HAS_DLSYM_TRUE
 CAIRO_HAS_DL_FALSE
 CAIRO_HAS_DL_TRUE
+lzo_LIBS
 VALGRIND_LIBS
 VALGRIND_CFLAGS
 CAIRO_HAS_LCOV_FALSE
@@ -1647,7 +1648,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures cairo 1.12.4 to adapt to many kinds of systems.
+\`configure' configures cairo 1.12.14 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1721,7 +1722,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of cairo 1.12.4:";;
+     short | recursive ) echo "Configuration of cairo 1.12.14:";;
    esac
   cat <<\_ACEOF
 
@@ -2040,7 +2041,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-cairo configure 1.12.4
+cairo configure 1.12.14
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2763,68 +2764,11 @@ $as_echo "$ac_res" >&6; }
   eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
 
 } # ac_fn_c_check_type
-
-# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
-# ----------------------------------------------------
-# Tries to find if the field MEMBER exists in type AGGR, after including
-# INCLUDES, setting cache variable VAR accordingly.
-ac_fn_c_check_member ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
-$as_echo_n "checking for $2.$3... " >&6; }
-if eval \${$4+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$5
-int
-main ()
-{
-static $2 ac_aggr;
-if (ac_aggr.$3)
-return 0;
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  eval "$4=yes"
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$5
-int
-main ()
-{
-static $2 ac_aggr;
-if (sizeof ac_aggr.$3)
-return 0;
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  eval "$4=yes"
-else
-  eval "$4=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-eval ac_res=\$$4
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_member
 cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by cairo $as_me 1.12.4, which was
+It was created by cairo $as_me 1.12.14, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -4955,7 +4899,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='cairo'
- VERSION='1.12.4'
+ VERSION='1.12.14'
 
 
 # Some tools Automake needs.
 
 CAIRO_VERSION_MAJOR=1
 CAIRO_VERSION_MINOR=12
-CAIRO_VERSION_MICRO=4
+CAIRO_VERSION_MICRO=14
 CAIRO_VERSION_SONUM=2
 CAIRO_RELEASE_STATUS=release
-CAIRO_LIBTOOL_VERSION_INFO=11202:4:11200
+CAIRO_LIBTOOL_VERSION_INFO=11202:14:11200
 
 
 
@@ -18206,8 +18150,11 @@ MAYBE_WARN="-Wall -Wextra \
 -Wno-missing-field-initializers -Wno-unused-parameter \
 -Wno-attributes -Wno-long-long -Winline"
 
+# New -Wno options should be added here
+# gcc-4.4 and later accept every -Wno- option but may complain later that this
+# option is unknow each time another warning happen.
 # -Wunused-but-set-variable is too noisy at present
-NO_WARN="-Wno-unused-but-set-variable"
+NO_WARN="unused-but-set-variable"
 
 MAYBE_WARN="$MAYBE_WARN -erroff=E_ENUM_TYPE_MISMATCH_ARG \
                        -erroff=E_ENUM_TYPE_MISMATCH_OP"
@@ -18243,8 +18190,6 @@ MAYBE_WARN="$MAYBE_WARN -fno-strict-aliasing -fno-common"
 
 MAYBE_WARN="$MAYBE_WARN -Wp,-D_FORTIFY_SOURCE=2"
 
-MAYBE_WARN="$MAYBE_WARN $NO_WARN"
-
 # invalidate cached value if MAYBE_WARN has changed
 if test "x$cairo_cv_warn_maybe" != "x$MAYBE_WARN"; then
        unset cairo_cv_warn_cflags
@@ -18367,7 +18312,104 @@ rm -f core conftest.err conftest.$ac_objext \
 $as_echo "$cairo_cc_flag" >&6; }
 
        done
+       for W in $NO_WARN; do
+                               _test_WERROR=${WERROR+set}
+       if test "z$_test_WERROR" != zset; then
+               WERROR=""
+               for _werror in -Werror -errwarn; do
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $_werror" >&5
+$as_echo_n "checking whether $CC supports $_werror... " >&6; }
+                                       # AC_LANG_PROGRAM() produces a main() w/o args,
+       # but -Wold-style-definition doesn't like that.
+       # We need _some_ program so that we don't get
+       # warnings about empty compilation units, so always
+       # append a reasonable main().
+       _compile_program=""'
+               int main(int c, char **v) { (void)c; (void)v; return 0; }'
+
+       _save_cflags="$CFLAGS"
+       _save_ldflags="$LDFLAGS"
+       _save_libs="$LIBS"
+       CFLAGS="$CFLAGS $_werror"
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$_compile_program
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  cairo_cc_stderr=`test -f conftest.err && cat conftest.err`
+                cairo_cc_flag=yes
+else
+  cairo_cc_stderr=`test -f conftest.err && cat conftest.err`
+                cairo_cc_flag=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 
+       if test "x$cairo_cc_stderr" != "x"; then
+               cairo_cc_flag=no
+       fi
+
+       if test "x$cairo_cc_flag" = "xyes"; then
+               WERROR="$WERROR $_werror"
+       else
+               :
+       fi
+       CFLAGS="$_save_cflags"
+       LDFLAGS="$_save_ldflags"
+       LIBS="$_save_libs"
+
+
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cairo_cc_flag" >&5
+$as_echo "$cairo_cc_flag" >&6; }
+               done
+       fi
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -W$W -Wno-$W" >&5
+$as_echo_n "checking whether $CC supports -W$W -Wno-$W... " >&6; }
+                       # AC_LANG_PROGRAM() produces a main() w/o args,
+       # but -Wold-style-definition doesn't like that.
+       # We need _some_ program so that we don't get
+       # warnings about empty compilation units, so always
+       # append a reasonable main().
+       _compile_program=""'
+               int main(int c, char **v) { (void)c; (void)v; return 0; }'
+
+       _save_cflags="$CFLAGS"
+       _save_ldflags="$LDFLAGS"
+       _save_libs="$LIBS"
+       CFLAGS="$CFLAGS $WERROR -W$W -Wno-$W"
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$_compile_program
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  cairo_cc_stderr=`test -f conftest.err && cat conftest.err`
+                cairo_cc_flag=yes
+else
+  cairo_cc_stderr=`test -f conftest.err && cat conftest.err`
+                cairo_cc_flag=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+       if test "x$cairo_cc_stderr" != "x"; then
+               cairo_cc_flag=no
+       fi
+
+       if test "x$cairo_cc_flag" = "xyes"; then
+               WARN_CFLAGS="$WARN_CFLAGS -Wno-$W"
+       else
+               :
+       fi
+       CFLAGS="$_save_cflags"
+       LDFLAGS="$_save_ldflags"
+       LIBS="$_save_libs"
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cairo_cc_flag" >&5
+$as_echo "$cairo_cc_flag" >&6; }
+
+       done
        cairo_cv_warn_cflags=$WARN_CFLAGS
        cairo_cv_warn_maybe=$MAYBE_WARN
 
@@ -20273,6 +20315,65 @@ else
 fi
 
 
+save_LIBS="$LIBS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for lzo2a_decompress in -llzo2" >&5
+$as_echo_n "checking for lzo2a_decompress in -llzo2... " >&6; }
+if ${ac_cv_lib_lzo2_lzo2a_decompress+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-llzo2  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char lzo2a_decompress ();
+int
+main ()
+{
+return lzo2a_decompress ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_lzo2_lzo2a_decompress=yes
+else
+  ac_cv_lib_lzo2_lzo2a_decompress=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzo2_lzo2a_decompress" >&5
+$as_echo "$ac_cv_lib_lzo2_lzo2a_decompress" >&6; }
+if test "x$ac_cv_lib_lzo2_lzo2a_decompress" = xyes; then :
+  ac_fn_c_check_header_mongrel "$LINENO" "lzo/lzo2a.h" "ac_cv_header_lzo_lzo2a_h" "$ac_includes_default"
+if test "x$ac_cv_header_lzo_lzo2a_h" = xyes; then :
+
+         have_lzo=yes
+
+$as_echo "#define HAVE_LZO 1" >>confdefs.h
+
+         lzo_LIBS="-llzo2"
+
+else
+  have_lzo="no (requires lzpo http://www.oberhumer.com/opensource/lzo/)"
+fi
+
+
+else
+  have_lzo="no (requires lzpo http://www.oberhumer.com/opensource/lzo/)"
+fi
+
+
+LIBS="$save_LIBS"
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlsym in -ldl" >&5
 $as_echo_n "checking for dlsym in -ldl... " >&6; }
 if ${ac_cv_lib_dl_dlsym+:} false; then :
@@ -20639,9 +20740,7 @@ fi
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                    xlib_REQUIRES=""
+                xlib_REQUIRES=""
                     if test "$no_x" = yes; then
   # Not all programs may use this symbol, but it does not hurt to define it.
 
@@ -21139,9 +21238,7 @@ fi
                       xlib_NONPKGCONFIG_CFLAGS=$X_CFLAGS
                     fi
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                    xlib_REQUIRES=""
+       xlib_REQUIRES=""
                     if test "$no_x" = yes; then
   # Not all programs may use this symbol, but it does not hurt to define it.
 
@@ -21646,6 +21743,81 @@ $as_echo "yes" >&6; }
        :
 fi
 
+  ac_fn_c_check_header_mongrel "$LINENO" "sys/ipc.h" "ac_cv_header_sys_ipc_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_ipc_h" = xyes; then :
+
+fi
+
+
+  ac_fn_c_check_header_mongrel "$LINENO" "sys/shm.h" "ac_cv_header_sys_shm_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_shm_h" = xyes; then :
+
+fi
+
+
+
+  if test "$ac_cv_header_sys_ipc_h" = "yes" -a "$ac_cv_header_sys_shm_h" = "yes"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether shmctl IPC_RMID allowes subsequent attaches" >&5
+$as_echo_n "checking whether shmctl IPC_RMID allowes subsequent attaches... " >&6; }
+      if test "$cross_compiling" = yes; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming no" >&5
+$as_echo "assuming no" >&6; }
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+                 #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;
+                 }
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+$as_echo "#define IPC_RMID_DEFERRED_RELEASE 1" >>confdefs.h
+
+                 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+      fi
+
+      for ac_header in X11/extensions/XShm.h X11/extensions/shmproto.h X11/extensions/shmstr.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include <X11/Xlibint.h>
+                       #include <X11/Xproto.h>
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
 
                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cairo's Xlib surface backend feature could be enabled" >&5
 $as_echo_n "checking whether cairo's Xlib surface backend feature could be enabled... " >&6; }
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                      xlib_xrender_REQUIRES=""
+                xlib_xrender_REQUIRES=""
                       old_CPPFLAGS=$CPPFLAGS
                       CPPFLAGS="$CPPFLAGS $xlib_CFLAGS $xlib_NONPKGCONFIG_CFLAGS"
-                      ac_fn_c_check_header_mongrel "$LINENO" "X11/extensions/Xrender.h" "ac_cv_header_X11_extensions_Xrender_h" "$ac_includes_default"
+                      ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xrender.h" "ac_cv_header_X11_extensions_Xrender_h" "#include <X11/X.h>
+"
 if test "x$ac_cv_header_X11_extensions_Xrender_h" = xyes; then :
   xlib_xrender_NONPKGCONFIG_LIBS="-lXrender"
 else
                       CPPFLAGS=$old_CPPFLAGS
 
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                      xlib_xrender_REQUIRES=""
+       xlib_xrender_REQUIRES=""
                       old_CPPFLAGS=$CPPFLAGS
                       CPPFLAGS="$CPPFLAGS $xlib_CFLAGS $xlib_NONPKGCONFIG_CFLAGS"
-                      ac_fn_c_check_header_mongrel "$LINENO" "X11/extensions/Xrender.h" "ac_cv_header_X11_extensions_Xrender_h" "$ac_includes_default"
+                      ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xrender.h" "ac_cv_header_X11_extensions_Xrender_h" "#include <X11/X.h>
+"
 if test "x$ac_cv_header_X11_extensions_Xrender_h" = xyes; then :
   xlib_xrender_NONPKGCONFIG_LIBS="-lXrender"
 else
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                   use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"
+                use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                   use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"
+       use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"
 else
        xcb_CFLAGS=$pkg_cv_xcb_CFLAGS
        xcb_LIBS=$pkg_cv_xcb_LIBS
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                     use_xlib_xcb="no (requires $xlib_xcb_REQUIRES http://xcb.freedesktop.org)"
+                use_xlib_xcb="no (requires $xlib_xcb_REQUIRES http://xcb.freedesktop.org)"
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                     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
        xlib_xcb_CFLAGS=$pkg_cv_xlib_xcb_CFLAGS
        xlib_xcb_LIBS=$pkg_cv_xlib_xcb_LIBS
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       use_xcb_shm="no (requires $xcb_shm http://xcb.freedesktop.org)"
+                use_xcb_shm="no (requires $xcb_shm http://xcb.freedesktop.org)"
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       use_xcb_shm="no (requires $xcb_shm http://xcb.freedesktop.org)"
+       use_xcb_shm="no (requires $xcb_shm http://xcb.freedesktop.org)"
 else
        xcb_shm_CFLAGS=$pkg_cv_xcb_shm_CFLAGS
        xcb_shm_LIBS=$pkg_cv_xcb_shm_LIBS
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                    qt_REQUIRES=""
+                qt_REQUIRES=""
                     use_qt="no (requires Qt4 development libraries)"
 
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                    qt_REQUIRES=""
+       qt_REQUIRES=""
                     use_qt="no (requires Qt4 development libraries)"
 
 else
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-  use_drm="no (requires $drm_REQUIRES, udev is available from git://git.kernel.org/pub/scm/linux/hotplug/udev.git)"
+                use_drm="no (requires $drm_REQUIRES, udev is available from git://git.kernel.org/pub/scm/linux/hotplug/udev.git)"
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-  use_drm="no (requires $drm_REQUIRES, udev is available from git://git.kernel.org/pub/scm/linux/hotplug/udev.git)"
+       use_drm="no (requires $drm_REQUIRES, udev is available from git://git.kernel.org/pub/scm/linux/hotplug/udev.git)"
 else
        drm_CFLAGS=$pkg_cv_drm_CFLAGS
        drm_LIBS=$pkg_cv_drm_LIBS
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+                :
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+       :
 else
        png_CFLAGS=$pkg_cv_png_CFLAGS
        png_LIBS=$pkg_cv_png_LIBS
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                   use_directfb="no (requires $directfb_REQUIRES http://www.directfb.org)"
+                use_directfb="no (requires $directfb_REQUIRES http://www.directfb.org)"
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                   use_directfb="no (requires $directfb_REQUIRES http://www.directfb.org)"
+       use_directfb="no (requires $directfb_REQUIRES http://www.directfb.org)"
 else
        directfb_CFLAGS=$pkg_cv_directfb_CFLAGS
        directfb_LIBS=$pkg_cv_directfb_LIBS
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                      freetype_pkgconfig=no
+                freetype_pkgconfig=no
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                      freetype_pkgconfig=no
+       freetype_pkgconfig=no
 else
        FREETYPE_CFLAGS=$pkg_cv_FREETYPE_CFLAGS
        FREETYPE_LIBS=$pkg_cv_FREETYPE_LIBS
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }; use_fc="no (requires $fc_REQUIRES)"
+                use_fc="no (requires $fc_REQUIRES)"
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }; use_fc="no (requires $fc_REQUIRES)"
+       use_fc="no (requires $fc_REQUIRES)"
 else
        FONTCONFIG_CFLAGS=$pkg_cv_FONTCONFIG_CFLAGS
        FONTCONFIG_LIBS=$pkg_cv_FONTCONFIG_LIBS
@@ -30075,22 +30213,8 @@ if test "x$use_ft" = "xyes"; then
   _save_cflags="$CFLAGS"
   LIBS="$LIBS $ft_LIBS"
   CFLAGS="$CFLAGS $ft_CFLAGS"
-  ac_fn_c_check_member "$LINENO" "FT_Bitmap_Size" "y_ppem" "ac_cv_member_FT_Bitmap_Size_y_ppem" "#include <ft2build.h>
-                   #include FT_FREETYPE_H
-"
-if test "x$ac_cv_member_FT_Bitmap_Size_y_ppem" = xyes; then :
-  HAVE_FT_BITMAP_SIZE_Y_PPEM=1
-else
-  HAVE_FT_BITMAP_SIZE_Y_PPEM=0
-fi
-
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_FT_BITMAP_SIZE_Y_PPEM $HAVE_FT_BITMAP_SIZE_Y_PPEM
-_ACEOF
-
 
-  for ac_func in FT_GlyphSlot_Embolden FT_GlyphSlot_Oblique FT_Load_Sfnt_Table FT_Library_SetLcdFilter
+  for ac_func in FT_Get_X11_Font_Format FT_GlyphSlot_Embolden FT_GlyphSlot_Oblique FT_Load_Sfnt_Table FT_Library_SetLcdFilter
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-  use_image="no (requires $pixman_REQUIRES http://cairographics.org/releases/)"
+                use_image="no (requires $pixman_REQUIRES http://cairographics.org/releases/)"
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-  use_image="no (requires $pixman_REQUIRES http://cairographics.org/releases/)"
+       use_image="no (requires $pixman_REQUIRES http://cairographics.org/releases/)"
 else
        pixman_CFLAGS=$pkg_cv_pixman_CFLAGS
        pixman_LIBS=$pkg_cv_pixman_LIBS
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-  use_gobject="no (requires $gobject_REQUIRES http://download.gnome.org/pub/GNOME/sources/glib/)"
+                use_gobject="no (requires $gobject_REQUIRES http://download.gnome.org/pub/GNOME/sources/glib/)"
 elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-  use_gobject="no (requires $gobject_REQUIRES http://download.gnome.org/pub/GNOME/sources/glib/)"
+       use_gobject="no (requires $gobject_REQUIRES http://download.gnome.org/pub/GNOME/sources/glib/)"
 else
        GOBJECT_CFLAGS=$pkg_cv_GOBJECT_CFLAGS
        GOBJECT_LIBS=$pkg_cv_GOBJECT_LIBS
@@ -35508,7 +35624,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by cairo $as_me 1.12.4, which was
+This file was extended by cairo $as_me 1.12.14, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -35575,7 +35691,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-cairo config.status 1.12.4
+cairo config.status 1.12.14
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index 67b68e2..928a169 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 2065901..2b2632e 100644 (file)
@@ -315,6 +315,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
index ca853ab..d25f7e9 100644 (file)
@@ -536,6 +536,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
@@ -657,12 +658,13 @@ cairo_sources = cairo-analysis-surface.c cairo-arc.c cairo-array.c \
        cairo-paginated-surface.c cairo-path-bounds.c cairo-path.c \
        cairo-path-fill.c cairo-path-fixed.c cairo-path-in-fill.c \
        cairo-path-stroke.c cairo-path-stroke-boxes.c \
-       cairo-path-stroke-polygon.c cairo-path-stroke-tristrip.c \
-       cairo-pattern.c cairo-pen.c cairo-polygon.c \
-       cairo-polygon-intersect.c cairo-polygon-reduce.c \
-       cairo-raster-source-pattern.c cairo-recording-surface.c \
-       cairo-rectangle.c cairo-rectangular-scan-converter.c \
-       cairo-region.c cairo-rtree.c cairo-scaled-font.c \
+       cairo-path-stroke-polygon.c cairo-path-stroke-traps.c \
+       cairo-path-stroke-tristrip.c cairo-pattern.c cairo-pen.c \
+       cairo-polygon.c cairo-polygon-intersect.c \
+       cairo-polygon-reduce.c cairo-raster-source-pattern.c \
+       cairo-recording-surface.c cairo-rectangle.c \
+       cairo-rectangular-scan-converter.c cairo-region.c \
+       cairo-rtree.c cairo-scaled-font.c \
        cairo-shape-mask-compositor.c cairo-slope.c cairo-spans.c \
        cairo-spans-compositor.c cairo-spline.c cairo-stroke-dash.c \
        cairo-stroke-style.c cairo-surface.c cairo-surface-clipper.c \
index 906524e..2a2f01b 100644 (file)
@@ -793,7 +793,8 @@ hold true for all possible cases.
 <tr>
 <td><p><span class="term"><span class="emphasis"><em>Returns</em></span> :</span></p></td>
 <td>The <a class="link" href="cairo-cairo-font-face-t.html#cairo-font-face-t" title="cairo_font_face_t"><span class="type">cairo_font_face_t</span></a> with which <em class="parameter"><code>scaled_font</code></em> was
-created.</td>
+created.  This object is owned by cairo. To keep a reference to it,
+you must call <a class="link" href="cairo-cairo-scaled-font-t.html#cairo-scaled-font-reference" title="cairo_scaled_font_reference ()"><code class="function">cairo_scaled_font_reference()</code></a>.</td>
 </tr>
 </tbody>
 </table></div>
index 11349f0..3b608fe 100644 (file)
@@ -136,7 +136,7 @@ functions. If you do this, keep in mind that it is mandatory that you call
 you must use <a class="link" href="cairo-cairo-surface-t.html#cairo-surface-mark-dirty" title="cairo_surface_mark_dirty ()"><code class="function">cairo_surface_mark_dirty()</code></a> after modifying it.
 </p>
 <div class="example">
-<a name="idp18123024"></a><p class="title"><b>Example 1. Directly modifying an image surface</b></p>
+<a name="idp18359440"></a><p class="title"><b>Example 1. Directly modifying an image surface</b></p>
 <div class="example-contents">
   <table class="listing_frame" border="0" cellpadding="0" cellspacing="0">
     <tbody>
@@ -1346,7 +1346,8 @@ memory and disk space.
 </p>
 <p>
 The recognized MIME types are the following: <a class="link" href="cairo-cairo-surface-t.html#CAIRO-MIME-TYPE-JPEG:CAPS" title="CAIRO_MIME_TYPE_JPEG"><code class="literal">CAIRO_MIME_TYPE_JPEG</code></a>,
-<a class="link" href="cairo-cairo-surface-t.html#CAIRO-MIME-TYPE-PNG:CAPS" title="CAIRO_MIME_TYPE_PNG"><code class="literal">CAIRO_MIME_TYPE_PNG</code></a>, <a class="link" href="cairo-cairo-surface-t.html#CAIRO-MIME-TYPE-JP2:CAPS" title="CAIRO_MIME_TYPE_JP2"><code class="literal">CAIRO_MIME_TYPE_JP2</code></a>, <a class="link" href="cairo-cairo-surface-t.html#CAIRO-MIME-TYPE-URI:CAPS" title="CAIRO_MIME_TYPE_URI"><code class="literal">CAIRO_MIME_TYPE_URI</code></a>.
+<a class="link" href="cairo-cairo-surface-t.html#CAIRO-MIME-TYPE-PNG:CAPS" title="CAIRO_MIME_TYPE_PNG"><code class="literal">CAIRO_MIME_TYPE_PNG</code></a>, <a class="link" href="cairo-cairo-surface-t.html#CAIRO-MIME-TYPE-JP2:CAPS" title="CAIRO_MIME_TYPE_JP2"><code class="literal">CAIRO_MIME_TYPE_JP2</code></a>, <a class="link" href="cairo-cairo-surface-t.html#CAIRO-MIME-TYPE-URI:CAPS" title="CAIRO_MIME_TYPE_URI"><code class="literal">CAIRO_MIME_TYPE_URI</code></a>,
+<a class="link" href="cairo-cairo-surface-t.html#CAIRO-MIME-TYPE-UNIQUE-ID:CAPS" title="CAIRO_MIME_TYPE_UNIQUE_ID"><code class="literal">CAIRO_MIME_TYPE_UNIQUE_ID</code></a>.
 </p>
 <p>
 See corresponding backend surface docs for details about which MIME
index 5754782..c4c1933 100644 (file)
@@ -14,7 +14,7 @@
 <div class="titlepage">
 <div>
 <div><table class="navigation" id="top" width="100%" cellpadding="2" cellspacing="0"><tr><th valign="middle"><p class="title">Cairo: A Vector Graphics Library</p></th></tr></table></div>
-<div><p class="releaseinfo">for Cairo 1.12.4
+<div><p class="releaseinfo">for Cairo 1.12.14
 </p></div>
 </div>
 <hr>
index 89c881b..d49ade8 100644 (file)
@@ -1 +1 @@
-1.12.4
+1.12.14
index 7102151..d19b3b9 100644 (file)
@@ -527,7 +527,8 @@ hold true for all possible cases.
 <varlistentry><term><parameter>scaled_font</parameter>&#160;:</term>
 <listitem><simpara>a <link linkend="cairo-scaled-font-t"><type>cairo_scaled_font_t</type></link></simpara></listitem></varlistentry>
 <varlistentry><term><emphasis>Returns</emphasis>&#160;:</term><listitem><simpara>The <link linkend="cairo-font-face-t"><type>cairo_font_face_t</type></link> with which <parameter>scaled_font</parameter> was
-created.</simpara></listitem></varlistentry>
+created.  This object is owned by cairo. To keep a reference to it,
+you must call <link linkend="cairo-scaled-font-reference"><function>cairo_scaled_font_reference()</function></link>.</simpara></listitem></varlistentry>
 </variablelist><para role="since">Since 1.2</para></refsect2>
 <refsect2 id="cairo-scaled-font-get-font-options" role="function" condition="since:1.2">
 <title>cairo_scaled_font_get_font_options ()</title>
index 3c47e9a..857b9d9 100644 (file)
@@ -979,7 +979,8 @@ memory and disk space.
 </para>
 <para>
 The recognized MIME types are the following: <link linkend="CAIRO-MIME-TYPE-JPEG:CAPS"><literal>CAIRO_MIME_TYPE_JPEG</literal></link>,
-<link linkend="CAIRO-MIME-TYPE-PNG:CAPS"><literal>CAIRO_MIME_TYPE_PNG</literal></link>, <link linkend="CAIRO-MIME-TYPE-JP2:CAPS"><literal>CAIRO_MIME_TYPE_JP2</literal></link>, <link linkend="CAIRO-MIME-TYPE-URI:CAPS"><literal>CAIRO_MIME_TYPE_URI</literal></link>.
+<link linkend="CAIRO-MIME-TYPE-PNG:CAPS"><literal>CAIRO_MIME_TYPE_PNG</literal></link>, <link linkend="CAIRO-MIME-TYPE-JP2:CAPS"><literal>CAIRO_MIME_TYPE_JP2</literal></link>, <link linkend="CAIRO-MIME-TYPE-URI:CAPS"><literal>CAIRO_MIME_TYPE_URI</literal></link>,
+<link linkend="CAIRO-MIME-TYPE-UNIQUE-ID:CAPS"><literal>CAIRO_MIME_TYPE_UNIQUE_ID</literal></link>.
 </para>
 <para>
 See corresponding backend surface docs for details about which MIME
index 045dec6..9045916 100644 (file)
@@ -414,6 +414,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
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 7f2ff5b..18db0c5 100644 (file)
@@ -69,6 +69,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 8cc6b0b..b7d7539 100644 (file)
@@ -318,6 +318,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
index 52f3d39..9ad7dd7 100644 (file)
@@ -473,12 +473,13 @@ am__libcairo_la_SOURCES_DIST = cairo.h cairo-deprecated.h cairo-xlib.h \
        cairo-paginated-surface.c cairo-path-bounds.c cairo-path.c \
        cairo-path-fill.c cairo-path-fixed.c cairo-path-in-fill.c \
        cairo-path-stroke.c cairo-path-stroke-boxes.c \
-       cairo-path-stroke-polygon.c cairo-path-stroke-tristrip.c \
-       cairo-pattern.c cairo-pen.c cairo-polygon.c \
-       cairo-polygon-intersect.c cairo-polygon-reduce.c \
-       cairo-raster-source-pattern.c cairo-recording-surface.c \
-       cairo-rectangle.c cairo-rectangular-scan-converter.c \
-       cairo-region.c cairo-rtree.c cairo-scaled-font.c \
+       cairo-path-stroke-polygon.c cairo-path-stroke-traps.c \
+       cairo-path-stroke-tristrip.c cairo-pattern.c cairo-pen.c \
+       cairo-polygon.c cairo-polygon-intersect.c \
+       cairo-polygon-reduce.c cairo-raster-source-pattern.c \
+       cairo-recording-surface.c cairo-rectangle.c \
+       cairo-rectangular-scan-converter.c cairo-region.c \
+       cairo-rtree.c cairo-scaled-font.c \
        cairo-shape-mask-compositor.c cairo-slope.c cairo-spans.c \
        cairo-spans-compositor.c cairo-spline.c cairo-stroke-dash.c \
        cairo-stroke-style.c cairo-surface.c cairo-surface-clipper.c \
@@ -618,12 +619,12 @@ am__objects_33 = cairo-analysis-surface.lo cairo-arc.lo cairo-array.lo \
        cairo-path-bounds.lo cairo-path.lo cairo-path-fill.lo \
        cairo-path-fixed.lo cairo-path-in-fill.lo cairo-path-stroke.lo \
        cairo-path-stroke-boxes.lo cairo-path-stroke-polygon.lo \
-       cairo-path-stroke-tristrip.lo cairo-pattern.lo cairo-pen.lo \
-       cairo-polygon.lo cairo-polygon-intersect.lo \
-       cairo-polygon-reduce.lo cairo-raster-source-pattern.lo \
-       cairo-recording-surface.lo cairo-rectangle.lo \
-       cairo-rectangular-scan-converter.lo cairo-region.lo \
-       cairo-rtree.lo cairo-scaled-font.lo \
+       cairo-path-stroke-traps.lo cairo-path-stroke-tristrip.lo \
+       cairo-pattern.lo cairo-pen.lo cairo-polygon.lo \
+       cairo-polygon-intersect.lo cairo-polygon-reduce.lo \
+       cairo-raster-source-pattern.lo cairo-recording-surface.lo \
+       cairo-rectangle.lo cairo-rectangular-scan-converter.lo \
+       cairo-region.lo cairo-rtree.lo cairo-scaled-font.lo \
        cairo-shape-mask-compositor.lo cairo-slope.lo cairo-spans.lo \
        cairo-spans-compositor.lo cairo-spline.lo cairo-stroke-dash.lo \
        cairo-stroke-style.lo cairo-surface.lo \
@@ -1094,6 +1095,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
@@ -1213,12 +1215,13 @@ cairo_sources = cairo-analysis-surface.c cairo-arc.c cairo-array.c \
        cairo-paginated-surface.c cairo-path-bounds.c cairo-path.c \
        cairo-path-fill.c cairo-path-fixed.c cairo-path-in-fill.c \
        cairo-path-stroke.c cairo-path-stroke-boxes.c \
-       cairo-path-stroke-polygon.c cairo-path-stroke-tristrip.c \
-       cairo-pattern.c cairo-pen.c cairo-polygon.c \
-       cairo-polygon-intersect.c cairo-polygon-reduce.c \
-       cairo-raster-source-pattern.c cairo-recording-surface.c \
-       cairo-rectangle.c cairo-rectangular-scan-converter.c \
-       cairo-region.c cairo-rtree.c cairo-scaled-font.c \
+       cairo-path-stroke-polygon.c cairo-path-stroke-traps.c \
+       cairo-path-stroke-tristrip.c cairo-pattern.c cairo-pen.c \
+       cairo-polygon.c cairo-polygon-intersect.c \
+       cairo-polygon-reduce.c cairo-raster-source-pattern.c \
+       cairo-recording-surface.c cairo-rectangle.c \
+       cairo-rectangular-scan-converter.c cairo-region.c \
+       cairo-rtree.c cairo-scaled-font.c \
        cairo-shape-mask-compositor.c cairo-slope.c cairo-spans.c \
        cairo-spans-compositor.c cairo-spline.c cairo-stroke-dash.c \
        cairo-stroke-style.c cairo-surface.c cairo-surface-clipper.c \
@@ -1970,6 +1973,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-in-fill.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-stroke-boxes.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-stroke-polygon.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-stroke-traps.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-stroke-tristrip.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-stroke.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path.Plo@am__quote@
index d6793b0..4abf57d 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 \
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;
 
index c792985..c26098a 100644 (file)
@@ -444,6 +444,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);
 }
 
index e5ad367..0199723 100644 (file)
@@ -129,6 +129,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;
index 3d828ef..fee08f0 100644 (file)
@@ -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;
index 0e9fd71..ba8f60f 100644 (file)
@@ -49,6 +49,9 @@ typedef struct _cairo_egl_context {
     EGLContext context;
 
     EGLSurface dummy_surface;
+
+    EGLContext previous_context;
+    EGLSurface previous_surface;
 } cairo_egl_context_t;
 
 typedef struct _cairo_egl_surface {
@@ -58,20 +61,51 @@ typedef struct _cairo_egl_surface {
 } cairo_egl_surface_t;
 
 
-static void
-_egl_acquire (void *abstract_ctx)
+static cairo_bool_t
+_context_acquisition_changed_egl_state (cairo_egl_context_t *ctx,
+                                       EGLSurface current_surface)
 {
-    cairo_egl_context_t *ctx = abstract_ctx;
-    EGLSurface current_surface;
+    return ctx->previous_context != ctx->context ||
+          ctx->previous_surface != current_surface;
+}
 
+static EGLSurface
+_egl_get_current_surface (cairo_egl_context_t *ctx)
+{
     if (ctx->base.current_target == NULL ||
         _cairo_gl_surface_is_texture (ctx->base.current_target)) {
-        current_surface = ctx->dummy_surface;
-    } else {
-        cairo_egl_surface_t *surface = (cairo_egl_surface_t *) ctx->base.current_target;
-        current_surface = surface->egl ;
+       return  ctx->dummy_surface;
     }
 
+    return ((cairo_egl_surface_t *) ctx->base.current_target)->egl;
+}
+
+static void
+_egl_query_current_state (cairo_egl_context_t *ctx)
+{
+    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_context == EGL_NO_CONTEXT) {
+       ctx->previous_surface = EGL_NO_SURFACE;
+       ctx->previous_context = EGL_NO_CONTEXT;
+    }
+}
+
+static void
+_egl_acquire (void *abstract_ctx)
+{
+    cairo_egl_context_t *ctx = abstract_ctx;
+    EGLSurface current_surface = _egl_get_current_surface (ctx);
+
+    _egl_query_current_state (ctx);
+    if (!_context_acquisition_changed_egl_state (ctx, current_surface))
+       return;
+
     eglMakeCurrent (ctx->display,
                    current_surface, current_surface, ctx->context);
 }
@@ -80,8 +114,11 @@ static void
 _egl_release (void *abstract_ctx)
 {
     cairo_egl_context_t *ctx = abstract_ctx;
-    if (!ctx->base.thread_aware)
+    if (!ctx->base.thread_aware ||
+       !_context_acquisition_changed_egl_state (ctx,
+                                                _egl_get_current_surface (ctx))) {
        return;
+    }
 
     eglMakeCurrent (ctx->display,
                    EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -161,6 +198,10 @@ cairo_egl_device_create (EGLDisplay dpy, EGLContext egl)
     ctx->base.swap_buffers = _egl_swap_buffers;
     ctx->base.destroy = _egl_destroy;
 
+    /* We are about the change the current state of EGL, so we should
+     * query the pre-existing surface now instead of later. */
+    _egl_query_current_state (ctx);
+
     if (!_egl_make_current_surfaceless (ctx)) {
        /* Fall back to dummy surface, meh. */
        EGLint config_attribs[] = {
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;
 
index 45fa042..c250e72 100644 (file)
@@ -56,11 +56,12 @@ cairo_int_status_t
 _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
                                const cairo_pattern_t *pattern,
                                const cairo_rectangle_int_t *sample,
-                               const cairo_rectangle_int_t *extents)
+                               const cairo_rectangle_int_t *extents,
+                               cairo_bool_t use_texgen)
 {
     _cairo_gl_operand_destroy (&setup->src);
     return _cairo_gl_operand_init (&setup->src, pattern, setup->dst,
-                                  sample, extents);
+                                  sample, extents, use_texgen);
 }
 
 void
@@ -83,14 +84,15 @@ cairo_int_status_t
 _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
                              const cairo_pattern_t *pattern,
                              const cairo_rectangle_int_t *sample,
-                             const cairo_rectangle_int_t *extents)
+                             const cairo_rectangle_int_t *extents,
+                             cairo_bool_t use_texgen)
 {
     _cairo_gl_operand_destroy (&setup->mask);
     if (pattern == NULL)
         return CAIRO_STATUS_SUCCESS;
 
     return _cairo_gl_operand_init (&setup->mask, pattern, setup->dst,
-                                  sample, extents);
+                                  sample, extents, use_texgen);
 }
 
 void
@@ -109,6 +111,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)
 {
@@ -242,10 +250,12 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
         _cairo_gl_texture_set_filter (ctx, ctx->tex_target,
                                       operand->texture.attributes.filter);
 
-       dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
-                                       GL_FLOAT, GL_FALSE, vertex_size,
-                                       ctx->vb + vertex_offset);
-       dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
+       if (! operand->texture.texgen) {
+           dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
+                                          GL_FLOAT, GL_FALSE, vertex_size,
+                                          ctx->vb + vertex_offset);
+           dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
+       }
         break;
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
@@ -256,21 +266,30 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
         _cairo_gl_texture_set_extend (ctx, ctx->tex_target, operand->gradient.extend);
         _cairo_gl_texture_set_filter (ctx, ctx->tex_target, CAIRO_FILTER_BILINEAR);
 
-       dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
-                                      GL_FLOAT, GL_FALSE, vertex_size,
-                                      ctx->vb + vertex_offset);
-       dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
+       if (! operand->gradient.texgen) {
+           dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
+                                          GL_FLOAT, GL_FALSE, vertex_size,
+                                          ctx->vb + vertex_offset);
+           dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
+       }
        break;
     }
 }
 
 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_COLOR_ATTRIB_INDEX);
+       ctx->spans = FALSE;
+       return;
+    }
+
     dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
                                   GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
                                   ctx->vb + vertex_offset);
@@ -488,8 +507,8 @@ _scissor_to_doubles (cairo_gl_surface_t     *surface,
     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);
@@ -542,19 +561,34 @@ _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
        goto disable_stencil_buffer_and_return;
     }
 
-    /* If we cannot reduce the clip to a rectangular region,
-       we clip using the stencil buffer. */
-    glDisable (GL_SCISSOR_TEST);
-
     if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
        status = CAIRO_INT_STATUS_UNSUPPORTED;
        goto disable_stencil_buffer_and_return;
     }
 
+    /* The clip is not rectangular, so use the stencil buffer. */
     glDepthMask (GL_TRUE);
     glEnable (GL_STENCIL_TEST);
+    glDisable (GL_SCISSOR_TEST);
+
+    /* Texture surfaces have private depth/stencil buffers, so we can
+     * rely on any previous clip being cached there. */
+    if (_cairo_gl_surface_is_texture (setup->dst)) {
+       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));
+       setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
+    }
+
     glClearStencil (0);
     glClear (GL_STENCIL_BUFFER_BIT);
+    glDisable (GL_SCISSOR_TEST);
+
     glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
     glStencilFunc (GL_EQUAL, 1, 0xffffffff);
     glColorMask (0, 0, 0, 0);
@@ -572,6 +606,7 @@ _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);
@@ -587,54 +622,53 @@ _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
                                    cairo_gl_context_t *ctx,
                                    int vertex_size)
 {
+    cairo_bool_t clip_changing = TRUE;
+    cairo_bool_t clip_region_changing = TRUE;
+
+    if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region)
+       goto disable_all_clipping;
 
+    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) ||
-        ! _cairo_clip_equal (ctx->clip, setup->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);
-    _cairo_clip_destroy (ctx->clip);
-    ctx->clip = _cairo_clip_copy (setup->clip);
-
     assert (!setup->clip_region || !setup->clip);
 
-    if (ctx->clip_region) {
-       _disable_stencil_buffer ();
-       glEnable (GL_SCISSOR_TEST);
-       return CAIRO_INT_STATUS_SUCCESS;
+    /* 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)
-       return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
-                                                          vertex_size);
+    /* 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);
+disable_all_clipping:
     _disable_stencil_buffer ();
     glDisable (GL_SCISSOR_TEST);
     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;
-
-    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);
-
-    glEnable (GL_BLEND);
+    cairo_bool_t component_alpha;
 
     component_alpha =
        setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
@@ -642,62 +676,81 @@ _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
 
     /* 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.type);
-    mask_size = _cairo_gl_operand_get_vertex_size (setup->mask.type);
+    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_COLOR_ATTRIB_INDEX);
+
+    _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size,
+                                  dst_size + src_size + mask_size);
 
     _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);
+    glEnable (GL_BLEND);
+    _cairo_gl_set_operands_and_operator (setup, ctx);
+
+    status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
     if (unlikely (status))
        goto FAIL;
 
@@ -710,13 +763,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)
 {
@@ -774,7 +820,7 @@ _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);
        _cairo_gl_composite_draw_triangles (ctx, count);
     }
 }
@@ -824,9 +870,7 @@ _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
 
 static inline void
 _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
-                                 GLfloat x,
-                                 GLfloat y,
-                                 uint8_t alpha)
+                                GLfloat x, GLfloat y)
 {
     GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
 
@@ -836,59 +880,177 @@ _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
     _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) {
-       union fi {
-           float f;
-           GLbyte bytes[4];
-       } fi;
-
-       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
+_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_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
+    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK  ], &vb, x, y);
+
+    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 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)
 {
     _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) {
+           switch (ctx->operands[CAIRO_GL_TEX_MASK].type) {
+           default:
+           case CAIRO_GL_OPERAND_COUNT:
+                   ASSERT_NOT_REACHED;
+           case CAIRO_GL_OPERAND_NONE:
+           case CAIRO_GL_OPERAND_CONSTANT:
+                   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:
+                   if (!ctx->operands[CAIRO_GL_TEX_MASK].gradient.texgen)
+                           return _cairo_gl_composite_emit_span;
+                   break;
+
+           case CAIRO_GL_OPERAND_TEXTURE:
+                   if (!ctx->operands[CAIRO_GL_TEX_MASK].texture.texgen)
+                           return _cairo_gl_composite_emit_span;
+                   break;
+           }
+    }
+
+    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:
+       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:
+       if (!ctx->operands[CAIRO_GL_TEX_SOURCE].gradient.texgen)
+               return _cairo_gl_composite_emit_span;
+       break;
+
+    case CAIRO_GL_OPERAND_TEXTURE:
+       if (!ctx->operands[CAIRO_GL_TEX_SOURCE].texture.texgen)
+               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);
+    return _cairo_gl_composite_emit_solid_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];
 
@@ -903,16 +1065,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)
 {
     _cairo_gl_composite_prepare_buffer (ctx, 6,
                                        CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
@@ -926,6 +1084,54 @@ _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:
+       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)
 {
@@ -934,13 +1140,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 &&
@@ -951,8 +1154,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;
@@ -1005,14 +1226,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);
 }
@@ -1025,8 +1246,8 @@ _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);
 }
index 9cb0c21..22297b3 100644 (file)
@@ -164,6 +164,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)
 {
@@ -173,6 +189,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.
@@ -195,7 +214,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;
@@ -206,49 +225,58 @@ _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 (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);
+    }
+#endif
+
     ctx->supports_msaa = ctx->num_samples > 1;
     if (ctx->num_samples > MAX_MSAA_SAMPLES)
        ctx->num_samples = MAX_MSAA_SAMPLES;
@@ -321,7 +349,7 @@ _get_depth_stencil_format (cairo_gl_context_t *ctx)
 
 #if CAIRO_HAS_GLESV2_SURFACE
     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
-       return GL_DEPTH24_STENCIL8;
+       return GL_DEPTH24_STENCIL8_OES;
 #endif
 
 #if CAIRO_HAS_GL_SURFACE
@@ -688,6 +716,7 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
            glDisable(GL_MULTISAMPLE);
 #endif
 
+        surface->msaa_active = multisampling;
         ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
 
 #if CAIRO_HAS_GL_SURFACE
index 0c5dc39..cabf76f 100644 (file)
@@ -53,7 +53,7 @@ typedef struct _cairo_gl_dispatch_entry {
                                   offsetof(cairo_gl_dispatch_t, name) }
 #define DISPATCH_ENTRY_ARB_OES(name) { { "gl"#name, "gl"#name"ARB", "gl"#name"OES" }, \
                                       offsetof(cairo_gl_dispatch_t, name) }
-#define DISPATCH_ENTRY_EXT_EXT(name) { { "gl"#name, "gl"#name"EXT", "gl"#name"EXT" }, \
+#define DISPATCH_ENTRY_EXT_IMG(name) { { "gl"#name, "gl"#name"EXT", "gl"#name"IMG" }, \
                                       offsetof(cairo_gl_dispatch_t, name) }
 #define DISPATCH_ENTRY_CUSTOM(name, name2) { { "gl"#name, "gl"#name2, "gl"#name }, \
                                             offsetof(cairo_gl_dispatch_t, name)}
@@ -117,8 +117,12 @@ cairo_private cairo_gl_dispatch_entry_t dispatch_fbo_entries[] = {
     DISPATCH_ENTRY_EXT (FramebufferRenderbuffer),
     DISPATCH_ENTRY_EXT (DeleteRenderbuffers),
     DISPATCH_ENTRY_EXT (BlitFramebuffer),
-    DISPATCH_ENTRY_EXT_EXT (RenderbufferStorageMultisample),
-    DISPATCH_ENTRY_EXT_EXT (FramebufferTexture2DMultisample),
+    DISPATCH_ENTRY_LAST
+};
+
+cairo_private cairo_gl_dispatch_entry_t dispatch_multisampling_entries[] = {
+    DISPATCH_ENTRY_EXT_IMG (RenderbufferStorageMultisample),
+    DISPATCH_ENTRY_EXT_IMG (FramebufferTexture2DMultisample),
     DISPATCH_ENTRY_LAST
 };
 
index 5bffddd..76c3115 100644 (file)
@@ -205,6 +205,27 @@ _cairo_gl_dispatch_init_fbo (cairo_gl_dispatch_t *dispatch,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_status_t
+_cairo_gl_dispatch_init_multisampling (cairo_gl_dispatch_t *dispatch,
+                                      cairo_gl_get_proc_addr_func_t get_proc_addr,
+                                      int gl_version,
+                                      cairo_gl_flavor_t gl_flavor)
+{
+    /* 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"))
+           dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
+       else if (_cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture"))
+           dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
+    }
+    _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
+                                    dispatch_multisampling_entries,
+                                    dispatch_name);
+    return CAIRO_STATUS_SUCCESS;
+}
+
 cairo_status_t
 _cairo_gl_dispatch_init (cairo_gl_dispatch_t *dispatch,
                         cairo_gl_get_proc_addr_func_t get_proc_addr)
@@ -231,5 +252,10 @@ _cairo_gl_dispatch_init (cairo_gl_dispatch_t *dispatch,
     if (status != CAIRO_STATUS_SUCCESS)
        return status;
 
+    status = _cairo_gl_dispatch_init_multisampling (dispatch, get_proc_addr,
+                                                   gl_version, gl_flavor);
+    if (status != CAIRO_STATUS_SUCCESS)
+       return status;
+
     return CAIRO_STATUS_SUCCESS;
 }
index 431f5ee..34b5d72 100644 (file)
@@ -134,7 +134,7 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
     status = _cairo_gl_surface_draw_image (cache->surface, glyph_surface,
                                            0, 0,
                                            glyph_surface->width, glyph_surface->height,
-                                           node->x, node->y);
+                                           node->x, node->y, FALSE);
     if (unlikely (status))
        return status;
 
@@ -199,16 +199,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 (&ctx->base,
-                                           content,
-                                           GLYPH_CACHE_WIDTH,
-                                           GLYPH_CACHE_HEIGHT);
-        if (unlikely (surface->status))
-            return surface->status;
+       surface = _cairo_gl_surface_create_scratch_for_caching (ctx,
+                                                               content,
+                                                               GLYPH_CACHE_WIDTH,
+                                                               GLYPH_CACHE_HEIGHT);
+       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 =
@@ -231,6 +231,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;
@@ -294,6 +295,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) {
@@ -329,10 +332,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;
index 1c1f972..ac32921 100644 (file)
@@ -328,6 +328,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);
     }
index 35715d3..28001fe 100644 (file)
@@ -45,6 +45,7 @@
 #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"
 
 static cairo_bool_t
@@ -153,18 +154,23 @@ _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)
+static cairo_int_status_t
+_clip_to_traps (cairo_clip_t *clip,
+               cairo_traps_t *traps)
 {
     cairo_int_status_t status;
-    cairo_traps_t traps;
-
     cairo_polygon_t polygon;
     cairo_antialias_t antialias;
     cairo_fill_rule_t fill_rule;
 
+    _cairo_traps_init (traps);
+
+    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);
+    }
+
     status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias);
     if (unlikely (status))
        return status;
@@ -180,14 +186,26 @@ _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
      * option.
      */
 
-    _cairo_traps_init (&traps);
-    status = _cairo_bentley_ottmann_tessellate_polygon (&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);
@@ -286,6 +304,97 @@ _cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
     _cairo_gl_composite_set_clip (setup, composite->clip);
 }
 
+/* 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
+_cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compositor,
+                                               cairo_composite_rectangles_t *composite)
+{
+    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_clip_t *clip = composite->clip;
+    cairo_traps_t 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))
+       return status;
+    status = _cairo_gl_composite_set_source (&setup,
+                                            &composite->mask_pattern.base,
+                                            &composite->mask_sample_area,
+                                            &composite->bounded,
+                                            FALSE);
+    if (unlikely (status))
+       goto finish;
+    _cairo_gl_composite_set_multisample (&setup);
+    status = _cairo_gl_composite_begin (&setup, &ctx);
+    if (unlikely (status))
+       goto finish;
+
+    if (! clip)
+       status = _draw_int_rect (ctx, &setup, &composite->bounded);
+    else
+       status = _draw_traps (ctx, &setup, &traps);
+
+    /* Now draw the second pass. */
+    _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD,
+                                     FALSE /* assume_component_alpha */);
+    if (unlikely (status))
+        goto finish;
+    status = _cairo_gl_composite_set_source (&setup,
+                                            &composite->source_pattern.base,
+                                            &composite->source_sample_area,
+                                            &composite->bounded,
+                                            FALSE);
+    if (unlikely (status))
+       goto finish;
+    status = _cairo_gl_composite_set_mask (&setup,
+                                          &composite->mask_pattern.base,
+                                          &composite->source_sample_area,
+                                          &composite->bounded,
+                                          FALSE);
+    if (unlikely (status))
+       goto finish;
+    status = _cairo_gl_set_operands_and_operator (&setup, ctx);
+    if (unlikely (status))
+       goto finish;
+
+    if (! clip)
+       status = _draw_int_rect (ctx, &setup, &composite->bounded);
+    else
+       status = _draw_traps (ctx, &setup, &traps);
+
+finish:
+    _cairo_gl_composite_fini (&setup);
+    if (ctx)
+       status = _cairo_gl_context_release (ctx, status);
+    if (clip)
+       _cairo_traps_fini (&traps);
+
+    return status;
+}
+
 static cairo_int_status_t
 _cairo_gl_msaa_compositor_mask (const cairo_compositor_t       *compositor,
                                cairo_composite_rectangles_t    *composite)
@@ -295,10 +404,15 @@ _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_clip_t *clip = composite->clip;
 
     if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT))
        return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    if (composite->op == CAIRO_OPERATOR_CLEAR &&
+       composite->original_mask_pattern != NULL)
+       return CAIRO_INT_STATUS_UNSUPPORTED;
+
     /* GL compositing operators cannot properly represent a mask operation
        using the SOURCE compositing operator in one pass. This only matters if
        there actually is a mask (there isn't in a paint operation) and if the
@@ -308,12 +422,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
-           return CAIRO_INT_STATUS_UNSUPPORTED;
+       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)) {
@@ -354,7 +469,8 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t    *compositor,
     status = _cairo_gl_composite_set_source (&setup,
                                             &composite->source_pattern.base,
                                             &composite->source_sample_area,
-                                            &composite->bounded);
+                                            &composite->bounded,
+                                            FALSE);
     if (unlikely (status))
        goto finish;
 
@@ -362,20 +478,24 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t  *compositor,
        status = _cairo_gl_composite_set_mask (&setup,
                                               &composite->mask_pattern.base,
                                               &composite->mask_sample_area,
-                                              &composite->bounded);
+                                              &composite->bounded,
+                                              FALSE);
     }
     if (unlikely (status))
        goto finish;
 
-    _cairo_gl_msaa_compositor_set_clip (composite, &setup);
-
     /* 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;
 
-    _draw_int_rect (ctx, &setup, &composite->bounded);
+    if (! clip)
+       status = _draw_int_rect (ctx, &setup, &composite->bounded);
+    else
+       status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, clip);
 
 finish:
     _cairo_gl_composite_fini (&setup);
@@ -424,10 +544,15 @@ _stroke_shaper_add_quad (void                     *closure,
 }
 
 static cairo_int_status_t
-_prevent_overlapping_drawing (cairo_gl_context_t *ctx,
-                             cairo_gl_composite_t *setup,
-                             cairo_composite_rectangles_t *composite)
+_prevent_overlapping_strokes (cairo_gl_context_t               *ctx,
+                             cairo_gl_composite_t              *setup,
+                             cairo_composite_rectangles_t      *composite,
+                             const cairo_path_fixed_t          *path,
+                             const cairo_stroke_style_t        *style,
+                             const cairo_matrix_t              *ctm)
 {
+    cairo_rectangle_int_t stroke_extents;
+
     if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
        return CAIRO_INT_STATUS_UNSUPPORTED;
 
@@ -436,13 +561,33 @@ _prevent_overlapping_drawing (cairo_gl_context_t *ctx,
        return CAIRO_INT_STATUS_SUCCESS;
 
    if (glIsEnabled (GL_STENCIL_TEST) == FALSE) {
+       cairo_bool_t scissor_was_enabled;
+
+       /* In case we have pending operations we have to flush before
+         adding the stencil buffer. */
+       _cairo_gl_composite_flush (ctx);
+
        /* Enable the stencil buffer, even if we are not using it for clipping,
           so we can use it below to prevent overlapping shapes. We initialize
           it all to one here which represents infinite clip. */
        glDepthMask (GL_TRUE);
        glEnable (GL_STENCIL_TEST);
+
+       /* 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. */
+       scissor_was_enabled = glIsEnabled (GL_SCISSOR_TEST);
+       if (! scissor_was_enabled) {
+           _cairo_path_fixed_approximate_stroke_extents (path, style, ctm,
+                                                         &stroke_extents);
+           _cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents);
+       }
        glClearStencil (1);
        glClear (GL_STENCIL_BUFFER_BIT);
+       if (! scissor_was_enabled)
+           glDisable (GL_SCISSOR_TEST);
+
        glStencilFunc (GL_EQUAL, 1, 1);
     }
 
@@ -450,6 +595,10 @@ _prevent_overlapping_drawing (cairo_gl_context_t *ctx,
        be drawn there until the stencil buffer is reset or the stencil test
        is disabled. */
     glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO);
+
+    _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
+    setup->dst->clip_on_stencil_buffer = NULL;
+
     return CAIRO_INT_STATUS_SUCCESS;
 }
 
@@ -534,18 +683,21 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t        *compositor,
     status = _cairo_gl_composite_set_source (&info.setup,
                                             &composite->source_pattern.base,
                                             &composite->source_sample_area,
-                                            &composite->bounded);
+                                            &composite->bounded,
+                                            FALSE);
     if (unlikely (status))
        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;
 
-    status = _prevent_overlapping_drawing (info.ctx, &info.setup, composite);
+    status = _prevent_overlapping_strokes (info.ctx, &info.setup,
+                                          composite, path, style, ctm);
     if (unlikely (status))
        goto finish;
 
@@ -571,6 +723,29 @@ finish:
 }
 
 static cairo_int_status_t
+_draw_simple_quad_path (cairo_gl_context_t *ctx,
+                       cairo_gl_composite_t *setup,
+                       const cairo_path_fixed_t *path)
+{
+    cairo_point_t triangle[3];
+    cairo_int_status_t 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;
+
+    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
 _cairo_gl_msaa_compositor_fill (const cairo_compositor_t       *compositor,
                                cairo_composite_rectangles_t    *composite,
                                const cairo_path_fixed_t        *path,
@@ -583,6 +758,7 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t    *compositor,
     cairo_gl_context_t *ctx = NULL;
     cairo_int_status_t status;
     cairo_traps_t traps;
+    cairo_bool_t draw_path_with_traps;
 
     if (! can_use_msaa_compositor (dst, antialias))
        return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -608,10 +784,14 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t  *compositor,
        return _paint_back_unbounded_surface (compositor, composite, surface);
     }
 
-    _cairo_traps_init (&traps);
-    status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
-    if (unlikely (status))
-       goto cleanup_traps;
+    draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path);
+
+    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,
@@ -623,18 +803,23 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t  *compositor,
     status = _cairo_gl_composite_set_source (&setup,
                                             &composite->source_pattern.base,
                                             &composite->source_sample_area,
-                                            &composite->bounded);
+                                            &composite->bounded,
+                                            FALSE);
     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;
 
@@ -645,7 +830,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;
 }
@@ -669,6 +855,9 @@ _cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t  *compositor,
     if (! dst->supports_stencil)
        return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    if (composite->op == CAIRO_OPERATOR_CLEAR)
+       return CAIRO_INT_STATUS_UNSUPPORTED;
+
     if (composite->is_bounded == FALSE) {
        cairo_surface_t* surface = _prepare_unbounded_surface (dst);
 
@@ -709,7 +898,8 @@ _cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t  *compositor,
     info.font = scaled_font;
     info.glyphs = glyphs;
     info.num_glyphs = num_glyphs;
-    info.use_mask = overlap || ! composite->is_bounded;
+    info.use_mask = overlap || ! composite->is_bounded ||
+                   composite->op == CAIRO_OPERATOR_SOURCE;
     info.extents = composite->bounded;
 
     _cairo_scaled_font_freeze_cache (scaled_font);
index ee6c08e..f99400c 100644 (file)
@@ -107,7 +107,8 @@ _cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand,
                                         const cairo_pattern_t *_src,
                                         cairo_gl_surface_t *dst,
                                         const cairo_rectangle_int_t *sample,
-                                        const cairo_rectangle_int_t *extents)
+                                        const cairo_rectangle_int_t *extents,
+                                        cairo_bool_t use_texgen)
 {
     const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
     cairo_surface_pattern_t local_pattern;
@@ -185,6 +186,8 @@ _cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand,
     attributes->extend = src->base.extend;
     attributes->filter = src->base.filter;
     attributes->has_component_alpha = src->base.has_component_alpha;
+
+    operand->texture.texgen = use_texgen;
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -193,7 +196,8 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
                                   const cairo_pattern_t *_src,
                                   cairo_gl_surface_t *dst,
                                   const cairo_rectangle_int_t *sample,
-                                  const cairo_rectangle_int_t *extents)
+                                  const cairo_rectangle_int_t *extents,
+                                  cairo_bool_t use_texgen)
 {
     const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
     cairo_surface_subsurface_t *sub;
@@ -208,7 +212,8 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
        sample->y + sample->height > sub->extents.height)
     {
        return _cairo_gl_subsurface_clone_operand_init (operand, _src,
-                                                       dst, sample, extents);
+                                                       dst, sample, extents,
+                                                       use_texgen);
     }
 
     surface = (cairo_gl_surface_t *) sub->target;
@@ -239,6 +244,8 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
     attributes->extend = src->base.extend;
     attributes->filter = src->base.filter;
     attributes->has_component_alpha = src->base.has_component_alpha;
+
+    operand->texture.texgen = use_texgen;
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -247,7 +254,8 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
                                const cairo_pattern_t *_src,
                                cairo_gl_surface_t *dst,
                                const cairo_rectangle_int_t *sample,
-                               const cairo_rectangle_int_t *extents)
+                               const cairo_rectangle_int_t *extents,
+                               cairo_bool_t use_texgen)
 {
     const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
     cairo_gl_surface_t *surface;
@@ -261,7 +269,8 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
     if (surface->base.backend->type != CAIRO_SURFACE_TYPE_GL) {
        if (_cairo_surface_is_subsurface (&surface->base))
            return _cairo_gl_subsurface_operand_init (operand, _src, dst,
-                                                     sample, extents);
+                                                     sample, extents,
+                                                     use_texgen);
 
        return CAIRO_INT_STATUS_UNSUPPORTED;
     }
@@ -269,6 +278,9 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
     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))
+       return CAIRO_INT_STATUS_UNSUPPORTED;
+
     status = _resolve_multisampling (surface);
     if (unlikely (status))
        return status;
@@ -283,6 +295,8 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
     attributes->extend = src->base.extend;
     attributes->filter = src->base.filter;
     attributes->has_component_alpha = src->base.has_component_alpha;
+
+    operand->texture.texgen = use_texgen;
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -389,7 +403,8 @@ _cairo_gl_operand_translate (cairo_gl_operand_t *operand,
 static cairo_status_t
 _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
                                  const cairo_pattern_t *pattern,
-                                cairo_gl_surface_t *dst)
+                                cairo_gl_surface_t *dst,
+                                cairo_bool_t use_texgen)
 {
     const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
     cairo_status_t status;
@@ -472,6 +487,7 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
     }
 
     operand->gradient.extend = pattern->extend;
+    operand->gradient.texgen = use_texgen;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -531,7 +547,8 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
                        const cairo_pattern_t *pattern,
                        cairo_gl_surface_t *dst,
                        const cairo_rectangle_int_t *sample,
-                       const cairo_rectangle_int_t *extents)
+                       const cairo_rectangle_int_t *extents,
+                       cairo_bool_t use_texgen)
 {
     cairo_int_status_t status;
 
@@ -543,7 +560,7 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
        return CAIRO_STATUS_SUCCESS;
     case CAIRO_PATTERN_TYPE_SURFACE:
        status = _cairo_gl_surface_operand_init (operand, pattern, dst,
-                                                sample, extents);
+                                                sample, extents, use_texgen);
        if (status == CAIRO_INT_STATUS_UNSUPPORTED)
            break;
 
@@ -551,7 +568,8 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
 
     case CAIRO_PATTERN_TYPE_LINEAR:
     case CAIRO_PATTERN_TYPE_RADIAL:
-       status = _cairo_gl_gradient_operand_init (operand, pattern, dst);
+       status = _cairo_gl_gradient_operand_init (operand, pattern, dst,
+                                                 use_texgen);
        if (status == CAIRO_INT_STATUS_UNSUPPORTED)
            break;
 
@@ -631,6 +649,7 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
     char uniform_name[50];
     char *custom_part;
     static const char *names[] = { "source", "mask" };
+    const cairo_matrix_t *texgen = NULL;
 
     strcpy (uniform_name, names[tex_unit]);
     custom_part = uniform_name + strlen (names[tex_unit]);
@@ -640,7 +659,8 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
     case CAIRO_GL_OPERAND_COUNT:
         ASSERT_NOT_REACHED;
     case CAIRO_GL_OPERAND_NONE:
-        break;
+       return;
+
     case CAIRO_GL_OPERAND_CONSTANT:
         strcpy (custom_part, "_constant");
        _cairo_gl_shader_bind_vec4 (ctx,
@@ -649,7 +669,8 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
                                     operand->constant.color[1],
                                     operand->constant.color[2],
                                     operand->constant.color[3]);
-        break;
+       return;
+
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
        strcpy (custom_part, "_a");
@@ -692,7 +713,21 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
            strcpy (custom_part, "_texdims");
            _cairo_gl_shader_bind_vec2 (ctx, uniform_name, width, height);
        }
-        break;
+       break;
+    }
+
+    if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
+           if (operand->texture.texgen)
+                   texgen = &operand->texture.attributes.matrix;
+    } else {
+           if (operand->gradient.texgen)
+                   texgen = &operand->gradient.m;
+    }
+    if (texgen) {
+           char name[20];
+
+           sprintf (name, "%s_texgen", names[tex_unit]);
+           _cairo_gl_shader_bind_matrix(ctx, name, texgen);
     }
 }
 
@@ -735,9 +770,9 @@ _cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
 }
 
 unsigned int
-_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
+_cairo_gl_operand_get_vertex_size (const cairo_gl_operand_t *operand)
 {
-    switch (type) {
+    switch (operand->type) {
     default:
     case CAIRO_GL_OPERAND_COUNT:
         ASSERT_NOT_REACHED;
@@ -745,11 +780,12 @@ _cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
     case CAIRO_GL_OPERAND_CONSTANT:
         return 0;
     case CAIRO_GL_OPERAND_TEXTURE:
+        return operand->texture.texgen ? 0 : 2 * sizeof (GLfloat);
     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:
-        return 2 * sizeof (GLfloat);
+        return operand->gradient.texgen ? 0 : 2 * sizeof (GLfloat);
     }
 }
 
@@ -770,7 +806,7 @@ _cairo_gl_operand_emit (cairo_gl_operand_t *operand,
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-        {
+       if (! operand->gradient.texgen) {
            double s = x;
            double t = y;
 
@@ -781,7 +817,7 @@ _cairo_gl_operand_emit (cairo_gl_operand_t *operand,
         }
        break;
     case CAIRO_GL_OPERAND_TEXTURE:
-        {
+       if (! operand->texture.texgen) {
             cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
             double s = x;
             double t = y;
index d6b0554..5c9193d 100644 (file)
  * 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)
 
 typedef struct _cairo_gl_surface cairo_gl_surface_t;
 
@@ -134,6 +136,7 @@ typedef struct cairo_gl_operand {
            cairo_gl_surface_t *surface;
            cairo_gl_surface_t *owns_surface;
            cairo_surface_attributes_t attributes;
+           int texgen;
        } texture;
        struct {
            GLfloat color[4];
@@ -144,6 +147,7 @@ typedef struct cairo_gl_operand {
            cairo_circle_double_t circle_d;
            double radius_0, a;
            cairo_extend_t extend;
+           int texgen;
        } gradient;
     };
     unsigned int vertex_offset;
@@ -175,6 +179,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;
@@ -209,6 +214,7 @@ typedef enum cairo_gl_shader_in {
 typedef enum cairo_gl_var_type {
   CAIRO_GL_VAR_NONE,
   CAIRO_GL_VAR_TEXCOORDS,
+  CAIRO_GL_VAR_TEXGEN,
 } cairo_gl_var_type_t;
 
 typedef enum cairo_gl_primitive_type {
@@ -216,8 +222,23 @@ typedef enum cairo_gl_primitive_type {
     CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS
 } cairo_gl_primitive_type_t;
 
-#define cairo_gl_var_type_hash(src,mask,spans,dest) ((spans) << 3) | ((mask) << 2 | (src << 1) | (dest))
-#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_TEXCOORDS << 3) | (CAIRO_GL_VAR_TEXCOORDS << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS)
+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,spans,dest) ((spans) << 5) | ((mask) << 3 | (src << 1) | (dest))
+#define CAIRO_GL_VAR_TYPE_MAX (1 << 6)
 
 typedef void (*cairo_gl_generic_func_t)(void);
 typedef cairo_gl_generic_func_t (*cairo_gl_get_proc_addr_func_t)(const char *procname);
@@ -316,7 +337,7 @@ struct _cairo_gl_context {
 
     cairo_bool_t has_shader_support;
 
-    GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX + 1];
+    GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX];
     cairo_gl_shader_t fill_rectangles_shader;
     cairo_cache_t shaders;
 
@@ -348,6 +369,7 @@ 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;
 
@@ -369,6 +391,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 {
@@ -414,7 +437,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
                              cairo_image_surface_t *src,
                              int src_x, int src_y,
                              int width, int height,
-                             int dst_x, int dst_y);
+                             int dst_x, int dst_y,
+                             cairo_bool_t force_flush);
 
 static cairo_always_inline cairo_bool_t
 _cairo_gl_device_has_glsl (cairo_device_t *device)
@@ -473,6 +497,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);
@@ -493,6 +531,11 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
 cairo_private void
 _cairo_gl_composite_fini (cairo_gl_composite_t *setup);
 
+cairo_private 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);
@@ -503,9 +546,10 @@ _cairo_gl_composite_set_clip(cairo_gl_composite_t *setup,
 
 cairo_private cairo_int_status_t
 _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
-                               const cairo_pattern_t *pattern,
+                               const cairo_pattern_t *pattern,
                                const cairo_rectangle_int_t *sample,
-                               const cairo_rectangle_int_t *extents);
+                               const cairo_rectangle_int_t *extents,
+                               cairo_bool_t use_texgen);
 
 cairo_private void
 _cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
@@ -519,7 +563,8 @@ cairo_private cairo_int_status_t
 _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
                              const cairo_pattern_t *pattern,
                              const cairo_rectangle_int_t *sample,
-                             const cairo_rectangle_int_t *extents);
+                             const cairo_rectangle_int_t *extents,
+                             cairo_bool_t use_texgen);
 
 cairo_private void
 _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
@@ -528,33 +573,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_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);
@@ -643,7 +671,7 @@ _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
 cairo_private void
 _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
                              const char *name,
-                             cairo_matrix_t* m);
+                             const cairo_matrix_t* m);
 
 cairo_private void
 _cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
@@ -675,7 +703,8 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
                        const cairo_pattern_t *pattern,
                        cairo_gl_surface_t *dst,
                        const cairo_rectangle_int_t *sample,
-                       const cairo_rectangle_int_t *extents);
+                       const cairo_rectangle_int_t *extents,
+                       cairo_bool_t use_texgen);
 
 cairo_private void
 _cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
@@ -691,7 +720,7 @@ cairo_private cairo_extend_t
 _cairo_gl_operand_get_extend (cairo_gl_operand_t *operand);
 
 cairo_private unsigned int
-_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type);
+_cairo_gl_operand_get_vertex_size (const cairo_gl_operand_t *operand);
 
 cairo_private cairo_bool_t
 _cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
@@ -763,6 +792,12 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
                                  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,
                             const cairo_pattern_t *pattern,
                             cairo_bool_t is_mask,
@@ -778,6 +813,10 @@ _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
 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)
 {
index 41672d6..0bc4e5e 100644 (file)
@@ -55,10 +55,13 @@ _cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
 typedef struct _cairo_shader_cache_entry {
     cairo_cache_entry_t base;
 
+    unsigned vertex;
+
     cairo_gl_operand_type_t src;
     cairo_gl_operand_type_t mask;
     cairo_gl_operand_type_t dest;
     cairo_bool_t use_coverage;
+
     cairo_gl_shader_in_t in;
     GLint src_gl_filter;
     cairo_bool_t src_border_fade;
@@ -79,13 +82,14 @@ _cairo_gl_shader_cache_equal_desktop (const void *key_a, const void *key_b)
     cairo_bool_t both_have_npot_repeat =
        a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
 
-    return a->src  == b->src  &&
-           a->mask == b->mask &&
-           a->dest == b->dest &&
-          a->use_coverage == b->use_coverage &&
-           a->in   == b->in &&
-          (both_have_npot_repeat || a->src_extend == b->src_extend) &&
-          (both_have_npot_repeat || a->mask_extend == b->mask_extend);
+    return (a->vertex == b->vertex &&
+           a->src  == b->src  &&
+           a->mask == b->mask &&
+           a->dest == b->dest &&
+           a->use_coverage == b->use_coverage &&
+           a->in   == b->in &&
+           (both_have_npot_repeat || a->src_extend == b->src_extend) &&
+           (both_have_npot_repeat || a->mask_extend == b->mask_extend));
 }
 
 /*
@@ -101,23 +105,24 @@ _cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b)
     cairo_bool_t both_have_npot_repeat =
        a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
 
-    return a->src  == b->src  &&
-          a->mask == b->mask &&
-          a->dest == b->dest &&
-          a->use_coverage == b->use_coverage &&
-          a->in   == b->in   &&
-          a->src_gl_filter == b->src_gl_filter &&
-          a->src_border_fade == b->src_border_fade &&
-          (both_have_npot_repeat || a->src_extend == b->src_extend) &&
-          a->mask_gl_filter == b->mask_gl_filter &&
-          a->mask_border_fade == b->mask_border_fade &&
-          (both_have_npot_repeat || a->mask_extend == b->mask_extend);
+    return (a->vertex && b->vertex &&
+           a->src  == b->src  &&
+           a->mask == b->mask &&
+           a->dest == b->dest &&
+           a->use_coverage == b->use_coverage &&
+           a->in   == b->in   &&
+           a->src_gl_filter == b->src_gl_filter &&
+           a->src_border_fade == b->src_border_fade &&
+           (both_have_npot_repeat || a->src_extend == b->src_extend) &&
+           a->mask_gl_filter == b->mask_gl_filter &&
+           a->mask_border_fade == b->mask_border_fade &&
+           (both_have_npot_repeat || a->mask_extend == b->mask_extend));
 }
 
 static unsigned long
 _cairo_gl_shader_cache_hash (const cairo_shader_cache_entry_t *entry)
 {
-    return (entry->src << 24) | (entry->mask << 16) | (entry->dest << 8) | (entry->in << 1) | entry->use_coverage;
+    return ((entry->src << 24) | (entry->mask << 16) | (entry->dest << 8) | (entry->in << 1) | entry->use_coverage) ^ entry->vertex;
 }
 
 static void
@@ -215,9 +220,9 @@ _cairo_gl_shader_fini (cairo_gl_context_t *ctx,
 static const char *operand_names[] = { "source", "mask", "dest" };
 
 static cairo_gl_var_type_t
-cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
+cairo_gl_operand_get_var_type (cairo_gl_operand_t *operand)
 {
-    switch (type) {
+    switch (operand->type) {
     default:
     case CAIRO_GL_OPERAND_COUNT:
         ASSERT_NOT_REACHED;
@@ -228,8 +233,9 @@ cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+        return operand->gradient.texgen ? CAIRO_GL_VAR_TEXGEN : CAIRO_GL_VAR_TEXCOORDS;
     case CAIRO_GL_OPERAND_TEXTURE:
-        return CAIRO_GL_VAR_TEXCOORDS;
+        return operand->texture.texgen ? CAIRO_GL_VAR_TEXGEN : CAIRO_GL_VAR_TEXCOORDS;
     }
 }
 
@@ -245,7 +251,16 @@ cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
         break;
     case CAIRO_GL_VAR_TEXCOORDS:
         _cairo_output_stream_printf (stream,
+                                    "attribute vec4 MultiTexCoord%d;\n"
+                                     "varying vec2 %s_texcoords;\n",
+                                     name,
+                                     operand_names[name]);
+        break;
+    case CAIRO_GL_VAR_TEXGEN:
+        _cairo_output_stream_printf (stream,
+                                    "uniform mat3 %s_texgen;\n"
                                      "varying vec2 %s_texcoords;\n",
+                                     operand_names[name],
                                      operand_names[name]);
         break;
     }
@@ -266,6 +281,12 @@ cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
                                      "    %s_texcoords = MultiTexCoord%d.xy;\n",
                                      operand_names[name], name);
         break;
+
+    case CAIRO_GL_VAR_TEXGEN:
+        _cairo_output_stream_printf (stream,
+                                    "    %s_texcoords = (%s_texgen * Vertex.xyw).xy;\n",
+                                     operand_names[name], operand_names[name]);
+        break;
     }
 }
 
@@ -301,8 +322,6 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
     _cairo_output_stream_printf (stream,
                                 "attribute vec4 Vertex;\n"
                                 "attribute vec4 Color;\n"
-                                "attribute vec4 MultiTexCoord0;\n"
-                                "attribute vec4 MultiTexCoord1;\n"
                                 "uniform mat4 ModelViewProjectionMatrix;\n"
                                 "void main()\n"
                                 "{\n"
@@ -920,7 +939,8 @@ _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
 
 void
 _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
-                             const char *name, cairo_matrix_t* m)
+                             const char *name,
+                             const cairo_matrix_t* m)
 {
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
     GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
@@ -973,6 +993,12 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
     cairo_status_t status;
 
     lookup.ctx = ctx;
+
+    lookup.vertex = cairo_gl_var_type_hash (cairo_gl_operand_get_var_type (source),
+                                           cairo_gl_operand_get_var_type (mask),
+                                           use_coverage,
+                                           CAIRO_GL_VAR_NONE);
+
     lookup.src = source->type;
     lookup.mask = mask->type;
     lookup.dest = CAIRO_GL_OPERAND_NONE;
@@ -1016,8 +1042,8 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
     _cairo_gl_shader_init (&entry->shader);
     status = _cairo_gl_shader_compile_and_link (ctx,
                                                &entry->shader,
-                                               cairo_gl_operand_get_var_type (source->type),
-                                               cairo_gl_operand_get_var_type (mask->type),
+                                               cairo_gl_operand_get_var_type (source),
+                                               cairo_gl_operand_get_var_type (mask),
                                                use_coverage,
                                                fs_source);
     free (fs_source);
index 294f6f9..1223529 100644 (file)
@@ -81,7 +81,8 @@ _cairo_gl_pattern_to_source (cairo_surface_t *dst,
     *src_x = *src_y = 0;
     status = _cairo_gl_operand_init (&source->operand, pattern,
                                     (cairo_gl_surface_t *)dst,
-                                    sample, extents);
+                                    sample, extents,
+                                    FALSE);
     if (unlikely (status)) {
        cairo_surface_destroy (&source->base);
        return _cairo_surface_create_in_error (status);
index 62da1eb..4317ccd 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);
        }
     }
 }
@@ -303,7 +311,7 @@ draw_image_boxes (void *_dst,
            status = _cairo_gl_surface_draw_image (dst, image,
                                                   x + dx, y + dy,
                                                   w, h,
-                                                  x, y);
+                                                  x, y, TRUE);
            if (unlikely (status))
                return status;
        }
@@ -423,6 +431,13 @@ _cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t       *_r,
     cairo_operator_t op = composite->op;
     cairo_int_status_t status;
 
+    if (op == CAIRO_OPERATOR_SOURCE) {
+       if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
+                                       &composite->source_sample_area))
+           return CAIRO_INT_STATUS_UNSUPPORTED;
+       op = CAIRO_OPERATOR_OVER;
+    }
+
     /* XXX earlier! */
     if (op == CAIRO_OPERATOR_CLEAR) {
        source = &_cairo_pattern_white.base;
@@ -446,7 +461,8 @@ _cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t        *_r,
 
     status = _cairo_gl_composite_set_source (&r->setup, source,
                                             &composite->source_sample_area,
-                                            &composite->unbounded);
+                                            &composite->unbounded,
+                                            TRUE);
     if (unlikely (status))
         goto FAIL;
 
@@ -457,7 +473,8 @@ _cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t        *_r,
        status = _cairo_gl_composite_set_mask (&r->setup,
                                               &composite->mask_pattern.base,
                                               &composite->mask_sample_area,
-                                              &composite->unbounded);
+                                              &composite->unbounded,
+                                              TRUE);
        if (unlikely (status))
            goto FAIL;
     }
@@ -468,6 +485,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 c0ee79f..1d7515a 100644 (file)
@@ -424,11 +424,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)
+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;
@@ -456,8 +457,13 @@ _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. */
-       format = GL_RGBA;
+       /* 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;
        break;
     case CAIRO_CONTENT_COLOR:
        /* GL_RGB is almost what we want here -- sampling 1 alpha when
@@ -478,6 +484,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)
@@ -508,9 +532,36 @@ _cairo_gl_surface_clear (cairo_gl_surface_t  *surface,
     glClearColor (r, g, b, a);
     glClear (GL_COLOR_BUFFER_BIT);
 
+    if (a == 0)
+       surface->base.is_clear = 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,
@@ -538,16 +589,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);
+       _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);
@@ -740,7 +788,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);
+    surface = _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height);
 
     status = _cairo_gl_context_release (ctx, status);
     if (unlikely (status)) {
@@ -774,7 +822,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);
 
@@ -792,7 +840,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
                              cairo_image_surface_t *src,
                              int src_x, int src_y,
                              int width, int height,
-                             int dst_x, int dst_y)
+                             int dst_x, int dst_y,
+                             cairo_bool_t force_flush)
 {
     GLenum internal_format, format, type;
     cairo_bool_t has_alpha, needs_swap;
@@ -834,9 +883,11 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 
     cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
 
-    status = _cairo_gl_surface_flush (&dst->base, 0);
-    if (unlikely (status))
-       goto FAIL;
+    if (force_flush) {
+       status = _cairo_gl_surface_flush (&dst->base, 0);
+       if (unlikely (status))
+           goto FAIL;
+    }
 
     if (_cairo_gl_surface_is_texture (dst)) {
        void *data_start = src->data + src_y * src->stride + src_x * cpp;
@@ -903,7 +954,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
                                                src,
                                                src_x, src_y,
                                                width, height,
-                                               0, 0);
+                                               0, 0, force_flush);
         if (status == CAIRO_INT_STATUS_SUCCESS) {
             cairo_surface_pattern_t tmp_pattern;
            cairo_rectangle_int_t r;
@@ -999,6 +1050,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;
@@ -1020,25 +1076,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;
     }
@@ -1049,20 +1106,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.
@@ -1177,7 +1234,8 @@ _cairo_gl_surface_unmap_image (void                     *abstract_surface,
                                           0, 0,
                                           image->width, image->height,
                                           image->base.device_transform_inverse.x0,
-                                          image->base.device_transform_inverse.y0);
+                                          image->base.device_transform_inverse.y0,
+                                          TRUE);
 
     cairo_surface_finish (&image->base);
     cairo_surface_destroy (&image->base);
index a87fd16..548162b 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)
@@ -95,7 +96,8 @@ draw_image_boxes (void *_dst,
            status = _cairo_gl_surface_draw_image (dst, image,
                                                   x + dx, y + dy,
                                                   w, h,
-                                                  x, y);
+                                                  x, y,
+                                                  TRUE);
            if (unlikely (status))
                return status;
        }
@@ -109,6 +111,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 +120,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 +230,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 +303,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,
@@ -313,8 +346,10 @@ traps_to_operand (void *_dst,
                                           (cairo_image_surface_t *)image,
                                           0, 0,
                                           extents->width, extents->height,
-                                          0, 0);
+                                          0, 0,
+                                          TRUE);
     cairo_surface_destroy (image);
+
     if (unlikely (status))
        goto error;
 
@@ -325,7 +360,8 @@ traps_to_operand (void *_dst,
     pattern.base.extend = CAIRO_EXTEND_NONE;
     status = _cairo_gl_operand_init (operand, &pattern.base, _dst,
                                     &_cairo_unbounded_rectangle,
-                                    &_cairo_unbounded_rectangle);
+                                    &_cairo_unbounded_rectangle,
+                                    FALSE);
     _cairo_pattern_fini (&pattern.base);
 
     if (unlikely (status))
@@ -371,10 +407,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:
@@ -422,7 +458,8 @@ tristrip_to_surface (void *_dst,
                                           (cairo_image_surface_t *)image,
                                           0, 0,
                                           extents->width, extents->height,
-                                          0, 0);
+                                          0, 0,
+                                          TRUE);
     cairo_surface_destroy (image);
     if (unlikely (status)) {
        cairo_surface_destroy (mask);
@@ -467,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 47634f1..3761b90 100644 (file)
@@ -53,6 +53,9 @@ typedef struct _cairo_glx_context {
     Window dummy_window;
     GLXContext context;
 
+    GLXDrawable previous_drawable;
+    GLXContext previous_context;
+
     cairo_bool_t has_multithread_makecurrent;
 } cairo_glx_context_t;
 
@@ -62,19 +65,50 @@ typedef struct _cairo_glx_surface {
     Window win;
 } cairo_glx_surface_t;
 
+static cairo_bool_t
+_context_acquisition_changed_glx_state (cairo_glx_context_t *ctx,
+                                       GLXDrawable current_drawable)
+{
+    return ctx->previous_drawable != current_drawable ||
+          ctx->previous_context != ctx->context;
+}
+
+static GLXDrawable
+_glx_get_current_drawable (cairo_glx_context_t *ctx)
+{
+    if (ctx->base.current_target == NULL ||
+       _cairo_gl_surface_is_texture (ctx->base.current_target)) {
+       return ctx->dummy_window;
+    }
+
+    return ((cairo_glx_surface_t *) ctx->base.current_target)->win;
+}
+
+static void
+_glx_query_current_state (cairo_glx_context_t * ctx)
+{
+    ctx->previous_drawable = glXGetCurrentDrawable ();
+    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_context == None) {
+       ctx->previous_drawable = None;
+       ctx->previous_context = None;
+    }
+}
+
 static void
 _glx_acquire (void *abstract_ctx)
 {
     cairo_glx_context_t *ctx = abstract_ctx;
-    GLXDrawable current_drawable;
+    GLXDrawable current_drawable = _glx_get_current_drawable (ctx);
 
-    if (ctx->base.current_target == NULL ||
-        _cairo_gl_surface_is_texture (ctx->base.current_target)) {
-        current_drawable = ctx->dummy_window;
-    } else {
-        cairo_glx_surface_t *surface = (cairo_glx_surface_t *) ctx->base.current_target;
-        current_drawable = surface->win;
-    }
+    _glx_query_current_state (ctx);
+    if (!_context_acquisition_changed_glx_state (ctx, current_drawable))
+       return;
 
     glXMakeCurrent (ctx->display, current_drawable, ctx->context);
 }
@@ -94,8 +128,11 @@ _glx_release (void *abstract_ctx)
 {
     cairo_glx_context_t *ctx = abstract_ctx;
 
-    if (ctx->has_multithread_makecurrent || !ctx->base.thread_aware)
+    if (ctx->has_multithread_makecurrent || !ctx->base.thread_aware ||
+       !_context_acquisition_changed_glx_state (ctx,
+                                               _glx_get_current_drawable (ctx))) {
        return;
+    }
 
     glXMakeCurrent (ctx->display, None, None);
 }
@@ -118,11 +155,11 @@ _glx_destroy (void *abstract_ctx)
     if (ctx->dummy_window != None)
        XDestroyWindow (ctx->display, ctx->dummy_window);
 
-    glXMakeCurrent (ctx->display, 0, 0);
+    glXMakeCurrent (ctx->display, None, None);
 }
 
 static cairo_status_t
-_glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy)
+_glx_dummy_window (Display *dpy, GLXContext gl_ctx, Window *dummy)
 {
     int attr[3] = { GLX_FBCONFIG_ID, 0, None };
     GLXFBConfig *config;
@@ -181,14 +218,20 @@ cairo_glx_device_create (Display *dpy, GLXContext gl_ctx)
     Window dummy = None;
     const char *glx_extensions;
 
-    status = _glx_dummy_ctx (dpy, gl_ctx, &dummy);
-    if (unlikely (status))
-       return _cairo_gl_context_create_in_error (status);
-
     ctx = calloc (1, sizeof (cairo_glx_context_t));
     if (unlikely (ctx == NULL))
        return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
 
+    /* glx_dummy_window will call glXMakeCurrent, so we need to
+     *  query the current state of the context now. */
+    _glx_query_current_state (ctx);
+
+    status = _glx_dummy_window (dpy, gl_ctx, &dummy);
+    if (unlikely (status)) {
+       free (ctx);
+       return _cairo_gl_context_create_in_error (status);
+    }
+
     ctx->display = dpy;
     ctx->dummy_window = dummy;
     ctx->context = gl_ctx;
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 768e3a5..be3db98 100644 (file)
@@ -1538,6 +1538,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;
@@ -1546,7 +1547,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));
 
@@ -2186,7 +2188,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);
@@ -2206,7 +2208,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 {
@@ -2250,7 +2252,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;
@@ -2265,7 +2267,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;
@@ -2298,7 +2300,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);
@@ -2311,7 +2313,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 {
@@ -2344,7 +2346,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;
@@ -2365,7 +2367,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 {
@@ -2417,31 +2419,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)
 {
@@ -2453,10 +2535,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,
@@ -2491,7 +2573,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) {
@@ -2520,7 +2602,7 @@ _inplace_src_spans (void *abstract_renderer,
 #endif
            }
 
-           m = r->buf;
+           m = r->_buf;
            x0 = spans[1].x;
        } else {
            *m++ = spans[0].coverage;
@@ -2561,6 +2643,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,
@@ -2568,12 +2740,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;
@@ -2588,7 +2761,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;
@@ -2650,24 +2823,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) {
@@ -2677,9 +2852,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,
@@ -2688,19 +2860,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;
 }
 
@@ -2716,7 +2899,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;
@@ -2749,11 +2933,19 @@ span_renderer_init (cairo_abstract_span_renderer_t      *_r,
                op == CAIRO_OPERATOR_ADD)) {
        op = PIXMAN_OP_SRC;
     } else if (op == CAIRO_OPERATOR_SOURCE) {
+       if (_cairo_pattern_is_opaque (&composite->source_pattern.base,
+                                     &composite->source_sample_area))
+       {
+           op = PIXMAN_OP_OVER;
+       }
+       else
+       {
 #if PIXMAN_HAS_OP_LERP
-       op = PIXMAN_OP_LERP_SRC;
+           op = PIXMAN_OP_LERP_SRC;
 #else
-       return CAIRO_INT_STATUS_UNSUPPORTED;
+           return CAIRO_INT_STATUS_UNSUPPORTED;
 #endif
+       }
     } else {
        op = _pixman_operator (op);
     }
@@ -2801,7 +2993,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,
@@ -2813,7 +3005,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 6a159d8..8ca694c 100644 (file)
@@ -226,6 +226,13 @@ cairo_private cairo_image_surface_t *
 _cairo_image_surface_clone_subimage (cairo_surface_t             *surface,
                                     const cairo_rectangle_int_t *extents);
 
+/* Similar to clone; but allow format conversion */
+cairo_private cairo_image_surface_t *
+_cairo_image_surface_create_from_image (cairo_image_surface_t *other,
+                                       pixman_format_code_t format,
+                                       int x, int y, int width, int height,
+                                       int stride);
+
 CAIRO_END_DECLS
 
 #endif /* CAIRO_IMAGE_SURFACE_PRIVATE_H */
index 3fe6e43..49f6e18 100644 (file)
@@ -1088,6 +1088,61 @@ _cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface,
     return clone;
 }
 
+cairo_image_surface_t *
+_cairo_image_surface_create_from_image (cairo_image_surface_t *other,
+                                       pixman_format_code_t format,
+                                       int x, int y,
+                                       int width, int height, int stride)
+{
+    cairo_image_surface_t *surface;
+    cairo_status_t status;
+    pixman_image_t *image;
+    void *mem = NULL;
+
+    status = other->base.status;
+    if (unlikely (status))
+       goto cleanup;
+
+    if (stride) {
+       mem = _cairo_malloc_ab (height, stride);
+       if (unlikely (mem == NULL)) {
+           status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+           goto cleanup;
+       }
+    }
+
+    image = pixman_image_create_bits (format, width, height, mem, stride);
+    if (unlikely (image == NULL)) {
+       status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+       goto cleanup_mem;
+    }
+
+    surface = (cairo_image_surface_t *)
+       _cairo_image_surface_create_for_pixman_image (image, format);
+    if (unlikely (surface->base.status)) {
+       status = surface->base.status;
+       goto cleanup_image;
+    }
+
+    pixman_image_composite32 (PIXMAN_OP_SRC,
+                              other->pixman_image, NULL, image,
+                              x, y,
+                              0, 0,
+                              0, 0,
+                              width, height);
+    surface->base.is_clear = FALSE;
+    surface->owns_data = mem != NULL;
+
+    return surface;
+
+cleanup_image:
+    pixman_image_unref (image);
+cleanup_mem:
+    free (mem);
+cleanup:
+    return (cairo_image_surface_t *) _cairo_surface_create_in_error (status);
+}
+
 cairo_image_transparency_t
 _cairo_image_analyze_transparency (cairo_image_surface_t *image)
 {
@@ -1240,7 +1295,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 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 c7b1cab..66fbdfe 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)
 {
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 66ab3bd..cd6b3a2 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;
@@ -134,13 +135,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 +638,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);
@@ -776,13 +777,13 @@ _compute_face (const cairo_point_t *point, cairo_slope_t *dev_slope,
      */
     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 */
@@ -1340,12 +1341,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 c714b32..b0424f6 100644 (file)
@@ -390,11 +390,6 @@ _add_clipped_edge (cairo_polygon_t *polygon,
            cairo_fixed_t left_y, right_y;
            cairo_bool_t top_left_to_bottom_right;
 
-           left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
-                                                              limits->p1.x);
-           right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
-                                                               limits->p2.x);
-
            /*
             * The edge intersects the lines corresponding to the left
             * and right sides of the limit box at left_y and right_y,
@@ -420,11 +415,16 @@ _add_clipped_edge (cairo_polygon_t *polygon,
             * inside the box if it is clipped to this vertical range.
             */
 
-           top_left_to_bottom_right = (p1->x < p2->x) == (p1->y < p2->y);
-
+           top_left_to_bottom_right = (p1->x <= p2->x) == (p1->y <= p2->y);
            if (top_left_to_bottom_right) {
-               if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x)
-                   left_y++;
+               if (pleft >= limits->p1.x) {
+                   left_y = top_y;
+               } else {
+                   left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
+                                                                      limits->p1.x);
+                   if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x)
+                       left_y++;
+               }
 
                left_y = MIN (left_y, bot_y);
                if (top_y < left_y) {
@@ -434,8 +434,14 @@ _add_clipped_edge (cairo_polygon_t *polygon,
                    top_y = left_y;
                }
 
-               if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p1.y)
-                   right_y--;
+               if (pright <= limits->p2.x) {
+                   right_y = bot_y;
+               } else {
+                   right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
+                                                                       limits->p2.x);
+                   if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p2.x)
+                       right_y--;
+               }
 
                right_y = MAX (right_y, top_y);
                if (bot_y > right_y) {
@@ -445,8 +451,14 @@ _add_clipped_edge (cairo_polygon_t *polygon,
                    bot_y = right_y;
                }
            } else {
-               if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p2.x)
-                   right_y++;
+               if (pright <= limits->p2.x) {
+                   right_y = top_y;
+               } else {
+                   right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
+                                                                       limits->p2.x);
+                   if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p2.x)
+                       right_y++;
+               }
 
                right_y = MIN (right_y, bot_y);
                if (top_y < right_y) {
@@ -456,8 +468,14 @@ _add_clipped_edge (cairo_polygon_t *polygon,
                    top_y = right_y;
                }
 
-               if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x)
-                   left_y--;
+               if (pleft >= limits->p1.x) {
+                   left_y = bot_y;
+               } else {
+                   left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
+                                                                      limits->p1.x);
+                   if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x)
+                       left_y--;
+               }
 
                left_y = MAX (left_y, top_y);
                if (bot_y > left_y) {
index b75f522..ce05dba 100644 (file)
@@ -48,6 +48,7 @@
 #include "cairo-image-surface-private.h"
 #include "cairo-pattern-private.h"
 #include "cairo-surface-backend-private.h"
+#include "cairo-surface-fallback-private.h"
 
 #include "cairo-ft.h"
 #include "cairo-qt.h"
@@ -64,7 +65,7 @@
 #include <QWidget>
 #include <QtCore/QVarLengthArray>
 
-#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT)
+#if ((QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT)) && 0
 extern void qt_draw_glyphs(QPainter *, const quint32 *glyphs, const QPointF *positions, int count);
 #endif
 
@@ -197,6 +198,9 @@ _qpainter_compositionmode_from_cairo_op (cairo_operator_t op)
 static bool
 _op_is_supported (cairo_qt_surface_t *qs, cairo_operator_t op)
 {
+    if (qs->p == NULL)
+       return false;
+
     if (qs->supports_porter_duff) {
        switch (op) {
        case CAIRO_OPERATOR_CLEAR:
@@ -555,32 +559,105 @@ _cairo_qt_surface_release_source_image (void *abstract_surface,
     cairo_surface_destroy (&image->base);
 }
 
-static cairo_status_t
-_cairo_qt_surface_acquire_dest_image (void *abstract_surface,
-                                     cairo_rectangle_int_t *interest_rect,
-                                     cairo_image_surface_t **image_out,
-                                     cairo_rectangle_int_t *image_rect,
-                                     void **image_extra)
+struct _qimage_surface {
+    cairo_image_surface_t image;
+    QImage *qimg;
+};
+
+static cairo_surface_t *
+map_qimage_to_image (QImage *qimg, const cairo_rectangle_int_t *extents)
 {
-    cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
-    QImage *qimg = NULL;
+    struct _qimage_surface  *surface;
+    pixman_image_t *pixman_image;
+    pixman_format_code_t pixman_format;
+    uint8_t *data;
 
-    D(fprintf(stderr, "q[%p] acquire_dest_image\n", abstract_surface));
+    if (qimg == NULL)
+        return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
 
-    *image_extra = NULL;
+    switch (qimg->format()) {
+    case QImage::Format_ARGB32_Premultiplied:
+       pixman_format = PIXMAN_a8r8g8b8;
+       break;
+    case QImage::Format_RGB32:
+       pixman_format = PIXMAN_x8r8g8b8;
+       break;
+    case QImage::Format_Indexed8: // XXX not quite
+       pixman_format = PIXMAN_a8;
+       break;
+#ifdef WORDS_BIGENDIAN
+    case QImage::Format_Mono:
+#else
+    case QImage::Format_MonoLSB:
+#endif
+       pixman_format = PIXMAN_a1;
+       break;
 
-    if (qs->image_equiv) {
-        *image_out = (cairo_image_surface_t*)
-                     cairo_surface_reference (qs->image_equiv);
+    case QImage::Format_Invalid:
+#ifdef WORDS_BIGENDIAN
+    case QImage::Format_MonoLSB:
+#else
+    case QImage::Format_Mono:
+#endif
+    case QImage::Format_ARGB32:
+    case QImage::Format_RGB16:
+    case QImage::Format_ARGB8565_Premultiplied:
+    case QImage::Format_RGB666:
+    case QImage::Format_ARGB6666_Premultiplied:
+    case QImage::Format_RGB555:
+    case QImage::Format_ARGB8555_Premultiplied:
+    case QImage::Format_RGB888:
+    case QImage::Format_RGB444:
+    case QImage::Format_ARGB4444_Premultiplied:
+    case QImage::NImageFormats:
+    default:
+       delete qimg;
+       return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT);
+    }
 
-        image_rect->x = qs->window.x();
-        image_rect->y = qs->window.y();
-        image_rect->width = qs->window.width();
-        image_rect->height = qs->window.height();
+    data = qimg->bits();
+    data += extents->y * qimg->bytesPerLine();
+    data += extents->x * PIXMAN_FORMAT_BPP (pixman_format) / 8;
+
+    pixman_image = pixman_image_create_bits (pixman_format,
+                                            extents->width,
+                                            extents->height,
+                                            (uint32_t *)data,
+                                            qimg->bytesPerLine());
+    if (pixman_image == NULL) {
+       delete qimg;
+       return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+    }
 
-        return CAIRO_STATUS_SUCCESS;
+    surface = (struct _qimage_surface *) malloc (sizeof(*surface));
+    if (unlikely (surface == NULL)) {
+       pixman_image_unref (pixman_image);
+       delete qimg;
+       return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
     }
 
+    _cairo_image_surface_init (&surface->image, pixman_image, pixman_format);
+    surface->qimg = qimg;
+
+    cairo_surface_set_device_offset (&surface->image.base,
+                                    -extents->x, -extents->y);
+
+    return &surface->image.base;
+}
+
+static cairo_image_surface_t *
+_cairo_qt_surface_map_to_image (void *abstract_surface,
+                               const cairo_rectangle_int_t *extents)
+{
+    cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
+    QImage *qimg = NULL;
+
+    D(fprintf(stderr, "q[%p] acquire_dest_image\n", abstract_surface));
+
+    if (qs->image_equiv)
+       return _cairo_image_surface_map_to_image (qs->image_equiv,
+                                                 extents);
+
     QPoint offset;
 
     if (qs->pixmap) {
@@ -590,7 +667,7 @@ _cairo_qt_surface_acquire_dest_image (void *abstract_surface,
         // how we can grab an image from it
         QPaintDevice *pd = qs->p->device();
        if (!pd)
-           return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+           return (cairo_image_surface_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
 
        QPaintDevice *rpd = QPainter::redirected(pd, &offset);
        if (rpd)
@@ -605,50 +682,42 @@ _cairo_qt_surface_acquire_dest_image (void *abstract_surface,
         }
     }
 
-    if (qimg == NULL)
-        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    *image_out = (cairo_image_surface_t*)
-                 cairo_image_surface_create_for_data (qimg->bits(),
-                                                      _cairo_format_from_qimage_format (qimg->format()),
-                                                      qimg->width(), qimg->height(),
-                                                      qimg->bytesPerLine());
-    *image_extra = qimg;
-
-    image_rect->x = qs->window.x() + offset.x();
-    image_rect->y = qs->window.y() + offset.y();
-    image_rect->width = qs->window.width() - offset.x();
-    image_rect->height = qs->window.height() - offset.y();
-
-    return CAIRO_STATUS_SUCCESS;
+    return (cairo_image_surface_t *) map_qimage_to_image (qimg, extents);
 }
 
-static void
-_cairo_qt_surface_release_dest_image (void *abstract_surface,
-                                     cairo_rectangle_int_t *interest_rect,
-                                     cairo_image_surface_t *image,
-                                     cairo_rectangle_int_t *image_rect,
-                                     void *image_extra)
+static cairo_int_status_t
+_cairo_qt_surface_unmap_image (void *abstract_surface,
+                              cairo_image_surface_t *image)
 {
     cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
-    D(fprintf(stderr, "q[%p] release_dest_image\n", abstract_surface));
 
-    cairo_surface_destroy (&image->base);
+    D(fprintf(stderr, "q[%p] release_dest_image\n", abstract_surface));
 
-    if (image_extra) {
-        QImage *qimg = (QImage*) image_extra;
+    if (!qs->image_equiv) {
+       struct _qimage_surface  *qimage = (struct _qimage_surface  *)image;
 
         // XXX should I be using setBackgroundMode here instead of setCompositionMode?
         if (qs->supports_porter_duff)
             qs->p->setCompositionMode (QPainter::CompositionMode_Source);
 
-        qs->p->drawImage (image_rect->x, image_rect->y, *qimg);
+        qs->p->drawImage ((int)qimage->image.base.device_transform.x0,
+                         (int)qimage->image.base.device_transform.y0,
+                         *qimage->qimg,
+                         (int)qimage->image.base.device_transform.x0,
+                         (int)qimage->image.base.device_transform.y0,
+                         (int)qimage->image.width,
+                         (int)qimage->image.height);
 
         if (qs->supports_porter_duff)
             qs->p->setCompositionMode (QPainter::CompositionMode_SourceOver);
 
-        delete qimg;
+       delete qimage->qimg;
     }
+
+    cairo_surface_finish (&image->base);
+    cairo_surface_destroy (&image->base);
+
+    return CAIRO_INT_STATUS_SUCCESS;
 }
 
 static cairo_bool_t
@@ -1212,11 +1281,8 @@ _cairo_qt_surface_paint (void *abstract_surface,
 
     D(fprintf(stderr, "q[%p] paint op:%s\n", abstract_surface, _opstr(op)));
 
-    if (!qs->p)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
-
     if (! _op_is_supported (qs, op))
-       return CAIRO_INT_STATUS_UNSUPPORTED;
+       return _cairo_surface_fallback_paint (abstract_surface, op, source, clip);
 
     status = _cairo_qt_surface_set_clip (qs, clip);
     if (unlikely (status))
@@ -1250,11 +1316,10 @@ _cairo_qt_surface_fill (void *abstract_surface,
 
     D(fprintf(stderr, "q[%p] fill op:%s\n", abstract_surface, _opstr(op)));
 
-    if (!qs->p)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
-
     if (! _op_is_supported (qs, op))
-       return CAIRO_INT_STATUS_UNSUPPORTED;
+       return _cairo_surface_fallback_fill (abstract_surface, op,
+                                            source, path, fill_rule,
+                                            tolerance, antialias, clip);
 
     cairo_int_status_t status = _cairo_qt_surface_set_clip (qs, clip);
     if (unlikely (status))
@@ -1297,17 +1362,16 @@ _cairo_qt_surface_stroke (void *abstract_surface,
 
     D(fprintf(stderr, "q[%p] stroke op:%s\n", abstract_surface, _opstr(op)));
 
-    if (!qs->p)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
-
     if (! _op_is_supported (qs, op))
-       return CAIRO_INT_STATUS_UNSUPPORTED;
+       return _cairo_surface_fallback_stroke (abstract_surface, op,
+                                              source, path, style, ctm,
+                                              ctm_inverse, tolerance,
+                                              antialias, clip);
 
     cairo_int_status_t int_status = _cairo_qt_surface_set_clip (qs, clip);
     if (unlikely (int_status))
        return int_status;
 
-
     QMatrix savedMatrix = qs->p->worldMatrix();
 
     if (qs->supports_porter_duff)
@@ -1342,7 +1406,7 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
                               cairo_scaled_font_t *scaled_font,
                               const cairo_clip_t *clip)
 {
-#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT)
+#if ((QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT)) && 0
     cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
 
     // pick out the colour to use from the cairo source
@@ -1374,7 +1438,9 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
     _cairo_scaled_font_thaw_cache(scaled_font);
     return CAIRO_INT_STATUS_SUCCESS;
 #else
-    return CAIRO_INT_STATUS_UNSUPPORTED;
+    return _cairo_surface_fallback_glyphs (abstract_surface, op,
+                                          source, glyphs, num_glyphs,
+                                          scaled_font, clip);
 #endif
 }
 
@@ -1389,10 +1455,7 @@ _cairo_qt_surface_mask (void *abstract_surface,
 
     D(fprintf(stderr, "q[%p] mask op:%s\n", abstract_surface, _opstr(op)));
 
-    if (!qs->p)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
+    if (qs->p && mask->type == CAIRO_PATTERN_TYPE_SOLID) {
         cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
         cairo_int_status_t result;
 
@@ -1406,7 +1469,7 @@ _cairo_qt_surface_mask (void *abstract_surface,
     }
 
     // otherwise skip for now
-    return CAIRO_INT_STATUS_UNSUPPORTED;
+    return _cairo_surface_fallback_mask (abstract_surface, op, source, mask, clip);
 }
 
 static cairo_status_t
@@ -1429,21 +1492,28 @@ _cairo_qt_surface_mark_dirty (void *abstract_surface,
 static const cairo_surface_backend_t cairo_qt_surface_backend = {
     CAIRO_SURFACE_TYPE_QT,
     _cairo_qt_surface_finish,
+
     _cairo_default_context_create, /* XXX */
+
     _cairo_qt_surface_create_similar,
     NULL, /* similar image */
-    NULL, /* map to image */
-    NULL, /* unmap image */
+    _cairo_qt_surface_map_to_image,
+    _cairo_qt_surface_unmap_image,
+
     _cairo_surface_default_source,
     _cairo_qt_surface_acquire_source_image,
     _cairo_qt_surface_release_source_image,
     NULL, /* snapshot */
+
     NULL, /* copy_page */
     NULL, /* show_page */
+
     _cairo_qt_surface_get_extents,
     NULL, /* get_font_options */
+
     NULL, /* flush */
     _cairo_qt_surface_mark_dirty,
+
     _cairo_qt_surface_paint,
     _cairo_qt_surface_mask,
     _cairo_qt_surface_stroke,
index 73fc48a..edbeed7 100644 (file)
@@ -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;
     }
@@ -1431,7 +1434,7 @@ _cairo_recording_surface_snapshot (void *abstract_other)
     surface->extents = other->extents;
     surface->unbounded = other->unbounded;
 
-    surface->base.is_clear = TRUE;
+    surface->base.is_clear = other->base.is_clear;
 
     surface->bbtree.left = surface->bbtree.right = NULL;
     surface->bbtree.chain = INVALID_CHAIN;
@@ -1441,7 +1444,7 @@ _cairo_recording_surface_snapshot (void *abstract_other)
     surface->optimize_clears = TRUE;
 
     _cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
-    status = _cairo_recording_surface_copy (other, surface);
+    status = _cairo_recording_surface_copy (surface, other);
     if (unlikely (status)) {
        cairo_surface_destroy (&surface->base);
        return _cairo_surface_create_in_error (status);
@@ -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 e7eb4cc..97460c2 100644 (file)
@@ -449,16 +449,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);
@@ -466,10 +466,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.
@@ -788,32 +802,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
@@ -848,6 +870,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);
@@ -1139,6 +1163,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);
@@ -1288,6 +1314,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);
 
@@ -2131,36 +2160,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;
 }
 
 /*
@@ -2805,6 +2835,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,
@@ -2830,7 +2862,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);
@@ -2922,6 +2954,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);
@@ -3004,7 +3037,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 c11e9e7..5c6969c 100644 (file)
@@ -1096,6 +1096,10 @@ void *
 cairo_surface_get_user_data (cairo_surface_t            *surface,
                             const cairo_user_data_key_t *key)
 {
+    /* Prevent reads of the array during teardown */
+    if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count))
+       return NULL;
+
     return _cairo_user_data_array_get_data (&surface->user_data, key);
 }
 
@@ -1126,6 +1130,9 @@ cairo_surface_set_user_data (cairo_surface_t               *surface,
     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
        return surface->status;
 
+    if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count))
+       return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
+
     return _cairo_user_data_array_set_data (&surface->user_data,
                                            key, user_data, destroy);
 }
@@ -1154,7 +1161,9 @@ cairo_surface_get_mime_data (cairo_surface_t              *surface,
 
     *data = NULL;
     *length = 0;
-    if (unlikely (surface->status))
+
+    /* Prevent reads of the array during teardown */
+    if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count))
        return;
 
     /* The number of mime-types attached to a surface is usually small,
@@ -1252,7 +1261,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
@@ -1275,6 +1285,12 @@ cairo_surface_set_mime_data (cairo_surface_t             *surface,
     cairo_status_t status;
     cairo_mime_data_t *mime_data;
 
+    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
+       return surface->status;
+
+    if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count))
+       return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
+
     if (unlikely (surface->status))
        return surface->status;
     if (unlikely (surface->finished))
index eeee20c..02fbe75 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);
     }
 
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..383c99a 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) {
@@ -508,13 +533,12 @@ cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
     if (font->scaled_font_subset->is_latin) {
        for (i = 1; i < 256; i++) {
            int subset_glyph = font->scaled_font_subset->latin_to_subset_glyph_index[i];
-           int glyph_num = font->subset_index_to_glyphs[subset_glyph];
 
            if (subset_glyph > 0) {
                _cairo_output_stream_printf (font->output,
                                             "dup %d /%s put\n",
                                             i,
-                                            font->glyph_names[glyph_num]);
+                                            _cairo_winansi_to_glyphname (i));
            }
        }
     } else {
@@ -719,17 +743,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 +784,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 +795,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 +868,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
@@ -1036,10 +1128,26 @@ write_used_glyphs (cairo_type1_font_subset_t *font,
     cairo_status_t status;
     char buffer[256];
     int length;
+    int subset_id;
+    int ch;
 
     if (font->glyphs[glyph_number].subset_index < 0)
        return CAIRO_STATUS_SUCCESS;
 
+    if (font->scaled_font_subset->is_latin) {
+       /* When using the WinAnsi encoding in PDF, the /Encoding array
+        * is ignored and instead glyphs are keyed by glyph names. To
+        * ensure correct rendering we replace the glyph name in the
+        * font with the standard name.
+         **/
+       subset_id = font->glyphs[glyph_number].subset_index;
+       if (subset_id > 0) {
+           ch = font->scaled_font_subset->to_latin_char[subset_id];
+           name = _cairo_winansi_to_glyphname (ch);
+           name_length = strlen(name);
+       }
+    }
+
     length = snprintf (buffer, sizeof buffer,
                       "/%.*s %d %s ",
                       name_length, name, charstring_length, font->rd);
@@ -1137,9 +1245,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 +1269,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 +1405,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 +1414,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 +1695,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;
 
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..013e2af 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);
@@ -1436,14 +1469,14 @@ _emit_glyphs_chunk (cairo_xlib_display_t *display,
        */
       if (_start_new_glyph_elt (j, &glyphs[i])) {
          if (j) {
-           elts[nelt].nchars = n;
-           nelt++;
-           n = 0;
+             elts[nelt].nchars = n;
+             nelt++;
+             n = 0;
          }
          elts[nelt].chars = char8 + size * j;
          elts[nelt].glyphset = info->glyphset;
-         elts[nelt].xOff = glyphs[i].i.x - dst_x;
-         elts[nelt].yOff = glyphs[i].i.y - dst_y;
+         elts[nelt].xOff = glyphs[i].i.x;
+         elts[nelt].yOff = glyphs[i].i.y;
       }
 
       switch (width) {
@@ -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;
 
@@ -1544,7 +1579,7 @@ composite_glyphs (void                            *surface,
     cairo_xlib_display_t *display = dst->display;
     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
     cairo_scaled_glyph_t *glyph;
-    cairo_fixed_t x = 0, y = 0;
+    cairo_fixed_t x = dst_x, y = dst_y;
     cairo_xlib_font_glyphset_t *glyphset = NULL, *this_glyphset_info;
 
     unsigned long max_index = 0;
@@ -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 7463595..861e2f7 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
@@ -1086,6 +1086,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,
@@ -1232,6 +1240,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);
@@ -1897,6 +1916,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);
@@ -2032,7 +2052,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 b3ee573..741e49e 100644 (file)
@@ -106,9 +106,9 @@ static cairo_bool_t is_win98 (void)
     os.dwOSVersionInfoSize = sizeof (os);
     GetVersionEx (&os);
 
-    return (VER_PLATFORM_WIN32_WINDOWS != os.dwPlatformId &&
-           os.dwMajorVersion != 4 &&
-           os.dwMinorVersion != 10);
+    return (VER_PLATFORM_WIN32_WINDOWS == os.dwPlatformId &&
+           os.dwMajorVersion == 4 &&
+           os.dwMinorVersion == 10);
 }
 
 static void *
index 2c5374c..ccd285d 100644 (file)
@@ -392,6 +392,7 @@ _cairo_win32_display_surface_create_similar_image (void         *abstract_other,
                                                   int       height)
 {
     cairo_win32_display_surface_t *surface = abstract_other;
+    cairo_image_surface_t *image;
 
     surface = (cairo_win32_display_surface_t *)
        _cairo_win32_display_surface_create_for_dc (surface->win32.dc,
@@ -399,7 +400,14 @@ _cairo_win32_display_surface_create_similar_image (void        *abstract_other,
     if (surface->win32.base.status)
        return &surface->win32.base;
 
-    return surface->image;
+    /* And clear in order to comply with our user API semantics */
+    image = (cairo_image_surface_t *) surface->image;
+    if (! image->base.is_clear) {
+       memset (image->data, 0, image->stride * height);
+       image->base.is_clear = TRUE;
+    }
+
+    return &image->base;
 }
 
 static cairo_status_t
@@ -497,6 +505,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 cc3b797..18fef07 100644 (file)
@@ -243,8 +243,8 @@ am__cairo_test_suite_SOURCES_DIST = buffer-diff.c cairo-test.c \
        rounded-rectangle-fill.c rounded-rectangle-stroke.c sample.c \
        scale-down-source-surface-paint.c scale-offset-image.c \
        scale-offset-similar.c scale-source-surface-paint.c \
-       scaled-font-zero-matrix.c stroke-ctm-caps.c stroke-image.c \
-       stroke-open-box.c select-font-face.c \
+       scaled-font-zero-matrix.c stroke-ctm-caps.c stroke-clipped.c \
+       stroke-image.c stroke-open-box.c select-font-face.c \
        select-font-no-show-text.c self-copy.c self-copy-overlap.c \
        self-intersecting.c set-source.c show-glyphs-advance.c \
        show-glyphs-many.c show-text-current-point.c \
@@ -272,15 +272,17 @@ am__cairo_test_suite_SOURCES_DIST = buffer-diff.c cairo-test.c \
        unantialiased-shapes.c unbounded-operator.c unclosed-strokes.c \
        user-data.c user-font.c user-font-mask.c user-font-proxy.c \
        user-font-rescale.c world-map.c white-in-noop.c \
-       xcb-huge-image-shm.c xcb-stress-cache.c xcb-snapshot-assert.c \
-       xcomposite-projection.c xlib-expose-event.c zero-alpha.c \
-       zero-mask.c pthread-same-source.c pthread-show-text.c \
-       pthread-similar.c bitmap-font.c ft-font-create-for-ft-face.c \
+       xcb-huge-image-shm.c xcb-huge-subimage.c xcb-stress-cache.c \
+       xcb-snapshot-assert.c xcomposite-projection.c \
+       xlib-expose-event.c zero-alpha.c zero-mask.c \
+       pthread-same-source.c pthread-show-text.c pthread-similar.c \
+       bitmap-font.c ft-font-create-for-ft-face.c \
        ft-show-glyphs-positioning.c ft-show-glyphs-table.c \
        ft-text-vertical-layout-type1.c \
        ft-text-vertical-layout-type3.c ft-text-antialias-none.c \
-       gl-surface-source.c quartz-surface-source.c pdf-features.c \
-       pdf-mime-data.c pdf-surface-source.c ps-eps.c ps-features.c \
+       gl-device-release.c gl-surface-source.c \
+       quartz-surface-source.c pdf-features.c pdf-mime-data.c \
+       pdf-surface-source.c ps-eps.c ps-features.c \
        ps-surface-source.c svg-surface.c svg-clip.c \
        svg-surface-source.c xcb-surface-source.c xlib-surface.c \
        xlib-surface-source.c get-xrender-format.c multi-page.c \
@@ -301,7 +303,8 @@ am__objects_5 = cairo_test_suite-bitmap-font.$(OBJEXT) \
        cairo_test_suite-ft-text-vertical-layout-type3.$(OBJEXT) \
        cairo_test_suite-ft-text-antialias-none.$(OBJEXT)
 @CAIRO_HAS_FC_FONT_TRUE@@CAIRO_HAS_FT_FONT_TRUE@am__objects_6 = $(am__objects_5)
-am__objects_7 = cairo_test_suite-gl-surface-source.$(OBJEXT)
+am__objects_7 = cairo_test_suite-gl-device-release.$(OBJEXT) \
+       cairo_test_suite-gl-surface-source.$(OBJEXT)
 @CAIRO_HAS_GL_SURFACE_TRUE@am__objects_8 = $(am__objects_7)
 am__objects_9 = cairo_test_suite-quartz-surface-source.$(OBJEXT)
 @CAIRO_HAS_QUARTZ_SURFACE_TRUE@am__objects_10 = $(am__objects_9)
@@ -623,6 +626,7 @@ am__objects_27 = cairo_test_suite-a1-bug.$(OBJEXT) \
        cairo_test_suite-scale-source-surface-paint.$(OBJEXT) \
        cairo_test_suite-scaled-font-zero-matrix.$(OBJEXT) \
        cairo_test_suite-stroke-ctm-caps.$(OBJEXT) \
+       cairo_test_suite-stroke-clipped.$(OBJEXT) \
        cairo_test_suite-stroke-image.$(OBJEXT) \
        cairo_test_suite-stroke-open-box.$(OBJEXT) \
        cairo_test_suite-select-font-face.$(OBJEXT) \
@@ -699,6 +703,7 @@ am__objects_27 = cairo_test_suite-a1-bug.$(OBJEXT) \
        cairo_test_suite-world-map.$(OBJEXT) \
        cairo_test_suite-white-in-noop.$(OBJEXT) \
        cairo_test_suite-xcb-huge-image-shm.$(OBJEXT) \
+       cairo_test_suite-xcb-huge-subimage.$(OBJEXT) \
        cairo_test_suite-xcb-stress-cache.$(OBJEXT) \
        cairo_test_suite-xcb-snapshot-assert.$(OBJEXT) \
        cairo_test_suite-xcomposite-projection.$(OBJEXT) \
@@ -1011,6 +1016,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
@@ -1169,8 +1175,8 @@ test_sources = a1-bug.c a1-clip.c a1-fill.c a1-image-sample.c \
        rounded-rectangle-fill.c rounded-rectangle-stroke.c sample.c \
        scale-down-source-surface-paint.c scale-offset-image.c \
        scale-offset-similar.c scale-source-surface-paint.c \
-       scaled-font-zero-matrix.c stroke-ctm-caps.c stroke-image.c \
-       stroke-open-box.c select-font-face.c \
+       scaled-font-zero-matrix.c stroke-ctm-caps.c stroke-clipped.c \
+       stroke-image.c stroke-open-box.c select-font-face.c \
        select-font-no-show-text.c self-copy.c self-copy-overlap.c \
        self-intersecting.c set-source.c show-glyphs-advance.c \
        show-glyphs-many.c show-text-current-point.c \
@@ -1198,12 +1204,13 @@ test_sources = a1-bug.c a1-clip.c a1-fill.c a1-image-sample.c \
        unantialiased-shapes.c unbounded-operator.c unclosed-strokes.c \
        user-data.c user-font.c user-font-mask.c user-font-proxy.c \
        user-font-rescale.c world-map.c white-in-noop.c \
-       xcb-huge-image-shm.c xcb-stress-cache.c xcb-snapshot-assert.c \
-       xcomposite-projection.c xlib-expose-event.c zero-alpha.c \
-       zero-mask.c $(am__append_1) $(am__append_2) $(am__append_3) \
-       $(am__append_4) $(am__append_5) $(am__append_6) \
-       $(am__append_7) $(am__append_8) $(am__append_9) \
-       $(am__append_10) $(am__append_11) $(am__append_12) $(test)
+       xcb-huge-image-shm.c xcb-huge-subimage.c xcb-stress-cache.c \
+       xcb-snapshot-assert.c xcomposite-projection.c \
+       xlib-expose-event.c zero-alpha.c zero-mask.c $(am__append_1) \
+       $(am__append_2) $(am__append_3) $(am__append_4) \
+       $(am__append_5) $(am__append_6) $(am__append_7) \
+       $(am__append_8) $(am__append_9) $(am__append_10) \
+       $(am__append_11) $(am__append_12) $(test)
 pthread_test_sources = \
        pthread-same-source.c                           \
        pthread-show-text.c                             \
@@ -1220,6 +1227,7 @@ ft_font_test_sources = \
        ft-text-antialias-none.c
 
 gl_surface_test_sources = \
+       gl-device-release.c \
        gl-surface-source.c
 
 quartz_surface_test_sources = quartz-surface-source.c
@@ -1655,6 +1663,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-get-group-target.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-get-path-extents.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-get-xrender-format.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-gl-device-release.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-gl-surface-source.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-glyph-cache-pressure.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-gradient-alpha.Po@am__quote@
@@ -1836,6 +1845,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-source-surface-scale-paint.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-spline-decomposition.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-stride-12-image.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-stroke-clipped.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-stroke-ctm-caps.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-stroke-image.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-stroke-open-box.Po@am__quote@
@@ -1891,6 +1901,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-white-in-noop.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-world-map.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-xcb-huge-image-shm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-xcb-huge-subimage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-xcb-snapshot-assert.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-xcb-stress-cache.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo_test_suite-xcb-surface-source.Po@am__quote@
@@ -6059,6 +6070,20 @@ cairo_test_suite-stroke-ctm-caps.obj: stroke-ctm-caps.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -c -o cairo_test_suite-stroke-ctm-caps.obj `if test -f 'stroke-ctm-caps.c'; then $(CYGPATH_W) 'stroke-ctm-caps.c'; else $(CYGPATH_W) '$(srcdir)/stroke-ctm-caps.c'; fi`
 
+cairo_test_suite-stroke-clipped.o: stroke-clipped.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -MT cairo_test_suite-stroke-clipped.o -MD -MP -MF $(DEPDIR)/cairo_test_suite-stroke-clipped.Tpo -c -o cairo_test_suite-stroke-clipped.o `test -f 'stroke-clipped.c' || echo '$(srcdir)/'`stroke-clipped.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/cairo_test_suite-stroke-clipped.Tpo $(DEPDIR)/cairo_test_suite-stroke-clipped.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='stroke-clipped.c' object='cairo_test_suite-stroke-clipped.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -c -o cairo_test_suite-stroke-clipped.o `test -f 'stroke-clipped.c' || echo '$(srcdir)/'`stroke-clipped.c
+
+cairo_test_suite-stroke-clipped.obj: stroke-clipped.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -MT cairo_test_suite-stroke-clipped.obj -MD -MP -MF $(DEPDIR)/cairo_test_suite-stroke-clipped.Tpo -c -o cairo_test_suite-stroke-clipped.obj `if test -f 'stroke-clipped.c'; then $(CYGPATH_W) 'stroke-clipped.c'; else $(CYGPATH_W) '$(srcdir)/stroke-clipped.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/cairo_test_suite-stroke-clipped.Tpo $(DEPDIR)/cairo_test_suite-stroke-clipped.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='stroke-clipped.c' object='cairo_test_suite-stroke-clipped.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -c -o cairo_test_suite-stroke-clipped.obj `if test -f 'stroke-clipped.c'; then $(CYGPATH_W) 'stroke-clipped.c'; else $(CYGPATH_W) '$(srcdir)/stroke-clipped.c'; fi`
+
 cairo_test_suite-stroke-image.o: stroke-image.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -MT cairo_test_suite-stroke-image.o -MD -MP -MF $(DEPDIR)/cairo_test_suite-stroke-image.Tpo -c -o cairo_test_suite-stroke-image.o `test -f 'stroke-image.c' || echo '$(srcdir)/'`stroke-image.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/cairo_test_suite-stroke-image.Tpo $(DEPDIR)/cairo_test_suite-stroke-image.Po
@@ -7123,6 +7148,20 @@ cairo_test_suite-xcb-huge-image-shm.obj: xcb-huge-image-shm.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -c -o cairo_test_suite-xcb-huge-image-shm.obj `if test -f 'xcb-huge-image-shm.c'; then $(CYGPATH_W) 'xcb-huge-image-shm.c'; else $(CYGPATH_W) '$(srcdir)/xcb-huge-image-shm.c'; fi`
 
+cairo_test_suite-xcb-huge-subimage.o: xcb-huge-subimage.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -MT cairo_test_suite-xcb-huge-subimage.o -MD -MP -MF $(DEPDIR)/cairo_test_suite-xcb-huge-subimage.Tpo -c -o cairo_test_suite-xcb-huge-subimage.o `test -f 'xcb-huge-subimage.c' || echo '$(srcdir)/'`xcb-huge-subimage.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/cairo_test_suite-xcb-huge-subimage.Tpo $(DEPDIR)/cairo_test_suite-xcb-huge-subimage.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='xcb-huge-subimage.c' object='cairo_test_suite-xcb-huge-subimage.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -c -o cairo_test_suite-xcb-huge-subimage.o `test -f 'xcb-huge-subimage.c' || echo '$(srcdir)/'`xcb-huge-subimage.c
+
+cairo_test_suite-xcb-huge-subimage.obj: xcb-huge-subimage.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -MT cairo_test_suite-xcb-huge-subimage.obj -MD -MP -MF $(DEPDIR)/cairo_test_suite-xcb-huge-subimage.Tpo -c -o cairo_test_suite-xcb-huge-subimage.obj `if test -f 'xcb-huge-subimage.c'; then $(CYGPATH_W) 'xcb-huge-subimage.c'; else $(CYGPATH_W) '$(srcdir)/xcb-huge-subimage.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/cairo_test_suite-xcb-huge-subimage.Tpo $(DEPDIR)/cairo_test_suite-xcb-huge-subimage.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='xcb-huge-subimage.c' object='cairo_test_suite-xcb-huge-subimage.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -c -o cairo_test_suite-xcb-huge-subimage.obj `if test -f 'xcb-huge-subimage.c'; then $(CYGPATH_W) 'xcb-huge-subimage.c'; else $(CYGPATH_W) '$(srcdir)/xcb-huge-subimage.c'; fi`
+
 cairo_test_suite-xcb-stress-cache.o: xcb-stress-cache.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -MT cairo_test_suite-xcb-stress-cache.o -MD -MP -MF $(DEPDIR)/cairo_test_suite-xcb-stress-cache.Tpo -c -o cairo_test_suite-xcb-stress-cache.o `test -f 'xcb-stress-cache.c' || echo '$(srcdir)/'`xcb-stress-cache.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/cairo_test_suite-xcb-stress-cache.Tpo $(DEPDIR)/cairo_test_suite-xcb-stress-cache.Po
@@ -7347,6 +7386,20 @@ cairo_test_suite-ft-text-antialias-none.obj: ft-text-antialias-none.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -c -o cairo_test_suite-ft-text-antialias-none.obj `if test -f 'ft-text-antialias-none.c'; then $(CYGPATH_W) 'ft-text-antialias-none.c'; else $(CYGPATH_W) '$(srcdir)/ft-text-antialias-none.c'; fi`
 
+cairo_test_suite-gl-device-release.o: gl-device-release.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -MT cairo_test_suite-gl-device-release.o -MD -MP -MF $(DEPDIR)/cairo_test_suite-gl-device-release.Tpo -c -o cairo_test_suite-gl-device-release.o `test -f 'gl-device-release.c' || echo '$(srcdir)/'`gl-device-release.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/cairo_test_suite-gl-device-release.Tpo $(DEPDIR)/cairo_test_suite-gl-device-release.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gl-device-release.c' object='cairo_test_suite-gl-device-release.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -c -o cairo_test_suite-gl-device-release.o `test -f 'gl-device-release.c' || echo '$(srcdir)/'`gl-device-release.c
+
+cairo_test_suite-gl-device-release.obj: gl-device-release.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -MT cairo_test_suite-gl-device-release.obj -MD -MP -MF $(DEPDIR)/cairo_test_suite-gl-device-release.Tpo -c -o cairo_test_suite-gl-device-release.obj `if test -f 'gl-device-release.c'; then $(CYGPATH_W) 'gl-device-release.c'; else $(CYGPATH_W) '$(srcdir)/gl-device-release.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/cairo_test_suite-gl-device-release.Tpo $(DEPDIR)/cairo_test_suite-gl-device-release.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gl-device-release.c' object='cairo_test_suite-gl-device-release.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -c -o cairo_test_suite-gl-device-release.obj `if test -f 'gl-device-release.c'; then $(CYGPATH_W) 'gl-device-release.c'; else $(CYGPATH_W) '$(srcdir)/gl-device-release.c'; fi`
+
 cairo_test_suite-gl-surface-source.o: gl-surface-source.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cairo_test_suite_CFLAGS) $(CFLAGS) -MT cairo_test_suite-gl-surface-source.o -MD -MP -MF $(DEPDIR)/cairo_test_suite-gl-surface-source.Tpo -c -o cairo_test_suite-gl-surface-source.o `test -f 'gl-surface-source.c' || echo '$(srcdir)/'`gl-surface-source.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/cairo_test_suite-gl-surface-source.Tpo $(DEPDIR)/cairo_test_suite-gl-surface-source.Po
index fdf262c..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                         \
@@ -389,6 +391,7 @@ ft_font_test_sources = \
        ft-text-antialias-none.c
 
 gl_surface_test_sources = \
+       gl-device-release.c \
        gl-surface-source.c
 
 quartz_surface_test_sources = quartz-surface-source.c
index 5a5fa43..c9b5c76 100644 (file)
@@ -401,6 +401,7 @@ extern void _register_scale_offset_similar (void);
 extern void _register_scale_source_surface_paint (void);
 extern void _register_scaled_font_zero_matrix (void);
 extern void _register_stroke_ctm_caps (void);
+extern void _register_stroke_clipped (void);
 extern void _register_stroke_image (void);
 extern void _register_stroke_open_box (void);
 extern void _register_select_font_face (void);
@@ -488,6 +489,7 @@ extern void _register_world_map_stroke (void);
 extern void _register_world_map_fill (void);
 extern void _register_white_in_noop (void);
 extern void _register_xcb_huge_image_shm (void);
+extern void _register_xcb_huge_subimage (void);
 extern void _register_xcb_stress_cache (void);
 extern void _register_xcb_snapshot_assert (void);
 extern void _register_xcomposite_projection (void);
@@ -920,6 +922,7 @@ _cairo_test_runner_register_tests (void)
     _register_scale_source_surface_paint ();
     _register_scaled_font_zero_matrix ();
     _register_stroke_ctm_caps ();
+    _register_stroke_clipped ();
     _register_stroke_image ();
     _register_stroke_open_box ();
     _register_select_font_face ();
@@ -1007,6 +1010,7 @@ _cairo_test_runner_register_tests (void)
     _register_world_map_fill ();
     _register_white_in_noop ();
     _register_xcb_huge_image_shm ();
+    _register_xcb_huge_subimage ();
     _register_xcb_stress_cache ();
     _register_xcb_snapshot_assert ();
     _register_xcomposite_projection ();
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
diff --git a/test/gl-device-release.c b/test/gl-device-release.c
new file mode 100644 (file)
index 0000000..7f554be
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright Â© 2012 Igalia S.L.
+ * Copyright Â© 2009 Eric Anholt
+ * Copyright Â© 2009 Chris Wilson
+ * Copyright Â© 2005 Red Hat, Inc
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * IGALIA S.L. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Martin Robinson <mrobinson@igalia.com>
+ */
+
+#include "cairo-test.h"
+#include <cairo-gl.h>
+#include <assert.h>
+
+static Window
+create_test_window (Display *display,
+                   GLXContext glx_context,
+                   XVisualInfo *visual_info)
+{
+    Colormap colormap;
+    XSetWindowAttributes window_attributes;
+    Window window = None;
+
+    colormap = XCreateColormap (display,
+                           RootWindow (display, visual_info->screen),
+                           visual_info->visual,
+                           AllocNone);
+    window_attributes.colormap = colormap;
+    window_attributes.border_pixel = 0;
+    window = XCreateWindow (display, RootWindow (display, visual_info->screen),
+                           -1, -1, 1, 1, 0,
+                           visual_info->depth,
+                           InputOutput,
+                           visual_info->visual,
+                           CWBorderPixel | CWColormap, &window_attributes);
+    XFreeColormap (display, colormap);
+
+    XFlush (display);
+    return window;
+}
+
+static cairo_bool_t
+multithread_makecurrent_available (Display *display)
+{
+    const char *extensions = glXQueryExtensionsString (display,
+                                                      DefaultScreen (display));
+    return !! strstr(extensions, "GLX_MESA_multithread_makecurrent");
+}
+
+static void
+draw_to_surface (cairo_surface_t *surface)
+{
+    cairo_t *cr = cairo_create (surface);
+    cairo_paint (cr);
+    cairo_destroy (cr);
+}
+
+static cairo_test_status_t
+preamble (cairo_test_context_t *test_ctx)
+{
+    int rgba_attribs[] = {
+       GLX_RGBA,
+       GLX_RED_SIZE, 1,
+       GLX_GREEN_SIZE, 1,
+       GLX_BLUE_SIZE, 1,
+       GLX_ALPHA_SIZE, 1,
+       GLX_DOUBLEBUFFER,
+       None
+    };
+
+    XVisualInfo *visual_info;
+    GLXContext glx_context;
+    cairo_device_t *device;
+    Display *display;
+    Window test_window;
+    cairo_surface_t *window_surface;
+    cairo_bool_t has_multithread_makecurrent;
+
+    display = XOpenDisplay (NULL);
+    if (display == NULL)
+       return CAIRO_TEST_UNTESTED;
+
+    visual_info = glXChooseVisual (display, DefaultScreen (display), rgba_attribs);
+    if (visual_info == NULL) {
+       XCloseDisplay (display);
+       return CAIRO_TEST_UNTESTED;
+    }
+
+    glx_context = glXCreateContext (display, visual_info, NULL, True);
+    if (glx_context == NULL) {
+       XCloseDisplay (display);
+       return CAIRO_TEST_UNTESTED;
+    }
+
+    test_window = create_test_window (display, glx_context, visual_info);
+    XFree (visual_info);
+    if (test_window == None) {
+       XCloseDisplay (display);
+       return CAIRO_TEST_UNTESTED;
+    }
+
+    has_multithread_makecurrent = multithread_makecurrent_available (display);
+
+    glXMakeCurrent (display, None, None);
+
+    /* Creating the device should actually change the GL context, because of
+     * the creation/activation of a dummy window used for texture surfaces. */
+    device = cairo_glx_device_create (display, glx_context);
+
+    /* It's important that when multithread_makecurrent isn't available the
+     * Cairo backend clears the current context, so that the dummy texture
+     * window is not active while the device is unlocked. */
+    if (has_multithread_makecurrent) {
+       assert (None != glXGetCurrentDrawable ());
+       assert (display == glXGetCurrentDisplay ());
+       assert (glx_context == glXGetCurrentContext ());
+    } else {
+       assert (None == glXGetCurrentDrawable ());
+       assert (None == glXGetCurrentDisplay ());
+       assert (None == glXGetCurrentContext ());
+    }
+
+    window_surface = cairo_gl_surface_create_for_window (device, test_window,
+                                                        1, 1);
+    assert (cairo_surface_status (window_surface) == CAIRO_STATUS_SUCCESS);
+
+    draw_to_surface (window_surface);
+    if (has_multithread_makecurrent) {
+       assert (test_window == glXGetCurrentDrawable ());
+       assert (display == glXGetCurrentDisplay ());
+       assert (glx_context == glXGetCurrentContext ());
+    } else {
+       assert (None == glXGetCurrentDrawable ());
+       assert (None == glXGetCurrentDisplay ());
+       assert (None == glXGetCurrentContext ());
+    }
+
+    /* In this case, drawing to the window surface will not change the current
+     * GL context, so Cairo setting the current surface and context to none. */
+    glXMakeCurrent (display, test_window, glx_context);
+    draw_to_surface (window_surface);
+    assert (test_window == glXGetCurrentDrawable ());
+    assert (display == glXGetCurrentDisplay ());
+    assert (glx_context == glXGetCurrentContext ());
+
+    /* There should be no context change when destroying the device. */
+    cairo_device_destroy (device);
+    assert (test_window == glXGetCurrentDrawable ());
+    assert (display == glXGetCurrentDisplay ());
+    assert (glx_context == glXGetCurrentContext ());
+
+    glXDestroyContext(display, glx_context);
+    XDestroyWindow (display, test_window);
+    XCloseDisplay (display);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (gl_device_creation_changes_context,
+           "Test that using the Cairo GL backend leaves the current GL context in the appropriate state",
+           "gl", /* keywords */
+           NULL, /* requirements */
+           0, 0,
+           preamble, NULL)
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)
 {
index 0e41f74..8a1bf8f 100644 (file)
@@ -310,6 +310,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
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 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
diff --git a/test/reference/record-fill-alpha.argb32.ref.png b/test/reference/record-fill-alpha.argb32.ref.png
deleted file mode 100644 (file)
index 9de7b50..0000000
Binary files a/test/reference/record-fill-alpha.argb32.ref.png and /dev/null 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
diff --git a/test/reference/record-fill-alpha.rgb24.ref.png b/test/reference/record-fill-alpha.rgb24.ref.png
deleted file mode 100644 (file)
index 9de7b50..0000000
Binary files a/test/reference/record-fill-alpha.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/record-paint-alpha-clip-mask.argb32.ref.png b/test/reference/record-paint-alpha-clip-mask.argb32.ref.png
deleted file mode 100644 (file)
index 5054672..0000000
Binary files a/test/reference/record-paint-alpha-clip-mask.argb32.ref.png and /dev/null 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
diff --git a/test/reference/record-paint-alpha-clip-mask.rgb24.ref.png b/test/reference/record-paint-alpha-clip-mask.rgb24.ref.png
deleted file mode 100644 (file)
index 5054672..0000000
Binary files a/test/reference/record-paint-alpha-clip-mask.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/record-text-transform.argb32.ref.png b/test/reference/record-text-transform.argb32.ref.png
deleted file mode 100644 (file)
index 4603bc5..0000000
Binary files a/test/reference/record-text-transform.argb32.ref.png and /dev/null differ
diff --git a/test/reference/record-text-transform.rgb24.ref.png b/test/reference/record-text-transform.rgb24.ref.png
deleted file mode 100644 (file)
index 4603bc5..0000000
Binary files a/test/reference/record-text-transform.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/record1414x-fill-alpha.argb32.ref.png b/test/reference/record1414x-fill-alpha.argb32.ref.png
deleted file mode 100644 (file)
index 545c0da..0000000
Binary files a/test/reference/record1414x-fill-alpha.argb32.ref.png and /dev/null differ
diff --git a/test/reference/record1414x-fill-alpha.ref.png b/test/reference/record1414x-fill-alpha.ref.png
new file mode 100644 (file)
index 0000000..4b4c780
Binary files /dev/null and b/test/reference/record1414x-fill-alpha.ref.png differ
diff --git a/test/reference/record1414x-fill-alpha.rgb24.ref.png b/test/reference/record1414x-fill-alpha.rgb24.ref.png
deleted file mode 100644 (file)
index 545c0da..0000000
Binary files a/test/reference/record1414x-fill-alpha.rgb24.ref.png and /dev/null 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
diff --git a/test/reference/record2x-fill-alpha.argb32.ref.png b/test/reference/record2x-fill-alpha.argb32.ref.png
deleted file mode 100644 (file)
index ce4dab1..0000000
Binary files a/test/reference/record2x-fill-alpha.argb32.ref.png and /dev/null differ
diff --git a/test/reference/record2x-fill-alpha.ref.png b/test/reference/record2x-fill-alpha.ref.png
new file mode 100644 (file)
index 0000000..ae0646e
Binary files /dev/null and b/test/reference/record2x-fill-alpha.ref.png differ
diff --git a/test/reference/record2x-fill-alpha.rgb24.ref.png b/test/reference/record2x-fill-alpha.rgb24.ref.png
deleted file mode 100644 (file)
index ce4dab1..0000000
Binary files a/test/reference/record2x-fill-alpha.rgb24.ref.png and /dev/null 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-fill-alpha.argb32.ref.png b/test/reference/record90-fill-alpha.argb32.ref.png
deleted file mode 100644 (file)
index afbc68e..0000000
Binary files a/test/reference/record90-fill-alpha.argb32.ref.png and /dev/null differ
diff --git a/test/reference/record90-fill-alpha.ref.png b/test/reference/record90-fill-alpha.ref.png
new file mode 100644 (file)
index 0000000..a4c4bb8
Binary files /dev/null and b/test/reference/record90-fill-alpha.ref.png differ
diff --git a/test/reference/record90-fill-alpha.rgb24.ref.png b/test/reference/record90-fill-alpha.rgb24.ref.png
deleted file mode 100644 (file)
index afbc68e..0000000
Binary files a/test/reference/record90-fill-alpha.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/record90-paint-alpha-clip-mask.argb32.ref.png b/test/reference/record90-paint-alpha-clip-mask.argb32.ref.png
deleted file mode 100644 (file)
index aa94252..0000000
Binary files a/test/reference/record90-paint-alpha-clip-mask.argb32.ref.png and /dev/null 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-mask.rgb24.ref.png b/test/reference/record90-paint-alpha-clip-mask.rgb24.ref.png
deleted file mode 100644 (file)
index aa94252..0000000
Binary files a/test/reference/record90-paint-alpha-clip-mask.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/record90-paint-alpha-clip.argb32.ref.png b/test/reference/record90-paint-alpha-clip.argb32.ref.png
deleted file mode 100644 (file)
index 15d1a31..0000000
Binary files a/test/reference/record90-paint-alpha-clip.argb32.ref.png and /dev/null 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-paint-alpha-clip.rgb24.ref.png b/test/reference/record90-paint-alpha-clip.rgb24.ref.png
deleted file mode 100644 (file)
index 15d1a31..0000000
Binary files a/test/reference/record90-paint-alpha-clip.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/record90-text-transform.argb32.ref.png b/test/reference/record90-text-transform.argb32.ref.png
deleted file mode 100644 (file)
index 22f6c1f..0000000
Binary files a/test/reference/record90-text-transform.argb32.ref.png and /dev/null 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
diff --git a/test/reference/record90-text-transform.rgb24.ref.png b/test/reference/record90-text-transform.rgb24.ref.png
deleted file mode 100644 (file)
index 22f6c1f..0000000
Binary files a/test/reference/record90-text-transform.rgb24.ref.png and /dev/null 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 e0cb6ed..f48f34d 100644 (file)
@@ -411,6 +411,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
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 d38b6b0..9d1cdc6 100644 (file)
@@ -330,6 +330,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
@@ -380,7 +381,7 @@ 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
-cairo_fdr_la_LIBADD = -ldl
+@CAIRO_HAS_DL_TRUE@cairo_fdr_la_LIBADD = -ldl
 all: all-am
 
 .SUFFIXES:
index 114218e..8a6fc8d 100644 (file)
@@ -338,6 +338,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
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 a11fda6..f4cda52 100644 (file)
@@ -302,6 +302,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
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 dab3327..54b5066 100644 (file)
@@ -118,7 +118,8 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(cairoincludedir)"
 LTLIBRARIES = $(lib_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libcairo_script_interpreter_la_DEPENDENCIES =  \
-       $(top_builddir)/src/libcairo.la $(am__DEPENDENCIES_1)
+       $(top_builddir)/src/libcairo.la $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1)
 am__objects_1 = libcairo_script_interpreter_la-cairo-script-file.lo \
        libcairo_script_interpreter_la-cairo-script-hash.lo \
        libcairo_script_interpreter_la-cairo-script-interpreter.lo \
@@ -414,6 +415,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
@@ -479,7 +481,7 @@ libcairo_script_interpreter_la_SOURCES = \
 
 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)
 csi_replay_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
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 9e16368..8a967b0 100644 (file)
@@ -269,6 +269,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
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 dca3da7..f759113 100644 (file)
@@ -340,6 +340,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
@@ -390,7 +391,7 @@ 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
-cairo_sphinx_la_LIBADD = -ldl
+@CAIRO_HAS_DL_TRUE@cairo_sphinx_la_LIBADD = -ldl
 cairo_sphinx_SOURCES = sphinx.c
 cairo_sphinx_CPPFLAGS = $(AM_CPPFLAGS) -DLIBDIR="\"$(cairolibdir)\""
 cairo_sphinx_CFLAGS = $(CAIRO_CFLAGS) $(real_pthread_CFLAGS)  $(glib_CFLAGS)
index 9ffa4cb..b3c1b87 100644 (file)
@@ -348,6 +348,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
 mandir = @mandir@
 mesa_DIR = @mesa_DIR@
 mkdir_p = @mkdir_p@
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);
 }