summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2009-07-23 15:32:13 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2009-07-23 15:32:14 +0100
commitbed2701e1c89095878d549cbca8f22d84f3dda3c (patch)
tree974807761b6d839839ecad9961eae8d567898dcc
parentf5a1cdf283a6aa1f4409ccbf3c2274fb587724fe (diff)
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of the operation state, is cumbersome and a hindrance to providing true proxy surface support. For example, the clip must be copied from the surface onto the fallback image, but this was forgotten causing undue hassle in each backend. Another example is the contortion the meta surface endures to ensure the clip is correctly recorded. By contrast passing the clip along with the operation is quite simple and enables us to write generic handlers for providing surface wrappers. (And in the future, we should be able to write more esoteric wrappers, e.g. automatic 2x FSAA, trivially.) In brief, instead of the surface automatically applying the clip before calling the backend, the backend can call into a generic helper to apply clipping. For raster surfaces, clip regions are handled automatically as part of the composite interface. For vector surfaces, a clip helper is introduced to replay and callback into an intersect_clip_path() function as necessary. Whilst this is not primarily a performance related change (the change should just move the computation of the clip from the moment it is applied by the user to the moment it is required by the backend), it is important to track any potential regression: ppc: Speedups ======== image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup ▌ image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup ▎ image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup ▏ image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup ▏ Slowdowns ========= image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown ▏
-rw-r--r--NEWS6
-rw-r--r--boilerplate/cairo-boilerplate-glitz-glx.c4
-rw-r--r--boilerplate/cairo-boilerplate-pdf.c1
-rw-r--r--boilerplate/cairo-boilerplate-ps.c8
-rw-r--r--boilerplate/cairo-boilerplate-qt.cpp4
-rw-r--r--boilerplate/cairo-boilerplate-svg.c1
-rw-r--r--boilerplate/cairo-boilerplate-test-surfaces.c113
-rw-r--r--boilerplate/cairo-boilerplate.c100
-rw-r--r--boilerplate/cairo-boilerplate.h2
-rw-r--r--perf/unaligned-clip.c3
-rw-r--r--src/Makefile.sources7
-rw-r--r--src/cairo-analysis-surface-private.h6
-rw-r--r--src/cairo-analysis-surface.c539
-rw-r--r--src/cairo-beos-surface.cpp409
-rw-r--r--src/cairo-clip-private.h87
-rw-r--r--src/cairo-clip.c1290
-rw-r--r--src/cairo-debug.c2
-rw-r--r--src/cairo-directfb-surface.c491
-rw-r--r--src/cairo-ft-font.c53
-rw-r--r--src/cairo-gl-private.h1
-rw-r--r--src/cairo-gl-surface.c216
-rw-r--r--src/cairo-glitz-surface.c213
-rw-r--r--src/cairo-gstate.c233
-rw-r--r--src/cairo-image-surface.c173
-rw-r--r--src/cairo-meta-surface-private.h43
-rw-r--r--src/cairo-meta-surface.c550
-rw-r--r--src/cairo-os2-surface.c14
-rw-r--r--src/cairo-paginated-private.h2
-rw-r--r--src/cairo-paginated-surface-private.h9
-rw-r--r--src/cairo-paginated-surface.c234
-rw-r--r--src/cairo-path-bounds.c65
-rw-r--r--src/cairo-path-fill.c11
-rw-r--r--src/cairo-path-fixed-private.h36
-rw-r--r--src/cairo-path-fixed.c201
-rw-r--r--src/cairo-path-in-fill.c27
-rw-r--r--src/cairo-path-stroke.c8
-rw-r--r--src/cairo-pattern.c127
-rw-r--r--src/cairo-pdf-surface-private.h3
-rw-r--r--src/cairo-pdf-surface.c220
-rw-r--r--src/cairo-ps-surface-private.h4
-rw-r--r--src/cairo-ps-surface.c367
-rw-r--r--src/cairo-qt-surface.cpp373
-rw-r--r--src/cairo-quartz-image-surface.c14
-rw-r--r--src/cairo-quartz-private.h2
-rw-r--r--src/cairo-quartz-surface.c136
-rw-r--r--src/cairo-region-private.h73
-rw-r--r--src/cairo-region.c170
-rw-r--r--src/cairo-scaled-font.c132
-rw-r--r--src/cairo-script-surface.c611
-rw-r--r--src/cairo-script.h10
-rw-r--r--src/cairo-spans-private.h19
-rw-r--r--src/cairo-spans.c20
-rw-r--r--src/cairo-stroke-style.c8
-rw-r--r--src/cairo-surface-clipper-private.h72
-rw-r--r--src/cairo-surface-clipper.c138
-rw-r--r--src/cairo-surface-fallback-private.h21
-rw-r--r--src/cairo-surface-fallback.c995
-rw-r--r--src/cairo-surface-private.h19
-rw-r--r--src/cairo-surface-wrapper-private.h156
-rw-r--r--src/cairo-surface-wrapper.c449
-rw-r--r--src/cairo-surface.c857
-rw-r--r--src/cairo-svg-surface-private.h4
-rw-r--r--src/cairo-svg-surface.c527
-rw-r--r--src/cairo-traps.c26
-rw-r--r--src/cairo-type3-glyph-surface-private.h9
-rw-r--r--src/cairo-type3-glyph-surface.c94
-rw-r--r--src/cairo-types-private.h9
-rw-r--r--src/cairo-user-font.c30
-rw-r--r--src/cairo-vg-surface.c122
-rw-r--r--src/cairo-win32-font.c16
-rw-r--r--src/cairo-win32-printing-surface.c194
-rw-r--r--src/cairo-win32-private.h15
-rw-r--r--src/cairo-win32-surface.c279
-rw-r--r--src/cairo-xcb-surface.c248
-rw-r--r--src/cairo-xlib-surface-private.h2
-rw-r--r--src/cairo-xlib-surface.c492
-rw-r--r--src/cairo.c83
-rw-r--r--src/cairo.h30
-rw-r--r--src/cairoint.h325
-rw-r--r--src/test-fallback-surface.c4
-rw-r--r--src/test-fallback16-surface.c4
-rw-r--r--src/test-null-surface.c35
-rw-r--r--src/test-paginated-surface.c100
-rw-r--r--src/test-paginated-surface.h6
-rw-r--r--src/test-wrapping-surface.c272
-rw-r--r--src/test-wrapping-surface.h51
-rw-r--r--test/Makefile.am75
-rw-r--r--test/Makefile.sources2
-rw-r--r--test/buffer-diff.c12
-rw-r--r--test/cairo-test.c18
-rw-r--r--test/clip-operator.pdf.argb32.ref.pngbin0 -> 9340 bytes
-rw-r--r--test/clip-operator.pdf.argb32.xfail.pngbin9340 -> 0 bytes
-rw-r--r--test/clip-operator.pdf.rgb24.ref.pngbin0 -> 5146 bytes
-rw-r--r--test/clip-operator.pdf.rgb24.xfail.pngbin5155 -> 0 bytes
-rw-r--r--test/clip-operator.svg12.argb32.xfail.pngbin8404 -> 8406 bytes
-rw-r--r--test/clip-operator.svg12.rgb24.xfail.pngbin4523 -> 4540 bytes
-rw-r--r--test/clip-operator.xlib-fallback.ref.pngbin0 -> 3226 bytes
-rw-r--r--test/clip-operator.xlib-fallback.rgb24.ref.pngbin3254 -> 0 bytes
-rw-r--r--test/clip-push-group.pdf.ref.pngbin0 -> 164 bytes
-rw-r--r--test/clip-push-group.ref.pngbin199 -> 164 bytes
-rw-r--r--test/clip-push-group.xlib.ref.pngbin0 -> 155 bytes
-rw-r--r--test/clip-unbounded.c80
-rw-r--r--test/clip-unbounded.ref.pngbin0 -> 100 bytes
-rw-r--r--test/clip-unbounded.rgb24.ref.pngbin0 -> 97 bytes
-rw-r--r--test/clip-unbounded.svg12.rgb24.xfail.pngbin0 -> 100 bytes
-rw-r--r--test/clipped-group.pdf.argb32.ref.pngbin298 -> 0 bytes
-rw-r--r--test/clipped-group.pdf.ref.pngbin0 -> 310 bytes
-rw-r--r--test/clipped-group.pdf.rgb24.ref.pngbin298 -> 0 bytes
-rw-r--r--test/clipped-group.ref.pngbin350 -> 316 bytes
-rw-r--r--test/composite-integer-translate-source.svg12.argb32.xfail.pngbin0 -> 16392 bytes
-rw-r--r--test/composite-integer-translate-source.svg12.rgb24.xfail.pngbin0 -> 16392 bytes
-rw-r--r--test/device-offset-fractional.pdf.argb32.ref.pngbin275 -> 0 bytes
-rw-r--r--test/device-offset-fractional.pdf.ref.pngbin277 -> 0 bytes
-rw-r--r--test/device-offset-fractional.pdf.rgb24.ref.pngbin275 -> 0 bytes
-rw-r--r--test/device-offset-fractional.pdf.xfail.pngbin0 -> 275 bytes
-rw-r--r--test/extended-blend-alpha.svg12.argb32.xfail.pngbin0 -> 6857 bytes
-rw-r--r--test/extended-blend-alpha.svg12.rgb24.xfail.pngbin0 -> 5014 bytes
-rw-r--r--test/extended-blend.svg12.argb32.xfail.pngbin0 -> 2273 bytes
-rw-r--r--test/extended-blend.svg12.rgb24.xfail.pngbin0 -> 1856 bytes
-rw-r--r--test/fill-empty.argb32.ref.pngbin0 -> 99 bytes
-rw-r--r--test/fill-empty.c62
-rw-r--r--test/fill-empty.rgb24.ref.pngbin0 -> 97 bytes
-rw-r--r--test/fill-empty.svg12.rgb24.xfail.pngbin0 -> 99 bytes
-rw-r--r--test/filter-nearest-offset.pdf.xfail.pngbin1926 -> 1867 bytes
-rw-r--r--test/filter-nearest-transformed.pdf.xfail.pngbin488 -> 482 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.pdf.argb32.ref.pngbin3632 -> 0 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.pdf.ref.pngbin3968 -> 3635 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.pdf.rgb24.ref.pngbin3632 -> 0 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.pdf.argb32.ref.pngbin3642 -> 0 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.pdf.ref.pngbin3634 -> 3639 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.pdf.rgb24.ref.pngbin3642 -> 0 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.ref.pngbin3609 -> 3608 bytes
-rw-r--r--test/group-unaligned.svg.argb32.xfail.pngbin522 -> 520 bytes
-rw-r--r--test/group-unaligned.xlib-fallback.ref.pngbin496 -> 474 bytes
-rw-r--r--test/image-surface-source.svg12.argb32.xfail.pngbin0 -> 278 bytes
-rw-r--r--test/image-surface-source.svg12.rgb24.xfail.pngbin0 -> 278 bytes
-rw-r--r--test/in-fill-trapezoid.c19
-rw-r--r--test/mask-glyphs.svg.ref.pngbin1211170 -> 1211147 bytes
-rw-r--r--test/mask.pdf.argb32.ref.pngbin0 -> 7837 bytes
-rw-r--r--test/mask.pdf.argb32.xfail.pngbin7944 -> 0 bytes
-rw-r--r--test/mask.pdf.rgb24.ref.pngbin0 -> 7301 bytes
-rw-r--r--test/mask.pdf.rgb24.xfail.pngbin7388 -> 0 bytes
-rw-r--r--test/mask.xlib-fallback.rgb24.ref.pngbin7216 -> 0 bytes
-rw-r--r--test/meta-surface-pattern.pdf.argb32.ref.pngbin4009 -> 3868 bytes
-rw-r--r--test/meta-surface-pattern.pdf.rgb24.ref.pngbin3905 -> 3806 bytes
-rw-r--r--test/operator-clear.xlib.argb32.ref.pngbin0 -> 1071 bytes
-rw-r--r--test/operator-clear.xlib.rgb24.ref.png (renamed from test/operator-clear.xlib.ref.png)bin951 -> 951 bytes
-rw-r--r--test/operator-source.pdf.rgb24.ref.png (renamed from test/operator-source.pdf.rgb24.xfail.png)bin3645 -> 3645 bytes
-rw-r--r--test/operator-source.svg12.argb32.xfail.pngbin2951 -> 2967 bytes
-rw-r--r--test/operator-source.svg12.rgb24.xfail.pngbin2963 -> 2976 bytes
-rw-r--r--test/operator-source.xlib-fallback.ref.pngbin0 -> 3177 bytes
-rw-r--r--test/operator-source.xlib-fallback.rgb24.ref.pngbin3193 -> 0 bytes
-rw-r--r--test/path-append.xlib-fallback.ref.pngbin6357 -> 6320 bytes
-rw-r--r--test/pdf-surface-source.svg12.argb32.xfail.pngbin0 -> 278 bytes
-rw-r--r--test/pdf-surface-source.svg12.rgb24.xfail.pngbin0 -> 278 bytes
-rw-r--r--test/ps-surface-source.svg12.argb32.xfail.pngbin0 -> 278 bytes
-rw-r--r--test/ps-surface-source.svg12.rgb24.xfail.pngbin0 -> 278 bytes
-rw-r--r--test/push-group.xlib-fallback.rgb24.ref.pngbin2912 -> 0 bytes
-rw-r--r--test/scale-offset-image.meta.xfail.pngbin0 -> 8599 bytes
-rw-r--r--test/scale-offset-image.pdf.rgb24.ref.pngbin8691 -> 0 bytes
-rw-r--r--test/scale-offset-image.pdf.xfail.png (renamed from test/scale-offset-image.pdf.argb32.ref.png)bin8692 -> 8692 bytes
-rw-r--r--test/scale-offset-image.xlib-fallback.xfail.pngbin0 -> 8580 bytes
-rw-r--r--test/scale-offset-similar.meta.xfail.pngbin0 -> 9095 bytes
-rw-r--r--test/scale-offset-similar.pdf.argb32.ref.pngbin9278 -> 0 bytes
-rw-r--r--test/scale-offset-similar.pdf.rgb24.ref.pngbin9278 -> 0 bytes
-rw-r--r--test/scale-offset-similar.pdf.xfail.pngbin0 -> 9369 bytes
-rw-r--r--test/scale-offset-similar.xlib-fallback.xfail.pngbin0 -> 8580 bytes
-rw-r--r--test/self-intersecting.argb32.xfail.pngbin287 -> 235 bytes
-rw-r--r--test/self-intersecting.pdf.argb32.xfail.pngbin295 -> 285 bytes
-rw-r--r--test/self-intersecting.pdf.rgb24.xfail.pngbin272 -> 269 bytes
-rw-r--r--test/self-intersecting.rgb24.xfail.pngbin282 -> 240 bytes
-rw-r--r--test/smask-fill.xlib-fallback.ref.pngbin1156 -> 0 bytes
-rw-r--r--test/smask-text.xlib.ref.pngbin0 -> 1672 bytes
-rw-r--r--test/smask.xlib.ref.pngbin0 -> 3393 bytes
-rw-r--r--test/surface-pattern-big-scale-down.ps.xfail.pngbin0 -> 238 bytes
-rw-r--r--test/svg-surface-source.svg12.argb32.xfail.pngbin0 -> 278 bytes
-rw-r--r--test/svg-surface-source.svg12.rgb24.xfail.pngbin0 -> 278 bytes
-rw-r--r--test/test-fallback16-surface-source.svg12.argb32.xfail.pngbin0 -> 278 bytes
-rw-r--r--test/test-fallback16-surface-source.svg12.rgb24.xfail.pngbin0 -> 278 bytes
-rw-r--r--test/text-pattern.pdf.argb32.ref.pngbin0 -> 1831 bytes
-rw-r--r--test/text-pattern.pdf.argb32.xfail.pngbin1845 -> 0 bytes
-rw-r--r--test/text-pattern.pdf.rgb24.ref.pngbin0 -> 1598 bytes
-rw-r--r--test/text-pattern.pdf.rgb24.xfail.pngbin1599 -> 0 bytes
-rw-r--r--test/unbounded-operator.svg12.argb32.xfail.pngbin2767 -> 2771 bytes
-rw-r--r--test/unbounded-operator.svg12.rgb24.xfail.pngbin1719 -> 1731 bytes
-rw-r--r--test/user-font-proxy.svg.ref.pngbin16817 -> 16814 bytes
-rw-r--r--test/xlib-surface-source.svg12.argb32.xfail.pngbin0 -> 278 bytes
-rw-r--r--test/xlib-surface-source.svg12.rgb24.xfail.pngbin0 -> 278 bytes
-rw-r--r--util/cairo-script/cairo-script-file.c39
-rw-r--r--util/cairo-script/cairo-script-objects.c22
-rw-r--r--util/cairo-script/cairo-script-private.h9
-rw-r--r--util/cairo-script/cairo-script-scanner.c52
-rw-r--r--util/cairo-trace/trace.c119
193 files changed, 7741 insertions, 5903 deletions
diff --git a/NEWS b/NEWS
index 681f2345..a561a3f9 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,12 @@ API additions:
Finally exporting the internal meta-surface so that applications
have a method to record and replay a sequence of drawing commands.
+ cairo_in_clip()
+
+ Determines whether a given point is inside the current clip.
+ ??? Should this be called cairo_in_paint() instead? in-clip is the test
+ that is performed, but in-paint would be similar to in-fill and in-stroke.
+
New utilities:
cairo-test-trace
diff --git a/boilerplate/cairo-boilerplate-glitz-glx.c b/boilerplate/cairo-boilerplate-glitz-glx.c
index 6dfdb7fe..6e3cfec3 100644
--- a/boilerplate/cairo-boilerplate-glitz-glx.c
+++ b/boilerplate/cairo-boilerplate-glitz-glx.c
@@ -33,7 +33,6 @@
static const cairo_user_data_key_t glitz_closure_key;
typedef struct _glitz_glx_target_closure {
- glitz_target_closure_base_t base;
Display *dpy;
int scr;
Window win;
@@ -206,9 +205,6 @@ _cairo_boilerplate_glitz_glx_create_surface (const char *name,
if (cairo_surface_status (surface))
goto FAIL_CLOSE_DISPLAY;
- gxtc->base.width = width;
- gxtc->base.height = height;
- gxtc->base.content = content;
status = cairo_surface_set_user_data (surface,
&glitz_closure_key, gxtc, NULL);
if (status == CAIRO_STATUS_SUCCESS)
diff --git a/boilerplate/cairo-boilerplate-pdf.c b/boilerplate/cairo-boilerplate-pdf.c
index 166ba1c9..e941d46f 100644
--- a/boilerplate/cairo-boilerplate-pdf.c
+++ b/boilerplate/cairo-boilerplate-pdf.c
@@ -129,7 +129,6 @@ _cairo_boilerplate_pdf_finish_surface (cairo_surface_t *surface)
if (status)
return status;
- cairo_surface_finish (surface);
status = cairo_surface_status (surface);
if (status)
return status;
diff --git a/boilerplate/cairo-boilerplate-ps.c b/boilerplate/cairo-boilerplate-ps.c
index 0fdd0cfa..40148dde 100644
--- a/boilerplate/cairo-boilerplate-ps.c
+++ b/boilerplate/cairo-boilerplate-ps.c
@@ -178,6 +178,7 @@ _cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface)
if (ptc->target) {
cairo_t *cr;
+
cr = cairo_create (ptc->target);
cairo_set_source_surface (cr, surface, 0, 0);
cairo_paint (cr);
@@ -188,7 +189,6 @@ _cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface)
if (status)
return status;
- cairo_surface_finish (surface);
status = cairo_surface_status (surface);
if (status)
return status;
@@ -197,11 +197,7 @@ _cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface)
}
cairo_surface_finish (surface);
- status = cairo_surface_status (surface);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
+ return cairo_surface_status (surface);
}
static cairo_status_t
diff --git a/boilerplate/cairo-boilerplate-qt.cpp b/boilerplate/cairo-boilerplate-qt.cpp
index 5d8d3f93..8f19811f 100644
--- a/boilerplate/cairo-boilerplate-qt.cpp
+++ b/boilerplate/cairo-boilerplate-qt.cpp
@@ -30,7 +30,7 @@
* The Initial Developer of the Original Code is Chris Wilson.
*/
-#include "cairo-boilerplate.h"
+#include "cairo-boilerplate-private.h"
#include <cairo-qt.h>
@@ -108,4 +108,6 @@ static const cairo_boilerplate_target_t targets[] = {
_cairo_boilerplate_qt_cleanup
},
};
+extern "C" {
CAIRO_BOILERPLATE (qt, targets)
+}
diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c
index 9d03b203..45e085ce 100644
--- a/boilerplate/cairo-boilerplate-svg.c
+++ b/boilerplate/cairo-boilerplate-svg.c
@@ -166,7 +166,6 @@ _cairo_boilerplate_svg_finish_surface (cairo_surface_t *surface)
if (status)
return status;
- cairo_surface_finish (surface);
status = cairo_surface_status (surface);
if (status)
return status;
diff --git a/boilerplate/cairo-boilerplate-test-surfaces.c b/boilerplate/cairo-boilerplate-test-surfaces.c
index 849627fd..501866ba 100644
--- a/boilerplate/cairo-boilerplate-test-surfaces.c
+++ b/boilerplate/cairo-boilerplate-test-surfaces.c
@@ -33,6 +33,7 @@
#include <test-paginated-surface.h>
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,9,3)
#include <test-null-surface.h>
+#include <test-wrapping-surface.h>
#endif
#include <cairo-types-private.h>
@@ -49,7 +50,8 @@ _cairo_boilerplate_test_fallback_create_surface (const char *name,
void **closure)
{
*closure = NULL;
- return _cairo_test_fallback_surface_create (content, width, height);
+ return _cairo_test_fallback_surface_create (content,
+ ceil (width), ceil (height));
}
static cairo_surface_t *
@@ -64,7 +66,8 @@ _cairo_boilerplate_test_fallback16_create_surface (const char *name,
void **closure)
{
*closure = NULL;
- return _cairo_test_fallback16_surface_create (content, width, height);
+ return _cairo_test_fallback16_surface_create (content,
+ ceil (width), ceil (height));
}
static cairo_surface_t *
@@ -89,11 +92,7 @@ _cairo_boilerplate_test_null_create_surface (const char *name,
static const cairo_user_data_key_t test_paginated_closure_key;
typedef struct {
- unsigned char *data;
- cairo_content_t content;
- int width;
- int height;
- int stride;
+ cairo_surface_t *target;
} test_paginated_closure_t;
static cairo_surface_t *
@@ -115,18 +114,10 @@ _cairo_boilerplate_test_paginated_create_surface (const char *name,
*closure = tpc = xmalloc (sizeof (test_paginated_closure_t));
format = cairo_boilerplate_format_from_content (content);
+ tpc->target = cairo_image_surface_create (format,
+ ceil (width), ceil (height));
- tpc->content = content;
- tpc->width = width;
- tpc->height = height;
- tpc->stride = cairo_format_stride_for_width (format, width);
- tpc->data = xcalloc (tpc->stride, height);
-
- surface = _cairo_test_paginated_surface_create_for_data (tpc->data,
- tpc->content,
- tpc->width,
- tpc->height,
- tpc->stride);
+ surface = _cairo_test_paginated_surface_create (tpc->target);
if (cairo_surface_status (surface))
goto CLEANUP;
@@ -139,8 +130,9 @@ _cairo_boilerplate_test_paginated_create_surface (const char *name,
cairo_surface_destroy (surface);
surface = cairo_boilerplate_surface_create_in_error (status);
+ cairo_surface_destroy (tpc->target);
+
CLEANUP:
- free (tpc->data);
free (tpc);
return surface;
}
@@ -160,8 +152,6 @@ static cairo_status_t
_cairo_boilerplate_test_paginated_surface_write_to_png (cairo_surface_t *surface,
const char *filename)
{
- cairo_surface_t *image;
- cairo_format_t format;
test_paginated_closure_t *tpc;
cairo_status_t status;
@@ -172,19 +162,7 @@ _cairo_boilerplate_test_paginated_surface_write_to_png (cairo_surface_t *surface
return status;
tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key);
-
- format = cairo_boilerplate_format_from_content (tpc->content);
-
- image = cairo_image_surface_create_for_data (tpc->data,
- format,
- tpc->width,
- tpc->height,
- tpc->stride);
-
- status = cairo_surface_write_to_png (image, filename);
- cairo_surface_destroy (image);
-
- return status;
+ return cairo_surface_write_to_png (tpc->target, filename);
}
static cairo_surface_t *
@@ -193,7 +171,6 @@ _cairo_boilerplate_test_paginated_get_image_surface (cairo_surface_t *surface,
int width,
int height)
{
- cairo_format_t format;
test_paginated_closure_t *tpc;
cairo_status_t status;
@@ -208,30 +185,7 @@ _cairo_boilerplate_test_paginated_get_image_surface (cairo_surface_t *surface,
return cairo_boilerplate_surface_create_in_error (status);
tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key);
-
- format = cairo_boilerplate_format_from_content (tpc->content);
-
- if (0) {
- return cairo_image_surface_create_for_data (tpc->data + tpc->stride * (tpc->height - height) + 4 * (tpc->width - width), /* hide the device offset */
- format,
- width,
- height,
- tpc->stride);
- } else {
- cairo_surface_t *image, *surface;
-
- image = cairo_image_surface_create_for_data (tpc->data,
- format,
- tpc->width,
- tpc->height,
- tpc->stride);
- cairo_surface_set_device_offset (image,
- tpc->width - width,
- tpc->height - height);
- surface = _cairo_boilerplate_get_image_surface (image, 0, width, height);
- cairo_surface_destroy (image);
- return surface;
- }
+ return _cairo_boilerplate_get_image_surface (tpc->target, 0, width, height);
}
static void
@@ -239,10 +193,40 @@ _cairo_boilerplate_test_paginated_cleanup (void *closure)
{
test_paginated_closure_t *tpc = closure;
- free (tpc->data);
+ cairo_surface_destroy (tpc->target);
free (tpc);
}
+static cairo_surface_t *
+_cairo_boilerplate_test_wrapping_create_surface (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,9,3)
+ cairo_surface_t *target;
+ cairo_surface_t *surface;
+ cairo_format_t format;
+
+ *closure = NULL;
+
+ format = cairo_boilerplate_format_from_content (content);
+ target = cairo_image_surface_create (format, ceil (width), ceil (height));
+ surface = _cairo_test_wrapping_surface_create (target);
+ cairo_surface_destroy (target);
+
+ return surface;
+#else
+ *closure = NULL;
+ return NULL;
+#endif
+}
+
static const cairo_boilerplate_target_t targets[] = {
{
"test-fallback", "image", NULL, NULL,
@@ -305,6 +289,15 @@ static const cairo_boilerplate_target_t targets[] = {
FALSE, TRUE
},
{
+ "test-wrapping", "image", NULL, NULL,
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
+ CAIRO_CONTENT_COLOR_ALPHA, 0,
+ _cairo_boilerplate_test_wrapping_create_surface,
+ NULL, NULL,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ },
+ {
"null", "image", NULL, NULL,
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
CAIRO_CONTENT_COLOR_ALPHA, 0,
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index ea88c691..a0810457 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -32,6 +32,10 @@
#include <cairo-types-private.h>
#include <cairo-scaled-font-private.h>
+#if CAIRO_HAS_SCRIPT_SURFACE
+#include <cairo-script.h>
+#endif
+
/* get the "real" version info instead of dummy cairo-version.h */
#undef CAIRO_VERSION_H
#include "../cairo-version.h"
@@ -136,48 +140,74 @@ _cairo_boilerplate_meta_create_surface (const char *name,
int id,
void **closure)
{
+ cairo_rectangle_t extents;
+
*closure = NULL;
- return cairo_meta_surface_create (content, width, height);
+
+ extents.x = 0;
+ extents.y = 0;
+ extents.width = width;
+ extents.height = height;
+ return cairo_meta_surface_create (content, &extents);
}
+const cairo_user_data_key_t cairo_boilerplate_output_basename_key;
+
+#if CAIRO_HAS_SCRIPT_SURFACE
+static cairo_status_t
+stdio_write (void *closure, const unsigned char *data, unsigned int len)
+{
+ if (fwrite (data, len, 1, closure) != 1)
+ return CAIRO_STATUS_WRITE_ERROR;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+#endif
+
cairo_surface_t *
_cairo_boilerplate_get_image_surface (cairo_surface_t *src,
int page,
int width,
int height)
{
- cairo_surface_t *surface;
+ FILE *file = NULL;
+ cairo_surface_t *surface, *image;
cairo_t *cr;
+ cairo_status_t status;
if (cairo_surface_status (src))
return cairo_surface_reference (src);
-#if 0
- if (cairo_surface_get_type (src) == CAIRO_SURFACE_TYPE_IMAGE) {
- int ww = cairo_image_surface_get_width (src);
- int hh = cairo_image_surface_get_height (src);
- if (width == ww && hh == height) {
- return cairo_surface_reference (src);
- } else {
- cairo_format_t format = cairo_image_surface_get_format (src);
- unsigned char *data = cairo_image_surface_get_data (src);
- int stride = cairo_image_surface_get_stride (src);
-
- data += stride * (hh - height) + 4 * (ww - width);
- return cairo_image_surface_create_for_data (data,
- format,
- width,
- height,
- stride);
- }
- }
-#endif
-
if (page != 0)
return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
/* extract sub-surface */
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ image = cairo_surface_reference (surface);
+
+ /* open a logging channel (only interesting for meta surfaces) */
+#if CAIRO_HAS_SCRIPT_SURFACE
+ if (cairo_surface_get_type (src) == CAIRO_SURFACE_TYPE_META) {
+ const char *test_name;
+
+ test_name = cairo_surface_get_user_data (src,
+ &cairo_boilerplate_output_basename_key);
+ if (test_name != NULL) {
+ char *filename;
+
+ xasprintf (&filename, "%s.out.trace", test_name);
+ file = fopen (filename, "w");
+ free (filename);
+
+ if (file != NULL) {
+ surface = cairo_script_surface_create_for_target (image,
+ stdio_write,
+ file);
+ }
+ }
+ }
+#endif
+
cr = cairo_create (surface);
cairo_surface_destroy (surface);
@@ -185,10 +215,17 @@ _cairo_boilerplate_get_image_surface (cairo_surface_t *src,
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
- surface = cairo_surface_reference (cairo_get_target (cr));
+ status = cairo_status (cr);
+ if (status) {
+ cairo_surface_destroy (image);
+ image = cairo_surface_reference (cairo_get_target (cr));
+ }
cairo_destroy (cr);
- return surface;
+ if (file != NULL)
+ fclose (file);
+
+ return image;
}
cairo_surface_t *
@@ -705,8 +742,13 @@ cairo_boilerplate_convert_to_image (const char *filename, int page)
image = cairo_boilerplate_image_surface_create_from_ppm_stream (file);
ret = pclose (file);
+ /* check for fatal errors from the interpreter */
+ if (ret) { /* any2pmm should never die... */
+ cairo_surface_destroy (image);
+ return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_INVALID_STATUS);
+ }
- if (cairo_surface_status (image) == CAIRO_STATUS_READ_ERROR) {
+ if (ret == 0 && cairo_surface_status (image) == CAIRO_STATUS_READ_ERROR) {
if (flags == 0) {
/* Try again in a standalone process. */
cairo_surface_destroy (image);
@@ -715,12 +757,6 @@ cairo_boilerplate_convert_to_image (const char *filename, int page)
}
}
- if (cairo_surface_status (image) == CAIRO_STATUS_SUCCESS && ret != 0) {
- cairo_surface_destroy (image);
- image =
- cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR);
- };
-
return image;
}
diff --git a/boilerplate/cairo-boilerplate.h b/boilerplate/cairo-boilerplate.h
index aaa196c5..377d2f91 100644
--- a/boilerplate/cairo-boilerplate.h
+++ b/boilerplate/cairo-boilerplate.h
@@ -99,6 +99,8 @@ CAIRO_BEGIN_DECLS
* PDF surfaces. */
#define CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED ((unsigned int) -1)
+extern const cairo_user_data_key_t cairo_boilerplate_output_basename_key;
+
cairo_content_t
cairo_boilerplate_content (cairo_content_t content);
diff --git a/perf/unaligned-clip.c b/perf/unaligned-clip.c
index 7fd5245e..f379b61e 100644
--- a/perf/unaligned-clip.c
+++ b/perf/unaligned-clip.c
@@ -49,6 +49,9 @@ do_unaligned_clip (cairo_t *cr, int width, int height)
cairo_rectangle (cr, 55, 55, 35, 35);
cairo_clip (cr);
+ /* And paint something to force the clip to be evaluated. */
+ cairo_paint (cr);
+
cairo_perf_timer_stop ();
cairo_restore (cr);
diff --git a/src/Makefile.sources b/src/Makefile.sources
index c5c14f73..d6fa582a 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -79,11 +79,14 @@ cairo_private = \
cairo-path-private.h \
cairo-private.h \
cairo-reference-count-private.h \
+ cairo-region-private.h \
cairo-scaled-font-private.h \
cairo-skiplist-private.h \
cairo-spans-private.h \
cairo-surface-fallback-private.h \
cairo-surface-private.h \
+ cairo-surface-clipper-private.h \
+ cairo-surface-wrapper-private.h \
cairo-types-private.h \
cairo-user-font-private.h \
cairo-wideint-private.h \
@@ -138,6 +141,8 @@ cairo_sources = \
cairo-stroke-style.c \
cairo-surface.c \
cairo-surface-fallback.c \
+ cairo-surface-clipper.c \
+ cairo-surface-wrapper.c \
cairo-tor-scan-converter.c \
cairo-system.c \
cairo-traps.c \
@@ -198,12 +203,14 @@ cairo_test_surfaces_private = \
test-fallback16-surface.h \
test-null-surface.h \
test-paginated-surface.h \
+ test-wrapping-surface.h \
$(NULL)
cairo_test_surfaces_sources = \
test-fallback-surface.c \
test-fallback16-surface.c \
test-null-surface.c \
test-paginated-surface.c \
+ test-wrapping-surface.c \
$(NULL)
cairo_xlib_headers = cairo-xlib.h
diff --git a/src/cairo-analysis-surface-private.h b/src/cairo-analysis-surface-private.h
index 28bfd3bf..f67caf90 100644
--- a/src/cairo-analysis-surface-private.h
+++ b/src/cairo-analysis-surface-private.h
@@ -38,13 +38,11 @@
#include "cairoint.h"
cairo_private cairo_surface_t *
-_cairo_analysis_surface_create (cairo_surface_t *target,
- int width,
- int height);
+_cairo_analysis_surface_create (cairo_surface_t *target);
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *surface,
- cairo_matrix_t *ctm);
+ const cairo_matrix_t *ctm);
cairo_private void
_cairo_analysis_surface_get_ctm (cairo_surface_t *surface,
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 3a1b2f9f..eb1e87d4 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -39,13 +39,12 @@
#include "cairo-analysis-surface-private.h"
#include "cairo-paginated-private.h"
#include "cairo-meta-surface-private.h"
+#include "cairo-region-private.h"
typedef struct {
cairo_surface_t base;
- int width;
- int height;
- cairo_surface_t *target;
+ cairo_surface_t *target;
cairo_bool_t first_op;
cairo_bool_t has_supported;
@@ -53,7 +52,6 @@ typedef struct {
cairo_region_t supported_region;
cairo_region_t fallback_region;
- cairo_rectangle_int_t current_clip;
cairo_box_t page_bbox;
cairo_bool_t has_ctm;
@@ -97,61 +95,38 @@ static cairo_int_status_t
_analyze_meta_surface_pattern (cairo_analysis_surface_t *surface,
const cairo_pattern_t *pattern)
{
- cairo_surface_t *analysis = &surface->base;
const cairo_surface_pattern_t *surface_pattern;
- cairo_status_t status;
cairo_bool_t old_has_ctm;
cairo_matrix_t old_ctm, p2d;
- cairo_rectangle_int_t old_clip;
- cairo_rectangle_int_t meta_extents;
- int old_width;
- int old_height;
+ cairo_status_t status;
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
surface_pattern = (const cairo_surface_pattern_t *) pattern;
assert (_cairo_surface_is_meta (surface_pattern->surface));
- old_width = surface->width;
- old_height = surface->height;
- old_clip = surface->current_clip;
- status = _cairo_surface_get_extents (surface_pattern->surface, &meta_extents);
- if (_cairo_status_is_error (status))
- return status;
-
- surface->width = meta_extents.width;
- surface->height = meta_extents.height;
- surface->current_clip.x = 0;
- surface->current_clip.y = 0;
- surface->current_clip.width = surface->width;
- surface->current_clip.height = surface->height;
old_ctm = surface->ctm;
old_has_ctm = surface->has_ctm;
+
p2d = pattern->matrix;
status = cairo_matrix_invert (&p2d);
- /* _cairo_pattern_set_matrix guarantees invertibility */
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
- surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
+ surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
status = _cairo_meta_surface_replay_and_create_regions (surface_pattern->surface,
- analysis);
- if (status == CAIRO_STATUS_SUCCESS)
- status = analysis->status;
+ &surface->base);
surface->ctm = old_ctm;
surface->has_ctm = old_has_ctm;
- surface->current_clip = old_clip;
- surface->width = old_width;
- surface->height = old_height;
return status;
}
static cairo_int_status_t
-_add_operation (cairo_analysis_surface_t *surface,
- cairo_rectangle_int_t *rect,
- cairo_int_status_t backend_status)
+_add_operation (cairo_analysis_surface_t *surface,
+ cairo_rectangle_int_t *rect,
+ cairo_int_status_t backend_status)
{
cairo_int_status_t status;
cairo_box_t bbox;
@@ -174,26 +149,33 @@ _add_operation (cairo_analysis_surface_t *surface,
_cairo_box_from_rectangle (&bbox, rect);
if (surface->has_ctm) {
-
- _cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL);
-
- if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
- /* Even though the operation is not visible we must be
- * careful to not allow unsupported operations to be
- * replayed to the backend during
- * CAIRO_PAGINATED_MODE_RENDER */
- if (backend_status == CAIRO_STATUS_SUCCESS ||
- backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
- {
- return CAIRO_STATUS_SUCCESS;
- }
- else
- {
- return CAIRO_INT_STATUS_IMAGE_FALLBACK;
+ int tx, ty;
+
+ if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
+ rect->x += tx;
+ rect->y += ty;
+ } else {
+ _cairo_matrix_transform_bounding_box_fixed (&surface->ctm,
+ &bbox, NULL);
+
+ if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
+ /* Even though the operation is not visible we must be
+ * careful to not allow unsupported operations to be
+ * replayed to the backend during
+ * CAIRO_PAGINATED_MODE_RENDER */
+ if (backend_status == CAIRO_STATUS_SUCCESS ||
+ backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+ else
+ {
+ return CAIRO_INT_STATUS_IMAGE_FALLBACK;
+ }
}
- }
- _cairo_box_round_to_rectangle (&bbox, rect);
+ _cairo_box_round_to_rectangle (&bbox, rect);
+ }
}
if (surface->first_op) {
@@ -234,8 +216,7 @@ _add_operation (cairo_analysis_surface_t *surface,
* this region will be emitted as native operations.
*/
surface->has_supported = TRUE;
- status = cairo_region_union_rectangle (&surface->supported_region, rect);
- return status;
+ return cairo_region_union_rectangle (&surface->supported_region, rect);
}
/* Add the operation to the unsupported region. This region will
@@ -270,101 +251,101 @@ _cairo_analysis_surface_finish (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_analysis_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
+static cairo_bool_t
+_cairo_analysis_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *rectangle)
{
cairo_analysis_surface_t *surface = abstract_surface;
- if (path == NULL) {
- surface->current_clip.x = 0;
- surface->current_clip.y = 0;
- surface->current_clip.width = surface->width;
- surface->current_clip.height = surface->height;
- } else {
- cairo_rectangle_int_t extents;
- cairo_bool_t is_empty;
+ return _cairo_surface_get_extents (surface->target, rectangle);
+}
- _cairo_path_fixed_approximate_clip_extents (path, &extents);
- is_empty = _cairo_rectangle_intersect (&surface->current_clip,
- &extents);
- }
+static void
+_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
+{
+ const cairo_rectangle_int_t *clip_extents;
+ cairo_bool_t is_empty;
- return CAIRO_STATUS_SUCCESS;
+ clip_extents = NULL;
+ if (clip != NULL)
+ clip_extents = _cairo_clip_get_extents (clip);
+
+ if (clip_extents != NULL)
+ is_empty = _cairo_rectangle_intersect (extents, clip_extents);
}
-static cairo_int_status_t
-_cairo_analysis_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *rectangle)
+static void
+_cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents)
{
- cairo_analysis_surface_t *surface = abstract_surface;
+ cairo_bool_t is_empty;
- return _cairo_surface_get_extents (surface->target, rectangle);
+ is_empty = _cairo_surface_get_extents (&surface->base, extents);
+
+ if (_cairo_operator_bounded_by_source (op)) {
+ cairo_rectangle_int_t source_extents;
+
+ _cairo_pattern_get_extents (source, &source_extents);
+ is_empty = _cairo_rectangle_intersect (extents, &source_extents);
+ }
+
+ _rectangle_intersect_clip (extents, clip);
}
static cairo_int_status_t
_cairo_analysis_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *paint_extents)
+ cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
- cairo_status_t status, backend_status;
+ cairo_status_t backend_status;
cairo_rectangle_int_t extents;
- cairo_bool_t is_empty;
- if (!surface->target->backend->paint)
+ if (surface->target->backend->paint == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
- else
- backend_status = (*surface->target->backend->paint) (surface->target, op,
- source, NULL);
+ } else {
+ backend_status =
+ surface->target->backend->paint (surface->target,
+ op, source, clip);
+ if (_cairo_status_is_error (backend_status))
+ return backend_status;
+ }
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
- status = _cairo_surface_get_extents (&surface->base, &extents);
- if (_cairo_status_is_error (status))
- return status;
-
- if (_cairo_operator_bounded_by_source (op)) {
- cairo_rectangle_int_t source_extents;
-
- status = _cairo_pattern_get_extents (source, &source_extents);
- if (unlikely (status))
- return status;
-
- is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
- }
-
- is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
- if (paint_extents)
- *paint_extents = extents;
-
- status = _add_operation (surface, &extents, backend_status);
+ _cairo_analysis_surface_operation_extents (surface,
+ op, source, clip,
+ &extents);
- return status;
+ return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
-_cairo_analysis_surface_mask (void *abstract_surface,
- cairo_operator_t op,
+_cairo_analysis_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *mask_extents)
+ cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
- cairo_int_status_t status, backend_status;
+ cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
- if (!surface->target->backend->mask)
+ if (surface->target->backend->mask == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
- else
- backend_status = (*surface->target->backend->mask) (surface->target, op,
- source, mask, NULL);
+ } else {
+ backend_status =
+ surface->target->backend->mask (surface->target,
+ op, source, mask, clip);
+ if (_cairo_status_is_error (backend_status))
+ return backend_status;
+ }
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) {
cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
@@ -395,37 +376,19 @@ _cairo_analysis_surface_mask (void *abstract_surface,
backend_mask_status);
}
- status = _cairo_surface_get_extents (&surface->base, &extents);
- if (_cairo_status_is_error (status))
- return status;
-
- if (_cairo_operator_bounded_by_source (op)) {
- cairo_rectangle_int_t source_extents;
-
- status = _cairo_pattern_get_extents (source, &source_extents);
- if (unlikely (status))
- return status;
-
- is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
- }
+ _cairo_analysis_surface_operation_extents (surface,
+ op, source, clip,
+ &extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
- status = _cairo_pattern_get_extents (mask, &mask_extents);
- if (unlikely (status))
- return status;
-
+ _cairo_pattern_get_extents (mask, &mask_extents);
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
- }
-
- is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
- if (mask_extents)
- *mask_extents = extents;
- status = _add_operation (surface, &extents, backend_status);
+ }
- return status;
+ return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
@@ -438,55 +401,61 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *stroke_extents)
+ cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
- cairo_status_t status, backend_status;
+ cairo_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
- if (!surface->target->backend->stroke)
+ if (surface->target->backend->stroke == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
- else
- backend_status = (*surface->target->backend->stroke) (surface->target, op,
- source, path, style,
- ctm, ctm_inverse,
- tolerance, antialias, NULL);
+ } else {
+ backend_status =
+ surface->target->backend->stroke (surface->target, op,
+ source, path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
+ if (_cairo_status_is_error (backend_status))
+ return backend_status;
+ }
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
- status = _cairo_surface_get_extents (&surface->base, &extents);
- if (_cairo_status_is_error (status))
- return status;
-
- if (_cairo_operator_bounded_by_source (op)) {
- cairo_rectangle_int_t source_extents;
-
- status = _cairo_pattern_get_extents (source, &source_extents);
- if (unlikely (status))
- return status;
-
- is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
- }
-
- is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
+ _cairo_analysis_surface_operation_extents (surface,
+ op, source, clip,
+ &extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
- _cairo_path_fixed_approximate_stroke_extents (path,
- style, ctm,
- &mask_extents);
+ /* If the backend can handle the stroke, then mark the approximate
+ * extents of the operation. However, if we need to fallback in order
+ * to draw the stroke, then ensure that the fallback is as tight as
+ * possible -- both to minimise output file size and to ensure good
+ * quality printed output for neighbouring regions.
+ */
+ if (backend_status == CAIRO_STATUS_SUCCESS) {
+ _cairo_path_fixed_approximate_stroke_extents (path,
+ style, ctm,
+ &mask_extents);
+ } else {
+ cairo_status_t status;
+
+ status = _cairo_path_fixed_stroke_extents (path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ &mask_extents);
+ if (unlikely (status))
+ return status;
+ }
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
- if (stroke_extents)
- *stroke_extents = extents;
- status = _add_operation (surface, &extents, backend_status);
-
- return status;
+ return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
@@ -497,53 +466,49 @@ _cairo_analysis_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *fill_extents)
+ cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
- cairo_status_t status, backend_status;
+ cairo_status_t backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
- if (!surface->target->backend->fill)
+ if (surface->target->backend->fill == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
- else
- backend_status = (*surface->target->backend->fill) (surface->target, op,
- source, path, fill_rule,
- tolerance, antialias, NULL);
+ } else {
+ backend_status =
+ surface->target->backend->fill (surface->target, op,
+ source, path, fill_rule,
+ tolerance, antialias,
+ clip);
+ if (_cairo_status_is_error (backend_status))
+ return backend_status;
+ }
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
- status = _cairo_surface_get_extents (&surface->base, &extents);
- if (_cairo_status_is_error (status))
- return status;
-
- if (_cairo_operator_bounded_by_source (op)) {
- cairo_rectangle_int_t source_extents;
-
- status = _cairo_pattern_get_extents (source, &source_extents);
- if (unlikely (status))
- return status;
-
- is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
- }
-
- is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
+ _cairo_analysis_surface_operation_extents (surface,
+ op, source, clip,
+ &extents);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
- _cairo_path_fixed_approximate_fill_extents (path,
- &mask_extents);
-
+ /* We want speed for the likely case where the operation can be
+ * performed natively, but accuracy if we have to resort to
+ * using images.
+ */
+ if (backend_status == CAIRO_STATUS_SUCCESS) {
+ _cairo_path_fixed_approximate_fill_extents (path, &mask_extents);
+ } else {
+ _cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
+ &mask_extents);
+ }
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
- if (fill_extents)
- *fill_extents = extents;
-
- status = _add_operation (surface, &extents, backend_status);
- return status;
+ return _add_operation (surface, &extents, backend_status);
}
static cairo_int_status_t
@@ -553,8 +518,8 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *show_glyphs_extents)
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
@@ -562,41 +527,42 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_bool_t is_empty;
/* Adapted from _cairo_surface_show_glyphs */
- if (surface->target->backend->show_glyphs)
- backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
- source,
- glyphs, num_glyphs,
- scaled_font,
- remaining_glyphs, NULL);
- else if (surface->target->backend->show_text_glyphs)
- backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
- source,
- NULL, 0,
- glyphs, num_glyphs,
- NULL, 0,
- FALSE,
- scaled_font, NULL);
+ if (surface->target->backend->show_glyphs != NULL) {
+ backend_status =
+ surface->target->backend->show_glyphs (surface->target, op,
+ source,
+ glyphs, num_glyphs,
+ scaled_font,
+ clip,
+ remaining_glyphs);
+ if (_cairo_status_is_error (backend_status))
+ return backend_status;
+ }
+ else if (surface->target->backend->show_text_glyphs != NULL)
+ {
+ backend_status =
+ surface->target->backend->show_text_glyphs (surface->target, op,
+ source,
+ NULL, 0,
+ glyphs, num_glyphs,
+ NULL, 0,
+ FALSE,
+ scaled_font,
+ clip);
+ if (_cairo_status_is_error (backend_status))
+ return backend_status;
+ }
else
+ {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
+ }
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
- status = _cairo_surface_get_extents (&surface->base, &extents);
- if (_cairo_status_is_error (status))
- return status;
-
- if (_cairo_operator_bounded_by_source (op)) {
- cairo_rectangle_int_t source_extents;
-
- status = _cairo_pattern_get_extents (source, &source_extents);
- if (unlikely (status))
- return status;
-
- is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
- }
-
- is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
+ _cairo_analysis_surface_operation_extents (surface,
+ op, source, clip,
+ &extents);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
@@ -608,12 +574,8 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
- if (show_glyphs_extents)
- *show_glyphs_extents = extents;
-
- status = _add_operation (surface, &extents, backend_status);
- return status;
+ return _add_operation (surface, &extents, backend_status);
}
static cairo_bool_t
@@ -636,7 +598,7 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
- cairo_rectangle_int_t *show_text_glyphs_extents)
+ cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
@@ -645,20 +607,33 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
/* Adapted from _cairo_surface_show_glyphs */
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (surface->target->backend->show_text_glyphs)
- backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
- source,
- utf8, utf8_len,
- glyphs, num_glyphs,
- clusters, num_clusters, cluster_flags,
- scaled_font, NULL);
- if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) {
+ if (surface->target->backend->show_text_glyphs != NULL) {
+ backend_status =
+ surface->target->backend->show_text_glyphs (surface->target, op,
+ source,
+ utf8, utf8_len,
+ glyphs, num_glyphs,
+ clusters, num_clusters,
+ cluster_flags,
+ scaled_font,
+ clip);
+ if (_cairo_status_is_error (backend_status))
+ return backend_status;
+ }
+ if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
+ surface->target->backend->show_glyphs != NULL)
+ {
int remaining_glyphs = num_glyphs;
- backend_status = surface->target->backend->show_glyphs (surface->target, op,
- source,
- glyphs, num_glyphs,
- scaled_font,
- &remaining_glyphs, NULL);
+ backend_status =
+ surface->target->backend->show_glyphs (surface->target, op,
+ source,
+ glyphs, num_glyphs,
+ scaled_font,
+ clip,
+ &remaining_glyphs);
+ if (_cairo_status_is_error (backend_status))
+ return backend_status;
+
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
@@ -668,21 +643,9 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
- status = _cairo_surface_get_extents (&surface->base, &extents);
- if (_cairo_status_is_error (status))
- return status;
-
- if (_cairo_operator_bounded_by_source (op)) {
- cairo_rectangle_int_t source_extents;
-
- status = _cairo_pattern_get_extents (source, &source_extents);
- if (unlikely (status))
- return status;
-
- is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
- }
-
- is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
+ _cairo_analysis_surface_operation_extents (surface,
+ op, source, clip,
+ &extents);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
@@ -694,12 +657,8 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
- if (show_text_glyphs_extents)
- *show_text_glyphs_extents = extents;
-
- status = _add_operation (surface, &extents, backend_status);
- return status;
+ return _add_operation (surface, &extents, backend_status);
}
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
@@ -718,8 +677,6 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- NULL, /* set_clip_region */
- _cairo_analysis_surface_intersect_clip_path,
_cairo_analysis_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -734,7 +691,6 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
_cairo_analysis_surface_show_glyphs,
NULL, /* snapshot */
NULL, /* is_similar */
- NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
@@ -743,9 +699,7 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
};
cairo_surface_t *
-_cairo_analysis_surface_create (cairo_surface_t *target,
- int width,
- int height)
+_cairo_analysis_surface_create (cairo_surface_t *target)
{
cairo_analysis_surface_t *surface;
cairo_status_t status;
@@ -763,8 +717,6 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
_cairo_surface_init (&surface->base, &cairo_analysis_surface_backend,
CAIRO_CONTENT_COLOR_ALPHA);
- surface->width = width;
- surface->height = height;
cairo_matrix_init_identity (&surface->ctm);
surface->has_ctm = FALSE;
@@ -781,24 +733,12 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
surface->page_bbox.p2.x = 0;
surface->page_bbox.p2.y = 0;
- if (width == -1 && height == -1) {
- surface->current_clip.x = CAIRO_RECT_INT_MIN;
- surface->current_clip.y = CAIRO_RECT_INT_MIN;
- surface->current_clip.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
- surface->current_clip.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
- } else {
- surface->current_clip.x = 0;
- surface->current_clip.y = 0;
- surface->current_clip.width = width;
- surface->current_clip.height = height;
- }
-
return &surface->base;
}
void
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
- cairo_matrix_t *ctm)
+ const cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface;
@@ -808,7 +748,7 @@ _cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
surface = (cairo_analysis_surface_t *) abstract_surface;
surface->ctm = *ctm;
- surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
+ surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
}
void
@@ -872,21 +812,17 @@ _return_success (void)
/* These typedefs are just to silence the compiler... */
typedef cairo_int_status_t
-(*_set_clip_region_func) (void *surface,
- cairo_region_t *region);
-
-typedef cairo_int_status_t
(*_paint_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
typedef cairo_int_status_t
(*_mask_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
typedef cairo_int_status_t
(*_stroke_func) (void *surface,
@@ -898,7 +834,7 @@ typedef cairo_int_status_t
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
typedef cairo_int_status_t
(*_fill_func) (void *surface,
@@ -908,7 +844,7 @@ typedef cairo_int_status_t
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
typedef cairo_int_status_t
(*_show_glyphs_func) (void *surface,
@@ -917,8 +853,8 @@ typedef cairo_int_status_t
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip,
+ int *remaining_glyphs);
static const cairo_surface_backend_t cairo_null_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
@@ -937,8 +873,6 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- (_set_clip_region_func) _return_success, /* set_clip_region */
- NULL, /* intersect_clip_path */
NULL, /* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -953,7 +887,6 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
(_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
- NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
diff --git a/src/cairo-beos-surface.cpp b/src/cairo-beos-surface.cpp
index e527272e..6fbdc470 100644
--- a/src/cairo-beos-surface.cpp
+++ b/src/cairo-beos-surface.cpp
@@ -56,6 +56,8 @@
struct cairo_beos_surface_t {
cairo_surface_t base;
+ cairo_region_t *clip_region;
+
BView* view;
/*
@@ -70,7 +72,6 @@ struct cairo_beos_surface_t {
BBitmap* bitmap;
-
// If true, surface and view should be deleted when this surface is
// destroyed
bool owns_bitmap_view;
@@ -101,27 +102,28 @@ _cairo_beos_surface_create_internal (BView* view,
BBitmap* bmp,
bool owns_bitmap_view = false);
-static BRect
-_cairo_rect_to_brect (const cairo_rectangle_int16_t* rect)
+static inline BRect
+_cairo_rectangle_to_brect (const cairo_rectangle_int_t* rect)
{
// A BRect is one pixel wider than you'd think
- return BRect(rect->x, rect->y, rect->x + rect->width - 1,
- rect->y + rect->height - 1);
+ return BRect (rect->x, rect->y,
+ rect->x + rect->width - 1,
+ rect->y + rect->height - 1);
}
-static cairo_rectangle_int16_t
-_brect_to_cairo_rect (const BRect& rect)
+static inline cairo_rectangle_int_t
+_brect_to_cairo_rectangle (const BRect &rect)
{
- cairo_rectangle_int16_t retval;
- retval.x = int(rect.left + 0.5);
- retval.y = int(rect.top + 0.5);
- retval.width = rect.IntegerWidth() + 1;
- retval.height = rect.IntegerHeight() + 1;
+ cairo_rectangle_int_t retval;
+ retval.x = floor (rect.left);
+ retval.y = floor (rect.top);
+ retval.width = ceil (rect.right) - retval.x + 1;
+ retval.height = ceil (rect.bottom) - rectval.y + 1;
return retval;
}
-static rgb_color
-_cairo_color_to_be_color (const cairo_color_t* color)
+static inline rgb_color
+_cairo_color_to_be_color (const cairo_color_t *color)
{
// This factor ensures a uniform distribution of numbers
const float factor = 256 - 1e-5;
@@ -199,32 +201,8 @@ _cairo_beos_view_to_bitmap (BView* view,
return ERROR;
}
-inline unsigned char
-unpremultiply (unsigned char color,
- unsigned char alpha)
-{
- if (alpha == 0)
- return 0;
- // plus alpha/2 to round instead of truncate
- return (color * 255 + alpha / 2) / alpha;
-}
-
-inline unsigned char
-premultiply (unsigned char color,
- unsigned char alpha)
-{
- // + 127 to round, instead of truncate
- return (color * alpha + 127) / 255;
-}
-
-/**
- * unpremultiply_rgba:
- *
- * Takes an input in ABGR premultiplied image data and unmultiplies it.
- * The result is stored in retdata.
- **/
static void
-unpremultiply_rgba (unsigned char* data,
+unpremultiply_bgra (unsigned char* data,
int width,
int height,
int stride,
@@ -235,52 +213,108 @@ unpremultiply_rgba (unsigned char* data,
in < end;
in += stride, out += stride)
{
- for (int i = 0; i < width; ++i) {
- // XXX for a big-endian platform this'd have to change
- int idx = 4 * i;
- unsigned char alpha = in[idx + 3];
- out[idx + 0] = unpremultiply(in[idx + 0], alpha); // B
- out[idx + 1] = unpremultiply(in[idx + 1], alpha); // G
- out[idx + 2] = unpremultiply(in[idx + 2], alpha); // R
- out[idx + 3] = in[idx + 3]; // Alpha
+ for (int i = 0; i < width; i ++) {
+ uint8_t *b = &out[4*i];
+ uint32_t pixel;
+ uint8_t alpha;
+
+ memcpy (&pixel, &data[4*i], sizeof (uint32_t));
+ alpha = pixel & 0xff;
+ if (alpha == 0) {
+ b[0] = b[1] = b[2] = b[3] = 0;
+ } else {
+ b[0] = (((pixel >> 24) & 0xff) * 255 + alpha / 2) / alpha;
+ b[1] = (((pixel >> 16) & 0xff) * 255 + alpha / 2) / alpha;
+ b[2] = (((pixel >> 8) & 0xff) * 255 + alpha / 2) / alpha;
+ b[3] = alpha;
+ }
}
}
}
-/**
- * premultiply_rgba:
- *
- * Takes an input in ABGR non-premultiplied image data and premultiplies it.
- * The returned data must be freed with free().
- **/
+static inline int
+multiply_alpha (int alpha, int color)
+{
+ int temp = (alpha * color) + 0x80;
+ return ((temp + (temp >> 8)) >> 8);
+}
+
static unsigned char*
-premultiply_rgba (unsigned char* data,
+premultiply_bgra (unsigned char* data,
int width,
int height,
int stride)
{
- unsigned char* retdata = reinterpret_cast<unsigned char*>(_cairo_malloc_ab(height, stride));
+ uint8_t * retdata = reinterpret_cast<unsigned char*>(_cairo_malloc_ab(height, stride));
if (!retdata)
return NULL;
- unsigned char* end = data + stride * height;
- for (unsigned char* in = data, *out = retdata;
+ uint8_t * end = data + stride * height;
+ for (uint8_t * in = data, *out = retdata;
in < end;
in += stride, out += stride)
{
- for (int i = 0; i < width; ++i) {
- // XXX for a big-endian platform this'd have to change
- int idx = 4 * i;
- unsigned char alpha = in[idx + 3];
- out[idx + 0] = premultiply(in[idx + 0], alpha); // B
- out[idx + 1] = premultiply(in[idx + 1], alpha); // G
- out[idx + 2] = premultiply(in[idx + 2], alpha); // R
- out[idx + 3] = in[idx + 3]; // Alpha
+ for (int i = 0; i < width; i ++) {
+ uint8_t *base = &in[4*i];
+ uint8_t alpha = base[3];
+ uint32_t p;
+
+ if (alpha == 0) {
+ p = 0;
+ } else {
+ uint8_t blue = base[0];
+ uint8_t green = base[1];
+ uint8_t red = base[2];
+
+ if (alpha != 0xff) {
+ blue = multiply_alpha (alpha, blue);
+ green = multiply_alpha (alpha, green);
+ red = multiply_alpha (alpha, red);
+ }
+ p = (alpha << 0) | (red << 8) | (green << 16) | (blue << 24);
+ }
+ memcpy (&out[4*i], &p, sizeof (uint32_t));
}
}
return retdata;
}
+static cairo_int_status_t
+_cairo_beos_surface_set_clip_region (cairo_beos_surface_t *surface,
+ cairo_region_t *region)
+{
+ cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
+ abstract_surface);
+ AutoLockView locker(surface->view);
+ assert (locker);
+
+ if (region == surface->clip_region)
+ return CAIRO_INT_STATUS_SUCCESS;
+
+ cairo_region_destroy (surface->clip_region);
+ surface->clip_region = cairo_region_reference (region);
+
+ if (region == NULL) {
+ // No clipping
+ surface->view->ConstrainClippingRegion(NULL);
+ return CAIRO_INT_STATUS_SUCCESS;
+ }
+
+ int count = cairo_region_num_rectangles (region);
+ BRegion bregion;
+ for (int i = 0; i < count; ++i) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (region, i, &rect);
+ // Have to substract one, because for pixman, the second coordinate
+ // lies outside the rectangle.
+ bregion.Include (_cairo_rectangle_to_brect (&rect));
+ }
+ surface->view->ConstrainClippingRegion(&bregion);
+ return CAIRO_INT_STATUS_SUCCESS;
+}
+
+
/**
* _cairo_beos_bitmap_to_surface:
*
@@ -309,8 +343,8 @@ _cairo_beos_bitmap_to_surface (BBitmap* bitmap)
return imgsurf;
}
- cairo_format_t cformat = format == B_RGB32 ? CAIRO_FORMAT_RGB24
- : CAIRO_FORMAT_ARGB32;
+ cairo_format_t cformat = format == B_RGB32 ?
+ CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32;
BRect bounds(bitmap->Bounds());
unsigned char* bits = reinterpret_cast<unsigned char*>(bitmap->Bits());
@@ -318,8 +352,8 @@ _cairo_beos_bitmap_to_surface (BBitmap* bitmap)
int height = bounds.IntegerHeight() + 1;
unsigned char* premultiplied;
if (cformat == CAIRO_FORMAT_ARGB32) {
- premultiplied = premultiply_rgba(bits, width, height,
- bitmap->BytesPerRow());
+ premultiplied = premultiply_bgra (bits, width, height,
+ bitmap->BytesPerRow());
} else {
premultiplied = reinterpret_cast<unsigned char*>(
_cairo_malloc_ab(bitmap->BytesPerRow(), height));
@@ -327,7 +361,7 @@ _cairo_beos_bitmap_to_surface (BBitmap* bitmap)
memcpy(premultiplied, bits, bitmap->BytesPerRow() * height);
}
if (!premultiplied)
- return NULL;
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
cairo_image_surface_t* surf = reinterpret_cast<cairo_image_surface_t*>
(cairo_image_surface_create_for_data(premultiplied,
@@ -355,11 +389,11 @@ _cairo_image_surface_to_bitmap (cairo_image_surface_t* surface)
switch (surface->format) {
case CAIRO_FORMAT_ARGB32: {
BBitmap* data = new BBitmap(size, B_RGBA32);
- unpremultiply_rgba(surface->data,
- surface->width,
- surface->height,
- surface->stride,
- reinterpret_cast<unsigned char*>(data->Bits()));
+ unpremultiply_bgra (surface->data,
+ surface->width,
+ surface->height,
+ surface->stride,
+ reinterpret_cast<unsigned char*>(data->Bits()));
return data;
}
case CAIRO_FORMAT_RGB24: {
@@ -384,44 +418,44 @@ _cairo_op_to_be_op (cairo_operator_t cairo_op,
drawing_mode* beos_op)
{
switch (cairo_op) {
-
- case CAIRO_OPERATOR_SOURCE:
- *beos_op = B_OP_COPY;
- return true;
- case CAIRO_OPERATOR_OVER:
- *beos_op = B_OP_ALPHA;
- return true;
-
- case CAIRO_OPERATOR_ADD:
- // Does not actually work
+ case CAIRO_OPERATOR_SOURCE:
+ *beos_op = B_OP_COPY;
+ return true;
+ case CAIRO_OPERATOR_OVER:
+ *beos_op = B_OP_ALPHA;
+ return true;
+
+ case CAIRO_OPERATOR_ADD:
+ // Does not actually work
+ // XXX This is a fundamental compositing operator, it has to work!
#if 1
- return false;
+ return false;
#else
- *beos_op = B_OP_ADD;
- return true;
+ *beos_op = B_OP_ADD;
+ return true;
#endif
- case CAIRO_OPERATOR_CLEAR:
- // Does not map to B_OP_ERASE - it replaces the dest with the low
- // color, instead of transparency; could be done by setting low
- // color appropriately.
+ case CAIRO_OPERATOR_CLEAR:
+ // Does not map to B_OP_ERASE - it replaces the dest with the low
+ // color, instead of transparency; could be done by setting low
+ // color appropriately.
- case CAIRO_OPERATOR_IN:
- case CAIRO_OPERATOR_OUT:
- case CAIRO_OPERATOR_ATOP:
+ case CAIRO_OPERATOR_IN:
+ case CAIRO_OPERATOR_OUT:
+ case CAIRO_OPERATOR_ATOP:
- case CAIRO_OPERATOR_DEST:
- case CAIRO_OPERATOR_DEST_OVER:
- case CAIRO_OPERATOR_DEST_IN:
- case CAIRO_OPERATOR_DEST_OUT:
- case CAIRO_OPERATOR_DEST_ATOP:
+ case CAIRO_OPERATOR_DEST:
+ case CAIRO_OPERATOR_DEST_OVER:
+ case CAIRO_OPERATOR_DEST_IN:
+ case CAIRO_OPERATOR_DEST_OUT:
+ case CAIRO_OPERATOR_DEST_ATOP:
- case CAIRO_OPERATOR_XOR:
- case CAIRO_OPERATOR_SATURATE:
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_SATURATE:
- default:
- return false;
- };
+ default:
+ return false;
+ }
}
static cairo_surface_t *
@@ -430,8 +464,6 @@ _cairo_beos_surface_create_similar (void *abstract_surface,
int width,
int height)
{
- fprintf(stderr, "Creating similar\n");
-
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
@@ -444,9 +476,7 @@ _cairo_beos_surface_create_similar (void *abstract_surface,
BBitmap* bmp;
switch (content) {
case CAIRO_CONTENT_ALPHA:
- // Can't support this natively
- return _cairo_image_surface_create_with_content(content, width,
- height);
+ return NULL;
case CAIRO_CONTENT_COLOR_ALPHA:
bmp = new BBitmap(rect, B_RGBA32, true);
break;
@@ -470,10 +500,9 @@ _cairo_beos_surface_create_similar (void *abstract_surface,
}
break;
default:
- assert(0);
+ ASSERT_NOT_REACHED;
return NULL;
-
- };
+ }
BView* view = new BView(rect, "Cairo bitmap view", B_FOLLOW_ALL_SIDES, 0);
bmp->AddChild(view);
return _cairo_beos_surface_create_internal(view, bmp, true);
@@ -495,6 +524,8 @@ _cairo_beos_surface_finish (void *abstract_surface)
surface->bitmap = NULL;
}
+ cairo_region_destroy (surface->clip_region);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -503,7 +534,6 @@ _cairo_beos_surface_acquire_source_image (void *abstract_surfa
cairo_image_surface_t **image_out,
void **image_extra)
{
- fprintf(stderr, "Getting source image\n");
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
AutoLockView locker(surface->view);
@@ -514,9 +544,9 @@ _cairo_beos_surface_acquire_source_image (void *abstract_surfa
surface->view->Sync();
if (surface->bitmap) {
- *image_out = _cairo_beos_bitmap_to_surface(surface->bitmap);
- if (!*image_out)
- return CAIRO_STATUS_NO_MEMORY;
+ *image_out = _cairo_beos_bitmap_to_surface (surface->bitmap);
+ if (unlikely ((*image_out)->base.status))
+ return (*image_out)->base.status;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
@@ -526,10 +556,10 @@ _cairo_beos_surface_acquire_source_image (void *abstract_surfa
if (_cairo_beos_view_to_bitmap(surface->view, &bmp) != OK)
return CAIRO_STATUS_NO_MEMORY; /// XXX incorrect if the error was NOT_VISIBLE
- *image_out = _cairo_beos_bitmap_to_surface(bmp);
- if (!*image_out) {
+ *image_out = _cairo_beos_bitmap_to_surface (bmp);
+ if (unlikely ((*image_out)->base.status)) {
delete bmp;
- return CAIRO_STATUS_NO_MEMORY;
+ return (*image_out)->base.status;
}
*image_extra = bmp;
@@ -543,17 +573,17 @@ _cairo_beos_surface_release_source_image (void *abstract_surfac
{
cairo_surface_destroy (&image->base);
- BBitmap* bmp = static_cast<BBitmap*>(image_extra);
- delete bmp;
+ if (image_extra != NULL) {
+ BBitmap* bmp = static_cast<BBitmap*>(image_extra);
+ delete bmp;
+ }
}
-
-
static cairo_status_t
_cairo_beos_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int16_t *interest_rect,
+ cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t **image_out,
- cairo_rectangle_int16_t *image_rect,
+ cairo_rectangle_int_t *image_rect,
void **image_extra)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
@@ -563,14 +593,14 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface,
if (!locker) {
*image_out = NULL;
*image_extra = NULL;
- return CAIRO_STATUS_SUCCESS;
+ return (cairo_status_t) CAIRO_INT_STATUS_NOTHING_TO_DO;
}
if (surface->bitmap) {
surface->view->Sync();
*image_out = _cairo_beos_bitmap_to_surface(surface->bitmap);
- if (!*image_out)
- return CAIRO_STATUS_NO_MEMORY;
+ if (unlikely ((*image_out)->base.status))
+ return (*image_out)->base.status;
image_rect->x = 0;
image_rect->y = 0;
@@ -581,7 +611,7 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
- BRect b_interest_rect(_cairo_rect_to_brect(interest_rect));
+ BRect b_interest_rect (_cairo_rectangle_to_brect (interest_rect));
BRect rect;
BBitmap* bitmap;
@@ -595,18 +625,11 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface,
if (status == ERROR)
return CAIRO_STATUS_NO_MEMORY;
- *image_rect = _brect_to_cairo_rect(rect);
-
-#if 0
- fprintf(stderr, "Requested: (cairo rects) (%ix%i) dim (%u, %u) returning (%ix%i) dim (%u, %u)\n",
- interest_rect->x, interest_rect->y, interest_rect->width, interest_rect->height,
- image_rect->x, image_rect->y, image_rect->width, image_rect->height);
-#endif
-
+ *image_rect = _brect_to_cairo_rectangle(rect);
*image_out = _cairo_beos_bitmap_to_surface(bitmap);
delete bitmap;
- if (!*image_out)
- return CAIRO_STATUS_NO_MEMORY;
+ if (unlikely ((*image_out)->base.status))
+ return (*image_out)->base.status;
*image_extra = NULL;
@@ -616,13 +639,11 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface,
static void
_cairo_beos_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int16_t *intersect_rect,
+ cairo_rectangle_int_t *intersect_rect,
cairo_image_surface_t *image,
- cairo_rectangle_int16_t *image_rect,
+ cairo_rectangle_int_t *image_rect,
void *image_extra)
{
- fprintf(stderr, "Fallback drawing\n");
-
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
@@ -634,9 +655,9 @@ _cairo_beos_surface_release_dest_image (void *abstract_surface,
surface->view->PushState();
surface->view->SetDrawingMode(B_OP_COPY);
- BRect rect(_cairo_rect_to_brect(image_rect));
- surface->view->DrawBitmap(bitmap_to_draw, rect);
+ surface->view->DrawBitmap (bitmap_to_draw,
+ _cairo_rectangle_to_brect (image_rect));
surface->view->PopState();
@@ -649,17 +670,19 @@ _cairo_beos_surface_composite (cairo_operator_t op,
cairo_pattern_t *src,
cairo_pattern_t *mask,
void *dst,
- int src_x,
+ int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
dst);
+ cairo_int_status_t status;
AutoLockView locker(surface->view);
if (!locker)
return CAIRO_INT_STATUS_SUCCESS;
@@ -684,6 +707,10 @@ _cairo_beos_surface_composite (cairo_operator_t op,
if (!_cairo_matrix_is_integer_translation(&src->matrix, &itx, &ity))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ status = _cairo_beos_surface_set_clip_region (surface, clip_region);
+ if (unlikely (status))
+ return status;
+
BRect srcRect(src_x + itx,
src_y + ity,
src_x + itx + width - 1,
@@ -731,8 +758,6 @@ _cairo_beos_surface_composite (cairo_operator_t op,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- fprintf(stderr, "Composite\n");
-
// Draw it on screen.
surface->view->PushState();
@@ -767,24 +792,17 @@ _cairo_beos_surface_composite (cairo_operator_t op,
}
-static void
-_cairo_beos_surface_fill_rectangle (cairo_beos_surface_t *surface,
- cairo_rectangle_int16_t *rect)
-{
- BRect brect(_cairo_rect_to_brect(rect));
- surface->view->FillRect(brect);
-}
-
static cairo_int_status_t
_cairo_beos_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t op,
const cairo_color_t *color,
- cairo_rectangle_int16_t *rects,
- int num_rects)
+ cairo_rectangle_int_t *rects,
+ int num_rects,
+ cairo_region_t *clip_region)
{
- fprintf(stderr, "Drawing %i rectangles\n", num_rects);
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
+ cairo_int_status_t status;
if (num_rects <= 0)
return CAIRO_INT_STATUS_SUCCESS;
@@ -797,6 +815,10 @@ _cairo_beos_surface_fill_rectangles (void *abstract_surface,
if (!_cairo_op_to_be_op(op, &mode))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ status = _cairo_beos_surface_set_clip_region (surface, clip_region);
+ if (unlikely (status))
+ return status;
+
rgb_color be_color = _cairo_color_to_be_color(color);
if (mode == B_OP_ALPHA && be_color.alpha == 0xFF)
@@ -808,9 +830,9 @@ _cairo_beos_surface_fill_rectangles (void *abstract_surface,
if (mode == B_OP_COPY && be_color.alpha != 0xFF &&
(!surface->bitmap || surface->bitmap->ColorSpace() != B_RGBA32))
{
- be_color.red = premultiply(be_color.red, be_color.alpha);
- be_color.green = premultiply(be_color.green, be_color.alpha);
- be_color.blue = premultiply(be_color.blue, be_color.alpha);
+ be_color.red = color->red_short >> 8;
+ be_color.green = color->green_short >> 8;
+ be_color.blue = color->blue_short >> 8;
}
surface->view->PushState();
@@ -822,65 +844,26 @@ _cairo_beos_surface_fill_rectangles (void *abstract_surface,
else
surface->view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
- for (int i = 0; i < num_rects; ++i) {
- _cairo_beos_surface_fill_rectangle(surface, &rects[i]);
- }
+ for (int i = 0; i < num_rects; ++i)
+ surface->view->FillRect (_cairo_rectangle_to_brect (&rects[i]));
surface->view->PopState();
return CAIRO_INT_STATUS_SUCCESS;
}
-
-
-static cairo_int_status_t
-_cairo_beos_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- fprintf(stderr, "Setting clip region\n");
- cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
- abstract_surface);
- AutoLockView locker(surface->view);
- if (!locker)
- return CAIRO_INT_STATUS_SUCCESS;
-
- if (region == NULL) {
- // No clipping
- surface->view->ConstrainClippingRegion(NULL);
- return CAIRO_INT_STATUS_SUCCESS;
- }
-
- int count = pixman_region_num_rects(region);
- pixman_box16_t* rects = pixman_region_rects(region);
- BRegion bregion;
- for (int i = 0; i < count; ++i) {
- // Have to substract one, because for pixman, the second coordinate
- // lies outside the rectangle.
- bregion.Include(BRect(rects[i].x1, rects[i].y1, rects[i].x2 - 1, rects[i].y2 - 1));
- }
- surface->view->ConstrainClippingRegion(&bregion);
- return CAIRO_INT_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
+static cairo_bool_t
_cairo_beos_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int16_t *rectangle)
+ cairo_rectangle_int_t *rectangle)
{
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
AutoLockView locker(surface->view);
if (!locker)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- BRect size = surface->view->Bounds();
-
- *rectangle = _brect_to_cairo_rect(size);
+ return FALSE;
- // Make sure to have our upperleft edge as (0,0)
- rectangle->x = 0;
- rectangle->y = 0;
-
- return CAIRO_INT_STATUS_SUCCESS;
+ *rectangle = _brect_to_cairo_rectangle (surface->view->Bounds());
+ return TRUE;
}
static const struct _cairo_surface_backend cairo_beos_surface_backend = {
@@ -899,8 +882,6 @@ static const struct _cairo_surface_backend cairo_beos_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- _cairo_beos_surface_set_clip_region,
- NULL, /* intersect_clip_path */
_cairo_beos_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -938,7 +919,9 @@ _cairo_beos_surface_create_internal (BView* view,
surface->bitmap = bmp;
surface->owns_bitmap_view = owns_bitmap_view;
- return (cairo_surface_t *) surface;
+ surface->clip_region = NULL;
+
+ return &surface->base;
}
/**
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 4229e4fb..8a3e867a 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -43,6 +43,11 @@
extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
+enum {
+ CAIRO_CLIP_PATH_HAS_REGION = 0x1,
+ CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED = 0x2
+};
+
struct _cairo_clip_path {
cairo_reference_count_t ref_count;
cairo_path_fixed_t path;
@@ -50,84 +55,74 @@ struct _cairo_clip_path {
double tolerance;
cairo_antialias_t antialias;
cairo_clip_path_t *prev;
+
+ cairo_rectangle_int_t extents;
+
+ /* partial caches */
+ unsigned int flags;
+ cairo_region_t *region;
+ cairo_surface_t *surface;
};
struct _cairo_clip {
- cairo_clip_mode_t mode;
+ /* can be used as a cairo_hash_entry_t for live clips */
+ cairo_clip_path_t *path;
cairo_bool_t all_clipped;
- /*
- * Mask-based clipping for cases where the backend
- * clipping isn't sufficiently able.
- *
- * The rectangle here represents the
- * portion of the destination surface that this
- * clip surface maps to, it does not
- * represent the extents of the clip region or
- * clip paths
- */
- cairo_surface_t *surface;
- cairo_rectangle_int_t surface_rect;
- /*
- * Surface clip serial number to store
- * in the surface when this clip is set
- */
- unsigned int serial;
- /*
- * A clip region that can be placed in the surface
- */
- cairo_region_t *region;
- /*
- * If the surface supports path clipping, we store the list of
- * clipping paths that has been set here as a linked list.
- */
- cairo_clip_path_t *path;
};
cairo_private void
-_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target);
+_cairo_clip_init (cairo_clip_t *clip);
cairo_private cairo_status_t
+_cairo_clip_init_rectangle (cairo_clip_t *clip,
+ const cairo_rectangle_int_t *rect);
+
+cairo_private void
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other);
cairo_private cairo_status_t
-_cairo_clip_init_deep_copy (cairo_clip_t *clip,
- cairo_clip_t *other,
- cairo_surface_t *target);
+_cairo_clip_init_copy_transformed (cairo_clip_t *clip,
+ cairo_clip_t *other,
+ const cairo_matrix_t *matrix);
cairo_private void
_cairo_clip_reset (cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_clip_clip (cairo_clip_t *clip,
- cairo_path_fixed_t *path,
+ const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias,
- cairo_surface_t *target);
+ cairo_antialias_t antialias);
cairo_private cairo_status_t
-_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
- cairo_rectangle_int_t *rectangle);
+_cairo_clip_apply_clip (cairo_clip_t *clip,
+ const cairo_clip_t *other);
-cairo_private cairo_status_t
-_cairo_clip_intersect_to_region (cairo_clip_t *clip,
- cairo_region_t *region);
+cairo_private const cairo_rectangle_int_t *
+_cairo_clip_get_extents (const cairo_clip_t *clip);
-cairo_private cairo_status_t
-_cairo_clip_combine_to_surface (cairo_clip_t *clip,
- cairo_operator_t op,
- cairo_surface_t *dst,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents);
+cairo_private cairo_surface_t *
+_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst);
+
+cairo_private cairo_int_status_t
+_cairo_clip_get_region (cairo_clip_t *clip,
+ cairo_region_t **region);
cairo_private void
_cairo_clip_translate (cairo_clip_t *clip,
cairo_fixed_t tx,
cairo_fixed_t ty);
+cairo_private void
+_cairo_clip_transform (cairo_clip_t *clip,
+ const cairo_matrix_t *transform);
+
+cairo_private void
+_cairo_clip_drop_cache (cairo_clip_t *clip);
+
cairo_private cairo_rectangle_list_t*
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate);
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 79e4cbe6..93348945 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -3,6 +3,7 @@
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2009 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -35,802 +36,777 @@
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Kristian Høgsberg <krh@redhat.com>
+ * Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-clip-private.h"
+#include "cairo-path-fixed-private.h"
-static cairo_clip_path_t *
-_cairo_clip_path_reference (cairo_clip_path_t *clip_path);
+/* Keep a stash of recently freed clip_paths, since we need to
+ * reallocate them frequently.
+ */
+#define MAX_FREED_POOL_SIZE 4
+typedef struct {
+ void *pool[MAX_FREED_POOL_SIZE];
+ int top;
+} freed_pool_t;
-static void
-_cairo_clip_path_destroy (cairo_clip_path_t *clip_path);
+static freed_pool_t clip_path_pool;
-void
-_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target)
+static void *
+_atomic_fetch (void **slot)
{
- if (target && target->backend)
- clip->mode = _cairo_surface_get_clip_mode (target);
- else
- clip->mode = CAIRO_CLIP_MODE_MASK;
-
- clip->all_clipped = FALSE;
+ return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL);
+}
- clip->surface = NULL;
- clip->surface_rect.x = 0;
- clip->surface_rect.y = 0;
- clip->surface_rect.width = 0;
- clip->surface_rect.height = 0;
+static cairo_bool_t
+_atomic_store (void **slot, void *ptr)
+{
+ return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr) == NULL;
+}
- clip->serial = 0;
+static void *
+_freed_pool_get (freed_pool_t *pool)
+{
+ void *ptr;
+ int i;
- clip->region = NULL;
+ i = pool->top - 1;
+ if (i < 0)
+ i = 0;
- clip->path = NULL;
-}
+ ptr = _atomic_fetch (&pool->pool[i]);
+ if (ptr != NULL) {
+ pool->top = i;
+ return ptr;
+ }
-cairo_status_t
-_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
-{
- clip->mode = other->mode;
-
- clip->all_clipped = other->all_clipped;
-
- clip->surface = cairo_surface_reference (other->surface);
- clip->surface_rect = other->surface_rect;
-
- clip->serial = other->serial;
-
- if (other->region) {
- cairo_status_t status;
-
- clip->region = cairo_region_copy (other->region);
-
- status = cairo_region_status (clip->region);
- if (unlikely (status)) {
- cairo_surface_destroy (clip->surface);
- cairo_region_destroy (clip->region);
- clip->region = NULL;
-
- return status;
+ /* either empty or contended */
+ for (i = ARRAY_LENGTH (pool->pool); i--;) {
+ ptr = _atomic_fetch (&pool->pool[i]);
+ if (ptr != NULL) {
+ pool->top = i;
+ return ptr;
}
- } else {
- clip->region = NULL;
}
-
- clip->path = _cairo_clip_path_reference (other->path);
- return CAIRO_STATUS_SUCCESS;
+ /* empty */
+ pool->top = 0;
+ return NULL;
}
-void
-_cairo_clip_reset (cairo_clip_t *clip)
+static void
+_freed_pool_put (freed_pool_t *pool, void *ptr)
{
- clip->all_clipped = FALSE;
-
- /* destroy any existing clip-region artifacts */
- cairo_surface_destroy (clip->surface);
- clip->surface = NULL;
-
- clip->serial = 0;
+ int i = pool->top;
- if (clip->region) {
- cairo_region_destroy (clip->region);
+ if (_atomic_store (&pool->pool[i], ptr)) {
+ pool->top = i + 1;
+ return;
+ }
- clip->region = NULL;
+ /* either full or contended */
+ for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
+ if (_atomic_store (&pool->pool[i], ptr)) {
+ pool->top = i + 1;
+ return;
+ }
}
- _cairo_clip_path_destroy (clip->path);
- clip->path = NULL;
+ /* full */
+ pool->top = ARRAY_LENGTH (pool->pool);
+ free (ptr);
}
static void
-_cairo_clip_set_all_clipped (cairo_clip_t *clip, cairo_surface_t *target)
+_freed_pool_reset (freed_pool_t *pool)
{
- _cairo_clip_reset (clip);
+ int i;
- clip->all_clipped = TRUE;
- clip->serial = _cairo_surface_allocate_clip_serial (target);
+ for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
+ free (pool->pool[i]);
+ pool->pool[i] = NULL;
+ }
}
-
-static cairo_status_t
-_cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path,
- cairo_rectangle_int_t *rectangle)
+static cairo_clip_path_t *
+_cairo_clip_path_create (cairo_clip_t *clip)
{
- while (clip_path) {
- cairo_rectangle_int_t extents;
+ cairo_clip_path_t *clip_path;
- _cairo_path_fixed_approximate_clip_extents (&clip_path->path, &extents);
+ clip_path = _freed_pool_get (&clip_path_pool);
+ if (unlikely (clip_path == NULL)) {
+ clip_path = malloc (sizeof (cairo_clip_path_t));
+ if (unlikely (clip_path == NULL))
+ return NULL;
+ }
- if (! _cairo_rectangle_intersect (rectangle, &extents))
- return CAIRO_STATUS_SUCCESS;
+ CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
- clip_path = clip_path->prev;
- }
+ clip_path->flags = 0;
+ clip_path->region = NULL;
+ clip_path->surface = NULL;
- return CAIRO_STATUS_SUCCESS;
+ clip_path->prev = clip->path;
+ clip->path = clip_path;
+
+ return clip_path;
}
-cairo_status_t
-_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
- cairo_rectangle_int_t *rectangle)
+static cairo_clip_path_t *
+_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
{
- cairo_status_t status;
- cairo_bool_t is_empty;
+ if (clip_path == NULL)
+ return NULL;
- if (!clip)
- return CAIRO_STATUS_SUCCESS;
+ assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
- if (clip->all_clipped) {
- *rectangle = clip->surface_rect;
- return CAIRO_STATUS_SUCCESS;
- }
+ _cairo_reference_count_inc (&clip_path->ref_count);
- if (clip->path) {
- status = _cairo_clip_path_intersect_to_rectangle (clip->path,
- rectangle);
- if (unlikely (status))
- return status;
- }
+ return clip_path;
+}
+
+static void
+_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
+{
+ assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
- if (clip->region) {
- cairo_rectangle_int_t extents;
+ if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
+ return;
- cairo_region_get_extents (clip->region, &extents);
- is_empty = _cairo_rectangle_intersect (rectangle, &extents);
- if (is_empty)
- return CAIRO_STATUS_SUCCESS;
- }
+ _cairo_path_fixed_fini (&clip_path->path);
+ if (clip_path->region != NULL)
+ cairo_region_destroy (clip_path->region);
+ if (clip_path->surface != NULL)
+ cairo_surface_destroy (clip_path->surface);
- if (clip->surface)
- is_empty = _cairo_rectangle_intersect (rectangle, &clip->surface_rect);
+ if (clip_path->prev != NULL)
+ _cairo_clip_path_destroy (clip_path->prev);
- return CAIRO_STATUS_SUCCESS;
+ _freed_pool_put (&clip_path_pool, clip_path);
+}
+
+void
+_cairo_clip_init (cairo_clip_t *clip)
+{
+ clip->all_clipped = FALSE;
+ clip->path = NULL;
}
+static void
+_cairo_clip_set_all_clipped (cairo_clip_t *clip)
+{
+ clip->all_clipped = TRUE;
+ if (clip->path != NULL) {
+ _cairo_clip_path_destroy (clip->path);
+ clip->path = NULL;
+ }
+}
+
+/* XXX consider accepting a matrix, no users yet. */
cairo_status_t
-_cairo_clip_intersect_to_region (cairo_clip_t *clip,
- cairo_region_t *region)
+_cairo_clip_init_rectangle (cairo_clip_t *clip,
+ const cairo_rectangle_int_t *rect)
{
+ cairo_clip_path_t *clip_path;
cairo_status_t status;
- if (!clip)
+ _cairo_clip_init (clip);
+ if (rect == NULL)
return CAIRO_STATUS_SUCCESS;
- if (clip->all_clipped)
- return cairo_region_intersect_rectangle (region, &clip->surface_rect);
-
- if (clip->path) {
- /* Intersect clip path into region. */
+ if (rect->width == 0 || rect->height == 0) {
+ _cairo_clip_set_all_clipped (clip);
+ return CAIRO_STATUS_SUCCESS;
}
- if (clip->region) {
- status = cairo_region_intersect (region, clip->region);
- if (unlikely (status))
- return status;
- }
+ clip_path = _cairo_clip_path_create (clip);
+ if (unlikely (clip_path == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- if (clip->surface)
- return cairo_region_intersect_rectangle (region, &clip->surface_rect);
+ _cairo_path_fixed_init (&clip_path->path);
+
+ status = _cairo_path_fixed_move_to (&clip_path->path,
+ _cairo_fixed_from_int (rect->x),
+ _cairo_fixed_from_int (rect->y));
+ assert (status == CAIRO_STATUS_SUCCESS);
+ status = _cairo_path_fixed_rel_line_to (&clip_path->path,
+ _cairo_fixed_from_int (rect->width),
+ _cairo_fixed_from_int (0));
+ assert (status == CAIRO_STATUS_SUCCESS);
+ status = _cairo_path_fixed_rel_line_to (&clip_path->path,
+ _cairo_fixed_from_int (0),
+ _cairo_fixed_from_int (rect->height));
+ assert (status == CAIRO_STATUS_SUCCESS);
+ status = _cairo_path_fixed_rel_line_to (&clip_path->path,
+ _cairo_fixed_from_int (-rect->width),
+ _cairo_fixed_from_int (0));
+ assert (status == CAIRO_STATUS_SUCCESS);
+ status = _cairo_path_fixed_close_path (&clip_path->path);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ clip_path->extents = *rect;
+ clip_path->fill_rule = CAIRO_FILL_RULE_WINDING;
+ clip_path->tolerance = 1;
+ clip_path->antialias = CAIRO_ANTIALIAS_NONE;
+
+ /* could preallocate the region if it proves worthwhile */
return CAIRO_STATUS_SUCCESS;
}
-/* Combines the region of clip->surface given by extents in
- * device backend coordinates into the given temporary surface,
- * which has its origin at dst_x, dst_y in backend coordinates
- */
-cairo_status_t
-_cairo_clip_combine_to_surface (cairo_clip_t *clip,
- cairo_operator_t op,
- cairo_surface_t *dst,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents)
+void
+_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
{
- cairo_surface_pattern_t pattern;
- cairo_status_t status;
-
- if (clip->all_clipped)
- return CAIRO_STATUS_SUCCESS;
-
- _cairo_pattern_init_for_surface (&pattern, clip->surface);
-
- status = _cairo_surface_composite (op,
- &pattern.base,
- NULL,
- dst,
- extents->x - clip->surface_rect.x,
- extents->y - clip->surface_rect.y,
- 0, 0,
- extents->x - dst_x,
- extents->y - dst_y,
- extents->width, extents->height);
-
- _cairo_pattern_fini (&pattern.base);
+ if (other != NULL) {
+ clip->all_clipped = other->all_clipped;
+ clip->path = _cairo_clip_path_reference (other->path);
+ } else {
+ clip->all_clipped = FALSE;
+ clip->path = NULL;
+ }
+}
- return status;
+void
+_cairo_clip_reset (cairo_clip_t *clip)
+{
+ clip->all_clipped = FALSE;
+ if (clip->path != NULL) {
+ _cairo_clip_path_destroy (clip->path);
+ clip->path = NULL;
+ }
}
static cairo_status_t
_cairo_clip_intersect_path (cairo_clip_t *clip,
- cairo_path_fixed_t *path,
+ const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_clip_path_t *clip_path;
cairo_status_t status;
+ cairo_rectangle_int_t extents;
+
+ if (clip->path != NULL) {
+ if (_cairo_path_fixed_equal (&clip->path->path, path)) {
+ if (clip->path->fill_rule == fill_rule) {
+ if (path->is_rectilinear ||
+ (tolerance == clip->path->tolerance &&
+ antialias == clip->path->antialias))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+ }
+ }
- if (clip->mode != CAIRO_CLIP_MODE_PATH)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ _cairo_path_fixed_approximate_clip_extents (path, &extents);
+ if (extents.width == 0 || extents.height == 0) {
+ _cairo_clip_set_all_clipped (clip);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (clip->path != NULL) {
+ cairo_box_t box;
+
+ if (! _cairo_rectangle_intersect (&extents, &clip->path->extents)) {
+ _cairo_clip_set_all_clipped (clip);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ /* does this clip wholly subsume the others? */
+ if (_cairo_path_fixed_is_box (path, &box)) {
+ if (box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) &&
+ box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) &&
+ box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) &&
+ box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+ }
- clip_path = malloc (sizeof (cairo_clip_path_t));
+ clip_path = _cairo_clip_path_create (clip);
if (unlikely (clip_path == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_path_fixed_init_copy (&clip_path->path, path);
if (unlikely (status)) {
- free (clip_path);
+ clip->path = clip->path->prev;
+ _cairo_clip_path_destroy (clip_path);
return status;
}
- CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
+ clip_path->extents = extents;
clip_path->fill_rule = fill_rule;
clip_path->tolerance = tolerance;
clip_path->antialias = antialias;
- clip_path->prev = clip->path;
- clip->path = clip_path;
return CAIRO_STATUS_SUCCESS;
}
-static cairo_clip_path_t *
-_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
-{
- if (clip_path == NULL)
- return NULL;
-
- assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
-
- _cairo_reference_count_inc (&clip_path->ref_count);
-
- return clip_path;
-}
-
-static void
-_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
-{
- if (clip_path == NULL)
- return;
-
- assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
-
- if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
- return;
-
- _cairo_path_fixed_fini (&clip_path->path);
- _cairo_clip_path_destroy (clip_path->prev);
- free (clip_path);
-}
-
-
-static cairo_int_status_t
-_cairo_clip_intersect_region (cairo_clip_t *clip,
- cairo_traps_t *traps,
- cairo_surface_t *target)
+cairo_status_t
+_cairo_clip_clip (cairo_clip_t *clip,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
{
- cairo_region_t *region;
- cairo_int_status_t status;
-
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
- if (clip->mode != CAIRO_CLIP_MODE_REGION)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_traps_extract_region (traps, &region);
- if (status)
- return status;
-
- if (clip->region) {
- status = cairo_region_intersect (clip->region, region);
- cairo_region_destroy (region);
- } else {
- clip->region = region;
+ /* catch the empty clip path */
+ if (_cairo_path_fixed_fill_is_empty (path)) {
+ _cairo_clip_set_all_clipped (clip);
+ return CAIRO_STATUS_SUCCESS;
}
- clip->serial = _cairo_surface_allocate_clip_serial (target);
-
- if (!clip->region || cairo_region_is_empty (clip->region))
- _cairo_clip_set_all_clipped (clip, target);
-
- return status;
+ return _cairo_clip_intersect_path (clip,
+ path, fill_rule, tolerance,
+ antialias);
}
static cairo_status_t
-_cairo_clip_intersect_mask (cairo_clip_t *clip,
- cairo_traps_t *traps,
- cairo_antialias_t antialias,
- cairo_surface_t *target)
+_cairo_clip_path_reapply_clip_path_transform (cairo_clip_t *clip,
+ cairo_clip_path_t *other_path,
+ const cairo_matrix_t *matrix)
{
- cairo_pattern_union_t pattern;
- cairo_box_t extents;
- cairo_rectangle_int_t surface_rect, target_rect;
- cairo_surface_t *surface = NULL;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- if (clip->all_clipped)
- return CAIRO_STATUS_SUCCESS;
+ cairo_status_t status;
+ cairo_clip_path_t *clip_path;
+ cairo_bool_t is_empty;
- /* Represent the clip as a mask surface. We create a new surface
- * the size of the intersection of the old mask surface and the
- * extents of the new clip path. */
+ if (other_path->prev != NULL) {
+ status = _cairo_clip_path_reapply_clip_path_transform (clip,
+ other_path->prev,
+ matrix);
+ if (unlikely (status))
+ return status;
+ }
- _cairo_traps_extents (traps, &extents);
- _cairo_box_round_to_rectangle (&extents, &surface_rect);
+ clip_path = _cairo_clip_path_create (clip);
+ if (unlikely (clip_path == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- if (clip->surface != NULL) {
- if (! _cairo_rectangle_intersect (&surface_rect, &clip->surface_rect))
- goto DONE;
+ status = _cairo_path_fixed_init_copy (&clip_path->path,
+ &other_path->path);
+ if (unlikely (status)) {
+ _cairo_clip_path_destroy (clip_path);
+ return status;
}
- /* Intersect with the target surface rectangle so we don't use
- * more memory and time than we need to. */
- status = _cairo_surface_get_extents (target, &target_rect);
- if (status == CAIRO_STATUS_SUCCESS) {
- if (! _cairo_rectangle_intersect (&surface_rect, &target_rect))
- goto DONE;
+ _cairo_path_fixed_transform (&clip_path->path, matrix);
+ _cairo_path_fixed_approximate_clip_extents (&clip_path->path,
+ &clip_path->extents);
+ if (clip_path->prev != NULL) {
+ is_empty = _cairo_rectangle_intersect (&clip_path->extents,
+ &clip_path->prev->extents);
}
- if (surface_rect.width == 0 || surface_rect.height == 0)
- goto DONE;
+ clip_path->fill_rule = other_path->fill_rule;
+ clip_path->tolerance = other_path->tolerance;
+ clip_path->antialias = other_path->antialias;
- _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
- /* The clipping operation should ideally be something like the following to
- * avoid having to do as many passes over the data
+ return CAIRO_STATUS_SUCCESS;
+}
- if (clip->surface != NULL) {
- _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
- } else {
- _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
- }
- status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
- &pattern.base,
- surface,
- antialias,
- 0, 0,
- 0, 0,
- surface_rect.width,
- surface_rect.height,
- traps->traps,
- traps->num_traps);
-
- However this operation is not accelerated by pixman
-
- I believe the best possible operation would probably an unbounded SRC
- operator. Using SRC we could potentially avoid having to initialize
- the surface which would be ideal from an efficiency point of view.
- However, CAIRO_OPERATOR_SOURCE is bounded by the trapezoid mask and
- _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_SOURCE) will assert
- because it assumes CAIRO_OPERATOR_SOURCE has been converted into other
- operations.
- */
+static cairo_status_t
+_cairo_clip_path_reapply_clip_path_translate (cairo_clip_t *clip,
+ cairo_clip_path_t *other_path,
+ int tx, int ty)
+{
+ cairo_status_t status;
+ cairo_clip_path_t *clip_path;
- surface = _cairo_surface_create_similar_solid (target,
- CAIRO_CONTENT_ALPHA,
- surface_rect.width,
- surface_rect.height,
- CAIRO_COLOR_TRANSPARENT);
- if (surface->status) {
- _cairo_pattern_fini (&pattern.base);
- return surface->status;
+ if (other_path->prev != NULL) {
+ status = _cairo_clip_path_reapply_clip_path_translate (clip,
+ other_path->prev,
+ tx, ty);
+ if (unlikely (status))
+ return status;
}
- /* Render the new clipping path into the new mask surface. */
-
- _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y);
-
- status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
- &pattern.base,
- surface,
- antialias,
- 0, 0,
- 0, 0,
- surface_rect.width,
- surface_rect.height,
- traps->traps,
- traps->num_traps);
-
- _cairo_pattern_fini (&pattern.base);
+ clip_path = _cairo_clip_path_create (clip);
+ if (unlikely (clip_path == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ status = _cairo_path_fixed_init_copy (&clip_path->path,
+ &other_path->path);
if (unlikely (status)) {
- cairo_surface_destroy (surface);
+ _cairo_clip_path_destroy (clip_path);
return status;
}
- /* If there was a clip surface already, combine it with the new
- * mask surface using the IN operator, so we get the intersection
- * of the old and new clipping paths. */
-
- if (clip->surface != NULL) {
- _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
+ _cairo_path_fixed_translate (&clip_path->path,
+ _cairo_fixed_from_int (tx),
+ _cairo_fixed_from_int (ty));
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &pattern.base,
- NULL,
- surface,
- surface_rect.x - clip->surface_rect.x,
- surface_rect.y - clip->surface_rect.y,
- 0, 0,
- 0, 0,
- surface_rect.width,
- surface_rect.height);
+ clip_path->fill_rule = other_path->fill_rule;
+ clip_path->tolerance = other_path->tolerance;
+ clip_path->antialias = other_path->antialias;
- _cairo_pattern_fini (&pattern.base);
-
- if (unlikely (status)) {
- cairo_surface_destroy (surface);
- return status;
- }
+ clip_path->flags = other_path->flags;
+ if (other_path->region != NULL) {
+ clip_path->region = cairo_region_copy (other_path->region);
+ cairo_region_translate (clip_path->region, tx, ty);
}
+ clip_path->surface = cairo_surface_reference (other_path->surface);
- DONE:
- cairo_surface_destroy (clip->surface);
- clip->surface = surface;
- clip->surface_rect = surface_rect;
- clip->serial = _cairo_surface_allocate_clip_serial (target);
+ clip_path->extents = other_path->extents;
+ clip_path->extents.x += tx;
+ clip_path->extents.y += ty;
- if (surface_rect.width == 0 || surface_rect.height == 0)
- _cairo_clip_set_all_clipped (clip, target);
-
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_clip_intersect_mask_using_spans (cairo_clip_t *clip,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- cairo_surface_t *target)
+cairo_status_t
+_cairo_clip_init_copy_transformed (cairo_clip_t *clip,
+ cairo_clip_t *other,
+ const cairo_matrix_t *matrix)
{
- cairo_span_renderer_t *renderer = NULL;
- cairo_pattern_union_t pattern;
- cairo_rectangle_int_t surface_rect;
- cairo_surface_t *surface = NULL;
- cairo_status_t status;
- cairo_operator_t op;
- cairo_composite_rectangles_t rects;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ int tx, ty;
- if (clip->all_clipped)
+ if (other == NULL) {
+ _cairo_clip_init (clip);
return CAIRO_STATUS_SUCCESS;
-
- _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
-
- /* If we have a clip surface we're going to use IN to combine our
- * new clip with the old clip. The ADD is done to a transparent
- * surface, as that's a fast way of doing it currently. We should
- * really be using SOURCE instead, but _cairo_surface_composite()
- * checks that it's not called with SOURCE or DEST. */
- op = clip->surface ? CAIRO_OPERATOR_IN : CAIRO_OPERATOR_ADD;
-
- /* Test if the target can composite spans. We're going to assume
- * this is a good indicator of whether a similar surface is going
- * to be able to composite spans too. */
- if ( !_cairo_surface_check_span_renderer (op,
- &pattern.base,
- target,
- antialias,
- NULL))
- {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto BAIL;
}
- status = _cairo_surface_get_extents (target, &surface_rect);
- if (status)
- goto BAIL;
+ if (other->all_clipped) {
+ _cairo_clip_init (clip);
+ clip->all_clipped = TRUE;
+ return CAIRO_STATUS_SUCCESS;
+ }
- /* We'll create a new surface the size of the intersection of the
- * old mask surface and the extents of the new clip path. */
- {
- cairo_rectangle_int_t extents;
+ if (_cairo_matrix_is_identity (matrix)) {
+ _cairo_clip_init_copy (clip, other);
+ return CAIRO_STATUS_SUCCESS;
+ }
- _cairo_path_fixed_approximate_clip_extents (path, &extents);
- if (! _cairo_rectangle_intersect (&surface_rect, &extents))
- goto SUCCESS;
+ if (other->path != NULL) {
+ _cairo_clip_init (clip);
- if (clip->surface != NULL &&
- ! _cairo_rectangle_intersect (&surface_rect, &clip->surface_rect))
- goto SUCCESS;
+ /* if we only need to translate, so we can reuse the caches... */
+ /* XXX we still loose the benefit of constructs when the copy is
+ * deleted though. Indirect clip_paths?
+ */
+ if (_cairo_matrix_is_integer_translation (matrix, &tx, &ty)) {
+ status = _cairo_clip_path_reapply_clip_path_translate (clip,
+ other->path,
+ tx, ty);
+ } else {
+ status = _cairo_clip_path_reapply_clip_path_transform (clip,
+ other->path,
+ matrix);
+ if (clip->path->extents.width == 0 &&
+ clip->path->extents.height == 0)
+ {
+ _cairo_clip_set_all_clipped (clip);
+ }
+ }
}
- /* Make the new mask surface and optionally initialise it from the
- * previous clip if we have one. */
- surface = _cairo_surface_create_similar_solid (target,
- CAIRO_CONTENT_ALPHA,
- surface_rect.width,
- surface_rect.height,
- CAIRO_COLOR_TRANSPARENT);
- if (surface->status) {
- _cairo_pattern_fini (&pattern.base);
- return surface->status;
- }
-
- if (clip->surface) {
- cairo_surface_pattern_t old_clip;
- _cairo_pattern_init_for_surface (&old_clip, clip->surface);
- status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
- &old_clip.base,
- NULL,
- surface,
- surface_rect.x - clip->surface_rect.x,
- surface_rect.y - clip->surface_rect.y,
- 0, 0,
- 0, 0,
- surface_rect.width,
- surface_rect.height);
- _cairo_pattern_fini (&old_clip.base);
- if (status)
- goto BAIL;
- }
+ return status;
+}
- _cairo_composite_rectangles_init (&rects,
- surface_rect.x,
- surface_rect.y,
- surface_rect.width,
- surface_rect.height);
- rects.dst.x = 0;
- rects.dst.y = 0;
-
- /* Render the new clipping path into the new mask surface. We've
- * chosen op to either combine the new clip path with the existing
- * clip mask (if there is one) or just render it. */
- status =_cairo_path_fixed_fill_using_spans (op, &pattern.base,
- path, surface,
- fill_rule, tolerance,
- antialias, &rects);
- if (status)
- goto BAIL;
+static cairo_status_t
+_cairo_clip_apply_clip_path (cairo_clip_t *clip,
+ const cairo_clip_path_t *path)
+{
+ cairo_status_t status;
- SUCCESS:
- if (clip->surface != NULL)
- cairo_surface_destroy (clip->surface);
- clip->surface = surface;
- clip->surface_rect = surface_rect;
- clip->serial = _cairo_surface_allocate_clip_serial (target);
- surface = NULL;
-
- if (surface_rect.width == 0 || surface_rect.height == 0)
- _cairo_clip_set_all_clipped (clip, target);
-
- BAIL:
- if (renderer)
- renderer->destroy(renderer);
- if (surface)
- cairo_surface_destroy (surface);
- _cairo_pattern_fini (&pattern.base);
- return status;
+ if (path->prev != NULL)
+ status = _cairo_clip_apply_clip_path (clip, path->prev);
+
+ return _cairo_clip_intersect_path (clip,
+ &path->path,
+ path->fill_rule,
+ path->tolerance,
+ path->antialias);
}
cairo_status_t
-_cairo_clip_clip (cairo_clip_t *clip,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- cairo_surface_t *target)
+_cairo_clip_apply_clip (cairo_clip_t *clip,
+ const cairo_clip_t *other)
{
cairo_status_t status;
- cairo_rectangle_int_t limits, extents;
- cairo_traps_t traps;
- cairo_box_t ignored_box;
- cairo_bool_t have_limits;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
- /* catch the empty clip path */
- if (! path->has_current_point) {
- _cairo_clip_set_all_clipped (clip, target);
+ if (other->all_clipped) {
+ _cairo_clip_set_all_clipped (clip);
return CAIRO_STATUS_SUCCESS;
}
- status = _cairo_clip_intersect_path (clip,
- path, fill_rule, tolerance,
- antialias);
- if (status == CAIRO_STATUS_SUCCESS)
- clip->serial = _cairo_surface_allocate_clip_serial (target);
+ status = CAIRO_STATUS_SUCCESS;
+ if (other->path != NULL)
+ status = _cairo_clip_apply_clip_path (clip, other->path);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_clip_path_to_region (cairo_clip_path_t *clip_path)
+{
+ cairo_int_status_t status;
+ cairo_traps_t traps;
+ cairo_region_t *prev = NULL;
+ cairo_box_t box;
- /* TODO: allow ANTIALIAS_NONE when we have a mono scan converter
- * again. */
- if (antialias != CAIRO_ANTIALIAS_NONE &&
- !_cairo_path_fixed_is_box (path, &ignored_box) &&
- !_cairo_path_fixed_is_region (path))
+ if (clip_path->flags &
+ (CAIRO_CLIP_PATH_HAS_REGION |
+ CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED))
{
- status = _cairo_clip_intersect_mask_using_spans (
- clip, path, fill_rule, tolerance, antialias, target);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ return clip_path->flags & CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED ?
+ CAIRO_INT_STATUS_UNSUPPORTED :
+ CAIRO_STATUS_SUCCESS;
}
- _cairo_traps_init (&traps);
-
- /* Limit the traps to the target surface and current clip
- * - so we don't add more traps than needed. */
- have_limits = FALSE;
- if (clip->region != NULL) {
- cairo_region_get_extents (clip->region, &limits);
- have_limits = TRUE;
+ if (! clip_path->path.maybe_fill_region) {
+ clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
- if (clip->surface != NULL) {
- if (have_limits) {
- if (! _cairo_rectangle_intersect (&limits, &clip->surface_rect)) {
- _cairo_clip_set_all_clipped (clip, target);
- return CAIRO_STATUS_SUCCESS;
- }
- } else {
- limits = clip->surface_rect;
- have_limits = TRUE;
+ /* first retrieve the region for our antecedents */
+ if (clip_path->prev != NULL) {
+ status = _cairo_clip_path_to_region (clip_path->prev);
+ if (status) {
+ clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
+ return status;
}
- }
- status = _cairo_surface_get_extents (target, &extents);
- if (status == CAIRO_STATUS_SUCCESS) {
- if (have_limits) {
- if (! _cairo_rectangle_intersect (&limits, &extents)) {
- _cairo_clip_set_all_clipped (clip, target);
- return CAIRO_STATUS_SUCCESS;
- }
- } else {
- limits = extents;
- have_limits = TRUE;
- }
+ prev = clip_path->prev->region;
}
- if (have_limits) {
- cairo_box_t box;
+ /* now extract the region for ourselves */
- _cairo_box_from_rectangle (&box, &limits);
- _cairo_traps_limit (&traps, &box);
- }
+ /* XXX fixed fill to region */
+ _cairo_traps_init (&traps);
+
+ _cairo_box_from_rectangle (&box, &clip_path->extents);
+ _cairo_traps_limit (&traps, &box);
- status = _cairo_path_fixed_fill_to_traps (path,
- fill_rule,
- tolerance,
+ status = _cairo_path_fixed_fill_to_traps (&clip_path->path,
+ clip_path->fill_rule,
+ clip_path->tolerance,
&traps);
if (unlikely (status))
- goto bail;
+ return status;
- status = _cairo_clip_intersect_region (clip, &traps, target);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- goto bail;
+ status = _cairo_traps_extract_region (&traps, &clip_path->region);
+ _cairo_traps_fini (&traps);
- status = _cairo_clip_intersect_mask (clip, &traps, antialias, target);
+ if (status) {
+ clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
+ return status;
+ }
- bail:
- _cairo_traps_fini (&traps);
+ if (prev != NULL) {
+ status = cairo_region_intersect (clip_path->region, prev);
+ if (unlikely (status))
+ return status;
+ }
- return status;
+ clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
+ return CAIRO_STATUS_SUCCESS;
}
-void
-_cairo_clip_translate (cairo_clip_t *clip,
- cairo_fixed_t tx,
- cairo_fixed_t ty)
+cairo_surface_t *
+_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target)
{
- if (clip->all_clipped)
- return;
+ cairo_surface_t *surface;
+ cairo_pattern_union_t pattern;
+ cairo_status_t status;
+ cairo_clip_path_t *clip_path = clip->path;
+ const cairo_rectangle_int_t *clip_extents = &clip_path->extents;
+ cairo_region_t *clip_region;
+ cairo_bool_t need_translate;
- if (clip->region) {
- cairo_region_translate (clip->region,
- _cairo_fixed_integer_part (tx),
- _cairo_fixed_integer_part (ty));
- }
+ assert (clip_path != NULL);
- if (clip->surface) {
- clip->surface_rect.x += _cairo_fixed_integer_part (tx);
- clip->surface_rect.y += _cairo_fixed_integer_part (ty);
+ if (clip_path->surface != NULL &&
+ clip_path->surface->backend == target->backend)
+ {
+ return cairo_surface_reference (clip_path->surface);
}
- if (clip->path) {
- cairo_clip_path_t *clip_path = clip->path;
- cairo_matrix_t matrix;
-
- cairo_matrix_init_translate (&matrix,
- _cairo_fixed_to_double (tx),
- _cairo_fixed_to_double (ty));
+ surface = _cairo_surface_create_similar_solid (target,
+ CAIRO_CONTENT_ALPHA,
+ clip_extents->width,
+ clip_extents->height,
+ CAIRO_COLOR_TRANSPARENT,
+ FALSE);
+ if (surface == NULL) {
+ if (clip_path->surface != NULL &&
+ clip_path->surface->backend == &_cairo_image_surface_backend)
+ {
+ return cairo_surface_reference (clip_path->surface);
+ }
- while (clip_path) {
- _cairo_path_fixed_transform (&clip_path->path, &matrix);
- clip_path = clip_path->prev;
- }
+ surface =
+ _cairo_image_surface_create_with_content (CAIRO_CONTENT_ALPHA,
+ clip_extents->width,
+ clip_extents->height);
}
-}
+ if (unlikely (surface->status))
+ return surface;
-static cairo_status_t
-_cairo_clip_path_reapply_clip_path (cairo_clip_t *clip,
- cairo_clip_path_t *clip_path)
-{
- cairo_status_t status;
+ _cairo_pattern_init_solid (&pattern.solid,
+ CAIRO_COLOR_WHITE,
+ CAIRO_CONTENT_COLOR);
- if (clip_path->prev) {
- status = _cairo_clip_path_reapply_clip_path (clip, clip_path->prev);
- if (_cairo_status_is_error (status))
- return status;
- }
+ status = _cairo_clip_get_region (clip, &clip_region);
+ if (_cairo_status_is_error (status))
+ goto BAIL;
- return _cairo_clip_intersect_path (clip,
- &clip_path->path,
- clip_path->fill_rule,
- clip_path->tolerance,
- clip_path->antialias);
-}
+ need_translate = clip_extents->x || clip_extents->y;
+ if (status == CAIRO_STATUS_SUCCESS) {
+ if (need_translate) {
+ cairo_region_translate (clip_region,
+ -clip_extents->x, -clip_extents->y);
+ }
+ status = _cairo_surface_fill_region (surface,
+ CAIRO_OPERATOR_ADD,
+ CAIRO_COLOR_WHITE,
+ clip_region);
+ if (need_translate) {
+ cairo_region_translate (clip_region,
+ clip_extents->x, clip_extents->y);
+ }
+ if (unlikely (status))
+ goto BAIL;
-cairo_status_t
-_cairo_clip_init_deep_copy (cairo_clip_t *clip,
- cairo_clip_t *other,
- cairo_surface_t *target)
-{
- cairo_status_t status;
+ goto DONE;
+ } else {
+ if (need_translate) {
+ _cairo_path_fixed_translate (&clip_path->path,
+ _cairo_fixed_from_int (-clip_extents->x),
+ _cairo_fixed_from_int (-clip_extents->y));
+ }
+ status = _cairo_surface_fill (surface,
+ CAIRO_OPERATOR_ADD,
+ &pattern.base,
+ &clip_path->path,
+ clip_path->fill_rule,
+ clip_path->tolerance,
+ clip_path->antialias,
+ NULL);
+ if (need_translate) {
+ _cairo_path_fixed_translate (&clip_path->path,
+ _cairo_fixed_from_int (clip_extents->x),
+ _cairo_fixed_from_int (clip_extents->y));
+ }
- _cairo_clip_init (clip, target);
+ if (unlikely (status))
+ goto BAIL;
+ }
- if (other->mode != clip->mode) {
- /* We should reapply the original clip path in this case, and let
- * whatever the right handling is happen */
- } else {
- if (other->region) {
- clip->region = cairo_region_copy (other->region);
- if (unlikely ((status = cairo_region_status (clip->region))))
- goto BAIL;
- }
+ while ((clip_path = clip_path->prev) != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ if (_cairo_status_is_error (status))
+ goto BAIL;
- if (other->surface) {
- int dx, dy;
- status = _cairo_surface_clone_similar (target, other->surface,
- CAIRO_CONTENT_ALPHA,
- 0,
- 0,
- other->surface_rect.width,
- other->surface_rect.height,
- &dx, &dy,
- &clip->surface);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ cairo_region_translate (clip_region,
+ -clip_extents->x, -clip_extents->y);
+ status = _cairo_surface_fill_region (surface,
+ CAIRO_OPERATOR_IN,
+ CAIRO_COLOR_WHITE,
+ clip_region);
+ cairo_region_translate (clip_region,
+ clip_extents->x, clip_extents->y);
if (unlikely (status))
goto BAIL;
- clip->surface_rect = other->surface_rect;
-
- /* src offset was 0, so we expect an exact replica of the surface */
- assert (dx == 0);
- assert (dy == 0);
- }
-
- if (other->path) {
- status = _cairo_clip_path_reapply_clip_path (clip, other->path);
- if (_cairo_status_is_error (status))
+ goto DONE;
+ } else {
+ if (clip_path->surface != NULL &&
+ clip_path->surface->backend == surface->backend)
+ {
+ _cairo_pattern_init_for_surface (&pattern.surface,
+ clip_path->surface);
+ cairo_matrix_init_translate (&pattern.base.matrix,
+ -clip_path->extents.x + clip_extents->x,
+ -clip_path->extents.y + clip_extents->y);
+ status = _cairo_surface_paint (surface,
+ CAIRO_OPERATOR_IN,
+ &pattern.base,
+ NULL);
+
+ _cairo_pattern_fini (&pattern.base);
+
+ if (unlikely (status))
+ goto BAIL;
+
+ goto DONE;
+ } else {
+ /* XXX build intermediate surfaces? */
+ if (need_translate) {
+ _cairo_path_fixed_translate (&clip_path->path,
+ _cairo_fixed_from_int (-clip_extents->x),
+ _cairo_fixed_from_int (-clip_extents->y));
+ }
+ status = _cairo_surface_fill (surface,
+ CAIRO_OPERATOR_IN,
+ &pattern.base,
+ &clip_path->path,
+ clip_path->fill_rule,
+ clip_path->tolerance,
+ clip_path->antialias,
+ NULL);
+ if (need_translate) {
+ _cairo_path_fixed_translate (&clip_path->path,
+ _cairo_fixed_from_int (clip_extents->x),
+ _cairo_fixed_from_int (clip_extents->y));
+ }
+ }
+ if (unlikely (status))
goto BAIL;
- }
+ }
}
- return CAIRO_STATUS_SUCCESS;
+DONE:
+ cairo_surface_destroy (clip->path->surface);
+ return clip->path->surface = cairo_surface_reference (surface);
BAIL:
- if (clip->region)
- cairo_region_destroy (clip->region);
- if (clip->surface)
- cairo_surface_destroy (clip->surface);
+ cairo_surface_destroy (surface);
+ return _cairo_surface_create_in_error (status);
+}
- return status;
+const cairo_rectangle_int_t *
+_cairo_clip_get_extents (const cairo_clip_t *clip)
+{
+ if (clip->path == NULL)
+ return NULL;
+
+ return &clip->path->extents;
+}
+
+void
+_cairo_clip_drop_cache (cairo_clip_t *clip)
+{
+ cairo_clip_path_t *clip_path;
+
+ if (clip->path == NULL)
+ return;
+
+ clip_path = clip->path;
+ do {
+ if (clip_path->region != NULL) {
+ cairo_region_destroy (clip_path->region);
+ clip_path->region = NULL;
+ }
+
+ if (clip_path->surface != NULL) {
+ cairo_surface_destroy (clip_path->surface);
+ clip_path->surface = NULL;
+ }
+
+ clip_path->flags = 0;
+ } while ((clip_path = clip_path->prev) != NULL);
}
const cairo_rectangle_list_t _cairo_rectangles_nil =
@@ -862,42 +838,90 @@ _cairo_clip_int_rect_to_user (cairo_gstate_t *gstate,
return is_tight;
}
+cairo_int_status_t
+_cairo_clip_get_region (cairo_clip_t *clip,
+ cairo_region_t **region)
+{
+ cairo_int_status_t status;
+
+ *region = NULL;
+ if (clip->all_clipped)
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+ if (clip->path == NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_clip_path_to_region (clip->path);
+ if (status)
+ return status;
+
+ *region = clip->path->region;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_rectangle_list_t *
+_cairo_rectangle_list_create_in_error (cairo_status_t status)
+{
+ cairo_rectangle_list_t *list;
+
+ if (status == CAIRO_STATUS_NO_MEMORY)
+ return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
+ if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
+ return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
+
+ list = malloc (sizeof (*list));
+ if (unlikely (list == NULL)) {
+ _cairo_error_throw (status);
+ return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
+ }
+
+ list->status = status;
+ list->rectangles = NULL;
+ list->num_rectangles = 0;
+
+ return list;
+}
+
cairo_rectangle_list_t *
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
{
+#define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S));
+
cairo_rectangle_list_t *list;
cairo_rectangle_t *rectangles = NULL;
+ cairo_int_status_t status;
+ cairo_region_t *region;
int n_rects = 0;
+ int i;
- if (clip->all_clipped)
+ status = _cairo_clip_get_region (clip, &region);
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
goto DONE;
-
- if (clip->path || clip->surface) {
- _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
- return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
+ } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
+ } else if (unlikely (status)) {
+ return ERROR_LIST (status);
}
- if (clip->region) {
- int i;
-
- n_rects = cairo_region_num_rectangles (clip->region);
-
+ if (region != NULL) {
+ n_rects = cairo_region_num_rectangles (region);
if (n_rects) {
rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
if (unlikely (rectangles == NULL)) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
+ return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
}
for (i = 0; i < n_rects; ++i) {
cairo_rectangle_int_t clip_rect;
- cairo_region_get_rectangle (clip->region, i, &clip_rect);
-
- if (!_cairo_clip_int_rect_to_user(gstate, &clip_rect, &rectangles[i])) {
- _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
+ cairo_region_get_rectangle (region, i, &clip_rect);
+
+ if (! _cairo_clip_int_rect_to_user (gstate,
+ &clip_rect,
+ &rectangles[i]))
+ {
free (rectangles);
- return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
+ return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
}
}
}
@@ -908,31 +932,31 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
rectangles = malloc(sizeof (cairo_rectangle_t));
if (unlikely (rectangles == NULL)) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
+ return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
}
- if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate), &extents) ||
- !_cairo_clip_int_rect_to_user(gstate, &extents, rectangles))
+ if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate),
+ &extents) ||
+ ! _cairo_clip_int_rect_to_user (gstate, &extents, rectangles))
{
- _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
free (rectangles);
- return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
+ return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
}
}
DONE:
list = malloc (sizeof (cairo_rectangle_list_t));
if (unlikely (list == NULL)) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
free (rectangles);
- return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
+ return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
}
list->status = CAIRO_STATUS_SUCCESS;
list->rectangles = rectangles;
list->num_rectangles = n_rects;
return list;
+
+#undef ERROR_LIST
}
/**
@@ -955,3 +979,9 @@ cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
free (rectangle_list->rectangles);
free (rectangle_list);
}
+
+void
+_cairo_clip_reset_static_data (void)
+{
+ _freed_pool_reset (&clip_path_pool);
+}
diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index d4548f15..4dccebeb 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -75,6 +75,8 @@ cairo_debug_reset_static_data (void)
_cairo_pattern_reset_static_data ();
+ _cairo_clip_reset_static_data ();
+
CAIRO_MUTEX_FINALIZE ();
}
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index f7de84ca..967b0447 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -38,14 +38,16 @@
#include "cairoint.h"
#include "cairo-directfb.h"
+#include "cairo-clip-private.h"
+
+#include <pixman.h>
+
#include <directfb.h>
#include <direct/types.h>
#include <direct/debug.h>
#include <direct/memcpy.h>
#include <direct/util.h>
-#include "cairo-clip-private.h"
-
/*
* Rectangle works fine.
* Bugs 361377, 359553, 359243 in Gnome BTS are caused
@@ -68,6 +70,8 @@
*/
#define DFB_SHOW_GLYPHS 1
+#define PIXMAN_invalid (pixman_format_code_t) 0
+
D_DEBUG_DOMAIN (CairoDFB_Acquire, "CairoDFB/Acquire", "Cairo DirectFB Acquire");
D_DEBUG_DOMAIN (CairoDFB_Clip, "CairoDFB/Clip", "Cairo DirectFB Clipping");
@@ -78,17 +82,15 @@ D_DEBUG_DOMAIN (CairoDFB_Surface, "CairoDFB/Surface", "Cairo DirectFB Surface");
/*****************************************************************************/
typedef struct _cairo_directfb_surface {
- cairo_surface_t base;
- cairo_format_t format;
- cairo_content_t content;
+ cairo_surface_t base;
- IDirectFB *dfb;
- IDirectFBSurface *dfbsurface;
- IDirectFBSurface *tmpsurface;
+ pixman_format_code_t pixman_format;
+ cairo_bool_t supported_destination;
- cairo_bool_t has_clip;
- DFBRegion *clips;
- int n_clips;
+ IDirectFB *dfb;
+ IDirectFBSurface *dfbsurface;
+ IDirectFBSurface *tmpsurface;
+ pixman_format_code_t tmpformat;
int width;
int height;
@@ -119,13 +121,18 @@ static int _directfb_argb_font = 0;
/*****************************************************************************/
-#define RUN_CLIPPED(surface, clip, func) {\
- if ((surface)->has_clip) {\
- int k;\
- for (k = 0; k < (surface)->n_clips; k++) {\
+#define RUN_CLIPPED(surface, clip_region, clip, func) {\
+ if ((clip_region) != NULL) {\
+ int n_clips = cairo_region_num_rectangles (clip_region), n; \
+ for (n = 0; n < n_clips; n++) {\
if (clip) {\
- DFBRegion reg = (surface)->clips[k];\
- DFBRegion *cli = (clip);\
+ DFBRegion reg, *cli = (clip); \
+ cairo_rectangle_int_t rect; \
+ cairo_region_get_rectangle (clip_region, n, &rect); \
+ reg.x1 = rect.x; \
+ reg.y1 = rect.y; \
+ reg.x2 = rect.x + rect.width - 1; \
+ reg.y2 = rect.y + rect.height - 1; \
if (reg.x2 < cli->x1 || reg.y2 < cli->y1 ||\
reg.x1 > cli->x2 || reg.y1 > cli->y2)\
continue;\
@@ -139,8 +146,14 @@ static int _directfb_argb_font = 0;
reg.y2 = cli->y2;\
(surface)->dfbsurface->SetClip ((surface)->dfbsurface, &reg);\
} else {\
- (surface)->dfbsurface->SetClip ((surface)->dfbsurface,\
- &(surface)->clips[k]);\
+ DFBRegion reg; \
+ cairo_rectangle_int_t rect; \
+ cairo_region_get_rectangle (clip_region, n, &rect); \
+ reg.x1 = rect.x; \
+ reg.y1 = rect.y; \
+ reg.x2 = rect.x + rect.width - 1; \
+ reg.y2 = rect.y + rect.height - 1; \
+ (surface)->dfbsurface->SetClip ((surface)->dfbsurface, &reg); \
}\
func;\
}\
@@ -150,19 +163,19 @@ static int _directfb_argb_font = 0;
}\
}
-#define TRANSFORM_POINT2X(m, x, y, ret_x, ret_y) {\
- double _x = (x);\
- double _y = (y);\
- (ret_x) = (_x * (m).xx + (m).x0);\
- (ret_y) = (_y * (m).yy + (m).y0);\
-}
+#define TRANSFORM_POINT2X(m, x, y, ret_x, ret_y) do { \
+ double _x = (x); \
+ double _y = (y); \
+ (ret_x) = (_x * (m).xx + (m).x0); \
+ (ret_y) = (_y * (m).yy + (m).y0); \
+} while (0)
-#define TRANSFORM_POINT3X(m, x, y, ret_x, ret_y) {\
- double _x = (x);\
- double _y = (y);\
- (ret_x) = (_x * (m).xx + _y * (m).xy + (m).x0);\
- (ret_y) = (_x * (m).yx + _y * (m).yy + (m).y0);\
-}
+#define TRANSFORM_POINT3X(m, x, y, ret_x, ret_y) do { \
+ double _x = (x); \
+ double _y = (y); \
+ (ret_x) = (_x * (m).xx + _y * (m).xy + (m).x0); \
+ (ret_y) = (_x * (m).yx + _y * (m).yy + (m).y0); \
+} while (0)
/* XXX: A1 has a different bits ordering in cairo.
* Probably we should drop it.
@@ -200,23 +213,65 @@ _cairo_to_directfb_format (cairo_format_t format)
return -1;
}
-static inline cairo_format_t
-_directfb_to_cairo_format (DFBSurfacePixelFormat format)
+static inline pixman_format_code_t
+_directfb_to_pixman_format (DFBSurfacePixelFormat format)
{
switch (format) {
- case DSPF_RGB32:
- return CAIRO_FORMAT_RGB24;
- case DSPF_ARGB:
- return CAIRO_FORMAT_ARGB32;
- case DSPF_A8:
- return CAIRO_FORMAT_A8;
- case DSPF_A1:
- return CAIRO_FORMAT_A1;
- default:
- break;
+ case DSPF_UNKNOWN: return PIXMAN_invalid;
+ case DSPF_ARGB1555: return PIXMAN_a1r5g5b5;
+ case DSPF_RGB16: return PIXMAN_r5g6b5;
+ case DSPF_RGB24: return PIXMAN_r8g8b8;
+ case DSPF_RGB32: return PIXMAN_x8r8g8b8;
+ case DSPF_ARGB: return PIXMAN_a8r8g8b8;
+ case DSPF_A8: return PIXMAN_a8;
+ case DSPF_YUY2: return PIXMAN_yuy2;
+ case DSPF_RGB332: return PIXMAN_r3g3b2;
+ case DSPF_UYVY: return PIXMAN_invalid;
+ case DSPF_I420: return PIXMAN_invalid;
+ case DSPF_YV12: return PIXMAN_yv12;
+ case DSPF_LUT8: return PIXMAN_invalid;
+ case DSPF_ALUT44: return PIXMAN_invalid;
+ case DSPF_AiRGB: return PIXMAN_invalid;
+ case DSPF_A1: return PIXMAN_a1; /* bit reversed, oops */
+ case DSPF_NV12: return PIXMAN_invalid;
+ case DSPF_NV16: return PIXMAN_invalid;
+ case DSPF_ARGB2554: return PIXMAN_invalid;
+ case DSPF_ARGB4444: return PIXMAN_a4r4g4b4;
+ case DSPF_NV21: return PIXMAN_invalid;
+ case DSPF_AYUV: return PIXMAN_invalid;
+ case DSPF_A4: return PIXMAN_a4;
+ case DSPF_ARGB1666: return PIXMAN_invalid;
+ case DSPF_ARGB6666: return PIXMAN_invalid;
+ case DSPF_RGB18: return PIXMAN_invalid;
+ case DSPF_LUT2: return PIXMAN_invalid;
+ case DSPF_RGB444: return PIXMAN_x4r4g4b4;
+ case DSPF_RGB555: return PIXMAN_x1r5g5b5;
+ case DSPF_BGR555: return PIXMAN_x1b5g5r5;
}
+ return PIXMAN_invalid;
+}
- return -1;
+static inline DFBSurfacePixelFormat
+_directfb_from_pixman_format (pixman_format_code_t format)
+{
+ switch ((int) format) {
+ case PIXMAN_a1r5g5b5: return DSPF_ARGB1555;
+ case PIXMAN_r5g6b5: return DSPF_RGB16;
+ case PIXMAN_r8g8b8: return DSPF_RGB24;
+ case PIXMAN_x8r8g8b8: return DSPF_RGB32;
+ case PIXMAN_a8r8g8b8: return DSPF_ARGB;
+ case PIXMAN_a8: return DSPF_A8;
+ case PIXMAN_yuy2: return DSPF_YUY2;
+ case PIXMAN_r3g3b2: return DSPF_RGB332;
+ case PIXMAN_yv12: return DSPF_YV12;
+ case PIXMAN_a1: return DSPF_A1; /* bit reversed, oops */
+ case PIXMAN_a4r4g4b4: return DSPF_ARGB4444;
+ case PIXMAN_a4: return DSPF_A4;
+ case PIXMAN_x4r4g4b4: return DSPF_RGB444;
+ case PIXMAN_x1r5g5b5: return DSPF_RGB555;
+ case PIXMAN_x1b5g5r5: return DSPF_BGR555;
+ default: return 0;
+ }
}
static cairo_bool_t
@@ -350,17 +405,14 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
IDirectFBSurface *buffer = NULL;
DFBRectangle source_rect;
cairo_surface_t *image;
- cairo_format_t cairo_format;
+ pixman_image_t *pixman_image;
+ pixman_format_code_t pixman_format;
cairo_status_t status;
void *data;
int pitch;
- if (surface->format == (cairo_format_t) -1 ||
- (lock_flags & DSLF_WRITE && surface->has_clip))
- {
- DFBSurfaceCapabilities caps;
-
- if (intrest_rec) {
+ if (surface->pixman_format == PIXMAN_invalid) {
+ if (intrest_rec != NULL) {
source_rect.x = intrest_rec->x;
source_rect.y = intrest_rec->y;
source_rect.w = intrest_rec->width;
@@ -372,30 +424,38 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
&source_rect.w, &source_rect.h);
}
- if (surface->tmpsurface) {
+ if (surface->tmpsurface != NULL) {
int w, h;
+
surface->tmpsurface->GetSize (surface->tmpsurface, &w, &h);
if (w < source_rect.w || h < source_rect.h) {
surface->tmpsurface->Release (surface->tmpsurface);
surface->tmpsurface = NULL;
+ surface->tmpformat = PIXMAN_invalid;
}
}
- cairo_format = _cairo_format_from_content (surface->content);
- if (!surface->tmpsurface) {
+ if (surface->tmpsurface == NULL) {
+ DFBSurfacePixelFormat format;
+
D_DEBUG_AT (CairoDFB_Acquire, "Allocating buffer for surface %p.\n", surface);
+ format = _cairo_to_directfb_format (_cairo_format_from_content (surface->base.content));
status =
- _directfb_buffer_surface_create (surface->dfb,
- _cairo_to_directfb_format (cairo_format),
+ _directfb_buffer_surface_create (surface->dfb, format,
source_rect.w, source_rect.h,
&surface->tmpsurface);
- if (status)
+ if (unlikely (status))
goto ERROR;
+
+ surface->tmpformat = _directfb_to_pixman_format (format);
}
buffer = surface->tmpsurface;
+ pixman_format = surface->tmpformat;
+
/* surface->dfbsurface->GetCapabilities (surface->dfbsurface, &caps);
+ DFBSurfaceCapabilities caps;
if (caps & DSCAPS_FLIPPING) {
DFBRegion region = { .x1 = source_rect.x, .y1 = source_rect.y,
.x2 = source_rect.x + source_rect.w - 1,
@@ -406,7 +466,7 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
} else {
/*might be a subsurface get the offset*/
surface->dfbsurface->GetVisibleRectangle (surface->dfbsurface, &source_rect);
- cairo_format = surface->format;
+ pixman_format = surface->pixman_format;
buffer = surface->dfbsurface;
}
@@ -416,9 +476,16 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
goto ERROR;
}
- image = cairo_image_surface_create_for_data (data, cairo_format,
- source_rect.w, source_rect.h,
- pitch);
+ pixman_image = pixman_image_create_bits (pixman_format,
+ source_rect.w, source_rect.h,
+ data, pitch);
+ if (pixman_image == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto ERROR;
+ }
+
+ image = _cairo_image_surface_create_for_pixman_image (pixman_image,
+ pixman_format);
status = image->status;
if (status)
goto ERROR;
@@ -451,37 +518,27 @@ ERROR:
}
static cairo_surface_t *
-_cairo_directfb_surface_create_similar (void *abstract_src,
- cairo_content_t content,
- int width,
- int height)
+_cairo_directfb_surface_create_internal (IDirectFB *dfb,
+ DFBSurfacePixelFormat format,
+ cairo_content_t content,
+ int width,
+ int height)
{
- cairo_directfb_surface_t *source = abstract_src;
cairo_directfb_surface_t *surface;
- cairo_format_t format;
cairo_status_t status;
- D_DEBUG_AT (CairoDFB_Surface,
- "%s( src=%p, content=0x%x, width=%d, height=%d).\n",
- __FUNCTION__, source, content, width, height);
-
- width = (width <= 0) ? 1 : width;
- height = (height<= 0) ? 1 : height;
-
- format = _cairo_format_from_content (content);
surface = calloc (1, sizeof (cairo_directfb_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- surface->dfb = source->dfb;
+ surface->dfb = dfb;
if (width < 8 || height < 8) {
IDirectFBSurface *tmp;
DFBRectangle rect = { .x=0, .y=0, .w=width, .h=height };
/* Some cards (e.g. Matrox) don't support surfaces smaller than 8x8 */
- status = _directfb_buffer_surface_create (surface->dfb,
- _cairo_to_directfb_format (format),
+ status = _directfb_buffer_surface_create (dfb, format,
MAX (width, 8), MAX (height, 8),
&tmp);
if (status) {
@@ -492,11 +549,9 @@ _cairo_directfb_surface_create_similar (void *abstract_src,
tmp->GetSubSurface (tmp, &rect, &surface->dfbsurface);
tmp->Release (tmp);
} else {
- status =
- _directfb_buffer_surface_create (surface->dfb,
- _cairo_to_directfb_format (format),
- width, height,
- &surface->dfbsurface);
+ status = _directfb_buffer_surface_create (dfb, format,
+ width, height,
+ &surface->dfbsurface);
if (status) {
free (surface);
return _cairo_surface_create_in_error (status);
@@ -506,8 +561,9 @@ _cairo_directfb_surface_create_similar (void *abstract_src,
_cairo_surface_init (&surface->base,
&_cairo_directfb_surface_backend,
content);
- surface->format = format;
- surface->content = content;
+ surface->pixman_format = _directfb_to_pixman_format (format);
+ surface->supported_destination = pixman_format_supported_destination (surface->pixman_format);
+
surface->width = width;
surface->height = height;
surface->local = TRUE;
@@ -516,6 +572,27 @@ _cairo_directfb_surface_create_similar (void *abstract_src,
return &surface->base;
}
+static cairo_surface_t *
+_cairo_directfb_surface_create_similar (void *abstract_src,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_directfb_surface_t *other = abstract_src;
+ DFBSurfacePixelFormat format;
+
+ D_DEBUG_AT (CairoDFB_Surface,
+ "%s( src=%p, content=0x%x, width=%d, height=%d).\n",
+ __FUNCTION__, other, content, width, height);
+
+ width = (width <= 0) ? 1 : width;
+ height = (height<= 0) ? 1 : height;
+
+ format = _cairo_to_directfb_format (_cairo_format_from_content (content));
+ return _cairo_directfb_surface_create_internal (other->dfb, format,
+ content, width, height);
+}
+
static cairo_status_t
_cairo_directfb_surface_finish (void *data)
{
@@ -523,12 +600,6 @@ _cairo_directfb_surface_finish (void *data)
D_DEBUG_AT (CairoDFB_Surface, "%s( surface=%p ).\n", __FUNCTION__, surface);
- if (surface->clips) {
- free (surface->clips);
- surface->clips = NULL;
- surface->n_clips = 0;
- }
-
if (surface->tmpsurface) {
surface->tmpsurface->Release (surface->tmpsurface);
surface->tmpsurface = NULL;
@@ -564,11 +635,10 @@ _cairo_directfb_surface_release_source_image (void *abstract_su
cairo_image_surface_t *image,
void *image_extra)
{
- cairo_directfb_surface_t *surface = abstract_surface;
IDirectFBSurface *buffer = image_extra;
D_DEBUG_AT (CairoDFB_Acquire,
- "%s( surface=%p ).\n", __FUNCTION__, surface);
+ "%s( release=%p ).\n", __FUNCTION__, abstract_surface);
buffer->Unlock (buffer);
@@ -620,10 +690,10 @@ _cairo_directfb_surface_release_dest_image (void *abstract_surf
.y2 = interest_rect->y + interest_rect->height - 1
};
surface->dfbsurface->SetBlittingFlags (surface->dfbsurface, DSBLIT_NOFX);
- RUN_CLIPPED (surface, &region,
- surface->dfbsurface->Blit (surface->dfbsurface,
- buffer, NULL,
- image_rect->x, image_rect->y));
+ surface->dfbsurface->SetClip (surface->dfbsurface, &region);
+ surface->dfbsurface->Blit (surface->dfbsurface,
+ buffer, NULL,
+ image_rect->x, image_rect->y);
}
cairo_surface_destroy (&image->base);
@@ -655,56 +725,51 @@ _cairo_directfb_surface_clone_similar (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
} else if (_cairo_surface_is_image (src)) {
cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
- unsigned char *dst, *src = image_src->data;
- int pitch;
- int i, j;
+ DFBSurfacePixelFormat format;
DFBResult ret;
+ pixman_image_t *pixman_image;
+ void *data;
+ int pitch;
- clone = (cairo_directfb_surface_t *)
- _cairo_directfb_surface_create_similar (surface,
- _cairo_content_from_format (image_src->format),
- width, height);
- if (clone == NULL)
+ format = _directfb_from_pixman_format (image_src->pixman_format);
+ if (format == 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (clone->base.status)
+
+ clone = (cairo_directfb_surface_t *)
+ _cairo_directfb_surface_create_internal (surface->dfb, format,
+ image_src->base.content,
+ width, height);
+ if (unlikely (clone->base.status))
return clone->base.status;
ret = clone->dfbsurface->Lock (clone->dfbsurface,
- DSLF_WRITE, (void *)&dst, &pitch);
+ DSLF_WRITE, (void *)&data, &pitch);
if (ret) {
DirectFBError ("IDirectFBSurface::Lock()", ret);
cairo_surface_destroy (&clone->base);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- src += image_src->stride * src_y;
- if (image_src->format == CAIRO_FORMAT_A1) {
- /* A1 -> A8 */
- dst -= src_x;
- for (i = 0; i < height; i++) {
- for (j = src_x; j < src_x + width; j++)
- dst[j] = (src[j>>3] & (1 << (j&7))) ? 0xff : 0x00;
- dst += pitch;
- src += image_src->stride;
- }
- } else {
- int len;
-
- if (image_src->format == CAIRO_FORMAT_A8) {
- src += src_x;
- len = width;
- } else {
- src += src_x * 4;
- len = width * 4;
- }
-
- for (i = 0; i < height; i++) {
- direct_memcpy (dst, src, len);
- dst += pitch;
- src += image_src->stride;
- }
+ pixman_image = pixman_image_create_bits (clone->pixman_format,
+ width, height,
+ data, pitch);
+ if (unlikely (pixman_image == NULL)) {
+ DirectFBError ("IDirectFBSurface::Lock()", ret);
+ cairo_surface_destroy (&clone->base);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
+ pixman_image_composite (PIXMAN_OP_SRC,
+ image_src->pixman_image,
+ NULL,
+ pixman_image,
+ src_x, src_y,
+ 0, 0,
+ 0, 0,
+ width, height);
+
+ pixman_image_unref (pixman_image);
+
clone->dfbsurface->Unlock (clone->dfbsurface);
*clone_offset_x = src_x;
@@ -745,8 +810,6 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
return CAIRO_INT_STATUS_UNSUPPORTED;
if (mask_pattern) {
- cairo_solid_pattern_t *pattern;
-
return CAIRO_INT_STATUS_UNSUPPORTED;
if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
const cairo_pattern_t *tmp;
@@ -794,7 +857,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- if (src->content == CAIRO_CONTENT_COLOR) {
+ if ((src->base.content & CAIRO_CONTENT_ALPHA) == 0) {
if (sblend == DSBF_SRCALPHA)
sblend = DSBF_ONE;
else if (sblend == DSBF_INVSRCALPHA)
@@ -806,7 +869,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
dblend = DSBF_ZERO;
}
- if (dst->content == CAIRO_CONTENT_COLOR) {
+ if ((dst->base.content & CAIRO_CONTENT_ALPHA) == 0) {
if (sblend == DSBF_DESTALPHA)
sblend = DSBF_ONE;
else if (sblend == DSBF_INVDESTALPHA)
@@ -913,7 +976,8 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
int mask_x, int mask_y,
int dst_x, int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_surface_t *src;
@@ -930,6 +994,9 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
__FUNCTION__, op, src_pattern, mask_pattern, dst,
src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height);
+ if (! dst->supported_destination)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
status = _directfb_prepare_composite (dst, src_pattern, mask_pattern, op,
&src_x, &src_y, &mask_x, &mask_y,
width, height, &src, &src_attr);
@@ -956,7 +1023,7 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
src_x += src_attr.x_offset;
src_y += src_attr.y_offset;
- switch (accel) {
+ switch ((int) accel) {
case DFXL_BLIT:
{
DFBRectangle sr;
@@ -974,11 +1041,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
if (src_attr.extend == CAIRO_EXTEND_NONE) {
D_DEBUG_AT (CairoDFB_Render, "Running Blit().\n");
- RUN_CLIPPED (dst, NULL,
+ RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->Blit (dst->dfbsurface,
src->dfbsurface,
- &sr,
- dst_x, dst_y));
+ &sr, dst_x, dst_y));
} else if (src_attr.extend == CAIRO_EXTEND_REPEAT) {
DFBRegion clip;
@@ -989,11 +1055,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running TileBlit().\n");
- RUN_CLIPPED (dst, &clip,
+ RUN_CLIPPED (dst, clip_region, &clip,
dst->dfbsurface->TileBlit (dst->dfbsurface,
src->dfbsurface,
- &sr,
- dst_x, dst_y));
+ &sr, dst_x, dst_y));
}
break;
}
@@ -1020,9 +1085,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running StretchBlit().\n");
- RUN_CLIPPED (dst, NULL,
+ RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->StretchBlit (dst->dfbsurface,
- src->dfbsurface, &sr, &dr));
+ src->dfbsurface,
+ &sr, &dr));
break;
}
@@ -1044,29 +1110,25 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
src->dfbsurface->GetSize (src->dfbsurface, &w, &h);
- TRANSFORM_POINT3X (src_attr.matrix,
- x1, y1, v[0].x, v[0].y);
+ TRANSFORM_POINT3X (src_attr.matrix, x1, y1, v[0].x, v[0].y);
v[0].z = 0;
v[0].w = 1;
v[0].s = x1 / w;
v[0].t = y1 / h;
- TRANSFORM_POINT3X (src_attr.matrix,
- x2, y1, v[1].x, v[1].y);
+ TRANSFORM_POINT3X (src_attr.matrix, x2, y1, v[1].x, v[1].y);
v[1].z = 0;
v[1].w = 1;
v[1].s = x2 / w;
v[1].t = y1 / h;
- TRANSFORM_POINT3X (src_attr.matrix,
- x2, y2, v[2].x, v[2].y);
+ TRANSFORM_POINT3X (src_attr.matrix, x2, y2, v[2].x, v[2].y);
v[2].z = 0;
v[2].w = 1;
v[2].s = x2 / w;
v[2].t = y2 / h;
- TRANSFORM_POINT3X (src_attr.matrix,
- x1, y2, v[3].x, v[3].y);
+ TRANSFORM_POINT3X (src_attr.matrix, x1, y2, v[3].x, v[3].y);
v[3].z = 0;
v[3].w = 1;
v[3].s = x1 / w;
@@ -1079,9 +1141,11 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n");
- RUN_CLIPPED (dst, &clip,
+ RUN_CLIPPED (dst, clip_region, &clip,
dst->dfbsurface->TextureTriangles (dst->dfbsurface,
- src->dfbsurface, v, NULL, 4, DTTF_FAN));
+ src->dfbsurface,
+ v, NULL,
+ 4, DTTF_FAN));
break;
}
@@ -1092,7 +1156,7 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
_directfb_finish_composite (dst, src_pattern, &src->base, &src_attr);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
#endif /* DFB_COMPOSITE */
@@ -1115,8 +1179,8 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface
"%s( dst=%p, op=%d, color=%p, rects=%p, n_rects=%d ).\n",
__FUNCTION__, dst, op, color, rects, n_rects);
- if (! _cairo_operator_bounded_by_source (op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (! dst->supported_destination)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
if (! _directfb_get_operator (op, &sblend, &dblend))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1132,7 +1196,7 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface
else if (dblend == DSBF_INVSRCALPHA)
dblend = DSBF_ZERO;
}
- if (dst->content == CAIRO_CONTENT_COLOR) {
+ if ((dst->base.content & CAIRO_CONTENT_ALPHA) == 0) {
if (sblend == DSBF_DESTALPHA)
sblend = DSBF_ONE;
else if (sblend == DSBF_INVDESTALPHA)
@@ -1164,7 +1228,7 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface
r[i].h = rects[i].height;
}
- RUN_CLIPPED (dst, NULL,
+ RUN_CLIPPED (dst, NULL, NULL,
dst->dfbsurface->FillRectangles (dst->dfbsurface, r, n_rects));
return CAIRO_STATUS_SUCCESS;
@@ -1182,7 +1246,8 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps)
+ int num_traps,
+ cairo_region_t *clip_region)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_surface_t *src;
@@ -1197,6 +1262,9 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
__FUNCTION__, op, pattern, dst, antialias,
src_x, src_y, dst_x, dst_y, width, height, traps, num_traps);
+ if (! dst->supported_destination)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (antialias != CAIRO_ANTIALIAS_NONE)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1291,7 +1359,7 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n");
- RUN_CLIPPED (dst, NULL,
+ RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->TextureTriangles (dst->dfbsurface,
src->dfbsurface,
vertex, NULL, n,
@@ -1306,64 +1374,7 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op,
}
#endif /* DFB_COMPOSITE_TRAPEZOIDS */
-static cairo_int_status_t
-_cairo_directfb_surface_set_clip_region (void *abstract_surface,
- cairo_region_t *region)
-{
- cairo_directfb_surface_t *surface = abstract_surface;
-
- D_DEBUG_AT (CairoDFB_Clip,
- "%s( surface=%p, region=%p ).\n",
- __FUNCTION__, surface, region);
-
- if (region) {
- int n_rects;
- cairo_status_t status;
- int i;
-
- surface->has_clip = TRUE;
-
- n_rects = cairo_region_num_rectangles (region);
-
- if (n_rects == 0)
- return CAIRO_STATUS_SUCCESS;
-
- if (surface->n_clips != n_rects) {
- if (surface->clips)
- free (surface->clips);
-
- surface->clips = _cairo_malloc_ab (n_rects, sizeof (DFBRegion));
- if (!surface->clips) {
- surface->n_clips = 0;
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- surface->n_clips = n_rects;
- }
-
- for (i = 0; i < n_rects; i++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (region, i, &rect);
-
- surface->clips[i].x1 = rect.x;
- surface->clips[i].y1 = rect.y;
- surface->clips[i].x2 = rect.x + rect.width - 1;
- surface->clips[i].y2 = rect.y + rect.height - 1;
- }
- } else {
- surface->has_clip = FALSE;
- if (surface->clips) {
- free (surface->clips);
- surface->clips = NULL;
- surface->n_clips = 0;
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
+static cairo_bool_t
_cairo_directfb_abstract_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -1383,7 +1394,7 @@ _cairo_directfb_abstract_surface_get_extents (void *abstract_su
rectangle->width = surface->width;
rectangle->height = surface->height;
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
#if DFB_SHOW_GLYPHS
@@ -1422,6 +1433,7 @@ _directfb_destroy_font_cache (cairo_directfb_font_cache_t *cache)
free (cache);
}
+/* XXX hook into rtree font cache from drm */
static cairo_status_t
_directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
cairo_scaled_font_t *scaled_font,
@@ -1473,6 +1485,7 @@ _directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
case CAIRO_FORMAT_A8:
case CAIRO_FORMAT_ARGB32:
break;
+ case CAIRO_FORMAT_RGB24:
default:
D_DEBUG_AT (CairoDFB_Font,
" -> Unsupported font format %d!\n", img->format);
@@ -1705,8 +1718,8 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_font_cache_t *cache;
@@ -1718,28 +1731,29 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
DFBPoint points[num_glyphs];
int num;
const cairo_color_t *color;
-
+ cairo_region_t *clip_region = NULL;
D_DEBUG_AT (CairoDFB_Font,
"%s( dst=%p, op=%d, pattern=%p, glyphs=%p, num_glyphs=%d, scaled_font=%p ).\n",
__FUNCTION__, dst, op, pattern, glyphs, num_glyphs, scaled_font);
+ if (! dst->supported_destination)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
return CAIRO_INT_STATUS_UNSUPPORTED;
/* Fallback if we need to emulate clip regions */
- if (dst->base.clip &&
- (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
- dst->base.clip->surface != NULL))
- {
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
+ if (status)
+ return status;
}
/* XXX Unbounded operators are not handled correctly */
if (! _cairo_operator_bounded_by_mask (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (! _cairo_operator_bounded_by_source (op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
if (! _directfb_get_operator (op, &sblend, &dblend) ||
sblend == DSBF_DESTALPHA || sblend == DSBF_INVDESTALPHA)
@@ -1788,7 +1802,7 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
D_DEBUG_AT (CairoDFB_Font, "Running BatchBlit().\n");
- RUN_CLIPPED (dst, NULL,
+ RUN_CLIPPED (dst, clip_region, NULL,
dst->dfbsurface->BatchBlit (dst->dfbsurface,
cache->dfbsurface, rects, points, num));
@@ -1835,8 +1849,6 @@ _cairo_directfb_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- _cairo_directfb_surface_set_clip_region,/* set_clip_region */
- NULL, /* intersect_clip_path */
_cairo_directfb_abstract_surface_get_extents,/* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -1860,7 +1872,6 @@ _cairo_directfb_surface_backend = {
#endif
NULL, /* snapshot */
_cairo_directfb_surface_is_similar,
- NULL /* reset */
};
@@ -1933,8 +1944,8 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
dfbsurface->GetSize (dfbsurface, &surface->width, &surface->height);
surface->dfb = dfb;
surface->dfbsurface = dfbsurface;
- surface->format = _directfb_to_cairo_format (format);
- surface->content = _directfb_format_to_content (format);
+ surface->pixman_format = _directfb_to_pixman_format (format);
+ surface->supported_destination = pixman_format_supported_destination (surface->pixman_format);
dfbsurface->GetCapabilities (dfbsurface, &caps);
if (caps & DSCAPS_PREMULTIPLIED)
@@ -1942,7 +1953,7 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
_cairo_surface_init (&surface->base,
&_cairo_directfb_surface_backend,
- surface->content);
+ _directfb_format_to_content (format));
return &surface->base;
}
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 6c6ff59f..26f4a833 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -1146,7 +1146,7 @@ _render_glyph_bitmap (FT_Face face,
cairo_image_surface_t **surface)
{
FT_GlyphSlot glyphslot = face->glyph;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_status_t status;
FT_Error error;
/* According to the FreeType docs, glyphslot->format could be
@@ -1162,7 +1162,9 @@ _render_glyph_bitmap (FT_Face face,
if (error == FT_Err_Out_Of_Memory)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- status = _get_bitmap_surface (&glyphslot->bitmap, FALSE, font_options, surface);
+ status = _get_bitmap_surface (&glyphslot->bitmap,
+ FALSE, font_options,
+ surface);
if (unlikely (status))
return status;
@@ -1177,7 +1179,7 @@ _render_glyph_bitmap (FT_Face face,
-glyphslot->bitmap_left,
+glyphslot->bitmap_top);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -1275,11 +1277,8 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
_cairo_pattern_init_for_surface (&pattern, &(*surface)->base);
cairo_pattern_set_matrix (&pattern.base, &transformed_to_original);
- status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
- &pattern.base, NULL, image,
- 0, 0, 0, 0, 0, 0,
- width,
- height);
+ status = _cairo_surface_paint (image, CAIRO_OPERATOR_OVER,
+ &pattern.base, NULL);
_cairo_pattern_fini (&pattern.base);
@@ -1301,7 +1300,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
cairo_surface_set_device_offset (&(*surface)->base,
_cairo_lround (origin_x),
_cairo_lround (origin_y));
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = {
@@ -1390,8 +1389,8 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL;
}
-#ifdef FC_HINT_STYLE
- if (FcPatternGetInteger (pattern,
+#ifdef FC_HINT_STYLE
+ if (FcPatternGetInteger (pattern,
FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch)
hintstyle = FC_HINT_FULL;
@@ -1400,7 +1399,7 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
switch (hintstyle) {
case FC_HINT_NONE:
- ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE;
+ ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE;
break;
case FC_HINT_SLIGHT:
ft_options.base.hint_style = CAIRO_HINT_STYLE_SLIGHT;
@@ -1444,14 +1443,14 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
if (vertical_layout)
ft_options.load_flags |= FT_LOAD_VERTICAL_LAYOUT;
-
+
#ifndef FC_EMBOLDEN
#define FC_EMBOLDEN "embolden"
#endif
if (FcPatternGetBool (pattern,
FC_EMBOLDEN, 0, &embolden) != FcResultMatch)
embolden = FcFalse;
-
+
if (embolden)
ft_options.extra_flags |= CAIRO_FT_OPTIONS_EMBOLDEN;
@@ -1468,7 +1467,7 @@ _cairo_ft_options_merge (cairo_ft_options_t *options,
/* clear load target mode */
load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(other->load_flags)));
-
+
if (load_flags & FT_LOAD_NO_HINTING)
other->base.hint_style = CAIRO_HINT_STYLE_NONE;
@@ -1479,7 +1478,7 @@ _cairo_ft_options_merge (cairo_ft_options_t *options,
}
if (other->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL &&
- (options->base.antialias == CAIRO_ANTIALIAS_DEFAULT ||
+ (options->base.antialias == CAIRO_ANTIALIAS_DEFAULT ||
options->base.antialias == CAIRO_ANTIALIAS_GRAY)) {
options->base.antialias = CAIRO_ANTIALIAS_SUBPIXEL;
options->base.subpixel_order = other->base.subpixel_order;
@@ -1934,12 +1933,12 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
x2 = (metrics->horiBearingX + metrics->width + 63) & -64;
y1 = (-metrics->horiBearingY) & -64;
y2 = (-metrics->horiBearingY + metrics->height + 63) & -64;
-
+
advance = ((metrics->horiAdvance + 32) & -64);
-
+
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor;
-
+
fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor;
fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor;
@@ -1950,12 +1949,12 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
x2 = (metrics->vertBearingX + metrics->width + 63) & -64;
y1 = (metrics->vertBearingY) & -64;
y2 = (metrics->vertBearingY + metrics->height + 63) & -64;
-
+
advance = ((metrics->vertAdvance + 32) & -64);
-
+
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor;
-
+
fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor;
fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor;
@@ -1969,7 +1968,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
if (!vertical_layout) {
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (-metrics->horiBearingY) * y_factor;
-
+
if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
fs_metrics.x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance) * x_factor;
else
@@ -1978,7 +1977,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
} else {
fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingX) * x_factor;
fs_metrics.y_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingY) * y_factor;
-
+
fs_metrics.x_advance = 0 * x_factor;
if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
fs_metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance) * y_factor;
@@ -2154,7 +2153,7 @@ static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
_cairo_ft_scaled_glyph_init,
NULL, /* text_to_glyphs */
_cairo_ft_ucs4_to_index,
- NULL, /* show_glyphs */
+ NULL, /* show_glyphs */
_cairo_ft_load_truetype_table,
_cairo_ft_index_to_ucs4
};
@@ -2911,10 +2910,10 @@ cairo_bool_t
_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font)
{
cairo_ft_scaled_font_t *ft_scaled_font;
-
+
if (!_cairo_scaled_font_is_ft (scaled_font))
return FALSE;
-
+
ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font;
if (ft_scaled_font->ft_options.load_flags & FT_LOAD_VERTICAL_LAYOUT)
return TRUE;
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 3d37fe09..5d8ff603 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -56,6 +56,7 @@ typedef struct _cairo_gl_surface {
int width, height;
GLuint tex; /* GL texture object containing our data. */
+ GLuint depth_stencil_tex;
GLuint fb; /* GL framebuffer object wrapping our data. */
} cairo_gl_surface_t;
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 571fc963..92c670d3 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -312,6 +312,10 @@ _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
case PIXMAN_g1:
case PIXMAN_yuy2:
case PIXMAN_yv12:
+#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
+ case PIXMAN_x2r10g10b10:
+ case PIXMAN_a2r10g10b10:
+#endif
default:
return CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -766,6 +770,8 @@ _cairo_gl_surface_finish (void *abstract_surface)
glDeleteFramebuffersEXT (1, &surface->fb);
glDeleteTextures (1, &surface->tex);
+ if (surface->depth_stencil_tex)
+ glDeleteTextures (1, &surface->depth_stencil_tex);
if (surface->ctx->current_target == surface)
surface->ctx->current_target = NULL;
@@ -1264,16 +1270,20 @@ _cairo_gl_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_gl_surface_t *dst = abstract_dst;
cairo_surface_attributes_t *src_attributes, *mask_attributes = NULL;
cairo_gl_context_t *ctx;
- GLfloat vertices[4][2];
- GLfloat texcoord_src[4][2];
- GLfloat texcoord_mask[4][2];
+ struct gl_point {
+ GLfloat x, y;
+ } vertices_stack[8], texcoord_src_stack[8], texcoord_mask_stack[8];
+ struct gl_point *vertices = vertices_stack;
+ struct gl_point *texcoord_src = texcoord_src_stack;
+ struct gl_point *texcoord_mask = texcoord_mask_stack;
cairo_status_t status;
- int i;
+ int num_vertices, i;
GLenum err;
cairo_gl_composite_setup_t setup;
@@ -1345,27 +1355,62 @@ _cairo_gl_surface_composite (cairo_operator_t op,
}
}
- vertices[0][0] = dst_x;
- vertices[0][1] = dst_y;
- vertices[1][0] = dst_x + width;
- vertices[1][1] = dst_y;
- vertices[2][0] = dst_x + width;
- vertices[2][1] = dst_y + height;
- vertices[3][0] = dst_x;
- vertices[3][1] = dst_y + height;
+ if (clip_region != NULL) {
+ int num_rectangles;
+
+ num_rectangles = cairo_region_num_rectangles (clip_region);
+ if (num_rectangles * 4 > ARRAY_LENGTH (vertices_stack)) {
+ vertices = _cairo_malloc_ab (num_rectangles,
+ 4*3*sizeof (vertices[0]));
+ if (unlikely (vertices == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto CONTEXT_RELEASE;
+ }
+
+ texcoord_src = vertices + num_rectangles * 4;
+ texcoord_mask = texcoord_src + num_rectangles * 4;
+ }
+
+ for (i = 0; i < num_rectangles; i++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (clip_region, i, &rect);
+ vertices[4*i + 0].x = rect.x;
+ vertices[4*i + 0].y = rect.y;
+ vertices[4*i + 1].x = rect.x + rect.width;
+ vertices[4*i + 1].y = rect.y;
+ vertices[4*i + 2].x = rect.x + rect.width;
+ vertices[4*i + 2].y = rect.y + rect.height;
+ vertices[4*i + 3].x = rect.x;
+ vertices[4*i + 3].y = rect.y + rect.height;
+ }
+
+ num_vertices = 4 * num_rectangles;
+ } else {
+ vertices[0].x = dst_x;
+ vertices[0].y = dst_y;
+ vertices[1].x = dst_x + width;
+ vertices[1].y = dst_y;
+ vertices[2].x = dst_x + width;
+ vertices[2].y = dst_y + height;
+ vertices[3].x = dst_x;
+ vertices[3].y = dst_y + height;
+
+ num_vertices = 4;
+ }
glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices);
glEnableClientState (GL_VERTEX_ARRAY);
if (setup.src.type == OPERAND_TEXTURE) {
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < num_vertices; i++) {
double s, t;
- s = vertices[i][0];
- t = vertices[i][1];
+ s = vertices[i].x;
+ t = vertices[i].y;
cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
- texcoord_src[i][0] = s;
- texcoord_src[i][1] = t;
+ texcoord_src[i].x = s;
+ texcoord_src[i].y = t;
}
glClientActiveTexture (GL_TEXTURE0);
@@ -1375,14 +1420,14 @@ _cairo_gl_surface_composite (cairo_operator_t op,
if (mask != NULL) {
if (setup.mask.type == OPERAND_TEXTURE) {
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < num_vertices; i++) {
double s, t;
- s = vertices[i][0];
- t = vertices[i][1];
+ s = vertices[i].x;
+ t = vertices[i].y;
cairo_matrix_transform_point (&mask_attributes->matrix, &s, &t);
- texcoord_mask[i][0] = s;
- texcoord_mask[i][1] = t;
+ texcoord_mask[i].x = s;
+ texcoord_mask[i].y = t;
}
glClientActiveTexture (GL_TEXTURE1);
@@ -1391,7 +1436,7 @@ _cairo_gl_surface_composite (cairo_operator_t op,
}
}
- glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
+ glDrawArrays (GL_QUADS, 0, num_vertices);
glDisable (GL_BLEND);
@@ -1410,13 +1455,17 @@ _cairo_gl_surface_composite (cairo_operator_t op,
while ((err = glGetError ()))
fprintf (stderr, "GL error 0x%08x\n", (int) err);
+ CONTEXT_RELEASE:
_cairo_gl_context_release (ctx);
_cairo_gl_operand_destroy (&setup.src);
if (mask != NULL)
_cairo_gl_operand_destroy (&setup.mask);
- return CAIRO_STATUS_SUCCESS;
+ if (vertices != vertices_stack)
+ free (vertices);
+
+ return status;
}
static cairo_int_status_t
@@ -1429,7 +1478,8 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps)
+ int num_traps,
+ cairo_region_t *clip_region)
{
cairo_gl_surface_t *dst = abstract_dst;
cairo_surface_pattern_t traps_pattern;
@@ -1447,7 +1497,8 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
src_x, src_y,
0, 0,
dst_x, dst_y,
- width, height);
+ width, height,
+ clip_region);
_cairo_pattern_fini (&traps_pattern.base);
@@ -1737,6 +1788,7 @@ _cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
glDisable (GL_TEXTURE_2D);
glDisable (GL_BLEND);
+ glDisable (GL_DEPTH_TEST);
return CAIRO_STATUS_SUCCESS;
}
@@ -1756,27 +1808,112 @@ _cairo_gl_surface_check_span_renderer (cairo_operator_t op,
return TRUE;
}
+static void
+_cairo_gl_surface_ensure_depth_buffer (cairo_gl_surface_t *surface)
+{
+ if (surface->depth_stencil_tex)
+ return;
+
+ glGenTextures (1, &surface->depth_stencil_tex);
+ glBindTexture (GL_TEXTURE_2D, surface->depth_stencil_tex);
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT,
+ surface->width, surface->height, 0,
+ GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
+ glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
+ GL_DEPTH_ATTACHMENT_EXT,
+ GL_TEXTURE_2D,
+ surface->depth_stencil_tex, 0);
+ glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
+ GL_STENCIL_ATTACHMENT_EXT,
+ GL_TEXTURE_2D,
+ surface->depth_stencil_tex, 0);
+}
+
+
+static cairo_status_t
+_cairo_gl_surface_set_clip_region (cairo_gl_surface_t *surface,
+ cairo_region_t *clip_region)
+{
+ GLfloat vertices_stack[CAIRO_STACK_ARRAY_LENGTH(GLfloat)], *vertices;
+ int num_rectangles, i, n;
+
+ if (clip_region == NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ num_rectangles = cairo_region_num_rectangles (clip_region);
+
+ vertices = vertices_stack;
+ if (num_rectangles * 8 > ARRAY_LENGTH (vertices_stack)) {
+ vertices = _cairo_malloc_ab (num_rectangles,
+ 4*3*sizeof (vertices[0]));
+ if (unlikely (vertices == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ for (i = n = 0; i < num_rectangles; i++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (clip_region, i, &rect);
+ vertices[n++] = rect.x;
+ vertices[n++] = rect.y;
+ vertices[n++] = rect.x + rect.width;
+ vertices[n++] = rect.y;
+ vertices[n++] = rect.x + rect.width;
+ vertices[n++] = rect.y + rect.height;
+ vertices[n++] = rect.x;
+ vertices[n++] = rect.y +rect. height;
+ }
+
+ _cairo_gl_surface_ensure_depth_buffer (surface);
+
+ glDisable (GL_BLEND);
+ glDepthFunc (GL_ALWAYS);
+ glEnable (GL_DEPTH_TEST);
+ glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ glDepthMask (GL_TRUE);
+ glClear (GL_DEPTH_BUFFER_BIT);
+
+ glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices);
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glDrawArrays (GL_QUADS, 0, 4 * num_rectangles);
+ glDisableClientState (GL_VERTEX_ARRAY);
+
+ glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthFunc (GL_EQUAL);
+ glDepthMask (GL_FALSE);
+
+ if (vertices != vertices_stack)
+ free (vertices);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_span_renderer_t *
_cairo_gl_surface_create_span_renderer (cairo_operator_t op,
const cairo_pattern_t *src,
void *abstract_dst,
cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects)
+ const cairo_composite_rectangles_t *rects,
+ cairo_region_t *clip_region)
{
cairo_gl_surface_t *dst = abstract_dst;
- cairo_gl_surface_span_renderer_t *renderer = calloc (1, sizeof (*renderer));
+ cairo_gl_surface_span_renderer_t *renderer;
cairo_status_t status;
int width = rects->width;
int height = rects->height;
cairo_surface_attributes_t *src_attributes;
GLenum err;
- if (renderer == NULL)
- return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
if (!GLEW_ARB_vertex_buffer_object)
return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED);
+ renderer = calloc (1, sizeof (*renderer));
+ if (unlikely (renderer == NULL))
+ return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
renderer->base.finish = _cairo_gl_surface_span_renderer_finish;
renderer->base.render_row =
@@ -1801,6 +1938,12 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op,
_cairo_gl_set_destination (dst);
+ status = _cairo_gl_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status)) {
+ _cairo_gl_surface_span_renderer_destroy (renderer);
+ return _cairo_span_renderer_create_in_error (status);
+ }
+
src_attributes = &renderer->setup.src.operand.texture.attributes;
status = _cairo_gl_set_operator (dst, op);
@@ -1838,7 +1981,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op,
return &renderer->base;
}
-static cairo_int_status_t
+static cairo_bool_t
_cairo_gl_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -1849,7 +1992,7 @@ _cairo_gl_surface_get_extents (void *abstract_surface,
rectangle->width = surface->width;
rectangle->height = surface->height;
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
static void
@@ -1888,20 +2031,21 @@ static const cairo_surface_backend_t _cairo_gl_surface_backend = {
CAIRO_SURFACE_TYPE_GL,
_cairo_gl_surface_create_similar,
_cairo_gl_surface_finish,
+
_cairo_gl_surface_acquire_source_image,
_cairo_gl_surface_release_source_image,
_cairo_gl_surface_acquire_dest_image,
_cairo_gl_surface_release_dest_image,
+
_cairo_gl_surface_clone_similar,
_cairo_gl_surface_composite,
_cairo_gl_surface_fill_rectangles,
_cairo_gl_surface_composite_trapezoids,
_cairo_gl_surface_create_span_renderer,
_cairo_gl_surface_check_span_renderer,
+
NULL, /* copy_page */
NULL, /* show_page */
- NULL, /* set_clip_region */
- NULL, /* intersect_clip_path */
_cairo_gl_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_gl_surface_get_font_options,
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 81881290..a649d500 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -27,6 +27,7 @@
#include "cairoint.h"
#include "cairo-glitz.h"
#include "cairo-glitz-private.h"
+#include "cairo-region-private.h"
typedef struct _cairo_glitz_surface {
cairo_surface_t base;
@@ -34,6 +35,7 @@ typedef struct _cairo_glitz_surface {
glitz_surface_t *surface;
glitz_format_t *format;
+ cairo_region_t *clip_region;
cairo_bool_t has_clip;
glitz_box_t *clip_boxes;
int num_clip_boxes;
@@ -50,6 +52,7 @@ _cairo_glitz_surface_finish (void *abstract_surface)
if (surface->clip_boxes)
free (surface->clip_boxes);
+ cairo_region_destroy (surface->clip_region);
glitz_surface_destroy (surface->surface);
return CAIRO_STATUS_SUCCESS;
@@ -107,43 +110,6 @@ _cairo_glitz_surface_create_similar (void *abstract_src,
}
static cairo_status_t
-_cairo_glitz_get_boxes_from_region (cairo_region_t *region,
- glitz_box_t **boxes,
- int *nboxes)
-{
- pixman_box32_t *pboxes;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- int n, i;
-
- n = 0;
- pboxes = pixman_region32_rectangles (&region->rgn, &n);
- if (n == 0) {
- *nboxes = 0;
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (n > *nboxes) {
- *boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t));
- if (*boxes == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto done;
- }
- }
-
- for (i = 0; i < n; i++) {
- (*boxes)[i].x1 = pboxes[i].x1;
- (*boxes)[i].y1 = pboxes[i].y1;
- (*boxes)[i].x2 = pboxes[i].x2;
- (*boxes)[i].y2 = pboxes[i].y2;
- }
-
- *nboxes = n;
-done:
- return status;
-}
-
-static cairo_status_t
_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
cairo_rectangle_int_t *interest,
cairo_image_surface_t **image_out,
@@ -463,6 +429,8 @@ _is_supported_operator (cairo_operator_t op)
case CAIRO_OPERATOR_ADD:
return TRUE;
+ default:
+ ASSERT_NOT_REACHED;
case CAIRO_OPERATOR_SATURATE:
/* nobody likes saturate, expect that it's required to do
* seamless polygons!
@@ -485,6 +453,7 @@ _is_supported_operator (cairo_operator_t op)
return FALSE;
}
}
+
static glitz_operator_t
_glitz_operator (cairo_operator_t op)
{
@@ -686,9 +655,9 @@ _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t *pattern,
}
src = (cairo_glitz_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- CAIRO_CONTENT_COLOR_ALPHA,
- gradient->n_stops, 1);
+ _cairo_glitz_surface_create_similar (&dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ gradient->n_stops, 1);
if (src->base.status) {
glitz_buffer_destroy (buffer);
free (data);
@@ -914,6 +883,77 @@ _cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface,
a->params, a->n_params);
}
+static cairo_status_t
+_cairo_glitz_get_boxes_from_region (cairo_region_t *region,
+ glitz_box_t **boxes,
+ int *nboxes)
+{
+ pixman_box32_t *pboxes;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ int n, i;
+
+ n = 0;
+ pboxes = pixman_region32_rectangles (&region->rgn, &n);
+ if (n == 0) {
+ *nboxes = 0;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (n > *nboxes) {
+ *boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t));
+ if (*boxes == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto done;
+ }
+ }
+
+ for (i = 0; i < n; i++) {
+ (*boxes)[i].x1 = pboxes[i].x1;
+ (*boxes)[i].y1 = pboxes[i].y1;
+ (*boxes)[i].x2 = pboxes[i].x2;
+ (*boxes)[i].y2 = pboxes[i].y2;
+ }
+
+ *nboxes = n;
+done:
+ return status;
+}
+
+static cairo_status_t
+_cairo_glitz_surface_set_clip_region (void *abstract_surface,
+ cairo_region_t *region)
+{
+ cairo_glitz_surface_t *surface = abstract_surface;
+
+ if (region == surface->clip_region)
+ return CAIRO_STATUS_SUCCESS;
+
+ cairo_region_destroy (surface->clip_region);
+ surface->clip_region = cairo_region_reference (region);
+
+ if (region != NULL) {
+ cairo_status_t status;
+
+ status = _cairo_glitz_get_boxes_from_region (region,
+ &surface->clip_boxes,
+ &surface->num_clip_boxes);
+ if (status)
+ return status;
+
+ glitz_surface_set_clip_region (surface->surface,
+ 0, 0,
+ surface->clip_boxes,
+ surface->num_clip_boxes);
+ surface->has_clip = TRUE;
+ } else {
+ glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
+ surface->has_clip = FALSE;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_int_status_t
_cairo_glitz_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src_pattern,
@@ -926,7 +966,8 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_glitz_surface_attributes_t src_attr, mask_attr;
cairo_glitz_surface_t *dst = abstract_dst;
@@ -940,6 +981,10 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ status = _cairo_glitz_surface_set_clip_region (dst, clip_region);
+ if (status)
+ return status;
+
status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern,
dst,
src_x, src_y,
@@ -1006,7 +1051,8 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
mask_width, mask_height,
src_x, src_y,
mask_x, mask_y,
- dst_x, dst_y, width, height);
+ dst_x, dst_y, width, height,
+ clip_region);
}
if (mask)
@@ -1037,11 +1083,15 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
glitz_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (glitz_rectangle_t)];
glitz_rectangle_t *glitz_rects = stack_rects;
glitz_rectangle_t *current_rect;
+ cairo_status_t status;
int i;
if (! _is_supported_operator (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ status = _cairo_glitz_surface_set_clip_region (dst, NULL);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
if (n_rects > ARRAY_LENGTH (stack_rects)) {
glitz_rects = _cairo_malloc_ab (n_rects, sizeof (glitz_rectangle_t));
if (glitz_rects == NULL)
@@ -1104,12 +1154,12 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
_cairo_surface_create_similar_solid (&dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
1, 1,
- (cairo_color_t *) color);
- if (src->base.status)
- {
+ (cairo_color_t *) color,
+ FALSE);
+ if (src == NULL || src->base.status) {
if (glitz_rects != stack_rects)
free (glitz_rects);
- return src->base.status;
+ return src ? src->base.status : CAIRO_INT_STATUS_UNSUPPORTED;
}
glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
@@ -1153,7 +1203,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int n_traps)
+ int n_traps,
+ cairo_region_t *clip_region)
{
cairo_glitz_surface_attributes_t attributes;
cairo_glitz_surface_t *dst = abstract_dst;
@@ -1179,6 +1230,10 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ status = _cairo_glitz_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ return status;
+
/* Convert traps to pixman traps */
if (n_traps > ARRAY_LENGTH (stack_traps)) {
pixman_traps = _cairo_malloc_ab (n_traps, sizeof (pixman_trapezoid_t));
@@ -1321,7 +1376,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
n_traps, (pixman_trapezoid_t *) pixman_traps);
mask = (cairo_glitz_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
+ _cairo_glitz_surface_create_similar (&dst->base,
CAIRO_CONTENT_ALPHA,
width, height);
status = mask->base.status;
@@ -1378,7 +1433,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
src_x, src_y,
0, 0,
dst_x, dst_y,
- width, height);
+ width, height,
+ clip_region);
}
FAIL:
@@ -1393,35 +1449,7 @@ FAIL:
return status;
}
-static cairo_int_status_t
-_cairo_glitz_surface_set_clip_region (void *abstract_surface,
- cairo_region_t *region)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
-
- if (region != NULL) {
- cairo_status_t status;
-
- status = _cairo_glitz_get_boxes_from_region (region,
- &surface->clip_boxes,
- &surface->num_clip_boxes);
- if (status)
- return status;
-
- glitz_surface_set_clip_region (surface->surface,
- 0, 0,
- surface->clip_boxes,
- surface->num_clip_boxes);
- surface->has_clip = TRUE;
- } else {
- glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
- surface->has_clip = FALSE;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
+static cairo_bool_t
_cairo_glitz_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -1432,7 +1460,7 @@ _cairo_glitz_surface_get_extents (void *abstract_surface,
rectangle->width = glitz_surface_get_width (surface->surface);
rectangle->height = glitz_surface_get_height (surface->surface);
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
#define CAIRO_GLITZ_AREA_AVAILABLE 0
@@ -2035,7 +2063,8 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
- int num_glyphs)
+ int num_glyphs,
+ cairo_region_t *clip_region)
{
cairo_glitz_surface_attributes_t attributes;
cairo_glitz_surface_glyph_private_t *glyph_private;
@@ -2078,6 +2107,10 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ status = _cairo_glitz_surface_set_clip_region (dst, NULL);
+ if (unlikely (status))
+ return status;
+
status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
src_x, src_y,
width, height,
@@ -2326,25 +2359,13 @@ _cairo_glitz_surface_is_similar (void *surface_a,
return drawable_a == drawable_b;
}
-static cairo_status_t
-_cairo_glitz_surface_reset (void *abstract_surface)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
- status = _cairo_glitz_surface_set_clip_region (surface, NULL);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static const cairo_surface_backend_t cairo_glitz_surface_backend = {
CAIRO_SURFACE_TYPE_GLITZ,
_cairo_glitz_surface_create_similar,
_cairo_glitz_surface_finish,
_cairo_glitz_surface_acquire_source_image,
_cairo_glitz_surface_release_source_image,
+
_cairo_glitz_surface_acquire_dest_image,
_cairo_glitz_surface_release_dest_image,
_cairo_glitz_surface_clone_similar,
@@ -2353,10 +2374,9 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_composite_trapezoids,
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
+
NULL, /* copy_page */
NULL, /* show_page */
- _cairo_glitz_surface_set_clip_region,
- NULL, /* intersect_clip_path */
_cairo_glitz_surface_get_extents,
_cairo_glitz_surface_old_show_glyphs,
NULL, /* get_font_options */
@@ -2373,8 +2393,6 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_snapshot,
_cairo_glitz_surface_is_similar,
-
- _cairo_glitz_surface_reset
};
static const cairo_surface_backend_t *
@@ -2424,6 +2442,7 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
crsurface->has_clip = FALSE;
crsurface->clip_boxes = NULL;
crsurface->num_clip_boxes = 0;
+ crsurface->clip_region = NULL;
return &crsurface->base;
}
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 8f206ad9..2257db0f 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -100,7 +100,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate,
_cairo_font_options_init_default (&gstate->font_options);
- _cairo_clip_init (&gstate->clip, target);
+ _cairo_clip_init (&gstate->clip);
gstate->target = cairo_surface_reference (target);
gstate->parent_target = NULL;
@@ -164,14 +164,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
_cairo_font_options_init_copy (&gstate->font_options , &other->font_options);
- status = _cairo_clip_init_copy (&gstate->clip, &other->clip);
- if (unlikely (status)) {
- _cairo_stroke_style_fini (&gstate->stroke_style);
- cairo_font_face_destroy (gstate->font_face);
- cairo_scaled_font_destroy (gstate->scaled_font);
- cairo_scaled_font_destroy (gstate->previous_scaled_font);
- return status;
- }
+ _cairo_clip_init_copy (&gstate->clip, &other->clip);
gstate->target = cairo_surface_reference (other->target);
/* parent_target is always set to NULL; it's only ever set by redirect_target */
@@ -299,7 +292,7 @@ _cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
cairo_status_t
_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
{
- cairo_status_t status;
+ cairo_matrix_t matrix;
/* If this gstate is already redirected, this is an error; we need a
* new gstate to be able to redirect */
@@ -315,18 +308,15 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
* since its ref is now owned by gstate->parent_target */
gstate->target = cairo_surface_reference (child);
- _cairo_clip_reset (&gstate->clip);
- status = _cairo_clip_init_deep_copy (&gstate->clip, &gstate->next->clip, child);
- if (unlikely (status))
- return status;
-
/* The clip is in surface backend coordinates for the previous target;
* translate it into the child's backend coordinates. */
- _cairo_clip_translate (&gstate->clip,
- _cairo_fixed_from_double (child->device_transform.x0 - gstate->parent_target->device_transform.x0),
- _cairo_fixed_from_double (child->device_transform.y0 - gstate->parent_target->device_transform.y0));
-
- return CAIRO_STATUS_SUCCESS;
+ cairo_matrix_init_translate (&matrix,
+ child->device_transform.x0 - gstate->parent_target->device_transform.x0,
+ child->device_transform.y0 - gstate->parent_target->device_transform.y0);
+ _cairo_clip_reset (&gstate->clip);
+ return _cairo_clip_init_copy_transformed (&gstate->clip,
+ &gstate->next->clip,
+ &matrix);
}
/**
@@ -870,43 +860,63 @@ _cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate,
&gstate->ctm_inverse);
}
+#define _gstate_get_clip(g) ((g)->clip.path ? &(g)->clip : NULL)
+
+static cairo_bool_t
+_clipped (const cairo_gstate_t *gstate)
+{
+ cairo_rectangle_int_t extents;
+
+ if (gstate->clip.all_clipped)
+ return TRUE;
+
+ if (gstate->clip.path == NULL)
+ return FALSE;
+
+ if (_cairo_surface_get_extents (gstate->target, &extents)) {
+ if (! _cairo_rectangle_intersect (&extents,
+ &gstate->clip.path->extents))
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate)
{
- cairo_status_t status;
cairo_pattern_union_t pattern;
- if (gstate->source->status)
+ if (unlikely (gstate->source->status))
return gstate->source->status;
- status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
- if (unlikely (status))
- return status;
+ if (_clipped (gstate))
+ return CAIRO_STATUS_SUCCESS;
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
return _cairo_surface_paint (gstate->target,
gstate->op,
&pattern.base,
- NULL);
+ _gstate_get_clip (gstate));
}
cairo_status_t
_cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_pattern_t *mask)
{
- cairo_status_t status;
cairo_pattern_union_t source_pattern, mask_pattern;
- if (mask->status)
+ if (unlikely (mask->status))
return mask->status;
- if (gstate->source->status)
+ if (unlikely (gstate->source->status))
return gstate->source->status;
- status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
- if (unlikely (status))
- return status;
+ if (_clipped (gstate))
+ return CAIRO_STATUS_SUCCESS;
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
_cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
@@ -915,24 +925,22 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
gstate->op,
&source_pattern.base,
&mask_pattern.base,
- NULL);
+ _gstate_get_clip (gstate));
}
cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
- cairo_status_t status;
cairo_pattern_union_t source_pattern;
- if (gstate->source->status)
+ if (unlikely (gstate->source->status))
return gstate->source->status;
if (gstate->stroke_style.line_width <= 0.0)
return CAIRO_STATUS_SUCCESS;
- status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
- if (unlikely (status))
- return status;
+ if (_clipped (gstate))
+ return CAIRO_STATUS_SUCCESS;
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
@@ -945,7 +953,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
&gstate->ctm_inverse,
gstate->tolerance,
gstate->antialias,
- NULL);
+ _gstate_get_clip (gstate));
}
cairo_status_t
@@ -1009,15 +1017,26 @@ BAIL:
cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
- cairo_status_t status;
cairo_pattern_union_t pattern;
- if (gstate->source->status)
+ if (unlikely (gstate->source->status))
return gstate->source->status;
- status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
- if (unlikely (status))
- return status;
+ if (_clipped (gstate))
+ return CAIRO_STATUS_SUCCESS;
+
+ if (_cairo_path_fixed_fill_is_empty (path)) {
+ if (_cairo_operator_bounded_by_mask (gstate->op))
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_pattern_init_solid (&pattern.solid,
+ CAIRO_COLOR_TRANSPARENT,
+ CAIRO_CONTENT_COLOR_ALPHA);
+ return _cairo_surface_paint (gstate->target,
+ CAIRO_OPERATOR_CLEAR,
+ &pattern.base,
+ _gstate_get_clip (gstate));
+ }
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
@@ -1028,23 +1047,56 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
gstate->fill_rule,
gstate->tolerance,
gstate->antialias,
- NULL);
+ _gstate_get_clip (gstate));
}
-void
+cairo_bool_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
- double y,
- cairo_bool_t *inside_ret)
+ double y)
+{
+ _cairo_gstate_user_to_backend (gstate, &x, &y);
+
+ return _cairo_path_fixed_in_fill (path,
+ gstate->fill_rule,
+ gstate->tolerance,
+ x, y);
+}
+
+cairo_bool_t
+_cairo_gstate_in_clip (cairo_gstate_t *gstate,
+ double x,
+ double y)
{
+ cairo_clip_path_t *clip_path;
+
+ if (gstate->clip.all_clipped)
+ return FALSE;
+
+ clip_path = gstate->clip.path;
+ if (clip_path == NULL)
+ return TRUE;
+
_cairo_gstate_user_to_backend (gstate, &x, &y);
- _cairo_path_fixed_in_fill (path,
- gstate->fill_rule,
- gstate->tolerance,
- x, y,
- inside_ret);
+ if (x < clip_path->extents.x ||
+ x >= clip_path->extents.x + clip_path->extents.width ||
+ y < clip_path->extents.y ||
+ y >= clip_path->extents.y + clip_path->extents.height)
+ {
+ return FALSE;
+ }
+
+ do {
+ if (! _cairo_path_fixed_in_fill (&clip_path->path,
+ clip_path->fill_rule,
+ clip_path->tolerance,
+ x, y))
+ return FALSE;
+ } while ((clip_path = clip_path->prev) != NULL);
+
+ return TRUE;
}
cairo_status_t
@@ -1179,26 +1231,31 @@ cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
return _cairo_clip_clip (&gstate->clip,
- path, gstate->fill_rule, gstate->tolerance,
- gstate->antialias, gstate->target);
+ path, gstate->fill_rule,
+ gstate->tolerance, gstate->antialias);
}
-static cairo_status_t
+static cairo_bool_t
_cairo_gstate_int_clip_extents (cairo_gstate_t *gstate,
cairo_rectangle_int_t *extents)
{
- cairo_status_t status;
+ const cairo_rectangle_int_t *clip_extents;
+ cairo_bool_t is_bounded;
- status = _cairo_surface_get_extents (gstate->target, extents);
- if (unlikely (status))
- return status;
+ is_bounded = _cairo_surface_get_extents (gstate->target, extents);
- status = _cairo_clip_intersect_to_rectangle (&gstate->clip, extents);
+ clip_extents = _cairo_clip_get_extents (&gstate->clip);
+ if (clip_extents != NULL) {
+ cairo_bool_t is_empty;
- return status;
+ is_empty = _cairo_rectangle_intersect (extents, clip_extents);
+ is_bounded = TRUE;
+ }
+
+ return is_bounded;
}
-cairo_status_t
+cairo_bool_t
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
double *x1,
double *y1,
@@ -1207,11 +1264,9 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
{
cairo_rectangle_int_t extents;
double px1, py1, px2, py2;
- cairo_status_t status;
- status = _cairo_gstate_int_clip_extents (gstate, &extents);
- if (unlikely (status))
- return status;
+ if (! _cairo_gstate_int_clip_extents (gstate, &extents))
+ return FALSE;
px1 = extents.x;
py1 = extents.y;
@@ -1231,7 +1286,7 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
if (y2)
*y2 = py2;
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
cairo_rectangle_list_t*
@@ -1576,12 +1631,11 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
cairo_text_cluster_t *transformed_clusters;
cairo_status_t status;
- if (gstate->source->status)
+ if (unlikely (gstate->source->status))
return gstate->source->status;
- status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
- if (unlikely (status))
- return status;
+ if (_clipped (gstate))
+ return CAIRO_STATUS_SUCCESS;
status = _cairo_gstate_ensure_scaled_font (gstate);
if (unlikely (status))
@@ -1635,7 +1689,8 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
*
* Needless to say, do this only if show_text_glyphs is not available. */
if (cairo_surface_has_show_text_glyphs (gstate->target) ||
- _cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) {
+ _cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240)
+ {
status = _cairo_surface_show_text_glyphs (gstate->target,
gstate->op,
&source_pattern.base,
@@ -1643,8 +1698,11 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
transformed_clusters, num_clusters,
cluster_flags,
- gstate->scaled_font, NULL);
- } else {
+ gstate->scaled_font,
+ _gstate_get_clip (gstate));
+ }
+ else
+ {
cairo_path_fixed_t path;
_cairo_path_fixed_init (&path);
@@ -1653,14 +1711,16 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
&path);
- if (status == CAIRO_STATUS_SUCCESS)
- status = _cairo_surface_fill (gstate->target,
- gstate->op,
- &source_pattern.base,
- &path,
- CAIRO_FILL_RULE_WINDING,
- gstate->tolerance,
- gstate->scaled_font->options.antialias, NULL);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ status = _cairo_surface_fill (gstate->target,
+ gstate->op,
+ &source_pattern.base,
+ &path,
+ CAIRO_FILL_RULE_WINDING,
+ gstate->tolerance,
+ gstate->scaled_font->options.antialias,
+ _gstate_get_clip (gstate));
+ }
_cairo_path_fixed_fini (&path);
}
@@ -1765,17 +1825,12 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
cairo_matrix_t *device_transform = &gstate->target->device_transform;
cairo_bool_t drop = FALSE;
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
- cairo_status_t status;
if (num_transformed_glyphs != NULL) {
cairo_rectangle_int_t surface_extents;
drop = TRUE;
- status = _cairo_gstate_int_clip_extents (gstate, &surface_extents);
- if (_cairo_status_is_error (status))
- return status;
-
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) {
drop = FALSE; /* unbounded surface */
} else {
double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 278654af..c7ceb262 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -37,6 +37,9 @@
#include "cairoint.h"
+#include "cairo-clip-private.h"
+#include "cairo-region-private.h"
+
static cairo_format_t
_cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
{
@@ -64,6 +67,14 @@ _cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
case PIXMAN_x2b10g10r10:
case PIXMAN_a2b10g10r10:
#endif
+#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1)
+ case PIXMAN_b8g8r8x8:
+ case PIXMAN_b8g8r8a8:
+#endif
+#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
+ case PIXMAN_x2r10g10b10:
+ case PIXMAN_a2r10g10b10:
+#endif
default:
return CAIRO_FORMAT_INVALID;
}
@@ -88,6 +99,12 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9)
case PIXMAN_a2b10g10r10:
#endif
+#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1)
+ case PIXMAN_b8g8r8a8:
+#endif
+#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
+ case PIXMAN_a2r10g10b10:
+#endif
return CAIRO_CONTENT_COLOR_ALPHA;
case PIXMAN_x8r8g8b8:
case PIXMAN_x8b8g8r8:
@@ -113,6 +130,12 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9)
case PIXMAN_x2b10g10r10:
#endif
+#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1)
+ case PIXMAN_b8g8r8x8:
+#endif
+#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
+ case PIXMAN_x2r10g10b10:
+#endif
return CAIRO_CONTENT_COLOR;
case PIXMAN_a8:
case PIXMAN_a1:
@@ -143,7 +166,6 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->format = _cairo_format_from_pixman_format (pixman_format);
surface->data = (unsigned char *) pixman_image_get_data (pixman_image);
surface->owns_data = FALSE;
- surface->has_clip = FALSE;
surface->transparency = CAIRO_IMAGE_UNKNOWN;
surface->width = pixman_image_get_width (pixman_image);
@@ -151,6 +173,8 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->stride = pixman_image_get_stride (pixman_image);
surface->depth = pixman_image_get_depth (pixman_image);
+ surface->clip_region = NULL;
+
return &surface->base;
}
@@ -725,6 +749,8 @@ _cairo_image_surface_finish (void *abstract_surface)
surface->data = NULL;
}
+ cairo_region_destroy (surface->clip_region);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -974,25 +1000,52 @@ _pixman_operator (cairo_operator_t op)
}
}
+static cairo_status_t
+_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
+ cairo_region_t *region)
+{
+ if (region == surface->clip_region)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (cairo_region_equal (surface->clip_region, region))
+ return CAIRO_STATUS_SUCCESS;
+
+ cairo_region_destroy (surface->clip_region);
+ surface->clip_region = cairo_region_reference (region);
+
+ if (! pixman_image_set_clip_region32 (surface->pixman_image,
+ region ? &region->rgn : NULL))
+ {
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_int_status_t
-_cairo_image_surface_composite (cairo_operator_t op,
+_cairo_image_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src_pattern,
const cairo_pattern_t *mask_pattern,
void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_region_t *clip_region)
{
- cairo_surface_attributes_t src_attr, mask_attr;
+ cairo_surface_attributes_t src_attr, mask_attr;
cairo_image_surface_t *dst = abstract_dst;
cairo_image_surface_t *src;
cairo_image_surface_t *mask;
- cairo_int_status_t status;
+ cairo_int_status_t status;
+
+ status = _cairo_image_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ return status;
status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
&dst->base,
@@ -1013,8 +1066,7 @@ _cairo_image_surface_composite (cairo_operator_t op,
if (unlikely (status))
goto CLEANUP_SURFACES;
- if (mask)
- {
+ if (mask) {
status = _cairo_image_surface_set_attributes (mask, &mask_attr,
dst_x + width / 2.,
dst_y + height / 2.);
@@ -1031,9 +1083,7 @@ _cairo_image_surface_composite (cairo_operator_t op,
mask_y + mask_attr.y_offset,
dst_x, dst_y,
width, height);
- }
- else
- {
+ } else {
pixman_image_composite (_pixman_operator (op),
src->pixman_image,
NULL,
@@ -1045,7 +1095,7 @@ _cairo_image_surface_composite (cairo_operator_t op,
width, height);
}
- if (! _cairo_operator_bounded_by_source (op))
+ if (! _cairo_operator_bounded_by_source (op)) {
status = _cairo_surface_composite_fixup_unbounded (&dst->base,
&src_attr, src->width, src->height,
mask ? &mask_attr : NULL,
@@ -1053,7 +1103,9 @@ _cairo_image_surface_composite (cairo_operator_t op,
mask ? mask->height : 0,
src_x, src_y,
mask_x, mask_y,
- dst_x, dst_y, width, height);
+ dst_x, dst_y, width, height,
+ clip_region);
+ }
CLEANUP_SURFACES:
if (mask)
@@ -1078,7 +1130,7 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
pixman_rectangle16_t *pixman_rects = stack_rects;
int i;
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_int_status_t status;
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -1088,6 +1140,9 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
pixman_color.blue = color->blue_short;
pixman_color.alpha = color->alpha_short;
+ status = _cairo_image_surface_set_clip_region (surface, NULL);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
if (num_rects > ARRAY_LENGTH (stack_rects)) {
pixman_rects = _cairo_malloc_ab (num_rects, sizeof (pixman_rectangle16_t));
if (unlikely (pixman_rects == NULL))
@@ -1101,7 +1156,8 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
pixman_rects[i].height = rects[i].height;
}
- /* XXX: pixman_fill_rectangles() should be implemented */
+ /* XXX: pixman_fill_region() should be implemented */
+ status = CAIRO_STATUS_SUCCESS;
if (! pixman_image_fill_rectangles (_pixman_operator (op),
surface->pixman_image,
&pixman_color,
@@ -1165,7 +1221,8 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps)
+ int num_traps,
+ cairo_region_t *clip_region)
{
cairo_surface_attributes_t attributes;
cairo_image_surface_t *dst = abstract_dst;
@@ -1186,22 +1243,26 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
* contained within the surface is bounded by [dst_x,dst_y,width,height];
* the Cairo core code passes bounds based on the trapezoid extents.
*
- * Currently the check surface->has_clip is needed for correct
+ * Currently the check clip_region == NULL is needed for correct
* functioning, since pixman_add_trapezoids() doesn't obey the
* surface clip, which is a libpixman bug , but there's no harm in
* falling through to the general case when the surface is clipped
* since libpixman would have to generate an intermediate mask anyways.
*/
if (op == CAIRO_OPERATOR_ADD &&
+ clip_region == NULL &&
_cairo_pattern_is_opaque_solid (pattern) &&
dst->base.content == CAIRO_CONTENT_ALPHA &&
- ! dst->has_clip &&
antialias != CAIRO_ANTIALIAS_NONE)
{
_pixman_add_trapezoids (dst->pixman_image, 0, 0, traps, num_traps);
return CAIRO_STATUS_SUCCESS;
}
+ status = _cairo_image_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ return status;
+
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
src_x, src_y, width, height,
@@ -1238,14 +1299,16 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
pixman_image_unref (mask);
- if (! _cairo_operator_bounded_by_mask (op))
+ if (! _cairo_operator_bounded_by_mask (op)) {
status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
&attributes,
src->width, src->height,
width, height,
src_x, src_y,
0, 0,
- dst_x, dst_y, width, height);
+ dst_x, dst_y, width, height,
+ clip_region);
+ }
CLEANUP_SOURCE:
_cairo_pattern_release_surface (pattern, &src->base, &attributes);
@@ -1382,7 +1445,7 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
rects->dst.x, rects->dst.y,
width, height);
- if (! _cairo_operator_bounded_by_mask (renderer->op))
+ if (! _cairo_operator_bounded_by_mask (renderer->op)) {
status = _cairo_surface_composite_shape_fixup_unbounded (
&dst->base,
src_attributes,
@@ -1391,7 +1454,9 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
rects->src.x, rects->src.y,
0, 0, /* mask.x, mask.y */
rects->dst.x, rects->dst.y,
- rects->width, rects->height);
+ rects->width, rects->height,
+ dst->clip_region);
+ }
}
if (status != CAIRO_STATUS_SUCCESS)
return _cairo_span_renderer_set_error (abstract_renderer,
@@ -1406,12 +1471,12 @@ _cairo_image_surface_check_span_renderer (cairo_operator_t op,
cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
{
+ return TRUE;
(void) op;
(void) pattern;
(void) abstract_dst;
(void) antialias;
(void) rects;
- return TRUE;
}
static cairo_span_renderer_t *
@@ -1419,22 +1484,25 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects)
+ const cairo_composite_rectangles_t *rects,
+ cairo_region_t *clip_region)
{
cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_span_renderer_t *renderer
- = calloc(1, sizeof(*renderer));
+ cairo_image_surface_span_renderer_t *renderer = calloc(1, sizeof(*renderer));
cairo_status_t status;
int width = rects->width;
int height = rects->height;
+ status = _cairo_image_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ return _cairo_span_renderer_create_in_error (status);
+
if (renderer == NULL)
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
renderer->base.finish = _cairo_image_surface_span_renderer_finish;
- renderer->base.render_row =
- _cairo_image_surface_span_renderer_render_row;
+ renderer->base.render_row = _cairo_image_surface_span_renderer_render_row;
renderer->op = op;
renderer->pattern = pattern;
renderer->antialias = antialias;
@@ -1475,21 +1543,7 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
return &renderer->base;
}
-cairo_int_status_t
-_cairo_image_surface_set_clip_region (void *abstract_surface,
- cairo_region_t *region)
-{
- cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
-
- if (! pixman_image_set_clip_region32 (surface->pixman_image, region? &region->rgn : NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- surface->has_clip = region != NULL;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
+static cairo_bool_t
_cairo_image_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -1500,7 +1554,7 @@ _cairo_image_surface_get_extents (void *abstract_surface,
rectangle->width = surface->width;
rectangle->height = surface->height;
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
static void
@@ -1512,18 +1566,6 @@ _cairo_image_surface_get_font_options (void *abstract_surface,
cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
}
-static cairo_status_t
-_cairo_image_surface_reset (void *abstract_surface)
-{
- cairo_image_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
- status = _cairo_image_surface_set_clip_region (surface, NULL);
- assert (status == CAIRO_STATUS_SUCCESS);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
/**
* _cairo_surface_is_image:
* @surface: a #cairo_surface_t
@@ -1554,8 +1596,6 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
_cairo_image_surface_check_span_renderer,
NULL, /* copy_page */
NULL, /* show_page */
- _cairo_image_surface_set_clip_region,
- NULL, /* intersect_clip_path */
_cairo_image_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_image_surface_get_font_options,
@@ -1571,8 +1611,6 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
NULL, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
-
- _cairo_image_surface_reset
};
/* A convenience function for when one needs to coerce an image
@@ -1600,7 +1638,8 @@ _cairo_image_surface_coerce (cairo_image_surface_t *surface,
_cairo_pattern_init_for_surface (&pattern, &surface->base);
status = _cairo_surface_paint (&clone->base,
CAIRO_OPERATOR_SOURCE,
- &pattern.base, NULL);
+ &pattern.base,
+ NULL);
_cairo_pattern_fini (&pattern.base);
if (unlikely (status)) {
diff --git a/src/cairo-meta-surface-private.h b/src/cairo-meta-surface-private.h
index f0c95c19..edfb20c3 100644
--- a/src/cairo-meta-surface-private.h
+++ b/src/cairo-meta-surface-private.h
@@ -39,6 +39,7 @@
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
+#include "cairo-clip-private.h"
typedef enum {
/* The 5 basic drawing operations. */
@@ -47,15 +48,6 @@ typedef enum {
CAIRO_COMMAND_STROKE,
CAIRO_COMMAND_FILL,
CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
-
- /* Other junk. For most of these, we should be able to assert that
- * they never get called except as part of fallbacks for the 5
- * basic drawing operations (which we implement already so the
- * fallbacks should never get triggered). So the plan is to
- * eliminate as many of these as possible. */
-
- CAIRO_COMMAND_INTERSECT_CLIP_PATH
-
} cairo_command_type_t;
typedef enum {
@@ -67,25 +59,23 @@ typedef enum {
typedef struct _cairo_command_header {
cairo_command_type_t type;
cairo_meta_region_type_t region;
- cairo_rectangle_int_t extents;
+ cairo_operator_t op;
+ cairo_clip_t clip;
} cairo_command_header_t;
typedef struct _cairo_command_paint {
cairo_command_header_t header;
- cairo_operator_t op;
cairo_pattern_union_t source;
} cairo_command_paint_t;
typedef struct _cairo_command_mask {
cairo_command_header_t header;
- cairo_operator_t op;
cairo_pattern_union_t source;
cairo_pattern_union_t mask;
} cairo_command_mask_t;
typedef struct _cairo_command_stroke {
cairo_command_header_t header;
- cairo_operator_t op;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
cairo_stroke_style_t style;
@@ -97,7 +87,6 @@ typedef struct _cairo_command_stroke {
typedef struct _cairo_command_fill {
cairo_command_header_t header;
- cairo_operator_t op;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
@@ -107,7 +96,6 @@ typedef struct _cairo_command_fill {
typedef struct _cairo_command_show_text_glyphs {
cairo_command_header_t header;
- cairo_operator_t op;
cairo_pattern_union_t source;
char *utf8;
int utf8_len;
@@ -119,27 +107,14 @@ typedef struct _cairo_command_show_text_glyphs {
cairo_scaled_font_t *scaled_font;
} cairo_command_show_text_glyphs_t;
-typedef struct _cairo_command_intersect_clip_path {
- cairo_command_header_t header;
- cairo_path_fixed_t *path_pointer;
- cairo_path_fixed_t path;
- cairo_fill_rule_t fill_rule;
- double tolerance;
- cairo_antialias_t antialias;
-} cairo_command_intersect_clip_path_t;
-
typedef union _cairo_command {
cairo_command_header_t header;
- /* The 5 basic drawing operations. */
cairo_command_paint_t paint;
cairo_command_mask_t mask;
cairo_command_stroke_t stroke;
cairo_command_fill_t fill;
cairo_command_show_text_glyphs_t show_text_glyphs;
-
- /* The other junk. */
- cairo_command_intersect_clip_path_t intersect_clip_path;
} cairo_command_t;
typedef struct _cairo_meta_surface {
@@ -150,14 +125,15 @@ typedef struct _cairo_meta_surface {
/* A meta-surface is logically unbounded, but when used as a
* source we need to render it to an image, so we need a size at
* which to create that image. */
- double width_pixels;
- double height_pixels;
+ cairo_rectangle_t extents_pixels;
cairo_rectangle_int_t extents;
+ cairo_bool_t unbounded;
+
+ cairo_clip_t clip;
cairo_array_t commands;
cairo_surface_t *commands_owner;
- cairo_bool_t is_clipped;
int replay_start_idx;
} cairo_meta_surface_t;
@@ -181,6 +157,11 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface,
cairo_surface_t *target,
cairo_meta_region_type_t region);
+cairo_private cairo_status_t
+_cairo_meta_surface_get_bbox (cairo_meta_surface_t *meta,
+ cairo_box_t *bbox,
+ const cairo_matrix_t *transform);
+
cairo_private cairo_bool_t
_cairo_surface_is_meta (const cairo_surface_t *surface);
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index 4fb2722c..f091a59f 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -50,6 +50,12 @@
* that would have been obtained if the original operations applied to
* the meta surface had instead been applied to the target surface.
*
+ * A meta surface is logically unbounded, i.e. it has no implicit constraint
+ * on the size of the drawing surface. However, in practice this is rarely
+ * useful as you wish to replay against a particular target surface with
+ * known bounds. For this case, it is more efficient to specify the target
+ * extents to the meta surface upon creation.
+ *
* The recording phase of the meta surface is careful to snapshot all
* necessary objects (paths, patterns, etc.), in order to achieve
* accurate replay. The efficiency of the meta surface could be
@@ -58,10 +64,13 @@
* copy-on-write implementation for _cairo_surface_snapshot.
*/
+/* XXX Rename to recording surface */
+
#include "cairoint.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-clip-private.h"
+#include "cairo-surface-wrapper-private.h"
typedef enum {
CAIRO_META_REPLAY,
@@ -82,8 +91,8 @@ static const cairo_surface_backend_t cairo_meta_surface_backend;
/**
* cairo_meta_surface_create:
* @content: the content of the meta surface
- * @width_pixels: width of the surface, in pixels
- * @height_pixels: height of the surface, in pixels
+ * @extents_pixels: the extents to record in pixels, can be %NULL to record
+ * unbounded operations.
*
* Creates a meta-surface which can be used to record all drawing operations
* at the highest level (that is, the level of paint, mask, stroke, fill
@@ -105,50 +114,45 @@ static const cairo_surface_backend_t cairo_meta_surface_backend;
* Since 1.10
**/
cairo_surface_t *
-cairo_meta_surface_create (cairo_content_t content,
- double width_pixels,
- double height_pixels)
+cairo_meta_surface_create (cairo_content_t content,
+ const cairo_rectangle_t *extents)
{
cairo_meta_surface_t *meta;
+ cairo_status_t status;
meta = malloc (sizeof (cairo_meta_surface_t));
if (unlikely (meta == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- _cairo_surface_init (&meta->base, &cairo_meta_surface_backend,
- content);
+ _cairo_surface_init (&meta->base, &cairo_meta_surface_backend, content);
meta->content = content;
- meta->width_pixels = width_pixels;
- meta->height_pixels = height_pixels;
/* unbounded -> 'infinite' extents */
- if (width_pixels < 0) {
- meta->extents.x = CAIRO_RECT_INT_MIN;
- meta->extents.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
- } else {
- meta->extents.x = 0;
- if (ceil (width_pixels) > CAIRO_RECT_INT_MAX)
- meta->extents.width = CAIRO_RECT_INT_MAX;
- else
- meta->extents.width = ceil (width_pixels);
- }
+ if (extents != NULL) {
+ meta->extents_pixels = *extents;
- if (height_pixels < 0) {
- meta->extents.y = CAIRO_RECT_INT_MIN;
- meta->extents.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
+ /* XXX check for overflow */
+ meta->extents.x = floor (extents->x);
+ meta->extents.y = floor (extents->y);
+ meta->extents.width = ceil (extents->x + extents->width) - meta->extents.x;
+ meta->extents.height = ceil (extents->y + extents->height) - meta->extents.y;
+
+ status = _cairo_clip_init_rectangle (&meta->clip, &meta->extents);
+ if (unlikely (status)) {
+ free (meta);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ meta->unbounded = FALSE;
} else {
- meta->extents.y = 0;
- if (ceil (height_pixels) > CAIRO_RECT_INT_MAX)
- meta->extents.height = CAIRO_RECT_INT_MAX;
- else
- meta->extents.height = ceil (height_pixels);
+ meta->unbounded = TRUE;
+ _cairo_clip_init (&meta->clip);
}
_cairo_array_init (&meta->commands, sizeof (cairo_command_t *));
meta->commands_owner = NULL;
- meta->is_clipped = FALSE;
meta->replay_start_idx = 0;
return &meta->base;
@@ -161,14 +165,17 @@ _cairo_meta_surface_create_similar (void *abstract_surface,
int width,
int height)
{
- return cairo_meta_surface_create (content, width, height);
+ cairo_rectangle_t extents;
+ extents.x = extents.y = 0;
+ extents.width = width;
+ extents.height = height;
+ return cairo_meta_surface_create (content, &extents);
}
static cairo_status_t
_cairo_meta_surface_finish (void *abstract_surface)
{
cairo_meta_surface_t *meta = abstract_surface;
- cairo_command_t *command;
cairo_command_t **elements;
int i, num_elements;
@@ -180,11 +187,11 @@ _cairo_meta_surface_finish (void *abstract_surface)
num_elements = meta->commands.num_elements;
elements = _cairo_array_index (&meta->commands, 0);
for (i = 0; i < num_elements; i++) {
- command = elements[i];
- switch (command->header.type) {
+ cairo_command_t *command = elements[i];
- /* 5 basic drawing operations */
+ _cairo_clip_reset (&command->header.clip);
+ switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
_cairo_pattern_fini_snapshot (&command->paint.source.base);
free (command);
@@ -218,19 +225,13 @@ _cairo_meta_surface_finish (void *abstract_surface)
free (command);
break;
- /* Other junk. */
- case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
- if (command->intersect_clip_path.path_pointer)
- _cairo_path_fixed_fini (&command->intersect_clip_path.path);
- free (command);
- break;
-
default:
ASSERT_NOT_REACHED;
}
}
_cairo_array_fini (&meta->commands);
+ _cairo_clip_reset (&meta->clip);
return CAIRO_STATUS_SUCCESS;
}
@@ -254,8 +255,12 @@ _cairo_meta_surface_acquire_source_image (void *abstract_surface,
}
image = _cairo_image_surface_create_with_content (surface->content,
- ceil (surface->width_pixels),
- ceil (surface->height_pixels));
+ surface->extents.width,
+ surface->extents.height);
+
+ cairo_surface_set_device_offset (image,
+ -surface->extents.x,
+ -surface->extents.y);
status = cairo_meta_surface_replay (&surface->base, image);
if (unlikely (status)) {
@@ -282,21 +287,30 @@ _cairo_meta_surface_release_source_image (void *abstract_surface,
cairo_surface_destroy (&image->base);
}
-static void
-_draw_command_init (cairo_command_header_t *command,
- cairo_command_type_t type,
- cairo_meta_surface_t *meta)
+static cairo_status_t
+_command_init (cairo_meta_surface_t *meta,
+ cairo_command_header_t *command,
+ cairo_command_type_t type,
+ cairo_operator_t op,
+ cairo_clip_t *clip)
{
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
command->type = type;
+ command->op = op;
command->region = CAIRO_META_REGION_ALL;
- command->extents = meta->extents;
+ _cairo_clip_init_copy (&command->clip, clip);
+ if (meta->clip.path != NULL)
+ status = _cairo_clip_apply_clip (&command->clip, &meta->clip);
+
+ return status;
}
static cairo_int_status_t
-_cairo_meta_surface_paint (void *abstract_surface,
- cairo_operator_t op,
+_cairo_meta_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
@@ -306,8 +320,10 @@ _cairo_meta_surface_paint (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- _draw_command_init (&command->header, CAIRO_COMMAND_PAINT, meta);
- command->op = op;
+ status = _command_init (meta,
+ &command->header, CAIRO_COMMAND_PAINT, op, clip);
+ if (unlikely (status))
+ goto CLEANUP_COMMAND;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
@@ -320,7 +336,7 @@ _cairo_meta_surface_paint (void *abstract_surface,
/* An optimisation that takes care to not replay what was done
* before surface is cleared. We don't erase recorded commands
* since we may have earlier snapshots of this surface. */
- if (op == CAIRO_OPERATOR_CLEAR && !meta->is_clipped)
+ if (op == CAIRO_OPERATOR_CLEAR && clip == NULL)
meta->replay_start_idx = meta->commands.num_elements;
return CAIRO_STATUS_SUCCESS;
@@ -337,7 +353,7 @@ _cairo_meta_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
@@ -347,8 +363,10 @@ _cairo_meta_surface_mask (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- _draw_command_init (&command->header, CAIRO_COMMAND_MASK, meta);
- command->op = op;
+ status = _command_init (meta,
+ &command->header, CAIRO_COMMAND_MASK, op, clip);
+ if (unlikely (status))
+ goto CLEANUP_COMMAND;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
@@ -383,7 +401,7 @@ _cairo_meta_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
@@ -393,8 +411,10 @@ _cairo_meta_surface_stroke (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- _draw_command_init (&command->header, CAIRO_COMMAND_STROKE, meta);
- command->op = op;
+ status = _command_init (meta,
+ &command->header, CAIRO_COMMAND_STROKE, op, clip);
+ if (unlikely (status))
+ goto CLEANUP_COMMAND;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
@@ -438,7 +458,7 @@ _cairo_meta_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
@@ -448,8 +468,10 @@ _cairo_meta_surface_fill (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- _draw_command_init (&command->header, CAIRO_COMMAND_FILL, meta);
- command->op = op;
+ status =_command_init (meta,
+ &command->header, CAIRO_COMMAND_FILL, op, clip);
+ if (unlikely (status))
+ goto CLEANUP_COMMAND;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
@@ -496,7 +518,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
@@ -506,8 +528,11 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface,
if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- _draw_command_init (&command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, meta);
- command->op = op;
+ status = _command_init (meta,
+ &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
+ op, clip);
+ if (unlikely (status))
+ goto CLEANUP_COMMAND;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
if (unlikely (status))
@@ -594,82 +619,31 @@ _cairo_meta_surface_snapshot (void *abstract_other)
_cairo_surface_init (&meta->base, &cairo_meta_surface_backend,
other->base.content);
- meta->width_pixels = other->width_pixels;
- meta->height_pixels = other->height_pixels;
+ meta->extents_pixels = other->extents_pixels;
meta->extents = other->extents;
+ meta->unbounded = other->unbounded;
meta->replay_start_idx = other->replay_start_idx;
meta->content = other->content;
_cairo_array_init_snapshot (&meta->commands, &other->commands);
meta->commands_owner = cairo_surface_reference (&other->base);
- return &meta->base;
-}
-
-static cairo_int_status_t
-_cairo_meta_surface_intersect_clip_path (void *dst,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_meta_surface_t *meta = dst;
- cairo_command_intersect_clip_path_t *command;
- cairo_status_t status;
-
- command = malloc (sizeof (cairo_command_intersect_clip_path_t));
- if (unlikely (command == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- command->header.type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
- command->header.region = CAIRO_META_REGION_ALL;
-
- if (path) {
- status = _cairo_path_fixed_init_copy (&command->path, path);
- if (unlikely (status)) {
- free (command);
- return status;
- }
- command->path_pointer = &command->path;
- meta->is_clipped = TRUE;
- } else {
- command->path_pointer = NULL;
- meta->is_clipped = FALSE;
- }
- command->fill_rule = fill_rule;
- command->tolerance = tolerance;
- command->antialias = antialias;
-
- status = _cairo_array_append (&meta->commands, &command);
- if (unlikely (status)) {
- if (path)
- _cairo_path_fixed_fini (&command->path);
- free (command);
- return status;
- }
+ _cairo_clip_init_copy (&meta->clip, &other->clip);
- return CAIRO_STATUS_SUCCESS;
+ return &meta->base;
}
-/* Currently, we're using as the "size" of a meta surface the largest
- * surface size against which the meta-surface is expected to be
- * replayed, (as passed in to cairo_meta_surface_create()).
- */
-static cairo_int_status_t
+static cairo_bool_t
_cairo_meta_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_meta_surface_t *surface = abstract_surface;
- if (surface->width_pixels < 0 || surface->height_pixels < 0)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- rectangle->x = 0;
- rectangle->y = 0;
- rectangle->width = ceil (surface->width_pixels);
- rectangle->height = ceil (surface->height_pixels);
+ if (surface->unbounded)
+ return FALSE;
- return CAIRO_STATUS_SUCCESS;
+ *rectangle = surface->extents;
+ return TRUE;
}
/**
@@ -702,8 +676,6 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- NULL, /* set_clip_region */
- _cairo_meta_surface_intersect_clip_path,
_cairo_meta_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -726,7 +698,6 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
_cairo_meta_surface_snapshot,
NULL, /* is_similar */
- NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
@@ -735,32 +706,12 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
_cairo_meta_surface_show_text_glyphs
};
-static cairo_path_fixed_t *
-_cairo_command_get_path (cairo_command_t *command)
-{
- switch (command->header.type) {
- case CAIRO_COMMAND_PAINT:
- case CAIRO_COMMAND_MASK:
- case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
- return NULL;
- case CAIRO_COMMAND_STROKE:
- return &command->stroke.path;
- case CAIRO_COMMAND_FILL:
- return &command->fill.path;
- case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
- return command->intersect_clip_path.path_pointer;
- }
-
- ASSERT_NOT_REACHED;
- return NULL;
-}
-
cairo_int_status_t
_cairo_meta_surface_get_path (cairo_surface_t *surface,
cairo_path_fixed_t *path)
{
cairo_meta_surface_t *meta;
- cairo_command_t *command, **elements;
+ cairo_command_t **elements;
int i, num_elements;
cairo_int_status_t status;
@@ -773,12 +724,11 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface,
num_elements = meta->commands.num_elements;
elements = _cairo_array_index (&meta->commands, 0);
for (i = meta->replay_start_idx; i < num_elements; i++) {
- command = elements[i];
+ cairo_command_t *command = elements[i];
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
case CAIRO_COMMAND_MASK:
- case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
status = CAIRO_INT_STATUS_UNSUPPORTED;
break;
@@ -804,7 +754,9 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface,
}
case CAIRO_COMMAND_FILL:
{
- status = _cairo_path_fixed_append (path, &command->fill.path, CAIRO_DIRECTION_FORWARD);
+ status = _cairo_path_fixed_append (path,
+ &command->fill.path, CAIRO_DIRECTION_FORWARD,
+ 0, 0);
break;
}
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
@@ -827,6 +779,7 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface,
return _cairo_surface_set_error (surface, status);
}
+#define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL)
static cairo_status_t
_cairo_meta_surface_replay_internal (cairo_surface_t *surface,
cairo_surface_t *target,
@@ -834,209 +787,155 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
cairo_meta_region_type_t region)
{
cairo_meta_surface_t *meta;
- cairo_command_t *command, **elements;
+ cairo_command_t **elements;
int i, num_elements;
- cairo_int_status_t status, status2;
- cairo_clip_t clip, *old_clip;
- cairo_bool_t has_device_transform = _cairo_surface_has_device_transform (target);
- cairo_matrix_t *device_transform = &target->device_transform;
- cairo_path_fixed_t path_copy, *dev_path;
+ cairo_int_status_t status;
+ cairo_surface_wrapper_t wrapper;
- if (surface->status)
+ if (unlikely (surface->status))
return surface->status;
- if (target->status)
+ if (unlikely (target->status))
return _cairo_surface_set_error (surface, target->status);
+ _cairo_surface_wrapper_init (&wrapper, target);
+
meta = (cairo_meta_surface_t *) surface;
status = CAIRO_STATUS_SUCCESS;
- _cairo_clip_init (&clip, target);
- old_clip = _cairo_surface_get_clip (target);
-
num_elements = meta->commands.num_elements;
elements = _cairo_array_index (&meta->commands, 0);
for (i = meta->replay_start_idx; i < num_elements; i++) {
- command = elements[i];
+ cairo_command_t *command = elements[i];
if (type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) {
if (command->header.region != region)
continue;
}
- /* For all commands except intersect_clip_path, we have to
- * ensure the current clip gets set on the surface. */
- if (command->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
- status = _cairo_surface_set_clip (target, &clip);
- if (unlikely (status))
- break;
- }
-
- dev_path = _cairo_command_get_path (command);
- if (dev_path && has_device_transform) {
- status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
- if (unlikely (status))
- break;
- _cairo_path_fixed_transform (&path_copy, device_transform);
- dev_path = &path_copy;
- }
-
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
- status = _cairo_surface_paint (target,
- command->paint.op,
- &command->paint.source.base, &command->header.extents);
+ status = _cairo_surface_wrapper_paint (&wrapper,
+ command->header.op,
+ &command->paint.source.base,
+ _clip (command));
break;
+
case CAIRO_COMMAND_MASK:
- status = _cairo_surface_mask (target,
- command->mask.op,
- &command->mask.source.base,
- &command->mask.mask.base, &command->header.extents);
+ status = _cairo_surface_wrapper_mask (&wrapper,
+ command->header.op,
+ &command->mask.source.base,
+ &command->mask.mask.base,
+ _clip (command));
break;
+
case CAIRO_COMMAND_STROKE:
{
- cairo_matrix_t dev_ctm = command->stroke.ctm;
- cairo_matrix_t dev_ctm_inverse = command->stroke.ctm_inverse;
-
- if (has_device_transform) {
- cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform);
- cairo_matrix_multiply (&dev_ctm_inverse,
- &target->device_transform_inverse,
- &dev_ctm_inverse);
- }
-
- status = _cairo_surface_stroke (target,
- command->stroke.op,
- &command->stroke.source.base,
- dev_path,
- &command->stroke.style,
- &dev_ctm,
- &dev_ctm_inverse,
- command->stroke.tolerance,
- command->stroke.antialias, &command->header.extents);
+ status = _cairo_surface_wrapper_stroke (&wrapper,
+ command->header.op,
+ &command->stroke.source.base,
+ &command->stroke.path,
+ &command->stroke.style,
+ &command->stroke.ctm,
+ &command->stroke.ctm_inverse,
+ command->stroke.tolerance,
+ command->stroke.antialias,
+ _clip (command));
break;
}
case CAIRO_COMMAND_FILL:
{
cairo_command_t *stroke_command;
- if (type != CAIRO_META_CREATE_REGIONS)
- stroke_command = (i < num_elements - 1) ? elements[i + 1] : NULL;
- else
- stroke_command = NULL;
+ stroke_command = NULL;
+ if (type != CAIRO_META_CREATE_REGIONS && i < num_elements - 1)
+ stroke_command = elements[i + 1];
if (stroke_command != NULL &&
- type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL)
+ type == CAIRO_META_REPLAY &&
+ region != CAIRO_META_REGION_ALL)
{
if (stroke_command->header.region != region)
stroke_command = NULL;
}
+
if (stroke_command != NULL &&
stroke_command->header.type == CAIRO_COMMAND_STROKE &&
- _cairo_path_fixed_is_equal (dev_path, _cairo_command_get_path (stroke_command))) {
- cairo_matrix_t dev_ctm;
- cairo_matrix_t dev_ctm_inverse;
-
- dev_ctm = stroke_command->stroke.ctm;
- dev_ctm_inverse = stroke_command->stroke.ctm_inverse;
-
- if (has_device_transform) {
- cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform);
- cairo_matrix_multiply (&dev_ctm_inverse,
- &surface->device_transform_inverse,
- &dev_ctm_inverse);
- }
-
- status = _cairo_surface_fill_stroke (target,
- command->fill.op,
- &command->fill.source.base,
- command->fill.fill_rule,
- command->fill.tolerance,
- command->fill.antialias,
- dev_path,
- stroke_command->stroke.op,
- &stroke_command->stroke.source.base,
- &stroke_command->stroke.style,
- &dev_ctm,
- &dev_ctm_inverse,
- stroke_command->stroke.tolerance,
- stroke_command->stroke.antialias,
- &stroke_command->header.extents);
+ _cairo_path_fixed_is_equal (&command->fill.path,
+ &stroke_command->stroke.path))
+ {
+ status = _cairo_surface_wrapper_fill_stroke (&wrapper,
+ command->header.op,
+ &command->fill.source.base,
+ command->fill.fill_rule,
+ command->fill.tolerance,
+ command->fill.antialias,
+ &command->fill.path,
+ stroke_command->header.op,
+ &stroke_command->stroke.source.base,
+ &stroke_command->stroke.style,
+ &stroke_command->stroke.ctm,
+ &stroke_command->stroke.ctm_inverse,
+ stroke_command->stroke.tolerance,
+ stroke_command->stroke.antialias,
+ _clip (command));
i++;
- } else
- status = _cairo_surface_fill (target,
- command->fill.op,
- &command->fill.source.base,
- dev_path,
- command->fill.fill_rule,
- command->fill.tolerance,
- command->fill.antialias, &command->header.extents);
+ }
+ else
+ {
+ status = _cairo_surface_wrapper_fill (&wrapper,
+ command->header.op,
+ &command->fill.source.base,
+ &command->fill.path,
+ command->fill.fill_rule,
+ command->fill.tolerance,
+ command->fill.antialias,
+ _clip (command));
+ }
break;
}
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
{
cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
- cairo_glyph_t *dev_glyphs;
- int i, num_glyphs = command->show_text_glyphs.num_glyphs;
+ cairo_glyph_t *glyphs_copy;
+ int num_glyphs = command->show_text_glyphs.num_glyphs;
/* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
* to modify the glyph array that's passed in. We must always
* copy the array before handing it to the backend.
*/
- dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
- if (unlikely (dev_glyphs == NULL)) {
+ glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
+ if (unlikely (glyphs_copy == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
break;
}
- if (has_device_transform) {
- for (i = 0; i < num_glyphs; i++) {
- dev_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (device_transform,
- &dev_glyphs[i].x,
- &dev_glyphs[i].y);
- }
- } else {
- memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
- }
-
- status = _cairo_surface_show_text_glyphs (target,
- command->show_text_glyphs.op,
- &command->show_text_glyphs.source.base,
- command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
- dev_glyphs, num_glyphs,
- command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
- command->show_text_glyphs.cluster_flags,
- command->show_text_glyphs.scaled_font, &command->header.extents);
-
- free (dev_glyphs);
+ memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
+
+ status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
+ command->header.op,
+ &command->show_text_glyphs.source.base,
+ command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
+ glyphs_copy, num_glyphs,
+ command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
+ command->show_text_glyphs.cluster_flags,
+ command->show_text_glyphs.scaled_font,
+ _clip (command));
+ free (glyphs_copy);
break;
}
- case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
- /* XXX Meta surface clipping is broken and requires some
- * cairo-gstate.c rewriting. Work around it for now. */
- if (dev_path == NULL)
- _cairo_clip_reset (&clip);
- else
- status = _cairo_clip_clip (&clip, dev_path,
- command->intersect_clip_path.fill_rule,
- command->intersect_clip_path.tolerance,
- command->intersect_clip_path.antialias,
- target);
- break;
default:
ASSERT_NOT_REACHED;
}
- if (dev_path == &path_copy)
- _cairo_path_fixed_fini (&path_copy);
-
if (type == CAIRO_META_CREATE_REGIONS) {
if (status == CAIRO_STATUS_SUCCESS) {
command->header.region = CAIRO_META_REGION_NATIVE;
} else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK;
status = CAIRO_STATUS_SUCCESS;
+ } else {
+ assert (_cairo_status_is_error (status));
}
}
@@ -1044,10 +943,14 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
break;
}
- _cairo_clip_reset (&clip);
- status2 = _cairo_surface_set_clip (target, old_clip);
- if (status == CAIRO_STATUS_SUCCESS)
- status = status2;
+ /* free up any caches */
+ for (i = meta->replay_start_idx; i < num_elements; i++) {
+ cairo_command_t *command = elements[i];
+
+ _cairo_clip_drop_cache (&command->header.clip);
+ }
+
+ _cairo_surface_wrapper_fini (&wrapper);
return _cairo_surface_set_error (surface, status);
}
@@ -1104,6 +1007,33 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface,
region);
}
+static cairo_status_t
+_meta_surface_get_ink_bbox (cairo_meta_surface_t *surface,
+ cairo_box_t *bbox,
+ const cairo_matrix_t *transform)
+{
+ cairo_surface_t *null_surface;
+ cairo_surface_t *analysis_surface;
+ cairo_status_t status;
+
+ null_surface = _cairo_null_surface_create (surface->content);
+ analysis_surface = _cairo_analysis_surface_create (null_surface);
+ cairo_surface_destroy (null_surface);
+
+ status = analysis_surface->status;
+ if (unlikely (status))
+ return status;
+
+ if (transform != NULL)
+ _cairo_analysis_surface_set_ctm (analysis_surface, transform);
+
+ status = cairo_meta_surface_replay (&surface->base, analysis_surface);
+ _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox);
+ cairo_surface_destroy (analysis_surface);
+
+ return status;
+}
+
/**
* cairo_meta_surface_ink_extents:
* @surface: a #cairo_meta_surface_t
@@ -1114,7 +1044,7 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface,
*
* Measures the extents of the operations stored within the meta-surface.
* This is useful to compute the required size of an image surface (or
- * equivalent) into which to replay the full sequence of drawing operaitions.
+ * equivalent) into which to replay the full sequence of drawing operations.
*
* Since: 1.10
**/
@@ -1125,8 +1055,6 @@ cairo_meta_surface_ink_extents (cairo_surface_t *surface,
double *width,
double *height)
{
- cairo_surface_t *null_surface;
- cairo_surface_t *analysis_surface;
cairo_status_t status;
cairo_box_t bbox;
@@ -1137,17 +1065,11 @@ cairo_meta_surface_ink_extents (cairo_surface_t *surface,
goto DONE;
}
- null_surface = _cairo_null_surface_create (CAIRO_CONTENT_COLOR_ALPHA);
- analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1);
- cairo_surface_destroy (null_surface);
-
- status = analysis_surface->status;
+ status = _meta_surface_get_ink_bbox ((cairo_meta_surface_t *) surface,
+ &bbox,
+ NULL);
if (unlikely (status))
- goto DONE;
-
- status = cairo_meta_surface_replay (surface, analysis_surface);
- _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox);
- cairo_surface_destroy (analysis_surface);
+ status = _cairo_surface_set_error (surface, status);
DONE:
if (x0)
@@ -1159,3 +1081,19 @@ DONE:
if (height)
*height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
}
+
+cairo_status_t
+_cairo_meta_surface_get_bbox (cairo_meta_surface_t *surface,
+ cairo_box_t *bbox,
+ const cairo_matrix_t *transform)
+{
+ if (! surface->unbounded) {
+ _cairo_box_from_rectangle (bbox, &surface->extents);
+ if (transform != NULL)
+ _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return _meta_surface_get_ink_bbox (surface, bbox, transform);
+}
diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c
index 82bab3be..3fda0b4f 100644
--- a/src/cairo-os2-surface.c
+++ b/src/cairo-os2-surface.c
@@ -716,26 +716,18 @@ _cairo_os2_surface_release_dest_image (void *abstract_surface
DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields);
}
-static cairo_int_status_t
+static cairo_bool_t
_cairo_os2_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_os2_surface_t *local_os2_surface;
- local_os2_surface = (cairo_os2_surface_t *) abstract_surface;
- if ((!local_os2_surface) ||
- (local_os2_surface->base.backend != &cairo_os2_surface_backend))
- {
- /* Invalid parameter (wrong surface)! */
- return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
- }
-
rectangle->x = 0;
rectangle->y = 0;
rectangle->width = local_os2_surface->bitmap_info.cx;
rectangle->height = local_os2_surface->bitmap_info.cy;
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
/**
@@ -1327,8 +1319,6 @@ static const cairo_surface_backend_t cairo_os2_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- NULL, /* set_clip_region */
- NULL, /* intersect_clip_path */
_cairo_os2_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
diff --git a/src/cairo-paginated-private.h b/src/cairo-paginated-private.h
index 5cb2e48b..0841a2b1 100644
--- a/src/cairo-paginated-private.h
+++ b/src/cairo-paginated-private.h
@@ -149,8 +149,6 @@ struct _cairo_paginated_surface_backend {
cairo_private cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
- int width,
- int height,
const cairo_paginated_surface_backend_t *backend);
cairo_private cairo_surface_t *
diff --git a/src/cairo-paginated-surface-private.h b/src/cairo-paginated-surface-private.h
index b406cac1..6c130727 100644
--- a/src/cairo-paginated-surface-private.h
+++ b/src/cairo-paginated-surface-private.h
@@ -48,14 +48,6 @@ typedef struct _cairo_paginated_surface {
cairo_content_t content;
- /* XXX: These shouldn't actually exist. We inherit this ugliness
- * from _cairo_meta_surface_create. The width/height parameters
- * from that function also should not exist. The fix that will
- * allow us to remove all of these is to fix acquire_source_image
- * to pass an interest rectangle. */
- int width;
- int height;
-
/* Paginated-surface specific functions for the target */
const cairo_paginated_surface_backend_t *backend;
@@ -66,7 +58,6 @@ typedef struct _cairo_paginated_surface {
int page_num;
cairo_bool_t page_is_blank;
-
} cairo_paginated_surface_t;
#endif /* CAIRO_PAGINATED_SURFACE_H */
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 033df35a..23443a5d 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -60,17 +60,36 @@ _cairo_paginated_surface_create_similar (void *abstract_surface,
int width,
int height)
{
- cairo_paginated_surface_t *surface = abstract_surface;
- return cairo_surface_create_similar (surface->target, content,
- width, height);
+ cairo_rectangle_t rect;
+ rect.x = rect.y = 0.;
+ rect.width = width;
+ rect.height = height;
+ return cairo_meta_surface_create (content, &rect);
+}
+
+static cairo_surface_t *
+_create_meta_surface_for_target (cairo_surface_t *target,
+ cairo_content_t content)
+{
+ cairo_rectangle_int_t rect;
+
+ if (_cairo_surface_get_extents (target, &rect)) {
+ cairo_rectangle_t meta_extents;
+
+ meta_extents.x = rect.x;
+ meta_extents.y = rect.y;
+ meta_extents.width = rect.width;
+ meta_extents.height = rect.height;
+
+ return cairo_meta_surface_create (content, &meta_extents);
+ } else {
+ return cairo_meta_surface_create (content, NULL);
+ }
}
-/* XXX The integer width,height here should be doubles and all uses updated */
cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
- int width,
- int height,
const cairo_paginated_surface_backend_t *backend)
{
cairo_paginated_surface_t *surface;
@@ -87,18 +106,15 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
/* Override surface->base.type with target's type so we don't leak
* evidence of the paginated wrapper out to the user. */
- surface->base.type = cairo_surface_get_type (target);
+ surface->base.type = target->type;
surface->target = cairo_surface_reference (target);
surface->content = content;
- surface->width = width;
- surface->height = height;
-
surface->backend = backend;
- surface->meta = cairo_meta_surface_create (content, width, height);
- status = cairo_surface_status (surface->meta);
+ surface->meta = _create_meta_surface_for_target (target, content);
+ status = surface->meta->status;
if (unlikely (status))
goto FAIL_CLEANUP_SURFACE;
@@ -132,31 +148,6 @@ _cairo_paginated_surface_get_target (cairo_surface_t *surface)
return paginated_surface->target;
}
-cairo_status_t
-_cairo_paginated_surface_set_size (cairo_surface_t *surface,
- int width,
- int height)
-{
- cairo_paginated_surface_t *paginated_surface;
- cairo_status_t status;
-
- assert (_cairo_surface_is_paginated (surface));
-
- paginated_surface = (cairo_paginated_surface_t *) surface;
-
- paginated_surface->width = width;
- paginated_surface->height = height;
-
- cairo_surface_destroy (paginated_surface->meta);
- paginated_surface->meta = cairo_meta_surface_create (paginated_surface->content,
- width, height);
- status = cairo_surface_status (paginated_surface->meta);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_status_t
_cairo_paginated_surface_finish (void *abstract_surface)
{
@@ -168,18 +159,11 @@ _cairo_paginated_surface_finish (void *abstract_surface)
status = cairo_surface_status (abstract_surface);
}
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_finish (surface->target);
- status = cairo_surface_status (surface->target);
- }
-
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_finish (surface->meta);
- status = cairo_surface_status (surface->meta);
- }
-
cairo_surface_destroy (surface->target);
+ cairo_surface_finish (surface->meta);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = cairo_surface_status (surface->meta);
cairo_surface_destroy (surface->meta);
return status;
@@ -210,13 +194,14 @@ _cairo_paginated_surface_acquire_source_image (void *abstract_surface,
void **image_extra)
{
cairo_paginated_surface_t *surface = abstract_surface;
+ cairo_bool_t is_bounded;
cairo_surface_t *image;
cairo_status_t status;
cairo_rectangle_int_t extents;
- status = _cairo_surface_get_extents (surface->target, &extents);
- if (unlikely (status))
- return status;
+ is_bounded = _cairo_surface_get_extents (surface->target, &extents);
+ if (! is_bounded)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
image = _cairo_paginated_surface_create_image_surface (surface,
extents.width,
@@ -248,11 +233,11 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
{
double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
- cairo_matrix_t matrix;
int x, y, width, height;
cairo_status_t status;
cairo_surface_t *image;
cairo_surface_pattern_t pattern;
+ cairo_clip_t clip;
x = rect->x;
y = rect->y;
@@ -271,15 +256,21 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
goto CLEANUP_IMAGE;
_cairo_pattern_init_for_surface (&pattern, image);
- cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
- cairo_pattern_set_matrix (&pattern.base, &matrix);
+ cairo_matrix_init (&pattern.base.matrix,
+ x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
/* the fallback should be rendered at native resolution, so disable
* filtering (if possible) to avoid introducing potential artifacts. */
pattern.base.filter = CAIRO_FILTER_NEAREST;
+ status = _cairo_clip_init_rectangle (&clip, rect);
+ if (unlikely (status))
+ goto CLEANUP_IMAGE;
+
status = _cairo_surface_paint (surface->target,
CAIRO_OPERATOR_SOURCE,
- &pattern.base, NULL);
+ &pattern.base, &clip);
+
+ _cairo_clip_reset (&clip);
_cairo_pattern_fini (&pattern.base);
CLEANUP_IMAGE:
@@ -295,12 +286,11 @@ _paint_page (cairo_paginated_surface_t *surface)
cairo_status_t status;
cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
- if (surface->target->status)
+ if (unlikely (surface->target->status))
return surface->target->status;
- analysis = _cairo_analysis_surface_create (surface->target,
- surface->width, surface->height);
- if (analysis->status)
+ analysis = _cairo_analysis_surface_create (surface->target);
+ if (unlikely (analysis->status))
return _cairo_surface_set_error (surface->target, analysis->status);
surface->backend->set_paginated_mode (surface->target,
@@ -365,16 +355,19 @@ _paint_page (cairo_paginated_surface_t *surface)
}
if (has_page_fallback) {
- cairo_rectangle_int_t rect;
+ cairo_rectangle_int_t extents;
+ cairo_bool_t is_bounded;
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
- rect.x = 0;
- rect.y = 0;
- rect.width = surface->width;
- rect.height = surface->height;
- status = _paint_fallback_image (surface, &rect);
+ is_bounded = _cairo_surface_get_extents (surface->target, &extents);
+ if (! is_bounded) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto FAIL;
+ }
+
+ status = _paint_fallback_image (surface, &extents);
if (unlikely (status))
goto FAIL;
}
@@ -386,15 +379,6 @@ _paint_page (cairo_paginated_surface_t *surface)
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
- /* Reset clip region before drawing the fall back images */
- status = _cairo_surface_intersect_clip_path (surface->target,
- NULL,
- CAIRO_FILL_RULE_WINDING,
- CAIRO_GSTATE_TOLERANCE_DEFAULT,
- CAIRO_ANTIALIAS_DEFAULT);
- if (unlikely (status))
- goto FAIL;
-
region = _cairo_analysis_surface_get_unsupported (analysis);
num_rects = cairo_region_num_rectangles (region);
@@ -402,9 +386,7 @@ _paint_page (cairo_paginated_surface_t *surface)
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
-
status = _paint_fallback_image (surface, &rect);
-
if (unlikely (status))
goto FAIL;
}
@@ -445,7 +427,7 @@ _cairo_paginated_surface_copy_page (void *abstract_surface)
surface->page_num++;
- /* XXX: It might make sense to add some suport here for calling
+ /* XXX: It might make sense to add some support here for calling
* cairo_surface_copy_page on the target surface. It would be an
* optimization for the output, but the interaction with image
* fallbacks gets tricky. For now, we just let the target see a
@@ -471,20 +453,19 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
return status;
cairo_surface_show_page (surface->target);
- status = cairo_surface_status (surface->target);
+ status = surface->target->status;
if (unlikely (status))
return status;
- status = cairo_surface_status (surface->meta);
+ status = surface->meta->status;
if (unlikely (status))
return status;
cairo_surface_destroy (surface->meta);
- surface->meta = cairo_meta_surface_create (surface->content,
- surface->width,
- surface->height);
- status = cairo_surface_status (surface->meta);
+ surface->meta = _create_meta_surface_for_target (surface->target,
+ surface->content);
+ status = surface->meta->status;
if (unlikely (status))
return status;
@@ -494,21 +475,7 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_paginated_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_paginated_surface_t *surface = abstract_surface;
-
- return _cairo_surface_intersect_clip_path (surface->meta,
- path, fill_rule,
- tolerance, antialias);
-}
-
-static cairo_int_status_t
+static cairo_bool_t
_cairo_paginated_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -530,7 +497,7 @@ static cairo_int_status_t
_cairo_paginated_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@@ -540,7 +507,7 @@ _cairo_paginated_surface_paint (void *abstract_surface,
surface->page_is_blank = FALSE;
- return _cairo_surface_paint (surface->meta, op, source, NULL);
+ return _cairo_surface_paint (surface->meta, op, source, clip);
}
static cairo_int_status_t
@@ -548,11 +515,17 @@ _cairo_paginated_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
- return _cairo_surface_mask (surface->meta, op, source, mask, NULL);
+ /* Optimize away erasing of nothing. */
+ if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->page_is_blank = FALSE;
+
+ return _cairo_surface_mask (surface->meta, op, source, mask, clip);
}
static cairo_int_status_t
@@ -565,7 +538,7 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@@ -578,7 +551,8 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
return _cairo_surface_stroke (surface->meta, op, source,
path, style,
ctm, ctm_inverse,
- tolerance, antialias, NULL);
+ tolerance, antialias,
+ clip);
}
static cairo_int_status_t
@@ -589,7 +563,7 @@ _cairo_paginated_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@@ -601,7 +575,8 @@ _cairo_paginated_surface_fill (void *abstract_surface,
return _cairo_surface_fill (surface->meta, op, source,
path, fill_rule,
- tolerance, antialias, NULL);
+ tolerance, antialias,
+ clip);
}
static cairo_bool_t
@@ -614,20 +589,19 @@ _cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
static cairo_int_status_t
_cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const char *utf8,
- int utf8_len,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- const cairo_text_cluster_t *clusters,
- int num_clusters,
- cairo_text_cluster_flags_t cluster_flags,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ const cairo_text_cluster_t *clusters,
+ int num_clusters,
+ cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
- cairo_int_status_t status;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
@@ -635,24 +609,13 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
surface->page_is_blank = FALSE;
- /* Since this is a "wrapping" surface, we're calling back into
- * _cairo_surface_show_text_glyphs from within a call to the same.
- * Since _cairo_surface_show_text_glyphs acquires a mutex, we release
- * and re-acquire the mutex around this nested call.
- *
- * Yes, this is ugly, but we consider it pragmatic as compared to
- * adding locking code to all 18 surface-backend-specific
- * show_glyphs functions, (which would get less testing and likely
- * lead to bugs).
- */
- status = _cairo_surface_show_text_glyphs (surface->meta, op, source,
- utf8, utf8_len,
- glyphs, num_glyphs,
- clusters, num_clusters,
- cluster_flags,
- scaled_font, NULL);
-
- return status;
+ return _cairo_surface_show_text_glyphs (surface->meta, op, source,
+ utf8, utf8_len,
+ glyphs, num_glyphs,
+ clusters, num_clusters,
+ cluster_flags,
+ scaled_font,
+ clip);
}
static cairo_surface_t *
@@ -679,8 +642,6 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
NULL, /* check_span_renderer */
_cairo_paginated_surface_copy_page,
_cairo_paginated_surface_show_page,
- NULL, /* set_clip_region */
- _cairo_paginated_surface_intersect_clip_path,
_cairo_paginated_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_paginated_surface_get_font_options,
@@ -695,7 +656,6 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
NULL, /* show_glyphs */
_cairo_paginated_surface_snapshot,
NULL, /* is_similar */
- NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index 1fadd84d..1a3cdf06 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -173,7 +173,7 @@ _cairo_path_bounder_close_path (void *closure)
* the control points of the curves, not the flattened path).
*/
void
-_cairo_path_fixed_approximate_clip_extents (cairo_path_fixed_t *path,
+_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
@@ -203,7 +203,7 @@ _cairo_path_fixed_approximate_clip_extents (cairo_path_fixed_t *path,
* Bezier, but we continue to ignore winding.
*/
void
-_cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path,
+_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
@@ -229,9 +229,37 @@ _cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path,
_cairo_path_bounder_fini (&bounder);
}
+void
+_cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_path_bounder_t bounder;
+ cairo_status_t status;
+
+ _cairo_path_bounder_init (&bounder);
+
+ status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
+ _cairo_path_bounder_move_to,
+ _cairo_path_bounder_line_to,
+ _cairo_path_bounder_close_path,
+ &bounder, tolerance);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ if (bounder.has_point) {
+ _cairo_box_round_to_rectangle (&bounder.extents, extents);
+ } else {
+ extents->x = extents->y = 0;
+ extents->width = extents->height = 0;
+ }
+
+ _cairo_path_bounder_fini (&bounder);
+}
+
/* Adjusts the fill extents (above) by the device-space pen. */
void
-_cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path,
+_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents)
@@ -268,8 +296,37 @@ _cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path,
_cairo_path_bounder_fini (&bounder);
}
+cairo_status_t
+_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
+ cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_traps_t traps;
+ cairo_box_t bbox;
+ cairo_status_t status;
+
+ _cairo_traps_init (&traps);
+
+ status = _cairo_path_fixed_stroke_to_traps (path,
+ stroke_style,
+ ctm,
+ ctm_inverse,
+ tolerance,
+ &traps);
+
+ _cairo_traps_extents (&traps, &bbox);
+ _cairo_traps_fini (&traps);
+
+ _cairo_box_round_to_rectangle (&bbox, extents);
+
+ return status;
+}
+
void
-_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
+_cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index 9569c9e9..123da96e 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -125,12 +125,12 @@ _cairo_filler_close_path (void *closure)
}
static cairo_int_status_t
-_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
+_cairo_path_fixed_fill_rectangle (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps);
cairo_status_t
-_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
+_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_traps_t *traps)
@@ -138,6 +138,8 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t filler;
+ traps->maybe_region = path->maybe_fill_region;
+
/* Before we do anything else, we use a special-case filler for
* a device-axis aligned rectangle if possible. */
status = _cairo_path_fixed_fill_rectangle (path, fill_rule, traps);
@@ -181,12 +183,15 @@ BAIL:
* this function will return %CAIRO_INT_STATUS_UNSUPPORTED.
*/
static cairo_int_status_t
-_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
+_cairo_path_fixed_fill_rectangle (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
cairo_box_t box;
+ if (! path->is_rectilinear)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (_cairo_path_fixed_is_box (path, &box)) {
if (box.p1.x > box.p2.x) {
cairo_fixed_t t;
diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h
index 6bd09f76..1ef7cdda 100644
--- a/src/cairo-path-fixed-private.h
+++ b/src/cairo-path-fixed-private.h
@@ -81,12 +81,26 @@ struct _cairo_path_fixed {
cairo_point_t current_point;
unsigned int has_current_point : 1;
unsigned int has_curve_to : 1;
- unsigned int is_box : 1;
- unsigned int is_region : 1;
+ unsigned int is_rectilinear : 1;
+ unsigned int maybe_fill_region : 1;
+ unsigned int is_empty_fill : 1;
cairo_path_buf_fixed_t buf;
};
+
+cairo_private void
+_cairo_path_fixed_translate (cairo_path_fixed_t *path,
+ cairo_fixed_t offx,
+ cairo_fixed_t offy);
+
+cairo_private cairo_status_t
+_cairo_path_fixed_append (cairo_path_fixed_t *path,
+ const cairo_path_fixed_t *other,
+ cairo_direction_t dir,
+ cairo_fixed_t tx,
+ cairo_fixed_t ty);
+
cairo_private unsigned long
_cairo_path_fixed_hash (const cairo_path_fixed_t *path);
@@ -98,14 +112,14 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a,
const cairo_path_fixed_t *b);
typedef struct _cairo_path_fixed_iter {
- cairo_path_buf_t *buf;
+ const cairo_path_buf_t *buf;
unsigned int n_op;
unsigned int n_point;
} cairo_path_fixed_iter_t;
cairo_private void
_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
- cairo_path_fixed_t *path);
+ const cairo_path_fixed_t *path);
cairo_private cairo_bool_t
_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter,
@@ -115,13 +129,19 @@ cairo_private cairo_bool_t
_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter);
static inline cairo_bool_t
-_cairo_path_fixed_is_region (cairo_path_fixed_t *path)
+_cairo_path_fixed_fill_is_empty (const cairo_path_fixed_t *path)
+{
+ return path->is_empty_fill;
+}
+
+static inline cairo_bool_t
+_cairo_path_fixed_maybe_fill_region (const cairo_path_fixed_t *path)
{
#if WATCH_PATH
- fprintf (stderr, "_cairo_path_fixed_is_region () = %s\n",
- path->is_region ? "true" : "false");
+ fprintf (stderr, "_cairo_path_fixed_maybe_fill_region () = %s\n",
+ path->maybe_fill_region ? "true" : "false");
#endif
- return path->is_region;
+ return path->maybe_fill_region;
}
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index 0a550399..9819353b 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -96,25 +96,32 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path)
path->last_move_point = path->current_point;
path->has_current_point = FALSE;
path->has_curve_to = FALSE;
- path->is_region = TRUE;
- path->is_box = TRUE;
+ path->is_rectilinear = TRUE;
+ path->maybe_fill_region = TRUE;
+ path->is_empty_fill = TRUE;
}
cairo_status_t
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
- cairo_path_fixed_t *other)
+ const cairo_path_fixed_t *other)
{
cairo_path_buf_t *buf, *other_buf;
unsigned int num_points, num_ops, buf_size;
- _cairo_path_fixed_init (path);
+ VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t)));
+
+ cairo_list_init (&path->buf.base.link);
+
+ path->buf.base.op = path->buf.op;
+ path->buf.base.points = path->buf.points;
path->current_point = other->current_point;
- path->has_current_point = other->has_current_point;
path->last_move_point = other->last_move_point;
+ path->has_current_point = other->has_current_point;
path->has_curve_to = other->has_curve_to;
- path->is_box = other->is_box;
- path->is_region = other->is_region;
+ path->is_rectilinear = other->is_rectilinear;
+ path->maybe_fill_region = other->maybe_fill_region;
+ path->is_empty_fill = other->is_empty_fill;
path->buf.base.num_ops = other->buf.base.num_ops;
path->buf.base.num_points = other->buf.base.num_points;
@@ -214,9 +221,10 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a,
return TRUE;
/* use the flags to quickly differentiate based on contents */
- if (a->has_curve_to != b->has_curve_to ||
- a->is_region != b->is_region ||
- a->is_box != b->is_box)
+ if (a->is_empty_fill != b->is_empty_fill ||
+ a->has_curve_to != b->has_curve_to ||
+ a->maybe_fill_region != b->maybe_fill_region ||
+ a->is_rectilinear != b->is_rectilinear)
{
return FALSE;
}
@@ -378,15 +386,16 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path,
if (unlikely (status))
return status;
- if (path->has_current_point && path->is_box) {
+ if (path->has_current_point && path->is_rectilinear) {
/* a move-to is first an implicit close */
- path->is_box = path->current_point.x == path->last_move_point.x ||
- path->current_point.y == path->last_move_point.y;
- path->is_region &= path->is_box;
+ path->is_rectilinear = path->current_point.x == path->last_move_point.x ||
+ path->current_point.y == path->last_move_point.y;
+ path->maybe_fill_region &= path->is_rectilinear;
}
- if (path->is_region) {
- path->is_region = _cairo_fixed_is_integer (x) &&
- _cairo_fixed_is_integer (y);
+ if (path->maybe_fill_region) {
+ path->maybe_fill_region =
+ _cairo_fixed_is_integer (path->last_move_point.x) &&
+ _cairo_fixed_is_integer (path->last_move_point.y);
}
}
@@ -437,14 +446,18 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
status = _cairo_path_fixed_move_to (path, point.x, point.y);
} else {
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
- if (path->is_box) {
- path->is_box = path->current_point.x == x ||
- path->current_point.y == y;
- path->is_region &= path->is_box;
+ if (path->is_rectilinear) {
+ path->is_rectilinear = path->current_point.x == x ||
+ path->current_point.y == y;
+ path->maybe_fill_region &= path->is_rectilinear;
+ }
+ if (path->maybe_fill_region) {
+ path->maybe_fill_region = _cairo_fixed_is_integer (x) &&
+ _cairo_fixed_is_integer (y);
}
- if (path->is_region) {
- path->is_region = _cairo_fixed_is_integer (x) &&
- _cairo_fixed_is_integer (y);
+ if (path->is_empty_fill) {
+ path->is_empty_fill = path->current_point.x == x &&
+ path->current_point.y == y;
}
}
@@ -495,9 +508,10 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
path->current_point = point[2];
path->has_current_point = TRUE;
+ path->is_empty_fill = FALSE;
path->has_curve_to = TRUE;
- path->is_box = FALSE;
- path->is_region = FALSE;
+ path->is_rectilinear = FALSE;
+ path->maybe_fill_region = FALSE;
return CAIRO_STATUS_SUCCESS;
}
@@ -732,49 +746,77 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path,
return CAIRO_STATUS_SUCCESS;
}
+typedef struct _cairo_path_fixed_append_closure {
+ cairo_point_t offset;
+ cairo_path_fixed_t *path;
+} cairo_path_fixed_append_closure_t;
+
static cairo_status_t
-_append_move_to (void *closure,
+_append_move_to (void *abstract_closure,
const cairo_point_t *point)
{
- return _cairo_path_fixed_move_to (closure, point->x, point->y);
+ cairo_path_fixed_append_closure_t *closure = abstract_closure;
+
+ return _cairo_path_fixed_move_to (closure->path,
+ point->x + closure->offset.x,
+ point->y + closure->offset.y);
}
static cairo_status_t
-_append_line_to (void *closure,
+_append_line_to (void *abstract_closure,
const cairo_point_t *point)
{
- return _cairo_path_fixed_line_to (closure, point->x, point->y);
+ cairo_path_fixed_append_closure_t *closure = abstract_closure;
+
+ return _cairo_path_fixed_line_to (closure->path,
+ point->x + closure->offset.x,
+ point->y + closure->offset.y);
}
static cairo_status_t
-_append_curve_to (void *closure,
+_append_curve_to (void *abstract_closure,
const cairo_point_t *p0,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
- return _cairo_path_fixed_curve_to (closure,
- p0->x, p0->y,
- p1->x, p1->y,
- p2->x, p2->y);
+ cairo_path_fixed_append_closure_t *closure = abstract_closure;
+
+ return _cairo_path_fixed_curve_to (closure->path,
+ p0->x + closure->offset.x,
+ p0->y + closure->offset.y,
+ p1->x + closure->offset.x,
+ p1->y + closure->offset.y,
+ p2->x + closure->offset.x,
+ p2->y + closure->offset.y);
}
static cairo_status_t
-_append_close_path (void *closure)
+_append_close_path (void *abstract_closure)
{
- return _cairo_path_fixed_close_path (closure);
+ cairo_path_fixed_append_closure_t *closure = abstract_closure;
+
+ return _cairo_path_fixed_close_path (closure->path);
}
cairo_status_t
-_cairo_path_fixed_append (cairo_path_fixed_t *path,
- const cairo_path_fixed_t *other,
- cairo_direction_t dir)
+_cairo_path_fixed_append (cairo_path_fixed_t *path,
+ const cairo_path_fixed_t *other,
+ cairo_direction_t dir,
+ cairo_fixed_t tx,
+ cairo_fixed_t ty)
{
+ cairo_path_fixed_append_closure_t closure;
+
+ closure.path = path;
+ closure.offset.x = tx;
+ closure.offset.y = ty;
+
return _cairo_path_fixed_interpret (other, dir,
_append_move_to,
_append_line_to,
_append_curve_to,
_append_close_path,
- path);
+ &closure);
}
static void
@@ -787,6 +829,13 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_path_buf_t *buf;
unsigned int i;
+ if (path->maybe_fill_region) {
+ path->maybe_fill_region = _cairo_fixed_is_integer (offx) &&
+ _cairo_fixed_is_integer (offy) &&
+ _cairo_fixed_is_integer (scalex) &&
+ _cairo_fixed_is_integer (scaley);
+ }
+
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
if (scalex != CAIRO_FIXED_ONE)
@@ -800,6 +849,36 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
} cairo_path_foreach_buf_end (buf, path);
}
+void
+_cairo_path_fixed_translate (cairo_path_fixed_t *path,
+ cairo_fixed_t offx,
+ cairo_fixed_t offy)
+{
+ cairo_path_buf_t *buf;
+ unsigned int i;
+
+ if (offx == 0 && offy == 0)
+ return;
+
+ if (path->maybe_fill_region &&
+ ! (_cairo_fixed_is_integer (offx) && _cairo_fixed_is_integer (offy)))
+ {
+ path->maybe_fill_region = FALSE;
+ }
+
+ path->last_move_point.x += offx;
+ path->last_move_point.y += offx;
+ path->current_point.x += offx;
+ path->current_point.y += offx;
+
+ cairo_path_foreach_buf_start (buf, path) {
+ for (i = 0; i < buf->num_points; i++) {
+ buf->points[i].x += offx;
+ buf->points[i].y += offy;
+ }
+ } cairo_path_foreach_buf_end (buf, path);
+}
+
/**
* _cairo_path_fixed_transform:
* @path: a #cairo_path_fixed_t to be transformed
@@ -811,12 +890,14 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
**/
void
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
- cairo_matrix_t *matrix)
+ const cairo_matrix_t *matrix)
{
cairo_path_buf_t *buf;
unsigned int i;
double dx, dy;
+ /* XXX current_point, last_move_to */
+
if (matrix->yx == 0.0 && matrix->xy == 0.0) {
/* Fast path for the common case of scale+transform */
_cairo_path_fixed_offset_and_scale (path,
@@ -827,6 +908,7 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path,
return;
}
+ path->maybe_fill_region = FALSE;
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
dx = _cairo_fixed_to_double (buf->points[i].x);
@@ -841,20 +923,22 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path,
}
cairo_bool_t
-_cairo_path_fixed_is_equal (cairo_path_fixed_t *path,
- cairo_path_fixed_t *other)
+_cairo_path_fixed_is_equal (const cairo_path_fixed_t *path,
+ const cairo_path_fixed_t *other)
{
- cairo_path_buf_t *path_buf, *other_buf;
+ const cairo_path_buf_t *path_buf, *other_buf;
if (path->current_point.x != other->current_point.x ||
path->current_point.y != other->current_point.y ||
path->has_current_point != other->has_current_point ||
path->has_curve_to != other->has_curve_to ||
- path->is_box != other->is_box ||
- path->is_region != other->is_region ||
+ path->is_rectilinear != other->is_rectilinear ||
+ path->maybe_fill_region != other->maybe_fill_region ||
path->last_move_point.x != other->last_move_point.x ||
path->last_move_point.y != other->last_move_point.y)
+ {
return FALSE;
+ }
other_buf = cairo_path_head (other);
cairo_path_foreach_buf_start (path_buf, path) {
@@ -970,25 +1054,16 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
&flattener);
}
-cairo_bool_t
-_cairo_path_fixed_is_empty (cairo_path_fixed_t *path)
-{
- if (cairo_path_head (path)->num_ops == 0)
- return TRUE;
-
- return FALSE;
-}
-
/*
* Check whether the given path contains a single rectangle.
*/
cairo_bool_t
-_cairo_path_fixed_is_box (cairo_path_fixed_t *path,
+_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
- cairo_path_buf_t *buf = cairo_path_head (path);
+ const cairo_path_buf_t *buf = cairo_path_head (path);
- if (! path->is_box)
+ if (! path->is_rectilinear)
return FALSE;
/* Do we have the right number of ops? */
@@ -1058,12 +1133,12 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
* </programlisting></informalexample>
*/
cairo_bool_t
-_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
+_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
- cairo_path_buf_t *buf;
+ const cairo_path_buf_t *buf;
- if (!_cairo_path_fixed_is_box (path, box))
+ if (! _cairo_path_fixed_is_box (path, box))
return FALSE;
buf = cairo_path_head (path);
@@ -1075,7 +1150,7 @@ _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
void
_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
- cairo_path_fixed_t *path)
+ const cairo_path_fixed_t *path)
{
iter->buf = cairo_path_head (path);
iter->n_op = 0;
diff --git a/src/cairo-path-in-fill.c b/src/cairo-path-in-fill.c
index 24f43ca5..2fa86505 100644
--- a/src/cairo-path-in-fill.c
+++ b/src/cairo-path-in-fill.c
@@ -38,10 +38,10 @@
typedef struct cairo_in_fill {
double tolerance;
+ cairo_bool_t on_edge;
int winding;
cairo_fixed_t x, y;
- cairo_bool_t on_edge;
cairo_bool_t has_current_point;
cairo_point_t current_point;
@@ -54,12 +54,12 @@ _cairo_in_fill_init (cairo_in_fill_t *in_fill,
double x,
double y)
{
+ in_fill->on_edge = FALSE;
in_fill->winding = 0;
in_fill->tolerance = tolerance;
in_fill->x = _cairo_fixed_from_double (x);
in_fill->y = _cairo_fixed_from_double (y);
- in_fill->on_edge = FALSE;
in_fill->has_current_point = FALSE;
in_fill->current_point.x = 0;
@@ -142,7 +142,7 @@ _cairo_in_fill_add_edge (cairo_in_fill_t *in_fill,
return;
if ((p1->x <= in_fill->x && p2->x <= in_fill->x) ||
- edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) <= 0)
+ edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) < 0)
{
in_fill->winding += dir;
}
@@ -243,16 +243,19 @@ _cairo_in_fill_close_path (void *closure)
return CAIRO_STATUS_SUCCESS;
}
-void
-_cairo_path_fixed_in_fill (cairo_path_fixed_t *path,
+cairo_bool_t
+_cairo_path_fixed_in_fill (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
double x,
- double y,
- cairo_bool_t *is_inside)
+ double y)
{
cairo_in_fill_t in_fill;
cairo_status_t status;
+ cairo_bool_t is_inside;
+
+ if (path->is_empty_fill)
+ return FALSE;
_cairo_in_fill_init (&in_fill, tolerance, x, y);
@@ -268,19 +271,21 @@ _cairo_path_fixed_in_fill (cairo_path_fixed_t *path,
_cairo_in_fill_close_path (&in_fill);
if (in_fill.on_edge) {
- *is_inside = TRUE;
+ is_inside = TRUE;
} else switch (fill_rule) {
case CAIRO_FILL_RULE_EVEN_ODD:
- *is_inside = in_fill.winding & 1;
+ is_inside = in_fill.winding & 1;
break;
case CAIRO_FILL_RULE_WINDING:
- *is_inside = in_fill.winding != 0;
+ is_inside = in_fill.winding != 0;
break;
default:
ASSERT_NOT_REACHED;
- *is_inside = FALSE;
+ is_inside = FALSE;
break;
}
_cairo_in_fill_fini (&in_fill);
+
+ return is_inside;
}
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 79bf09b0..4fa4ce5a 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -1140,13 +1140,13 @@ _cairo_stroker_close_path (void *closure)
}
static cairo_int_status_t
-_cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path,
+_cairo_path_fixed_stroke_rectilinear (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps);
cairo_status_t
-_cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
+_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
@@ -1737,7 +1737,7 @@ _cairo_rectilinear_stroker_close_path (void *closure)
}
static cairo_int_status_t
-_cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path,
+_cairo_path_fixed_stroke_rectilinear (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps)
@@ -1755,7 +1755,7 @@ _cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path,
* UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any
* non-rectilinear line_to is encountered.
*/
- if (path->has_curve_to)
+ if (! path->is_rectilinear)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (stroke_style->line_join != CAIRO_LINE_JOIN_MITER)
return CAIRO_INT_STATUS_UNSUPPORTED;
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 9fe94ad4..6eabaa40 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1686,10 +1686,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
pattern,
dst))
{
- status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
- if (unlikely (status))
- goto UNLOCK;
-
goto DONE;
}
@@ -1698,10 +1694,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
pattern,
dst))
{
- status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
- if (unlikely (status))
- goto UNLOCK;
-
goto DONE;
}
}
@@ -1717,11 +1709,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
dst))
{
/* Reuse the surface instead of evicting */
-
- status = _cairo_surface_reset (surface);
- if (unlikely (status))
- goto EVICT;
-
status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
if (unlikely (status))
goto EVICT;
@@ -1738,14 +1725,21 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
if (surface == NULL) {
/* Not cached, need to create new */
surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
- if (surface->status) {
+ if (surface == NULL) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto UNLOCK;
+ }
+ if (unlikely (surface->status)) {
status = surface->status;
goto UNLOCK;
}
- if (! _cairo_surface_is_similar (surface, dst, pattern->content)) {
- /* in the rare event of a substitute surface being returned (e.g.
- * malloc failure) don't cache the fallback surface */
+ if (unlikely (! _cairo_surface_is_similar (surface,
+ dst, pattern->content)))
+ {
+ /* In the rare event of a substitute surface being returned,
+ * don't cache the fallback.
+ */
*out = surface;
goto NOCACHE;
}
@@ -1953,6 +1947,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
double pad;
cairo_bool_t is_identity;
cairo_bool_t is_empty;
+ cairo_bool_t is_bounded;
cairo_int_status_t status;
surface = cairo_surface_reference (pattern->surface);
@@ -2010,9 +2005,8 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
cairo_surface_t *src;
int w, h;
- status = _cairo_surface_get_extents (surface, &extents);
- if (unlikely (status))
- goto BAIL;
+ is_bounded = _cairo_surface_get_extents (surface, &extents);
+ assert (is_bounded);
status = _cairo_surface_clone_similar (dst, surface, content,
extents.x, extents.y,
@@ -2045,8 +2039,13 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
}
cairo_surface_destroy (surface);
- surface = cairo_surface_create_similar (dst, dst->content, w, h);
- if (surface->status) {
+ surface = _cairo_surface_create_similar_solid (dst,
+ dst->content, w, h,
+ CAIRO_COLOR_TRANSPARENT,
+ FALSE);
+ if (surface == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (unlikely (surface->status)) {
cairo_surface_destroy (src);
return surface->status;
}
@@ -2092,10 +2091,6 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
attr->extend = CAIRO_EXTEND_REPEAT;
}
- status = _cairo_surface_get_extents (surface, &extents);
- if (unlikely (status))
- goto BAIL;
-
/* We first transform the rectangle to the coordinate space of the
* source surface so that we only need to clone that portion of the
* surface that will be read.
@@ -2118,36 +2113,38 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
sampled_area.x += tx;
sampled_area.y += ty;
- if (attr->extend != CAIRO_EXTEND_REPEAT) {
- /* Never acquire a larger area than the source itself */
- is_empty = _cairo_rectangle_intersect (&extents, &sampled_area);
- } else {
- int trim = 0;
+ if ( _cairo_surface_get_extents (surface, &extents)) {
+ if (attr->extend != CAIRO_EXTEND_REPEAT) {
+ /* Never acquire a larger area than the source itself */
+ is_empty = _cairo_rectangle_intersect (&extents, &sampled_area);
+ } else {
+ int trim = 0;
- if (sampled_area.x >= extents.x &&
- sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width)
- {
- /* source is horizontally contained within extents, trim */
- extents.x = sampled_area.x;
- extents.width = sampled_area.width;
- trim |= 0x1;
- }
+ if (sampled_area.x >= extents.x &&
+ sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width)
+ {
+ /* source is horizontally contained within extents, trim */
+ extents.x = sampled_area.x;
+ extents.width = sampled_area.width;
+ trim |= 0x1;
+ }
- if (sampled_area.y >= extents.y &&
- sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height)
- {
- /* source is vertically contained within extents, trim */
- extents.y = sampled_area.y;
- extents.height = sampled_area.height;
- trim |= 0x2;
- }
+ if (sampled_area.y >= extents.y &&
+ sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height)
+ {
+ /* source is vertically contained within extents, trim */
+ extents.y = sampled_area.y;
+ extents.height = sampled_area.height;
+ trim |= 0x2;
+ }
- if (trim == 0x3) {
- /* source is wholly contained within extents, drop the REPEAT */
- attr->extend = CAIRO_EXTEND_NONE;
- }
+ if (trim == 0x3) {
+ /* source is wholly contained within extents, drop the REPEAT */
+ attr->extend = CAIRO_EXTEND_NONE;
+ }
- is_empty = extents.width == 0 || extents.height == 0;
+ is_empty = extents.width == 0 || extents.height == 0;
+ }
}
/* XXX can we use is_empty? */
@@ -2237,7 +2234,7 @@ _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
{
cairo_status_t status;
- if (pattern->status) {
+ if (unlikely (pattern->status)) {
*surface_out = NULL;
return pattern->status;
}
@@ -2371,9 +2368,9 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
cairo_int_status_t status;
cairo_pattern_union_t src_tmp;
- if (src->status)
+ if (unlikely (src->status))
return src->status;
- if (mask && mask->status)
+ if (unlikely (mask != NULL && mask->status))
return mask->status;
/* If src and mask are both solid, then the mask alpha can be
@@ -2441,7 +2438,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
* "infinite" extents, though it would be possible to optimize these
* with a little more work.
**/
-cairo_status_t
+void
_cairo_pattern_get_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents)
{
@@ -2457,11 +2454,8 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
double x1, y1, x2, y2;
double pad;
- status = _cairo_surface_get_extents (surface, &surface_extents);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ if (! _cairo_surface_get_extents (surface, &surface_extents))
goto UNBOUNDED;
- if (unlikely (status))
- return status;
/* The filter can effectively enlarge the extents of the
* pattern, so extend as necessary.
@@ -2497,8 +2491,7 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
extents->x = x1; extents->width = x2 - x1;
extents->y = y1; extents->height = y2 - y1;
-
- return CAIRO_STATUS_SUCCESS;
+ return;
}
/* XXX: We could optimize gradients with pattern->extend of NONE
@@ -2508,12 +2501,7 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
UNBOUNDED:
/* unbounded patterns -> 'infinite' extents */
- extents->x = CAIRO_RECT_INT_MIN;
- extents->y = CAIRO_RECT_INT_MIN;
- extents->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
- extents->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
-
- return CAIRO_STATUS_SUCCESS;
+ _cairo_unbounded_rectangle_init (extents);
}
@@ -2749,6 +2737,9 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
if (a->status || b->status)
return FALSE;
+ if (a == b)
+ return TRUE;
+
if (a->type != b->type)
return FALSE;
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 2e7d2445..5c28f70c 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -45,6 +45,7 @@
#include "cairo-pdf.h"
#include "cairo-surface-private.h"
+#include "cairo-surface-clipper-private.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-path-fixed-private.h"
@@ -174,6 +175,8 @@ struct _cairo_pdf_surface {
cairo_bool_t is_knockout;
} group_stream;
+ cairo_surface_clipper_t clipper;
+
cairo_pdf_operators_t pdf_operators;
cairo_paginated_mode_t paginated_mode;
cairo_bool_t select_pattern_gstate_saved;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 0e5c8403..8cd46723 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -50,6 +50,7 @@
#include "cairo-output-stream-private.h"
#include "cairo-paginated-private.h"
#include "cairo-scaled-font-subsets-private.h"
+#include "cairo-surface-clipper-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include <time.h>
@@ -243,6 +244,34 @@ _cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface,
&surface->cairo_to_pdf);
}
+static cairo_status_t
+_cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_pdf_surface_t *surface = cairo_container_of (clipper,
+ cairo_pdf_surface_t,
+ clipper);
+ cairo_int_status_t status;
+
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ if (unlikely (status))
+ return status;
+
+ if (path == NULL) {
+ _cairo_output_stream_printf (surface->output, "Q q\n");
+
+ surface->current_pattern_is_solid_color = FALSE;
+ _cairo_pdf_operators_reset (&surface->pdf_operators);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
+}
+
static cairo_surface_t *
_cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
double width,
@@ -313,6 +342,9 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->current_operator = CAIRO_OPERATOR_OVER;
surface->header_emitted = FALSE;
+ _cairo_surface_clipper_init (&surface->clipper,
+ _cairo_pdf_surface_clipper_intersect_clip_path);
+
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->output,
&surface->cairo_to_pdf,
@@ -325,7 +357,6 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->paginated_surface = _cairo_paginated_surface_create (
&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
- width, height,
&cairo_pdf_surface_paginated_backend);
status = surface->paginated_surface->status;
@@ -572,11 +603,6 @@ cairo_pdf_surface_set_size (cairo_surface_t *surface,
_cairo_pdf_surface_set_size_internal (pdf_surface,
width_in_points,
height_in_points);
- status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface,
- width_in_points,
- height_in_points);
- if (unlikely (status))
- status = _cairo_surface_set_error (surface, status);
}
static void
@@ -981,9 +1007,9 @@ _get_jpx_image_info (cairo_surface_t *source,
static cairo_int_status_t
_get_jpeg_image_info (cairo_surface_t *source,
- cairo_image_info_t *info,
- const unsigned char **mime_data,
- unsigned int *mime_data_length)
+ cairo_image_info_t *info,
+ const unsigned char **mime_data,
+ unsigned int *mime_data_length)
{
cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
mime_data, mime_data_length);
@@ -998,52 +1024,48 @@ _get_source_surface_size (cairo_surface_t *source,
int *width,
int *height)
{
- cairo_image_surface_t *image;
- void *image_extra;
cairo_status_t status;
+ cairo_rectangle_int_t extents;
cairo_image_info_t info;
const unsigned char *mime_data;
unsigned int mime_data_length;
if (_cairo_surface_is_meta (source)) {
- cairo_rectangle_int_t extents;
+ cairo_meta_surface_t *meta_surface = (cairo_meta_surface_t *) source;
+ cairo_box_t bbox;
- status = _cairo_surface_get_extents (source, &extents);
+ status = _cairo_meta_surface_get_bbox (meta_surface, &bbox, NULL);
if (unlikely (status))
return status;
+ _cairo_box_round_to_rectangle (&bbox, &extents);
+
*width = extents.width;
*height = extents.height;
-
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length);
- if (status == CAIRO_STATUS_SUCCESS) {
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
*width = info.width;
*height = info.height;
- } else if (_cairo_status_is_error (status)) {
return status;
}
status = _get_jpeg_image_info (source, &info, &mime_data, &mime_data_length);
- if (status == CAIRO_STATUS_SUCCESS) {
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
*width = info.width;
*height = info.height;
- } else if (_cairo_status_is_error (status)) {
return status;
}
- status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
- if (unlikely (status))
- return status;
-
- *width = image->width;
- *height = image->height;
+ if (! _cairo_surface_get_extents (source, &extents))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- _cairo_surface_release_source_image (source, image, image_extra);
+ *width = extents.width;
+ *height = extents.height;
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -1123,7 +1145,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
static cairo_status_t
_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
- cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip,
cairo_pdf_resource_t *pattern_res,
cairo_pdf_resource_t *gstate_res)
{
@@ -1182,8 +1204,8 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
pdf_pattern.width = surface->width;
pdf_pattern.height = surface->height;
- if (extents) {
- pdf_pattern.extents = *extents;
+ if (clip != NULL) {
+ pdf_pattern.extents = clip->path->extents;
} else {
pdf_pattern.extents.x = 0;
pdf_pattern.extents.y = 0;
@@ -1540,15 +1562,6 @@ _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
return _cairo_output_stream_get_status (surface->output);
}
-static cairo_surface_t *
-_cairo_pdf_surface_create_similar (void *abstract_surface,
- cairo_content_t content,
- int width,
- int height)
-{
- return cairo_meta_surface_create (content, width, height);
-}
-
static void
_cairo_pdf_source_surface_entry_pluck (void *entry, void *closure)
{
@@ -1653,6 +1666,8 @@ _cairo_pdf_surface_finish (void *abstract_surface)
surface->font_subsets = NULL;
}
+ _cairo_surface_clipper_reset (&surface->clipper);
+
return status;
}
@@ -2090,7 +2105,7 @@ _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface,
return status;
pad_image = &image->base;
- if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) {
+ if (pattern->base.extend == CAIRO_EXTEND_PAD) {
cairo_box_t box;
cairo_rectangle_int_t rect;
cairo_surface_pattern_t pad_pattern;
@@ -2121,7 +2136,8 @@ _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface,
0, 0,
0, 0,
rect.width,
- rect.height);
+ rect.height,
+ NULL);
_cairo_pattern_fini (&pad_pattern.base);
if (unlikely (status))
goto BAIL;
@@ -2173,19 +2189,18 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
{
double old_width, old_height;
cairo_paginated_mode_t old_paginated_mode;
- cairo_clip_t *old_clip;
cairo_rectangle_int_t meta_extents;
+ cairo_bool_t is_bounded;
cairo_status_t status;
int alpha = 0;
- status = _cairo_surface_get_extents (meta_surface, &meta_extents);
- if (unlikely (status))
- return status;
+ is_bounded = _cairo_surface_get_extents (meta_surface, &meta_extents);
+ assert (is_bounded);
old_width = surface->width;
old_height = surface->height;
old_paginated_mode = surface->paginated_mode;
- old_clip = _cairo_surface_get_clip (&surface->base);
+
_cairo_pdf_surface_set_size_internal (surface,
meta_extents.width,
meta_extents.height);
@@ -2217,10 +2232,6 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
if (unlikely (status))
return status;
- status = _cairo_surface_set_clip (&surface->base, old_clip);
- if (unlikely (status))
- return status;
-
status = _cairo_pdf_surface_close_content_stream (surface);
_cairo_pdf_surface_set_size_internal (surface,
@@ -2264,7 +2275,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
int bbox_x, bbox_y;
char draw_surface[200];
- if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD &&
+ if (pattern->base.extend == CAIRO_EXTEND_PAD &&
! _cairo_surface_is_meta (pattern->surface))
{
status = _cairo_pdf_surface_emit_padded_image_surface (surface,
@@ -3249,7 +3260,7 @@ _cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -3405,7 +3416,7 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
+static cairo_bool_t
_cairo_pdf_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -3421,32 +3432,7 @@ _cairo_pdf_surface_get_extents (void *abstract_surface,
rectangle->width = (int) ceil (surface->width);
rectangle->height = (int) ceil (surface->height);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_pdf_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
- cairo_int_status_t status;
-
- if (path == NULL) {
- status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (unlikely (status))
- return status;
-
- _cairo_output_stream_printf (surface->output, "Q q\n");
- surface->current_pattern_is_solid_color = FALSE;
- _cairo_pdf_operators_reset (&surface->pdf_operators);
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule);
+ return TRUE;
}
static void
@@ -5227,7 +5213,7 @@ static cairo_int_status_t
_cairo_pdf_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -5244,17 +5230,21 @@ _cairo_pdf_surface_paint (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
&pattern_res, &gstate_res);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
status = _cairo_pdf_surface_select_operator (surface, op);
- if (status)
+ if (unlikely (status))
return status;
if (gstate_res.id != 0) {
@@ -5292,7 +5282,8 @@ _cairo_pdf_surface_paint (void *abstract_surface,
gstate_res.id,
group->group_res.id);
} else {
- status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
+ status = _cairo_pdf_surface_select_pattern (surface, source,
+ pattern_res, FALSE);
if (unlikely (status))
return status;
@@ -5313,7 +5304,7 @@ _cairo_pdf_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_smask_group_t *group;
@@ -5341,6 +5332,10 @@ _cairo_pdf_surface_mask (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
assert (_cairo_pdf_surface_operation_supported (surface, op, mask));
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
group = _cairo_pdf_surface_create_smask_group (surface);
if (unlikely (group == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -5381,7 +5376,7 @@ _cairo_pdf_surface_mask (void *abstract_surface,
return status;
status = _cairo_pdf_surface_select_operator (surface, op);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -5402,7 +5397,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -5414,17 +5409,21 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
&pattern_res, &gstate_res);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
status = _cairo_pdf_surface_select_operator (surface, op);
- if (status)
+ if (unlikely (status))
return status;
if (gstate_res.id != 0) {
@@ -5499,7 +5498,7 @@ _cairo_pdf_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -5516,17 +5515,21 @@ _cairo_pdf_surface_fill (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
&pattern_res, &gstate_res);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
status = _cairo_pdf_surface_select_operator (surface, op);
- if (status)
+ if (unlikely (status))
return status;
if (gstate_res.id != 0) {
@@ -5604,7 +5607,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -5632,14 +5635,18 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
if (fill_op != stroke_op)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
status = _cairo_pdf_surface_select_operator (surface, fill_op);
- if (status)
+ if (unlikely (status))
return status;
fill_pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
- extents,
+ clip,
&fill_pattern_res,
&gstate_res);
if (unlikely (status))
@@ -5651,7 +5658,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface,
stroke_source,
- extents,
+ clip,
&stroke_pattern_res,
&gstate_res);
if (unlikely (status))
@@ -5705,7 +5712,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -5717,17 +5724,21 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, source));
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
&pattern_res, &gstate_res);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
status = _cairo_pdf_surface_select_operator (surface, op);
- if (status)
+ if (unlikely (status))
return status;
if (gstate_res.id != 0) {
@@ -5840,7 +5851,7 @@ _cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
static const cairo_surface_backend_t cairo_pdf_surface_backend = {
CAIRO_SURFACE_TYPE_PDF,
- _cairo_pdf_surface_create_similar,
+ NULL, /* create similar: handled by wrapper */
_cairo_pdf_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
@@ -5854,8 +5865,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* _cairo_pdf_surface_copy_page */
_cairo_pdf_surface_show_page,
- NULL, /* set_clip_region */
- _cairo_pdf_surface_intersect_clip_path,
_cairo_pdf_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_pdf_surface_get_font_options,
@@ -5874,7 +5883,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
NULL, /* snapshot */
NULL, /* is_compatible */
- NULL, /* reset */
_cairo_pdf_surface_fill_stroke,
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
diff --git a/src/cairo-ps-surface-private.h b/src/cairo-ps-surface-private.h
index 8567aff5..e892103b 100644
--- a/src/cairo-ps-surface-private.h
+++ b/src/cairo-ps-surface-private.h
@@ -44,6 +44,7 @@
#include "cairo-ps.h"
#include "cairo-surface-private.h"
+#include "cairo-surface-clipper-private.h"
#include "cairo-pdf-operators-private.h"
#include <time.h>
@@ -65,6 +66,7 @@ typedef struct cairo_ps_surface {
cairo_content_t content;
double width;
double height;
+ cairo_rectangle_int_t page_bbox;
int bbox_x1, bbox_y1, bbox_x2, bbox_y2;
cairo_matrix_t cairo_to_ps;
@@ -97,6 +99,8 @@ typedef struct cairo_ps_surface {
cairo_ps_level_t ps_level;
cairo_ps_level_t ps_level_used;
+ cairo_surface_clipper_t clipper;
+
cairo_pdf_operators_t pdf_operators;
cairo_surface_t *paginated_surface;
} cairo_ps_surface_t;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index cfe730cb..a577d40f 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -61,6 +61,7 @@
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-paginated-private.h"
#include "cairo-meta-surface-private.h"
+#include "cairo-surface-clipper-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include "cairo-image-info-private.h"
@@ -73,6 +74,13 @@
#define DEBUG_PS 0
+#if DEBUG_PS
+#define DEBUG_FALLBACK(s) \
+ fprintf (stderr, "%s::%d -- %s\n", __FUNCTION__, __LINE__, (s))
+#else
+#define DEBUG_FALLBACK(s)
+#endif
+
#ifndef HAVE_CTIME_R
#define ctime_r(T, BUF) ctime (T)
#endif
@@ -700,6 +708,74 @@ _cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface)
"%%%%EOF\n");
}
+static cairo_bool_t
+_path_covers_bbox (cairo_ps_surface_t *surface,
+ cairo_path_fixed_t *path)
+{
+ cairo_box_t box;
+
+ if (_cairo_path_fixed_is_rectangle (path, &box)) {
+ cairo_rectangle_int_t rect;
+
+ _cairo_box_round_to_rectangle (&box, &rect);
+
+ /* skip trivial whole-page clips */
+ if (_cairo_rectangle_intersect (&rect, &surface->page_bbox)) {
+ if (rect.x == surface->page_bbox.x &&
+ rect.width == surface->page_bbox.width &&
+ rect.y == surface->page_bbox.y &&
+ rect.height == surface->page_bbox.height)
+ {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static cairo_status_t
+_cairo_ps_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_ps_surface_t *surface = cairo_container_of (clipper,
+ cairo_ps_surface_t,
+ clipper);
+ cairo_output_stream_t *stream = surface->stream;
+ cairo_status_t status;
+
+ assert (surface->paginated_mode != CAIRO_PAGINATED_MODE_ANALYZE);
+
+#if DEBUG_PS
+ _cairo_output_stream_printf (stream,
+ "%% _cairo_ps_surface_intersect_clip_path\n");
+#endif
+
+ if (path == NULL) {
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (stream, "Q q\n");
+
+ surface->current_pattern_is_solid_color = FALSE;
+ _cairo_pdf_operators_reset (&surface->pdf_operators);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (_path_covers_bbox (surface, path))
+ return CAIRO_STATUS_SUCCESS;
+
+ return _cairo_pdf_operators_clip (&surface->pdf_operators,
+ path,
+ fill_rule);
+}
+
+
static cairo_surface_t *
_cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
double width,
@@ -756,6 +832,9 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->use_string_datasource = FALSE;
surface->current_pattern_is_solid_color = FALSE;
+ _cairo_surface_clipper_init (&surface->clipper,
+ _cairo_ps_surface_clipper_intersect_clip_path);
+
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->stream,
&surface->cairo_to_ps,
@@ -771,7 +850,6 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->paginated_surface = _cairo_paginated_surface_create (
&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
- width, height,
&cairo_ps_surface_paginated_backend);
status = surface->paginated_surface->status;
if (status == CAIRO_STATUS_SUCCESS) {
@@ -1083,11 +1161,6 @@ cairo_ps_surface_set_size (cairo_surface_t *surface,
cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points);
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators,
&ps_surface->cairo_to_ps);
- status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
- width_in_points,
- height_in_points);
- if (unlikely (status))
- status = _cairo_surface_set_error (surface, status);
}
/**
@@ -1288,15 +1361,6 @@ cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface)
}
}
-static cairo_surface_t *
-_cairo_ps_surface_create_similar (void *abstract_surface,
- cairo_content_t content,
- int width,
- int height)
-{
- return cairo_meta_surface_create (content, width, height);
-}
-
static cairo_status_t
_cairo_ps_surface_finish (void *abstract_surface)
{
@@ -1346,6 +1410,8 @@ CLEANUP:
free (comments[i]);
_cairo_array_fini (&surface->dsc_page_setup_comments);
+ _cairo_surface_clipper_reset (&surface->clipper);
+
return status;
}
@@ -1369,8 +1435,11 @@ _cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
if (unlikely (status))
return status;
- _cairo_output_stream_printf (surface->stream,
- "Q\n");
+ if (surface->clipper.clip.path != NULL) {
+ _cairo_output_stream_printf (surface->stream, "Q Q\n");
+ _cairo_surface_clipper_reset (&surface->clipper);
+ } else
+ _cairo_output_stream_printf (surface->stream, "Q\n");
return CAIRO_STATUS_SUCCESS;
}
@@ -1448,8 +1517,6 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t
static cairo_bool_t
surface_pattern_supported (const cairo_surface_pattern_t *pattern)
{
- cairo_extend_t extend;
-
if (_cairo_surface_is_meta (pattern->surface))
return TRUE;
@@ -1465,24 +1532,7 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern)
return FALSE;
*/
- /* Cast away the const, trusting get_extend not to muck with it.
- * And I really wish I had a way to cast away just the const, and
- * not potentially coerce this pointer to an incorrect type at the
- * same time. :-(
- */
- extend = cairo_pattern_get_extend ((cairo_pattern_t*)&pattern->base);
- switch (extend) {
- case CAIRO_EXTEND_NONE:
- case CAIRO_EXTEND_REPEAT:
- case CAIRO_EXTEND_REFLECT:
- /* There's no point returning FALSE for EXTEND_PAD, as the image
- * surface does not currently implement it either */
- case CAIRO_EXTEND_PAD:
- return TRUE;
- }
-
- ASSERT_NOT_REACHED;
- return FALSE;
+ return TRUE;
}
static cairo_bool_t
@@ -1567,10 +1617,11 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
}
if (! pattern_supported (surface, pattern))
+ {
return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
- if (!(op == CAIRO_OPERATOR_SOURCE ||
- op == CAIRO_OPERATOR_OVER))
+ if (! (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
return CAIRO_INT_STATUS_UNSUPPORTED;
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
@@ -1596,7 +1647,6 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
* render stage and we blend the transparency into the white
* background to convert the pattern to opaque.
*/
-
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
@@ -1606,8 +1656,8 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
if (_cairo_pattern_is_opaque (pattern))
return CAIRO_STATUS_SUCCESS;
- else
- return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
+
+ return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
}
static cairo_bool_t
@@ -1824,7 +1874,8 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
0, 0,
0, 0,
image->width,
- image->height);
+ image->height,
+ NULL);
if (unlikely (status))
goto fail;
@@ -2109,6 +2160,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
data_compressed,
data_compressed_size,
FALSE);
+ _cairo_output_stream_printf (surface->stream, "\n");
} else {
status = CAIRO_STATUS_SUCCESS;
}
@@ -2221,31 +2273,31 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
double old_width, old_height;
cairo_matrix_t old_cairo_to_ps;
cairo_content_t old_content;
- cairo_clip_t *old_clip;
- cairo_rectangle_int_t meta_extents;
+ cairo_box_t bbox;
cairo_status_t status;
- status = _cairo_surface_get_extents (meta_surface, &meta_extents);
- if (unlikely (status))
- return status;
-
old_content = surface->content;
old_width = surface->width;
old_height = surface->height;
old_cairo_to_ps = surface->cairo_to_ps;
- old_clip = _cairo_surface_get_clip (&surface->base);
- surface->width = meta_extents.width;
- surface->height = meta_extents.height;
+
+ status =
+ _cairo_meta_surface_get_bbox ((cairo_meta_surface_t *) meta_surface,
+ &bbox,
+ NULL);
+ if (unlikely (status))
+ return status;
+
+ /* XXX is this still necessary? */
+ surface->width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
+ surface->height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
+
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
&surface->cairo_to_ps);
- _cairo_output_stream_printf (surface->stream,
- " q\n"
- " 0 0 %f %f rectclip\n",
- surface->width,
- surface->height);
+ _cairo_output_stream_printf (surface->stream, " q\n");
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
surface->content = CAIRO_CONTENT_COLOR;
@@ -2265,17 +2317,13 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
if (unlikely (status))
return status;
- _cairo_output_stream_printf (surface->stream,
- " Q\n");
+ _cairo_output_stream_printf (surface->stream, " Q\n");
surface->content = old_content;
surface->width = old_width;
surface->height = old_height;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
surface->cairo_to_ps = old_cairo_to_ps;
- status = _cairo_surface_set_clip (&surface->base, old_clip);
- if (unlikely (status))
- return status;
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
&surface->cairo_to_ps);
@@ -2331,11 +2379,11 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
cairo_rectangle_int_t *extents,
int *width,
int *height,
- int *origin_x,
- int *origin_y)
+ int *origin_x,
+ int *origin_y)
{
cairo_status_t status;
- cairo_surface_t *pad_image;
+ cairo_surface_t *pad_image;
int x = 0;
int y = 0;
@@ -2343,15 +2391,18 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
surface->image = NULL;
if (_cairo_surface_is_meta (pattern->surface)) {
- cairo_surface_t *meta_surface = pattern->surface;
- cairo_rectangle_int_t pattern_extents;
+ cairo_meta_surface_t *meta_surface = (cairo_meta_surface_t *) pattern->surface;
+ cairo_box_t bbox;
+ cairo_rectangle_int_t extents;
- status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
+ status = _cairo_meta_surface_get_bbox (meta_surface, &bbox, NULL);
if (unlikely (status))
return status;
- *width = pattern_extents.width;
- *height = pattern_extents.height;
+ _cairo_box_round_to_rectangle (&bbox, &extents);
+ *width = extents.width;
+ *height =extents.height;
+ return CAIRO_STATUS_SUCCESS;
} else {
status = _cairo_surface_acquire_source_image (pattern->surface,
&surface->acquired_image,
@@ -2391,7 +2442,8 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
0, 0,
0, 0,
rect.width,
- rect.height);
+ rect.height,
+ NULL);
_cairo_pattern_fini (&pad_pattern.base);
if (unlikely (status)) {
if (pad_image != &surface->acquired_image->base)
@@ -2406,13 +2458,11 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
*height = surface->image->height;
*origin_x = x;
*origin_y = y;
+ return CAIRO_STATUS_SUCCESS;
}
- return CAIRO_STATUS_SUCCESS;
-
BAIL:
_cairo_ps_surface_release_surface (surface, pattern);
-
return status;
}
@@ -2428,10 +2478,9 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
if (_cairo_surface_is_meta (pattern->surface)) {
cairo_surface_t *meta_surface = pattern->surface;
- status = _cairo_ps_surface_emit_meta_surface (surface,
- meta_surface);
+ status = _cairo_ps_surface_emit_meta_surface (surface, meta_surface);
} else {
- if (cairo_pattern_get_extend (&pattern->base) != CAIRO_EXTEND_PAD) {
+ if (pattern->base.extend != CAIRO_EXTEND_PAD) {
status = _cairo_ps_surface_emit_jpeg_image (surface, pattern->surface,
width, height);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@@ -2540,7 +2589,6 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
int pattern_height = 0; /* squelch bogus compiler warning */
double xstep, ystep;
cairo_matrix_t cairo_p2d, ps_p2d;
- cairo_rectangle_int_t surface_extents;
cairo_bool_t old_use_string_datasource;
int origin_x = 0;
int origin_y = 0;
@@ -2550,12 +2598,6 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
- ps_p2d = surface->cairo_to_ps;
- cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
- cairo_matrix_translate (&ps_p2d, -origin_x, -origin_y);
- cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
- cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
-
status = _cairo_ps_surface_acquire_surface (surface,
pattern,
extents,
@@ -2669,17 +2711,13 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
_cairo_output_stream_printf (surface->stream,
">>\n");
- status = _cairo_surface_get_extents (&surface->base, &surface_extents);
- if (unlikely (status))
- return status;
-
cairo_p2d = pattern->base.matrix;
status = cairo_matrix_invert (&cairo_p2d);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_init_identity (&ps_p2d);
- cairo_matrix_translate (&ps_p2d, 0.0, surface_extents.height);
+ cairo_matrix_translate (&ps_p2d, 0.0, surface->height);
cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
@@ -3163,43 +3201,7 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_ps_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_ps_surface_t *surface = abstract_surface;
- cairo_output_stream_t *stream = surface->stream;
- cairo_status_t status;
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return CAIRO_STATUS_SUCCESS;
-
-#if DEBUG_PS
- _cairo_output_stream_printf (stream,
- "%% _cairo_ps_surface_intersect_clip_path\n");
-#endif
-
- if (path == NULL) {
- status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (unlikely (status))
- return status;
-
- _cairo_output_stream_printf (stream, "Q q\n");
- surface->current_pattern_is_solid_color = FALSE;
- _cairo_pdf_operators_reset (&surface->pdf_operators);
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return _cairo_pdf_operators_clip (&surface->pdf_operators,
- path,
- fill_rule);
-}
-
-static cairo_int_status_t
+static cairo_bool_t
_cairo_ps_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -3215,7 +3217,7 @@ _cairo_ps_surface_get_extents (void *abstract_surface,
rectangle->width = (int) ceil (surface->width);
rectangle->height = (int) ceil (surface->height);
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
static void
@@ -3229,11 +3231,26 @@ _cairo_ps_surface_get_font_options (void *abstract_surface,
cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
}
+static cairo_bool_t
+_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
+{
+ const cairo_rectangle_int_t *clip_extents;
+
+ clip_extents = NULL;
+ if (clip != NULL)
+ clip_extents = _cairo_clip_get_extents (clip);
+
+ if (clip_extents != NULL)
+ return _cairo_rectangle_intersect (extents, clip_extents);
+
+ return TRUE;
+}
+
static cairo_int_status_t
_cairo_ps_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *paint_extents)
+ cairo_clip_t *clip)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
@@ -3250,11 +3267,11 @@ _cairo_ps_surface_paint (void *abstract_surface,
"%% _cairo_ps_surface_paint\n");
#endif
- status = _cairo_surface_get_extents (&surface->base, &extents);
- if (unlikely (status))
- return status;
+ extents = surface->page_bbox;
+ if (! _rectangle_intersect_clip (&extents, clip))
+ return CAIRO_STATUS_SUCCESS;
- status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
@@ -3262,28 +3279,25 @@ _cairo_ps_surface_paint (void *abstract_surface,
(source->extend == CAIRO_EXTEND_NONE ||
source->extend == CAIRO_EXTEND_PAD))
{
- _cairo_output_stream_printf (stream, "q 0 0 %d %d rectclip\n",
- extents.width,
- extents.height);
-
+ _cairo_output_stream_printf (stream, "q\n");
status = _cairo_ps_surface_paint_surface (surface,
(cairo_surface_pattern_t *) source,
- paint_extents, op);
+ &extents, op);
if (unlikely (status))
return status;
_cairo_output_stream_printf (stream, "Q\n");
} else {
- status = _cairo_ps_surface_emit_pattern (surface, source, paint_extents, op);
+ status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
if (unlikely (status))
return status;
- _cairo_output_stream_printf (stream, "0 0 %d %d rectfill\n",
- extents.width,
- extents.height);
+ _cairo_output_stream_printf (stream, "%d %d %d %d rectfill\n",
+ extents.x, extents.y,
+ extents.width, extents.height);
}
return CAIRO_STATUS_SUCCESS;
@@ -3299,10 +3313,11 @@ _cairo_ps_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_int_status_t status;
+ cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
@@ -3314,7 +3329,15 @@ _cairo_ps_surface_stroke (void *abstract_surface,
"%% _cairo_ps_surface_stroke\n");
#endif
- status = _cairo_ps_surface_emit_pattern (surface, source, extents, op);
+ extents = surface->page_bbox;
+ if (! _rectangle_intersect_clip (&extents, clip))
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@@ -3336,10 +3359,11 @@ _cairo_ps_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_int_status_t status;
+ cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
@@ -3351,14 +3375,22 @@ _cairo_ps_surface_fill (void *abstract_surface,
"%% _cairo_ps_surface_fill\n");
#endif
+ extents = surface->page_bbox;
+ if (! _rectangle_intersect_clip (&extents, clip))
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_NONE ||
source->extend == CAIRO_EXTEND_PAD))
{
- status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (unlikely (status))
- return status;
-
_cairo_output_stream_printf (surface->stream, "q\n");
status = _cairo_pdf_operators_clip (&surface->pdf_operators,
@@ -3369,14 +3401,14 @@ _cairo_ps_surface_fill (void *abstract_surface,
status = _cairo_ps_surface_paint_surface (surface,
(cairo_surface_pattern_t *) source,
- extents, op);
+ &extents, op);
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream, "Q\n");
_cairo_pdf_operators_reset (&surface->pdf_operators);
} else {
- status = _cairo_ps_surface_emit_pattern (surface, source, extents, op);
+ status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@@ -3398,11 +3430,12 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_status_t status;
+ cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
@@ -3417,7 +3450,15 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
if (num_glyphs <= 0)
return CAIRO_STATUS_SUCCESS;
- status = _cairo_ps_surface_emit_pattern (surface, source, extents, op);
+ extents = surface->page_bbox;
+ if (! _rectangle_intersect_clip (&extents, clip))
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@@ -3439,6 +3480,11 @@ _cairo_ps_surface_set_paginated_mode (void *abstract_surface,
cairo_ps_surface_t *surface = abstract_surface;
surface->paginated_mode = paginated_mode;
+
+ if (surface->clipper.clip.path != NULL) {
+ _cairo_output_stream_printf (surface->stream, "Q\n");
+ _cairo_surface_clipper_reset (&surface->clipper);
+ }
}
static cairo_int_status_t
@@ -3462,6 +3508,11 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
y2 = (int) ceil (surface->height);
}
+ surface->page_bbox.x = x1;
+ surface->page_bbox.y = y1;
+ surface->page_bbox.width = x2 - x1;
+ surface->page_bbox.height = y2 - y1;
+
_cairo_output_stream_printf (surface->stream,
"%%%%Page: %d %d\n",
surface->num_pages,
@@ -3486,7 +3537,11 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
_cairo_output_stream_printf (surface->stream,
"%%%%EndPageSetup\n"
- "q\n");
+ "q %d %d %d %d rectclip q\n",
+ surface->page_bbox.x,
+ surface->page_bbox.y,
+ surface->page_bbox.width,
+ surface->page_bbox.height);
if (surface->num_pages == 1) {
surface->bbox_x1 = x1;
@@ -3517,7 +3572,7 @@ _cairo_ps_surface_supports_fine_grained_fallbacks (void *abstract_surface)
static const cairo_surface_backend_t cairo_ps_surface_backend = {
CAIRO_SURFACE_TYPE_PS,
- _cairo_ps_surface_create_similar,
+ NULL, /* create similar: handled by wrapper */
_cairo_ps_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
@@ -3531,8 +3586,6 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* cairo_ps_surface_copy_page */
_cairo_ps_surface_show_page,
- NULL, /* set_clip_region */
- _cairo_ps_surface_intersect_clip_path,
_cairo_ps_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_ps_surface_get_font_options,
diff --git a/src/cairo-qt-surface.cpp b/src/cairo-qt-surface.cpp
index 70f6d1a7..a0d573da 100644
--- a/src/cairo-qt-surface.cpp
+++ b/src/cairo-qt-surface.cpp
@@ -39,6 +39,9 @@
#include "cairoint.h"
#include "cairo-types-private.h"
+#include "cairo-clip-private.h"
+#include "cairo-surface-clipper-private.h"
+#include "cairo-region-private.h"
#include "cairo-qt.h"
@@ -65,6 +68,8 @@
#include <sys/time.h>
+#define ENABLE_FAST_FILL 1 /* Enable workaround slow regional Qt paths */
+
#if 0
#define D(x) x
static const char *
@@ -104,14 +109,9 @@ _opstr (cairo_operator_t op)
#define DOT_LENGTH 1.0
#define DASH_LENGTH 3.0
-typedef struct {
+struct cairo_qt_surface_t {
cairo_surface_t base;
- bool has_clipping;
- // if this is true, calls to intersect_clip_path won't
- // update the clip_bounds rect
- bool no_update_clip_bounds;
-
cairo_bool_t supports_porter_duff;
#if defined(Q_WS_X11) && CAIRO_HAS_XLIB_XRENDER_SURFACE
@@ -131,11 +131,10 @@ typedef struct {
QRect window;
-
- QRect clip_bounds;
+ cairo_surface_clipper_t clipper;
cairo_surface_t *image_equiv;
-} cairo_qt_surface_t;
+};
/* Will be true if we ever try to create a QPixmap and end
* up with one without an alpha channel.
@@ -186,6 +185,21 @@ _qpainter_compositionmode_from_cairo_op (cairo_operator_t op)
default:
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
+ case CAIRO_OPERATOR_MULTIPLY:
+ case CAIRO_OPERATOR_SCREEN:
+ case CAIRO_OPERATOR_OVERLAY:
+ case CAIRO_OPERATOR_DARKEN:
+ case CAIRO_OPERATOR_LIGHTEN:
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ case CAIRO_OPERATOR_COLOR_BURN:
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ case CAIRO_OPERATOR_DIFFERENCE:
+ case CAIRO_OPERATOR_EXCLUSION:
+ case CAIRO_OPERATOR_HSL_HUE:
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ case CAIRO_OPERATOR_HSL_COLOR:
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
ASSERT_NOT_REACHED;
}
}
@@ -211,12 +225,27 @@ _op_is_supported (cairo_qt_surface_t *qs, cairo_operator_t op)
case CAIRO_OPERATOR_XOR:
return TRUE;
+ default:
+ ASSERT_NOT_REACHED;
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
+ case CAIRO_OPERATOR_MULTIPLY:
+ case CAIRO_OPERATOR_SCREEN:
+ case CAIRO_OPERATOR_OVERLAY:
+ case CAIRO_OPERATOR_DARKEN:
+ case CAIRO_OPERATOR_LIGHTEN:
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ case CAIRO_OPERATOR_COLOR_BURN:
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ case CAIRO_OPERATOR_DIFFERENCE:
+ case CAIRO_OPERATOR_EXCLUSION:
+ case CAIRO_OPERATOR_HSL_HUE:
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ case CAIRO_OPERATOR_HSL_COLOR:
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
return FALSE;
- default:
- ASSERT_NOT_REACHED;
}
} else {
return op == CAIRO_OPERATOR_OVER;
@@ -458,6 +487,8 @@ _cairo_qt_surface_finish (void *abstract_surface)
if (qs->image_equiv)
cairo_surface_destroy (qs->image_equiv);
+ _cairo_surface_clipper_reset (&qs->clipper);
+
#if defined(Q_WS_X11) && CAIRO_HAS_XLIB_XRENDER_SURFACE
if (qs->xlib_equiv)
cairo_surface_destroy (qs->xlib_equiv);
@@ -655,7 +686,7 @@ _cairo_qt_surface_clone_similar (void *abstract_surface,
return (cairo_status_t) CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_int_status_t
+static cairo_bool_t
_cairo_qt_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *extents)
{
@@ -666,25 +697,40 @@ _cairo_qt_surface_get_extents (void *abstract_surface,
extents->width = qs->window.width();
extents->height = qs->window.height();
- return CAIRO_INT_STATUS_SUCCESS;
+ return TRUE;
}
-static cairo_int_status_t
-_cairo_qt_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
+static cairo_status_t
+_cairo_qt_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
{
- cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
+ cairo_qt_surface_t *qs = cairo_container_of (clipper,
+ cairo_qt_surface_t,
+ clipper);
+ QPainterPath qpath;
+ cairo_status_t status;
- D(fprintf(stderr, "q[%p] intersect_clip_path %s\n", abstract_surface, path ? "(path)" : "(clear)"));
+ // XXX Antialiasing is ignored
+ status = _cairo_quartz_cairo_path_to_qpainterpath (path,
+ &qpath,
+ fill_rule);
+ if (unlikely (status))
+ return status;
- if (!qs->p)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ qs->p->setClipPath (qpath, Qt::IntersectClip);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_qt_surface_set_clip_region (cairo_qt_surface_t *qs,
+ cairo_region_t *clip_region)
+{
+ _cairo_surface_clipper_reset (&qs->clipper);
- if (path == NULL) {
- //fprintf (stderr, "clip clear\n");
+ if (clip_region == NULL) {
// How the clip path is reset depends on whether we own p or not
if (qs->pixmap || qs->image) {
// we own p
@@ -693,10 +739,38 @@ _cairo_qt_surface_intersect_clip_path (void *abstract_surface,
qs->p->restore ();
qs->p->save ();
}
+ } else {
+ QRegion qr;
+ int num_rects = cairo_region_num_rectangles (clip_region);
+ for (int i = 0; i < num_rects; ++i) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (clip_region, i, &rect);
- if (!qs->no_update_clip_bounds) {
- qs->clip_bounds.setRect(0, 0, 0, 0);
- qs->has_clipping = false;
+ QRect r(rect.x, rect.y, rect.width, rect.height);
+ qr = qr.unite(r);
+ }
+
+ qs->p->setClipRegion (qr, Qt::IntersectClip);
+ }
+}
+
+static cairo_int_status_t
+_cairo_qt_surface_set_clip (cairo_qt_surface_t *qs,
+ cairo_clip_t *clip)
+{
+
+ D(fprintf(stderr, "q[%p] intersect_clip_path %s\n", abstract_surface, path ? "(path)" : "(clear)"));
+
+ if (clip == NULL) {
+ _cairo_surface_clipper_reset (&qs->clipper);
+ // How the clip path is reset depends on whether we own p or not
+ if (qs->pixmap || qs->image) {
+ // we own p
+ qs->p->setClipping (false);
+ } else {
+ qs->p->restore ();
+ qs->p->save ();
}
return CAIRO_INT_STATUS_SUCCESS;
@@ -711,125 +785,21 @@ _cairo_qt_surface_intersect_clip_path (void *abstract_surface,
// we do a bunch of work here to try to get rectangles or regions
// down to Qt for clipping.
- QRect clip_bounds;
+ cairo_region_t *clip_region = NULL;
- // First check if it's an integer-aligned single rectangle
- cairo_box_t box;
- if (_cairo_path_fixed_is_box (path, &box) &&
- _cairo_fixed_is_integer (box.p1.x) &&
- _cairo_fixed_is_integer (box.p1.y) &&
- _cairo_fixed_is_integer (box.p2.x) &&
- _cairo_fixed_is_integer (box.p2.y))
- {
- QRect r(_cairo_fixed_integer_part(box.p1.x),
- _cairo_fixed_integer_part(box.p1.y),
- _cairo_fixed_integer_part(box.p2.x - box.p1.x),
- _cairo_fixed_integer_part(box.p2.y - box.p1.y));
-
- r = r.normalized();
-
- clip_bounds = r;
-
- qs->p->setClipRect (r, Qt::IntersectClip);
- } else {
- // Then if it's not an integer-aligned rectangle, check
- // if we can extract a region (a set of rectangles) out.
- // We use cairo to convert the path to traps.
-
- cairo_traps_t traps;
- cairo_int_status_t status;
- cairo_region_t *region = NULL;
-
- _cairo_traps_init (&traps);
+ cairo_int_status_t status;
+ status = _cairo_clip_get_region (clip, &clip_region);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ // We weren't able to extract a region from the traps.
+ // Just hand the path down to QPainter.
status = (cairo_int_status_t)
- _cairo_path_fixed_fill_to_traps (path,
- fill_rule, tolerance, &traps);
- if (status) {
- _cairo_traps_fini (&traps);
- return status;
- }
-
- status = _cairo_traps_extract_region (&traps, &region);
- _cairo_traps_fini (&traps);
-
- if (_cairo_status_is_error ((cairo_status_t) status))
- return status;
-
- if (status == CAIRO_INT_STATUS_SUCCESS) {
-#if 0
- cairo_box_int_t *boxes;
- int n_boxes;
-
- QRegion qr;
-
- _cairo_region_get_boxes (&region, &n_boxes, &boxes);
-
- for (int i = 0; i < n_boxes; i++) {
- QRect r(boxes[i].p1.x,
- boxes[i].p1.y,
- boxes[i].p2.x - boxes[i].p1.x,
- boxes[i].p2.y - boxes[i].p1.y);
-
- if (i == 0)
- clip_bounds = r;
- else
- clip_bounds = clip_bounds.united(r);
-
- qr = qr.unite(r);
- }
- _cairo_region_boxes_fini (&region, boxes);
-#else
- int n_boxes;
-
- QRegion qr;
-
- n_boxes = cairo_region_num_rectangles (region);
- for (int i = 0; i < n_boxes; ++i) {
- cairo_rectangle_int_t box;
- cairo_region_get_rectangle (region, i, &box);
- QRect r(box.x, box.y, box.width, box.height);
-
- if (0 == i)
- clip_bounds = r;
- else
- clip_bounds = clip_bounds.united(r);
-
- qr = qr.unite(r);
- }
-#endif
- _cairo_region_fini (region);
-
- qs->p->setClipRegion (qr, Qt::IntersectClip);
- } else {
- // We weren't able to extract a region from the traps.
- // Just hand the path down to QPainter.
- QPainterPath qpath;
- cairo_status_t status;
-
- status = _cairo_quartz_cairo_path_to_qpainterpath (path,
- &qpath,
- fill_rule);
- assert (status == CAIRO_STATUS_SUCCESS);
-
- clip_bounds = qpath.boundingRect().toAlignedRect();
-
- // XXX Antialiasing is ignored
- qs->p->setClipPath (qpath, Qt::IntersectClip);
- }
+ _cairo_surface_clipper_set_clip (&qs->clipper, clip);
+ } else if (status == CAIRO_INT_STATUS_SUCCESS) {
+ _cairo_qt_surface_set_clip_region (qs, clip_region);
+ status = CAIRO_INT_STATUS_SUCCESS;
}
- if (!qs->no_update_clip_bounds) {
- clip_bounds = qs->p->worldTransform().mapRect(clip_bounds);
-
- if (qs->has_clipping) {
- qs->clip_bounds = qs->clip_bounds.intersect(clip_bounds);
- } else {
- qs->clip_bounds = clip_bounds;
- qs->has_clipping = true;
- }
- }
-
- return CAIRO_INT_STATUS_SUCCESS;
+ return status;
}
/**
@@ -1156,10 +1126,12 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs,
double tolerance = 0.0,
cairo_antialias_t antialias = CAIRO_ANTIALIAS_NONE)
{
+#if ENABLE_FAST_FILL
QImage *qsSrc_image = NULL;
QPixmap *qsSrc_pixmap = NULL;
std::auto_ptr<QImage> qsSrc_image_d;
+
if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t*) source;
if (spattern->surface->type == CAIRO_SURFACE_TYPE_QT) {
@@ -1190,7 +1162,6 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs,
}
QMatrix sourceMatrix = _qmatrix_from_cairo_matrix (source->matrix);
- cairo_int_status_t status;
// We can draw this faster by clipping and calling drawImage/drawPixmap.
// Use our own clipping function so that we can get the
@@ -1201,14 +1172,29 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs,
qs->p->save();
if (path) {
- qs->no_update_clip_bounds = true;
- status = _cairo_qt_surface_intersect_clip_path (qs, path, fill_rule, tolerance, antialias);
- qs->no_update_clip_bounds = false;
+ cairo_int_status_t status;
- if (status != CAIRO_INT_STATUS_SUCCESS) {
- qs->p->restore();
- return false;
- }
+ cairo_clip_t clip, old_clip = qs->clipper.clip;
+
+ _cairo_clip_init_copy (&clip, &qs->clipper.clip);
+ status = (cairo_int_status_t) _cairo_clip_clip (&clip,
+ path,
+ fill_rule,
+ tolerance,
+ antialias);
+ if (unlikely (status)) {
+ qs->p->restore();
+ return false;
+ }
+
+ status = _cairo_qt_surface_set_clip (qs, &clip);
+ if (unlikely (status)) {
+ qs->p->restore();
+ return false;
+ }
+
+ _cairo_clip_reset (&clip);
+ qs->clipper.clip = old_clip;
}
qs->p->setWorldMatrix (sourceMatrix.inverted(), true);
@@ -1242,16 +1228,19 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs,
qs->p->restore();
return true;
+#else
+ return false;
+#endif
}
static cairo_int_status_t
_cairo_qt_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
- Q_UNUSED(extents);
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
+ cairo_int_status_t status;
D(fprintf(stderr, "q[%p] paint op:%s\n", abstract_surface, _opstr(op)));
@@ -1261,6 +1250,10 @@ _cairo_qt_surface_paint (void *abstract_surface,
if (! _op_is_supported (qs, op))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ status = _cairo_qt_surface_set_clip (qs, clip);
+ if (unlikely (status))
+ return status;
+
if (qs->supports_porter_duff)
qs->p->setCompositionMode (_qpainter_compositionmode_from_cairo_op (op));
@@ -1283,9 +1276,8 @@ _cairo_qt_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t * extents)
+ cairo_clip_t *clip)
{
- Q_UNUSED(extents);
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
D(fprintf(stderr, "q[%p] fill op:%s\n", abstract_surface, _opstr(op)));
@@ -1296,6 +1288,10 @@ _cairo_qt_surface_fill (void *abstract_surface,
if (! _op_is_supported (qs, op))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ cairo_int_status_t status = _cairo_qt_surface_set_clip (qs, clip);
+ if (unlikely (status))
+ return status;
+
if (qs->supports_porter_duff)
qs->p->setCompositionMode (_qpainter_compositionmode_from_cairo_op (op));
@@ -1333,9 +1329,8 @@ _cairo_qt_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
- Q_UNUSED(extents);
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
D(fprintf(stderr, "q[%p] stroke op:%s\n", abstract_surface, _opstr(op)));
@@ -1346,6 +1341,10 @@ _cairo_qt_surface_stroke (void *abstract_surface,
if (! _op_is_supported (qs, op))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ cairo_int_status_t int_status = _cairo_qt_surface_set_clip (qs, clip);
+ if (unlikely (int_status))
+ return int_status;
+
QPainterPath qpath;
cairo_status_t status;
@@ -1387,8 +1386,8 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
@@ -1404,37 +1403,6 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
glyphs[i].y -= qs->redir_offset.y();
}
- if (qs->has_clipping != qs->xlib_has_clipping ||
- qs->clip_bounds != qs->xlib_clip_bounds)
- {
- cairo_status_t status;
-
- status = _cairo_surface_reset_clip (qs->xlib_equiv);
- assert (status == CAIRO_STATUS_SUCCESS);
-
- if (qs->has_clipping) {
- cairo_region_t region;
- cairo_rectangle_int_t rect = {
- qs->clip_bounds.x() - qs->redir_offset.x(),
- qs->clip_bounds.y() - qs->redir_offset.y(),
- qs->clip_bounds.width(),
- qs->clip_bounds.height()
- };
-
- _cairo_region_init_rectangle (&region, &rect);
- status = _cairo_surface_set_clip_region (qs->xlib_equiv,
- &region,
- ++qs->xlib_clip_serial);
- _cairo_region_fini (&region);
-
- if (status)
- return (cairo_int_status_t) status;
- }
-
- qs->xlib_has_clipping = qs->has_clipping;
- qs->xlib_clip_bounds = qs->clip_bounds;
- }
-
return (cairo_int_status_t)
_cairo_surface_show_text_glyphs (qs->xlib_equiv,
op, source,
@@ -1443,7 +1411,7 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
NULL, 0,
(cairo_text_cluster_flags_t) 0,
scaled_font,
- extents);
+ clip);
}
#endif
@@ -1452,12 +1420,11 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
static cairo_int_status_t
_cairo_qt_surface_mask (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
{
- Q_UNUSED(extents);
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
D(fprintf(stderr, "q[%p] mask op:%s\n", abstract_surface, _opstr(op)));
@@ -1471,7 +1438,7 @@ _cairo_qt_surface_mask (void *abstract_surface,
qs->p->setOpacity (solid_mask->color.alpha);
- result = _cairo_qt_surface_paint (abstract_surface, op, source, 0);
+ result = _cairo_qt_surface_paint (abstract_surface, op, source, clip);
qs->p->setOpacity (1.0);
@@ -1498,7 +1465,8 @@ _cairo_qt_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
@@ -1508,6 +1476,8 @@ _cairo_qt_surface_composite (cairo_operator_t op,
if (! _op_is_supported (qs, op))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ _cairo_qt_surface_set_clip_region (qs, clip_region);
+
D(fprintf(stderr, "q[%p] composite op:%s src:%p [%d %d] dst [%d %d] dim [%d %d]\n",
abstract_surface, _opstr(op), (void*)pattern,
src_x, src_y, dst_x, dst_y, width, height));
@@ -1618,8 +1588,6 @@ static const cairo_surface_backend_t cairo_qt_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- NULL, /* set_clip_region */
- _cairo_qt_surface_intersect_clip_path,
_cairo_qt_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -1636,7 +1604,6 @@ static const cairo_surface_backend_t cairo_qt_surface_backend = {
NULL, /* snapshot */
NULL, /* is_similar */
- NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
@@ -1728,6 +1695,10 @@ cairo_qt_surface_create (QPainter *painter)
qs->window = painter->window();
+ _cairo_surface_clipper_init (&qs->clipper,
+ _cairo_qt_surface_clipper_intersect_clip_path);
+
+
#if defined(Q_WS_X11) && CAIRO_HAS_XLIB_XRENDER_SURFACE
qs->xlib_equiv = _cairo_qt_create_xlib_surface (qs);
#endif
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index dab3dc87..7aa7ffdc 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -58,9 +58,8 @@ _cairo_quartz_image_surface_create_similar (void *asurface,
int height)
{
cairo_surface_t *result;
- cairo_surface_t *isurf = cairo_image_surface_create (_cairo_format_from_content (content),
- width,
- height);
+ cairo_surface_t *isurf =
+ _cairo_image_surface_create_for_content (content, width, height);
if (cairo_surface_status(isurf))
return isurf;
@@ -108,18 +107,16 @@ _cairo_quartz_image_surface_acquire_dest_image (void *asurface,
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
-
}
-static cairo_int_status_t
+static cairo_bool_t
_cairo_quartz_image_surface_get_extents (void *asurface,
cairo_rectangle_int_t *extents)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
*extents = surface->extents;
-
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
/* we assume some drawing happened to the image buffer; make sure it's
@@ -168,8 +165,6 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- NULL, /* set_clip_region */
- NULL, /* intersect_clip_path */
_cairo_quartz_image_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -185,7 +180,6 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
NULL, /* surface_show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
- NULL, /* reset */
NULL /* fill_stroke */
};
diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h
index 8ba89687..d7e07ac8 100644
--- a/src/cairo-quartz-private.h
+++ b/src/cairo-quartz-private.h
@@ -42,6 +42,7 @@
#if CAIRO_HAS_QUARTZ_SURFACE
#include "cairo-quartz.h"
+#include "cairo-surface-clipper-private.h"
typedef struct cairo_quartz_surface {
cairo_surface_t base;
@@ -52,6 +53,7 @@ typedef struct cairo_quartz_surface {
void *imageData;
cairo_surface_t *imageSurfaceEquiv;
+ cairo_surface_clipper_t clipper;
cairo_rectangle_int_t extents;
/* These are stored while drawing operations are in place, set up
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 892a156d..1db8ba72 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -38,6 +38,7 @@
#include "cairoint.h"
#include "cairo-quartz-private.h"
+#include "cairo-surface-clipper-private.h"
#include <dlfcn.h>
@@ -837,7 +838,8 @@ _cairo_surface_to_cgimage (cairo_surface_t *target,
}
if (stype != CAIRO_SURFACE_TYPE_IMAGE) {
- status = _cairo_surface_acquire_source_image (source, &isurf, &image_extra);
+ status = _cairo_surface_acquire_source_image (source,
+ &isurf, &image_extra);
if (status)
return status;
} else {
@@ -848,12 +850,11 @@ _cairo_surface_to_cgimage (cairo_surface_t *target,
*image_out = NULL;
} else {
cairo_image_surface_t *isurf_snap = NULL;
- isurf_snap = (cairo_image_surface_t*) _cairo_surface_snapshot ((cairo_surface_t*) isurf);
- if (isurf_snap == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- if (isurf_snap->base.type != CAIRO_SURFACE_TYPE_IMAGE)
- return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
+ isurf_snap = (cairo_image_surface_t*)
+ _cairo_surface_snapshot (&isurf->base);
+ if (isurf_snap->base.status)
+ return isurf_snap->base.status;
image = _cairo_quartz_create_cgimage (isurf_snap->format,
isurf_snap->width,
@@ -868,10 +869,10 @@ _cairo_surface_to_cgimage (cairo_surface_t *target,
*image_out = image;
}
- if ((cairo_surface_t*) isurf != source)
+ if (&isurf->base != source)
_cairo_surface_release_source_image (source, isurf, image_extra);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
/* Generic #cairo_pattern_t -> CGPattern function */
@@ -942,6 +943,7 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
SurfacePatternDrawInfo *info;
float rw, rh;
cairo_status_t status;
+ cairo_bool_t is_bounded;
cairo_matrix_t m;
@@ -952,9 +954,8 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
spattern = (cairo_surface_pattern_t *) apattern;
pat_surf = spattern->surface;
- status = _cairo_surface_get_extents (pat_surf, &extents);
- if (status)
- return status;
+ is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
+ assert (is_bounded);
status = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf, &image);
if (status != CAIRO_STATUS_SUCCESS)
@@ -1042,9 +1043,7 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
double x0, y0, w, h;
cairo_surface_t *fallback;
- cairo_t *fallback_cr;
CGImageRef img;
- cairo_pattern_t *source_copy;
cairo_status_t status;
@@ -1070,20 +1069,38 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
fallback = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, (int) w, (int) h);
cairo_surface_set_device_offset (fallback, -x0, -y0);
- /* Paint the source onto our temporary */
- fallback_cr = cairo_create (fallback);
- cairo_set_operator (fallback_cr, CAIRO_OPERATOR_SOURCE);
+#if 0
+ {
+ cairo_t *fallback_cr;
+ cairo_pattern_t *source_copy;
+
+ /* Paint the source onto our temporary */
+ fallback_cr = cairo_create (fallback);
+ cairo_set_operator (fallback_cr, CAIRO_OPERATOR_SOURCE);
- /* Use a copy of the pattern because it is const and could be allocated
- * on the stack */
- status = _cairo_pattern_create_copy (&source_copy, source);
- cairo_set_source (fallback_cr, source_copy);
- cairo_pattern_destroy (source_copy);
+ /* Use a copy of the pattern because it is const and could be allocated
+ * on the stack */
+ status = _cairo_pattern_create_copy (&source_copy, source);
+ cairo_set_source (fallback_cr, source_copy);
+ cairo_pattern_destroy (source_copy);
+
+ cairo_paint (fallback_cr);
+ cairo_destroy (fallback_cr);
+ }
+#else
+ {
+ cairo_pattern_union_t pattern;
- cairo_paint (fallback_cr);
- cairo_destroy (fallback_cr);
+ _cairo_pattern_init_static_copy (&pattern, source);
+ _cairo_pattern_transform (pattern_copy,
+ &fallback->device_transform_inverse);
+ status = _cairo_surface_paint (fallback,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base, NULL);
+ }
+#endif
- status = _cairo_surface_to_cgimage ((cairo_surface_t*) surface, fallback, &img);
+ status = _cairo_surface_to_cgimage (&surface->base, fallback, &img);
if (status == CAIRO_STATUS_SUCCESS && img == NULL)
return DO_NOTHING;
if (status)
@@ -1251,6 +1268,7 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
CGAffineTransform xform;
CGRect srcRect;
cairo_fixed_t fw, fh;
+ cairo_bool_t is_bounded;
status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
if (status == CAIRO_STATUS_SUCCESS && img == NULL)
@@ -1263,9 +1281,8 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
cairo_matrix_invert(&m);
_cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceTransform);
- status = _cairo_surface_get_extents (pat_surf, &extents);
- if (status)
- return DO_UNSUPPORTED;
+ is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
+ assert (is_bounded);
if (source->extend == CAIRO_EXTEND_NONE) {
surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height);
@@ -1485,6 +1502,7 @@ _cairo_quartz_surface_finish (void *abstract_surface)
/* Restore our saved gstate that we use to reset clipping */
CGContextRestoreGState (surface->cgContext);
+ _cairo_surface_clipper_reset (&surface->clipper);
CGContextRelease (surface->cgContext);
@@ -1700,22 +1718,21 @@ FINISH:
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
+static cairo_bool_t
_cairo_quartz_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *extents)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
*extents = surface->extents;
-
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
static cairo_int_status_t
_cairo_quartz_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@@ -1729,6 +1746,10 @@ _cairo_quartz_surface_paint (void *abstract_surface,
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
+ rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (rv))
+ return rv;
+
CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
action = _cairo_quartz_setup_source (surface, source);
@@ -1771,7 +1792,7 @@ _cairo_quartz_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@@ -1790,7 +1811,7 @@ _cairo_quartz_surface_fill (void *abstract_surface,
/* Check whether the path would be a no-op */
/* XXX handle unbounded ops */
- if (_cairo_path_fixed_is_empty(path) ||
+ if (_cairo_path_fixed_fill_is_empty(path) ||
(_cairo_path_fixed_is_box(path, &box) &&
box.p1.x == box.p2.x &&
box.p1.y == box.p2.y))
@@ -1798,6 +1819,10 @@ _cairo_quartz_surface_fill (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
+ rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (rv))
+ return rv;
+
CGContextSaveGState (surface->cgContext);
CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
@@ -1879,7 +1904,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@@ -1896,6 +1921,10 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
+ rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (rv))
+ return rv;
+
CGContextSaveGState (surface->cgContext);
// Turning antialiasing off used to cause misrendering with
@@ -2024,7 +2053,7 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
CGAffineTransform textTransform, ctm;
#define STATIC_BUF_SIZE 64
@@ -2055,6 +2084,10 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (rv))
+ return rv;
+
CGContextSaveGState (surface->cgContext);
action = _cairo_quartz_setup_source (surface, source);
@@ -2239,10 +2272,10 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
cairo_surface_t *pat_surf = mask->surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
CGAffineTransform ctm, mask_matrix;
+ cairo_bool_t is_bounded;
- status = _cairo_surface_get_extents (pat_surf, &mask_extents);
- if (status)
- return status;
+ is_bounded = _cairo_surface_get_extents (pat_surf, &mask_extents);
+ assert (is_bounded);
// everything would be masked out, so do nothing
if (mask_extents.width == 0 || mask_extents.height == 0)
@@ -2347,7 +2380,7 @@ _cairo_quartz_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@@ -2357,6 +2390,10 @@ _cairo_quartz_surface_mask (void *abstract_surface,
if (IS_EMPTY(surface))
return CAIRO_STATUS_SUCCESS;
+ rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (rv))
+ return rv;
+
if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
/* This is easy; we just need to paint with the alpha. */
cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
@@ -2387,14 +2424,15 @@ _cairo_quartz_surface_mask (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_quartz_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
+static cairo_status_t
+_cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
{
- cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+ cairo_quartz_surface_t *surface =
+ cairo_container_of (clipper, cairo_quartz_surface_t, clipper);
quartz_stroke_t stroke;
cairo_status_t status;
@@ -2455,8 +2493,6 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- NULL, /* set_clip_region */
- _cairo_quartz_surface_intersect_clip_path,
_cairo_quartz_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -2477,7 +2513,6 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
_cairo_quartz_surface_snapshot,
NULL, /* is_similar */
- NULL, /* reset */
NULL /* fill_stroke */
};
@@ -2501,6 +2536,9 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
_cairo_surface_init(&surface->base, &cairo_quartz_surface_backend,
content);
+ _cairo_surface_clipper_init (&surface->clipper,
+ _cairo_quartz_surface_intersect_clip_path);
+
/* Save our extents */
surface->extents.x = surface->extents.y = 0;
surface->extents.width = width;
diff --git a/src/cairo-region-private.h b/src/cairo-region-private.h
new file mode 100644
index 00000000..8a10115d
--- /dev/null
+++ b/src/cairo-region-private.h
@@ -0,0 +1,73 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Owen Taylor <otaylor@redhat.com>
+ * Vladimir Vukicevic <vladimir@pobox.com>
+ * Søren Sandmann <sandmann@daimi.au.dk>
+ */
+
+#ifndef CAIRO_REGION_PRIVATE_H
+#define CAIRO_REGION_PRIVATE_H
+
+#include "cairo-types-private.h"
+#include "cairo-reference-count-private.h"
+
+#include <pixman.h>
+
+CAIRO_BEGIN_DECLS
+
+struct _cairo_region {
+ cairo_reference_count_t ref_count;
+ cairo_status_t status;
+
+ pixman_region32_t rgn;
+};
+
+cairo_private void
+_cairo_region_init (cairo_region_t *region);
+
+cairo_private void
+_cairo_region_init_rectangle (cairo_region_t *region,
+ const cairo_rectangle_int_t *rectangle);
+
+cairo_private cairo_status_t
+_cairo_region_init_rectangles (cairo_region_t *region,
+ const cairo_rectangle_int_t *rects,
+ int count);
+
+cairo_private void
+_cairo_region_fini (cairo_region_t *region);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_REGION_PRIVATE_H */
diff --git a/src/cairo-region.c b/src/cairo-region.c
index 6dfa9332..d6fff7f7 100644
--- a/src/cairo-region.c
+++ b/src/cairo-region.c
@@ -38,7 +38,13 @@
#include "cairoint.h"
+#include "cairo-region-private.h"
+
+/* XXX need to update pixman headers to be const as appropriate */
+#define CONST_CAST (pixman_region32_t *)
+
static const cairo_region_t _cairo_region_nil = {
+ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
};
@@ -82,6 +88,7 @@ _cairo_region_init (cairo_region_t *region)
VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
region->status = CAIRO_STATUS_SUCCESS;
+ CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
pixman_region32_init (&region->rgn);
}
@@ -92,6 +99,7 @@ _cairo_region_init_rectangle (cairo_region_t *region,
VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
region->status = CAIRO_STATUS_SUCCESS;
+ CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
pixman_region32_init_rect (&region->rgn,
rectangle->x, rectangle->y,
rectangle->width, rectangle->height);
@@ -100,6 +108,7 @@ _cairo_region_init_rectangle (cairo_region_t *region,
void
_cairo_region_fini (cairo_region_t *region)
{
+ assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
pixman_region32_fini (&region->rgn);
VG (VALGRIND_MAKE_MEM_NOACCESS (region, sizeof (cairo_region_t)));
}
@@ -127,6 +136,7 @@ cairo_region_create (void)
return (cairo_region_t *) &_cairo_region_nil;
region->status = CAIRO_STATUS_SUCCESS;
+ CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
pixman_region32_init (&region->rgn);
@@ -134,29 +144,23 @@ cairo_region_create (void)
}
slim_hidden_def (cairo_region_create);
-cairo_region_t *
-cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
- int count)
+cairo_status_t
+_cairo_region_init_rectangles (cairo_region_t *region,
+ const cairo_rectangle_int_t *rects,
+ int count)
{
pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
pixman_box32_t *pboxes = stack_pboxes;
- cairo_region_t *region;
+ cairo_status_t status;
int i;
- region = _cairo_malloc (sizeof (cairo_region_t));
-
- if (!region)
- return (cairo_region_t *)&_cairo_region_nil;
-
- region->status = CAIRO_STATUS_SUCCESS;
+ status = CAIRO_STATUS_SUCCESS;
+ CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
if (count > ARRAY_LENGTH (stack_pboxes)) {
pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
-
- if (unlikely (pboxes == NULL)) {
- free (region);
- return (cairo_region_t *)&_cairo_region_nil;
- }
+ if (unlikely (pboxes == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
for (i = 0; i < count; i++) {
@@ -166,15 +170,35 @@ cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
pboxes[i].y2 = rects[i].y + rects[i].height;
}
- if (! pixman_region32_init_rects (&region->rgn, pboxes, count)) {
- free (region);
-
- region = (cairo_region_t *)&_cairo_region_nil;
- }
+ if (! pixman_region32_init_rects (&region->rgn, pboxes, count))
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (pboxes != stack_pboxes)
free (pboxes);
+ return region->status = status;
+}
+
+cairo_region_t *
+cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
+ int count)
+{
+ cairo_region_t *region;
+ cairo_status_t status;
+
+ region = _cairo_malloc (sizeof (cairo_region_t));
+ if (unlikely (region == NULL)) {
+ _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_region_t *) &_cairo_region_nil;
+ }
+
+ status = _cairo_region_init_rectangles (region, rects, count);
+ if (unlikely (status)) {
+ cairo_region_destroy (region);
+ return (cairo_region_t *) &_cairo_region_nil;
+ }
+
+ CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
return region;
}
slim_hidden_def (cairo_region_create_rectangles);
@@ -199,10 +223,11 @@ cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
cairo_region_t *region;
region = _cairo_malloc (sizeof (cairo_region_t));
- if (region == NULL)
+ if (unlikely (region == NULL))
return (cairo_region_t *) &_cairo_region_nil;
region->status = CAIRO_STATUS_SUCCESS;
+ CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
pixman_region32_init_rect (&region->rgn,
rectangle->x, rectangle->y,
@@ -227,18 +252,20 @@ slim_hidden_def (cairo_region_create_rectangle);
* Since: 1.10
**/
cairo_region_t *
-cairo_region_copy (cairo_region_t *original)
+cairo_region_copy (const cairo_region_t *original)
{
cairo_region_t *copy;
- if (original->status)
+ if (original != NULL && original->status)
return (cairo_region_t *) &_cairo_region_nil;
copy = cairo_region_create ();
- if (copy->status)
+ if (unlikely (copy->status))
return copy;
- if (! pixman_region32_copy (&copy->rgn, &original->rgn)) {
+ if (original != NULL &&
+ ! pixman_region32_copy (&copy->rgn, CONST_CAST &original->rgn))
+ {
cairo_region_destroy (copy);
return (cairo_region_t *) &_cairo_region_nil;
}
@@ -248,6 +275,31 @@ cairo_region_copy (cairo_region_t *original)
slim_hidden_def (cairo_region_copy);
/**
+ * cairo_region_reference:
+ * @region: a #cairo_region_t
+ *
+ * Increases the reference count on @region by one. This prevents
+ * @region from being destroyed until a matching call to
+ * cairo_region_destroy() is made.
+ *
+ * Return value: the referenced #cairo_region_t.
+ *
+ * Since: 1.10
+ **/
+cairo_region_t *
+cairo_region_reference (cairo_region_t *region)
+{
+ if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
+ return NULL;
+
+ assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
+
+ _cairo_reference_count_inc (&region->ref_count);
+ return region;
+}
+slim_hidden_def (cairo_region_reference);
+
+/**
* cairo_region_destroy:
* @region: a #cairo_region_t
*
@@ -260,10 +312,15 @@ slim_hidden_def (cairo_region_copy);
void
cairo_region_destroy (cairo_region_t *region)
{
- if (region == (cairo_region_t *) &_cairo_region_nil)
+ if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
return;
- pixman_region32_fini (&region->rgn);
+ assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
+
+ if (! _cairo_reference_count_dec_and_test (&region->ref_count))
+ return;
+
+ _cairo_region_fini (region);
free (region);
}
slim_hidden_def (cairo_region_destroy);
@@ -279,12 +336,12 @@ slim_hidden_def (cairo_region_destroy);
* Since: 1.10
**/
int
-cairo_region_num_rectangles (cairo_region_t *region)
+cairo_region_num_rectangles (const cairo_region_t *region)
{
if (region->status)
return 0;
- return pixman_region32_n_rects (&region->rgn);
+ return pixman_region32_n_rects (CONST_CAST &region->rgn);
}
slim_hidden_def (cairo_region_num_rectangles);
@@ -299,7 +356,7 @@ slim_hidden_def (cairo_region_num_rectangles);
* Since: 1.10
**/
void
-cairo_region_get_rectangle (cairo_region_t *region,
+cairo_region_get_rectangle (const cairo_region_t *region,
int nth,
cairo_rectangle_int_t *rectangle)
{
@@ -311,7 +368,7 @@ cairo_region_get_rectangle (cairo_region_t *region,
return;
}
- pbox = pixman_region32_rectangles (&region->rgn, NULL) + nth;
+ pbox = pixman_region32_rectangles (CONST_CAST &region->rgn, NULL) + nth;
rectangle->x = pbox->x1;
rectangle->y = pbox->y1;
@@ -330,7 +387,7 @@ slim_hidden_def (cairo_region_get_rectangle);
* Since: 1.10
**/
void
-cairo_region_get_extents (cairo_region_t *region,
+cairo_region_get_extents (const cairo_region_t *region,
cairo_rectangle_int_t *extents)
{
pixman_box32_t *pextents;
@@ -341,7 +398,7 @@ cairo_region_get_extents (cairo_region_t *region,
return;
}
- pextents = pixman_region32_extents (&region->rgn);
+ pextents = pixman_region32_extents (CONST_CAST &region->rgn);
extents->x = pextents->x1;
extents->y = pextents->y1;
@@ -362,7 +419,7 @@ slim_hidden_def (cairo_region_get_extents);
* Since: 1.10
**/
cairo_status_t
-cairo_region_status (cairo_region_t *region)
+cairo_region_status (const cairo_region_t *region)
{
return region->status;
}
@@ -564,12 +621,12 @@ slim_hidden_def (cairo_region_union_rectangle);
* Since: 1.10
**/
cairo_bool_t
-cairo_region_is_empty (cairo_region_t *region)
+cairo_region_is_empty (const cairo_region_t *region)
{
if (region->status)
return TRUE;
- return ! pixman_region32_not_empty (&region->rgn);
+ return ! pixman_region32_not_empty (CONST_CAST &region->rgn);
}
slim_hidden_def (cairo_region_is_empty);
@@ -610,7 +667,7 @@ slim_hidden_def (cairo_region_translate);
* Since: 1.10
**/
cairo_region_overlap_t
-cairo_region_contains_rectangle (cairo_region_t *region,
+cairo_region_contains_rectangle (const cairo_region_t *region,
const cairo_rectangle_int_t *rectangle)
{
pixman_box32_t pbox;
@@ -624,7 +681,8 @@ cairo_region_contains_rectangle (cairo_region_t *region,
pbox.x2 = rectangle->x + rectangle->width;
pbox.y2 = rectangle->y + rectangle->height;
- poverlap = pixman_region32_contains_rectangle (&region->rgn, &pbox);
+ poverlap = pixman_region32_contains_rectangle (CONST_CAST &region->rgn,
+ &pbox);
switch (poverlap) {
default:
case PIXMAN_REGION_OUT: return CAIRO_REGION_OVERLAP_OUT;
@@ -647,14 +705,44 @@ slim_hidden_def (cairo_region_contains_rectangle);
* Since: 1.10
**/
cairo_bool_t
-cairo_region_contains_point (cairo_region_t *region,
+cairo_region_contains_point (const cairo_region_t *region,
int x, int y)
{
pixman_box32_t box;
-
+
if (region->status)
return FALSE;
- return pixman_region32_contains_point (&region->rgn, x, y, &box);
+ return pixman_region32_contains_point (CONST_CAST &region->rgn, x, y, &box);
}
slim_hidden_def (cairo_region_contains_point);
+
+/**
+ * cairo_region_equal:
+ * @region_a: a #cairo_region_t
+ * @region_b: a #cairo_region_t
+ *
+ * Compares whether region_a is equivalent to region_b.
+ *
+ * Return value: %TRUE if both regions contained the same coverage,
+ * %FALSE if it is not.
+ *
+ * Since: 1.10
+ **/
+cairo_bool_t
+cairo_region_equal (const cairo_region_t *a,
+ const cairo_region_t *b)
+{
+ /* error objects are never equal */
+ if ((a != NULL && a->status) || (b != NULL && b->status))
+ return FALSE;
+
+ if (a == b)
+ return TRUE;
+
+ if (a == NULL || b == NULL)
+ return FALSE;
+
+ return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
+}
+slim_hidden_def (cairo_region_equal);
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 0510264b..bf5a4f73 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1969,18 +1969,19 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
}
cairo_status_t
-_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
- cairo_operator_t op,
+_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t op,
const cairo_pattern_t *pattern,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- cairo_glyph_t *glyphs,
- int num_glyphs)
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_region_t *clip_region)
{
cairo_status_t status;
cairo_surface_t *mask = NULL;
@@ -2008,7 +2009,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
source_x, source_y,
dest_x, dest_y,
width, height,
- glyphs, num_glyphs, &remaining_glyphs);
+ glyphs, num_glyphs,
+ clip_region,
+ &remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
@@ -2088,7 +2091,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
0, 0,
0, 0,
0, 0,
- width, height);
+ width, height,
+ NULL);
_cairo_pattern_fini (&mask_pattern.base);
@@ -2116,7 +2120,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
0, 0,
x - dest_x, y - dest_y,
glyph_surface->width,
- glyph_surface->height);
+ glyph_surface->height,
+ NULL);
_cairo_pattern_fini (&glyph_pattern.base);
@@ -2134,7 +2139,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
source_x, source_y,
0, 0,
dest_x, dest_y,
- width, height);
+ width, height,
+ clip_region);
_cairo_pattern_fini (&mask_pattern.base);
@@ -2148,58 +2154,6 @@ CLEANUP_MASK:
return _cairo_scaled_font_set_error (scaled_font, status);
}
-typedef struct _cairo_scaled_glyph_path_closure {
- cairo_point_t offset;
- cairo_path_fixed_t *path;
-} cairo_scaled_glyph_path_closure_t;
-
-static cairo_status_t
-_scaled_glyph_path_move_to (void *abstract_closure,
- const cairo_point_t *point)
-{
- cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
-
- return _cairo_path_fixed_move_to (closure->path,
- point->x + closure->offset.x,
- point->y + closure->offset.y);
-}
-
-static cairo_status_t
-_scaled_glyph_path_line_to (void *abstract_closure,
- const cairo_point_t *point)
-{
- cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
-
- return _cairo_path_fixed_line_to (closure->path,
- point->x + closure->offset.x,
- point->y + closure->offset.y);
-}
-
-static cairo_status_t
-_scaled_glyph_path_curve_to (void *abstract_closure,
- const cairo_point_t *p0,
- const cairo_point_t *p1,
- const cairo_point_t *p2)
-{
- cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
-
- return _cairo_path_fixed_curve_to (closure->path,
- p0->x + closure->offset.x,
- p0->y + closure->offset.y,
- p1->x + closure->offset.x,
- p1->y + closure->offset.y,
- p2->x + closure->offset.x,
- p2->y + closure->offset.y);
-}
-
-static cairo_status_t
-_scaled_glyph_path_close_path (void *abstract_closure)
-{
- cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
-
- return _cairo_path_fixed_close_path (closure->path);
-}
-
/* Add a single-device-unit rectangle to a path. */
static cairo_status_t
_add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y)
@@ -2309,14 +2263,13 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
{
cairo_status_t status;
int i;
- cairo_scaled_glyph_path_closure_t closure;
+ cairo_path_fixed_t glyph_path_static;
cairo_path_fixed_t *glyph_path;
status = scaled_font->status;
if (unlikely (status))
return status;
- closure.path = path;
_cairo_scaled_font_freeze_cache (scaled_font);
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
@@ -2325,14 +2278,12 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_PATH,
&scaled_glyph);
- if (status == CAIRO_STATUS_SUCCESS)
+ if (status == CAIRO_STATUS_SUCCESS) {
glyph_path = scaled_glyph->path;
- else if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- goto BAIL;
-
- /* If the font is incapable of providing a path, then we'll
- * have to trace our own from a surface. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ /* If the font is incapable of providing a path, then we'll
+ * have to trace our own from a surface.
+ */
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
@@ -2340,31 +2291,22 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
if (unlikely (status))
goto BAIL;
- glyph_path = _cairo_path_fixed_create ();
- if (unlikely (glyph_path == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
-
+ _cairo_path_fixed_init (&glyph_path_static);
+ glyph_path = &glyph_path_static;
status = _trace_mask_to_path (scaled_glyph->surface, glyph_path);
- if (unlikely (status)) {
- _cairo_path_fixed_destroy (glyph_path);
+ if (unlikely (status))
goto BAIL;
- }
+ } else {
+ goto BAIL;
}
- closure.offset.x = _cairo_fixed_from_double (glyphs[i].x);
- closure.offset.y = _cairo_fixed_from_double (glyphs[i].y);
+ status = _cairo_path_fixed_append (path,
+ glyph_path, CAIRO_DIRECTION_FORWARD,
+ _cairo_fixed_from_double (glyphs[i].x),
+ _cairo_fixed_from_double (glyphs[i].y));
- status = _cairo_path_fixed_interpret (glyph_path,
- CAIRO_DIRECTION_FORWARD,
- _scaled_glyph_path_move_to,
- _scaled_glyph_path_line_to,
- _scaled_glyph_path_curve_to,
- _scaled_glyph_path_close_path,
- &closure);
if (glyph_path != scaled_glyph->path)
- _cairo_path_fixed_destroy (glyph_path);
+ _cairo_path_fixed_fini (glyph_path);
if (unlikely (status))
goto BAIL;
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 059ef95b..fb1a4f8f 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -51,6 +51,10 @@
#include "cairo-list-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-output-stream-private.h"
+#include "cairo-surface-clipper-private.h"
+#include "cairo-surface-wrapper-private.h"
+
+#include <ctype.h>
#define _cairo_output_stream_puts(S, STR) \
_cairo_output_stream_write ((S), (STR), strlen (STR))
@@ -85,6 +89,7 @@ struct _cairo_script_vmcontext {
cairo_list_t deferred;
cairo_script_surface_font_private_t *fonts;
+ cairo_list_t defines;
};
struct _cairo_script_surface_font_private {
@@ -114,7 +119,10 @@ struct _cairo_script_implicit_context {
struct _cairo_script_surface {
cairo_surface_t base;
+ cairo_surface_wrapper_t wrapper;
+
cairo_script_vmcontext_t *ctx;
+ cairo_surface_clipper_t clipper;
unsigned long id;
cairo_list_t operand;
@@ -131,7 +139,11 @@ static const cairo_surface_backend_t _cairo_script_surface_backend;
static cairo_script_surface_t *
_cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx,
double width,
- double height);
+ double height,
+ cairo_surface_t *passthrough);
+
+static cairo_status_t
+_vmcontext_destroy (cairo_script_vmcontext_t *ctx);
static void
_cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
@@ -637,9 +649,10 @@ _emit_dash (cairo_script_surface_t *surface,
if (num_dashes) {
surface->cr.current_style.dash = _cairo_realloc_ab
- (surface->cr.current_style.dash,
- num_dashes,
- sizeof (double));
+ (surface->cr.current_style.dash, num_dashes, sizeof (double));
+ if (unlikely (surface->cr.current_style.dash == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
memcpy (surface->cr.current_style.dash, dash,
sizeof (double) * num_dashes);
} else {
@@ -833,50 +846,46 @@ static cairo_status_t
_emit_meta_surface_pattern (cairo_script_surface_t *surface,
const cairo_pattern_t *pattern)
{
+ cairo_script_implicit_context_t old_cr;
cairo_surface_pattern_t *surface_pattern;
- cairo_surface_t *source;
- cairo_surface_t *null_surface;
- cairo_surface_t *analysis_surface;
+ cairo_meta_surface_t *source;
cairo_script_surface_t *similar;
cairo_status_t status;
cairo_box_t bbox;
- int width, height;
+ cairo_rectangle_int_t rect;
surface_pattern = (cairo_surface_pattern_t *) pattern;
- source = surface_pattern->surface;
+ source = (cairo_meta_surface_t *) surface_pattern->surface;
/* first measure the extents */
- null_surface = _cairo_null_surface_create (source->content);
- analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1);
- cairo_surface_destroy (null_surface);
-
- status = analysis_surface->status;
- if (unlikely (status))
- return status;
-
- status = cairo_meta_surface_replay (source, analysis_surface);
- _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox);
- cairo_surface_destroy (analysis_surface);
+ status = _cairo_meta_surface_get_bbox (source, &bbox, NULL);
if (unlikely (status))
return status;
- width = _cairo_fixed_integer_ceil (bbox.p2.x - bbox.p1.x);
- height = _cairo_fixed_integer_ceil (bbox.p2.y - bbox.p1.y);
+ /* convert to extents so that it matches the public api */
+ _cairo_box_round_to_rectangle (&bbox, &rect);
similar = _cairo_script_surface_create_internal (surface->ctx,
- width, height);
+ rect.width,
+ rect.height,
+ NULL);
if (unlikely (similar->base.status))
return similar->base.status;
+ cairo_surface_set_device_offset (&similar->base, -rect.x, -rect.y);
_get_target (surface);
_cairo_output_stream_printf (surface->ctx->stream,
- "%u %u //%s similar dup context\n",
- width, height,
+ "%d %d //%s similar dup context\n",
+ rect.width, rect.height,
_content_to_string (source->content));
target_push (similar);
- status = cairo_meta_surface_replay (source, &similar->base);
+ old_cr = surface->cr;
+ _cairo_script_implicit_context_init (&surface->cr);
+ status = cairo_meta_surface_replay (&source->base, &similar->base);
+ surface->cr = old_cr;
+
if (unlikely (status)) {
cairo_surface_destroy (&similar->base);
return status;
@@ -1048,6 +1057,23 @@ _emit_png_surface (cairo_script_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
+struct def {
+ cairo_script_vmcontext_t *ctx;
+ cairo_user_data_array_t *user_data;
+ unsigned int tag;
+ cairo_list_t link;
+};
+
+static void
+_undef (void *data)
+{
+ struct def *def = data;
+
+ cairo_list_del (&def->link);
+ _cairo_output_stream_printf (def->ctx->stream, "/s%u undef ", def->tag);
+ free (def);
+}
+
static cairo_status_t
_emit_image_surface (cairo_script_surface_t *surface,
cairo_image_surface_t *image)
@@ -1057,12 +1083,23 @@ _emit_image_surface (cairo_script_surface_t *surface,
cairo_status_t status, status2;
const uint8_t *mime_data;
unsigned int mime_data_length;
+ struct def *tag;
+
+ if (_cairo_user_data_array_get_data (&image->base.user_data,
+ (cairo_user_data_key_t *) surface->ctx))
+ {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "s%u pattern ",
+ image->base.unique_id);
+ return CAIRO_STATUS_SUCCESS;
+ }
status = _emit_png_surface (surface, image);
if (_cairo_status_is_error (status)) {
return status;
} else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
cairo_image_surface_t *clone;
+ uint32_t len;
if (image->format == CAIRO_FORMAT_INVALID) {
clone =
@@ -1078,14 +1115,34 @@ _emit_image_surface (cairo_script_surface_t *surface,
"/width %d "
"/height %d "
"/format //%s "
- "/source <~",
+ "/source ",
clone->width, clone->height,
_format_to_string (clone->format));
- if (clone->width * clone->height > 8) {
+ switch (clone->format) {
+ case CAIRO_FORMAT_A1:
+ len = (clone->width + 7)/8;
+ break;
+ case CAIRO_FORMAT_A8:
+ len = clone->width;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ len = clone->width * 3;
+ break;
+ case CAIRO_FORMAT_ARGB32:
+ len = clone->width * 4;
+ break;
+ }
+ len *= clone->height;
+
+ if (len > 24) {
+ _cairo_output_stream_puts (surface->ctx->stream, "<|");
+
base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
- zlib_stream = _cairo_deflate_stream_create (base85_stream);
+ _cairo_output_stream_write (base85_stream, &len, sizeof (len));
+
+ zlib_stream = _cairo_deflate_stream_create (base85_stream);
status = _write_image_surface (zlib_stream, clone);
status2 = _cairo_output_stream_destroy (zlib_stream);
@@ -1096,23 +1153,42 @@ _emit_image_surface (cairo_script_surface_t *surface,
status = status2;
if (unlikely (status))
return status;
-
- _cairo_output_stream_puts (surface->ctx->stream,
- " /deflate filter >> image ");
} else {
+ _cairo_output_stream_puts (surface->ctx->stream, "<~");
+
base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
status = _write_image_surface (base85_stream, clone);
status2 = _cairo_output_stream_destroy (base85_stream);
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
-
- _cairo_output_stream_puts (surface->ctx->stream,
- " >> image ");
+ if (unlikely (status))
+ return status;
}
+ _cairo_output_stream_puts (surface->ctx->stream, " >> image ");
cairo_surface_destroy (&clone->base);
}
+ tag = malloc (sizeof (*tag));
+ if (unlikely (tag == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ tag->ctx = surface->ctx;
+ tag->tag = image->base.unique_id;
+ tag->user_data = &image->base.user_data;
+ cairo_list_add (&tag->link, &surface->ctx->defines);
+ status = _cairo_user_data_array_set_data (&image->base.user_data,
+ (cairo_user_data_key_t *) surface->ctx,
+ tag, _undef);
+ if (unlikely (status)) {
+ free (tag);
+ return status;
+ }
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "dup /s%u exch def ",
+ image->base.unique_id);
+
cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JPEG,
&mime_data, &mime_data_length);
if (mime_data != NULL) {
@@ -1126,14 +1202,28 @@ _emit_image_surface (cairo_script_surface_t *surface,
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream,
- " set-mime-data\n");
+ _cairo_output_stream_puts (surface->ctx->stream, " set-mime-data\n");
}
- _cairo_output_stream_puts (surface->ctx->stream,
- "pattern");
+ cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JP2,
+ &mime_data, &mime_data_length);
+ if (mime_data != NULL) {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "\n (%s) <~",
+ CAIRO_MIME_TYPE_JP2);
- return status;
+ base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ _cairo_output_stream_write (base85_stream, mime_data, mime_data_length);
+ status = _cairo_output_stream_destroy (base85_stream);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream, " set-mime-data\n");
+ }
+
+ _cairo_output_stream_puts (surface->ctx->stream, "pattern");
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -1141,22 +1231,17 @@ _emit_image_surface_pattern (cairo_script_surface_t *surface,
const cairo_pattern_t *pattern)
{
cairo_surface_pattern_t *surface_pattern;
- cairo_surface_t *source;
cairo_image_surface_t *image;
- void *image_extra;
cairo_status_t status;
+ /* XXX keeping a copy is nasty, but we want to hook into the surface's
+ * lifetime. Using a snapshot is a convenient method.
+ */
surface_pattern = (cairo_surface_pattern_t *) pattern;
- source = surface_pattern->surface;
-
- /* XXX snapshot-cow */
- status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
- if (unlikely (status))
- return status;
-
+ image = (cairo_image_surface_t *)
+ _cairo_surface_snapshot (surface_pattern->surface);
status = _emit_image_surface (surface, image);
-
- _cairo_surface_release_source_image (source, image, image_extra);
+ cairo_surface_destroy (&image->base);
return status;
}
@@ -1249,6 +1334,9 @@ _emit_pattern (cairo_script_surface_t *surface,
_extend_to_string (pattern->extend));
}
+ if (need_newline)
+ _cairo_output_stream_puts (surface->ctx->stream, "\n ");
+
return CAIRO_STATUS_SUCCESS;
}
@@ -1414,13 +1502,21 @@ _emit_path (cairo_script_surface_t *surface,
}
static cairo_status_t
-_emit_matrix (cairo_script_surface_t *surface,
- const cairo_matrix_t *ctm,
- cairo_bool_t *matrix_updated)
+_emit_scaling_matrix (cairo_script_surface_t *surface,
+ const cairo_matrix_t *ctm,
+ cairo_bool_t *matrix_updated)
{
+ cairo_matrix_t current, ctm_scaling;
+
assert (target_is_active (surface));
- if (memcmp (&surface->cr.current_ctm, ctm, sizeof (cairo_matrix_t)) == 0)
+ current = surface->cr.current_ctm;
+ current.x0 = current.y0 = 0;
+
+ ctm_scaling = *ctm;
+ ctm_scaling.x0 = ctm_scaling.y0 = 0;
+
+ if (memcmp (&current, &ctm_scaling, sizeof (cairo_matrix_t)) == 0)
return CAIRO_STATUS_SUCCESS;
*matrix_updated = TRUE;
@@ -1475,11 +1571,11 @@ _cairo_script_surface_create_similar (void *abstract_surface,
int width,
int height)
{
- cairo_script_surface_t *surface, *other;
+ cairo_script_surface_t *surface, *other = abstract_surface;
+ cairo_surface_t *passthrough = NULL;
cairo_script_vmcontext_t *ctx;
cairo_status_t status;
- other = abstract_surface;
ctx = other->ctx;
if (other->id == (unsigned long) -1) {
@@ -1490,8 +1586,20 @@ _cairo_script_surface_create_similar (void *abstract_surface,
target_push (other);
}
- surface = _cairo_script_surface_create_internal (ctx, width, height);
- if (surface->base.status)
+ if (_cairo_surface_wrapper_is_active (&other->wrapper)) {
+ passthrough =
+ _cairo_surface_wrapper_create_similar (&other->wrapper,
+ content, width, height);
+ if (unlikely (passthrough->status))
+ return passthrough;
+ }
+
+ surface = _cairo_script_surface_create_internal (ctx,
+ width, height,
+ passthrough);
+ cairo_surface_destroy (passthrough);
+
+ if (unlikely (surface->base.status))
return &surface->base;
status = _bitmap_next_id (&ctx->surface_id,
@@ -1527,6 +1635,16 @@ _vmcontext_destroy (cairo_script_vmcontext_t *ctx)
_cairo_script_surface_scaled_font_fini (font->parent);
}
+ while (! cairo_list_is_empty (&ctx->defines)) {
+ struct def *def = cairo_list_first_entry (&ctx->defines,
+ struct def, link);
+
+ status = _cairo_user_data_array_set_data (def->user_data,
+ (cairo_user_data_key_t *) ctx,
+ NULL, NULL);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ }
+
status = _cairo_output_stream_destroy (ctx->stream);
free (ctx);
@@ -1535,13 +1653,49 @@ _vmcontext_destroy (cairo_script_vmcontext_t *ctx)
}
static cairo_status_t
+_cairo_script_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+
+ if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
+ return _cairo_surface_wrapper_acquire_source_image (&surface->wrapper,
+ image_out,
+ image_extra);
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static void
+_cairo_script_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+
+ assert (_cairo_surface_wrapper_is_active (&surface->wrapper));
+ _cairo_surface_wrapper_release_source_image (&surface->wrapper,
+ image,
+ image_extra);
+}
+
+static cairo_status_t
_cairo_script_surface_finish (void *abstract_surface)
{
cairo_script_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS, status2;
+ _cairo_surface_wrapper_fini (&surface->wrapper);
+
+ if (surface->cr.current_style.dash != NULL) {
+ free (surface->cr.current_style.dash);
+ surface->cr.current_style.dash = NULL;
+ }
_cairo_pattern_fini (&surface->cr.current_source.base);
_cairo_path_fixed_fini (&surface->cr.current_path);
+ _cairo_surface_clipper_reset (&surface->clipper);
if (surface->id != (unsigned long) -1) {
if (! surface->ctx->active) {
@@ -1622,16 +1776,19 @@ _cairo_script_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_script_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_script_surface_t *surface = abstract_surface;
+static cairo_status_t
+_cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_script_surface_t *surface = cairo_container_of (clipper,
+ cairo_script_surface_t,
+ clipper);
cairo_bool_t matrix_updated = FALSE;
cairo_status_t status;
+ cairo_box_t box;
status = _emit_context (surface);
if (unlikely (status))
@@ -1645,6 +1802,18 @@ _cairo_script_surface_intersect_clip_path (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
+ /* skip the trivial clip covering the surface extents */
+ if (surface->width >=0 && surface->height >= 0 &&
+ _cairo_path_fixed_is_rectangle (path, &box))
+ {
+ if (box.p1.x <= 0 && box.p1.y <= 0 &&
+ box.p2.x - box.p1.x >= _cairo_fixed_from_double (surface->width) &&
+ box.p2.y - box.p1.y >= _cairo_fixed_from_double (surface->height))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
status = _emit_identity (surface, &matrix_updated);
if (unlikely (status))
return status;
@@ -1653,13 +1822,17 @@ _cairo_script_surface_intersect_clip_path (void *abstract_surface,
if (unlikely (status))
return status;
- status = _emit_tolerance (surface, tolerance, matrix_updated);
- if (unlikely (status))
- return status;
+ if (! path->is_rectilinear) {
+ status = _emit_tolerance (surface, tolerance, matrix_updated);
+ if (unlikely (status))
+ return status;
+ }
- status = _emit_antialias (surface, antialias);
- if (unlikely (status))
- return status;
+ if (! path->maybe_fill_region) {
+ status = _emit_antialias (surface, antialias);
+ if (unlikely (status))
+ return status;
+ }
status = _emit_path (surface, path);
if (unlikely (status))
@@ -1721,18 +1894,18 @@ static cairo_int_status_t
_cairo_script_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_script_surface_t *surface = abstract_surface;
cairo_status_t status;
ctx_active (surface->ctx);
- status = _emit_context (surface);
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
- status = _emit_operator (surface, op);
+ status = _emit_context (surface);
if (unlikely (status))
return status;
@@ -1740,10 +1913,20 @@ _cairo_script_surface_paint (void *abstract_surface,
if (unlikely (status))
return status;
+ status = _emit_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
_cairo_output_stream_puts (surface->ctx->stream,
"paint\n");
ctx_inactive (surface->ctx);
+
+ if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
+ return _cairo_surface_wrapper_paint (&surface->wrapper,
+ op, source, clip);
+ }
+
return CAIRO_STATUS_SUCCESS;
}
@@ -1752,18 +1935,18 @@ _cairo_script_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_script_surface_t *surface = abstract_surface;
cairo_status_t status;
ctx_active (surface->ctx);
- status = _emit_context (surface);
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
- status = _emit_operator (surface, op);
+ status = _emit_context (surface);
if (unlikely (status))
return status;
@@ -1771,14 +1954,30 @@ _cairo_script_surface_mask (void *abstract_surface,
if (unlikely (status))
return status;
- status = _emit_pattern (surface, mask);
+ status = _emit_operator (surface, op);
if (unlikely (status))
return status;
+ if (_cairo_pattern_equal (source, mask)) {
+ _cairo_output_stream_puts (surface->ctx->stream, "/source get");
+ } else {
+ status = _emit_pattern (surface, mask);
+ if (unlikely (status))
+ return status;
+ }
+
+ assert (surface->cr.current_operator == op);
+
_cairo_output_stream_puts (surface->ctx->stream,
" mask\n");
ctx_inactive (surface->ctx);
+
+ if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
+ return _cairo_surface_wrapper_mask (&surface->wrapper,
+ op, source, mask, clip);
+ }
+
return CAIRO_STATUS_SUCCESS;
}
@@ -1792,7 +1991,7 @@ _cairo_script_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_script_surface_t *surface = abstract_surface;
cairo_bool_t matrix_updated = FALSE;
@@ -1800,6 +1999,10 @@ _cairo_script_surface_stroke (void *abstract_surface,
ctx_active (surface->ctx);
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
status = _emit_context (surface);
if (unlikely (status))
return status;
@@ -1816,7 +2019,7 @@ _cairo_script_surface_stroke (void *abstract_surface,
if (unlikely (status))
return status;
- status = _emit_matrix (surface, ctm, &matrix_updated);
+ status = _emit_scaling_matrix (surface, ctm, &matrix_updated);
if (unlikely (status))
return status;
@@ -1828,9 +2031,11 @@ _cairo_script_surface_stroke (void *abstract_surface,
if (unlikely (status))
return status;
- status = _emit_tolerance (surface, tolerance, matrix_updated);
- if (unlikely (status))
- return status;
+ if (! path->is_rectilinear) {
+ status = _emit_tolerance (surface, tolerance, matrix_updated);
+ if (unlikely (status))
+ return status;
+ }
status = _emit_antialias (surface, antialias);
if (unlikely (status))
@@ -1839,6 +2044,16 @@ _cairo_script_surface_stroke (void *abstract_surface,
_cairo_output_stream_puts (surface->ctx->stream, "stroke+\n");
ctx_inactive (surface->ctx);
+
+ if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
+ return _cairo_surface_wrapper_stroke (&surface->wrapper,
+ op, source, path,
+ style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
+ }
+
return CAIRO_STATUS_SUCCESS;
}
@@ -1850,7 +2065,7 @@ _cairo_script_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_script_surface_t *surface = abstract_surface;
cairo_bool_t matrix_updated = FALSE;
@@ -1858,11 +2073,11 @@ _cairo_script_surface_fill (void *abstract_surface,
ctx_active (surface->ctx);
- status = _emit_context (surface);
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
- status = _emit_operator (surface, op);
+ status = _emit_context (surface);
if (unlikely (status))
return status;
@@ -1878,21 +2093,39 @@ _cairo_script_surface_fill (void *abstract_surface,
if (unlikely (status))
return status;
- status = _emit_tolerance (surface, tolerance, matrix_updated);
- if (unlikely (status))
- return status;
+ if (! path->is_rectilinear) {
+ status = _emit_tolerance (surface, tolerance, matrix_updated);
+ if (unlikely (status))
+ return status;
+ }
- status = _emit_antialias (surface, antialias);
+ if (! path->maybe_fill_region) {
+ status = _emit_antialias (surface, antialias);
+ if (unlikely (status))
+ return status;
+ }
+
+ status = _emit_path (surface, path);
if (unlikely (status))
return status;
- status = _emit_path (surface, path);
+ status = _emit_operator (surface, op);
if (unlikely (status))
return status;
_cairo_output_stream_puts (surface->ctx->stream, "fill+\n");
ctx_inactive (surface->ctx);
+
+ if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
+ return _cairo_surface_wrapper_fill (&surface->wrapper,
+ op, source, path,
+ fill_rule,
+ tolerance,
+ antialias,
+ clip);
+ }
+
return CAIRO_STATUS_SUCCESS;
}
@@ -2024,6 +2257,7 @@ _emit_type42_font (cairo_script_surface_t *surface,
cairo_status_t status, status2;
unsigned long size;
unsigned int load_flags;
+ uint32_t len;
uint8_t *buf;
backend = scaled_font->backend;
@@ -2049,13 +2283,15 @@ _emit_type42_font (cairo_script_surface_t *surface,
_cairo_output_stream_printf (surface->ctx->stream,
"<< "
"/type 42 "
- "/size %lu "
"/index 0 "
"/flags %d "
- "/source <~",
- size, load_flags);
+ "/source <|",
+ load_flags);
base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ len = size;
+ _cairo_output_stream_write (base85_stream, &len, sizeof (len));
+
zlib_stream = _cairo_deflate_stream_create (base85_stream);
_cairo_output_stream_write (zlib_stream, buf, size);
@@ -2071,7 +2307,6 @@ _emit_type42_font (cairo_script_surface_t *surface,
font_private = scaled_font->surface_private;
_cairo_output_stream_printf (surface->ctx->stream,
- " /deflate filter"
" >> font dup /f%lu exch def set-font-face\n",
font_private->id);
@@ -2146,7 +2381,7 @@ _emit_scaled_font (cairo_script_surface_t *surface,
cairo_script_surface_font_private_t *font_private;
cairo_scaled_font_get_ctm (scaled_font, &matrix);
- status = _emit_matrix (surface, &matrix, &matrix_updated);
+ status = _emit_scaling_matrix (surface, &matrix, &matrix_updated);
if (unlikely (status))
return status;
@@ -2268,7 +2503,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface,
if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) {
_cairo_output_stream_printf (surface->ctx->stream,
- " [%f %f %f %f %f %f] set-matrix\n",
+ "\n [%f %f %f %f %f %f] set-matrix\n",
scaled_font->font_matrix.xx,
scaled_font->font_matrix.yx,
scaled_font->font_matrix.xy,
@@ -2390,6 +2625,65 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
return status;
}
+static void
+_emit_string_literal (cairo_script_surface_t *surface,
+ const char *utf8, int len)
+{
+ char c;
+ const char *end;
+
+ _cairo_output_stream_puts (surface->ctx->stream, "(");
+
+ if (utf8 == NULL) {
+ end = utf8;
+ } else {
+ if (len < 0)
+ len = strlen (utf8);
+ end = utf8 + len;
+ }
+
+ while (utf8 < end) {
+ switch ((c = *utf8++)) {
+ case '\n':
+ c = 'n';
+ goto ESCAPED_CHAR;
+ case '\r':
+ c = 'r';
+ goto ESCAPED_CHAR;
+ case '\t':
+ c = 't';
+ goto ESCAPED_CHAR;
+ case '\b':
+ c = 'b';
+ goto ESCAPED_CHAR;
+ case '\f':
+ c = 'f';
+ goto ESCAPED_CHAR;
+ case '\\':
+ case '(':
+ case ')':
+ESCAPED_CHAR:
+ _cairo_output_stream_printf (surface->ctx->stream, "\\%c", c);
+ break;
+ default:
+ if (isprint (c) || isspace (c)) {
+ _cairo_output_stream_printf (surface->ctx->stream, "%c", c);
+ } else {
+ int octal = 0;
+ while (c) {
+ octal *= 10;
+ octal += c&7;
+ c /= 8;
+ }
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "\\%03d", octal);
+ }
+ break;
+ }
+ }
+ _cairo_output_stream_puts (surface->ctx->stream, ")");
+}
+
static cairo_int_status_t
_cairo_script_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
@@ -2402,7 +2696,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
int num_clusters,
cairo_text_cluster_flags_t backward,
cairo_scaled_font_t *scaled_font,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_script_surface_t *surface = abstract_surface;
cairo_script_surface_font_private_t *font_private;
@@ -2415,11 +2709,11 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
ctx_active (surface->ctx);
- status = _emit_context (surface);
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
- status = _emit_operator (surface, op);
+ status = _emit_context (surface);
if (unlikely (status))
return status;
@@ -2431,6 +2725,10 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
if (unlikely (status))
return status;
+ status = _emit_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs);
if (unlikely (status))
return status;
@@ -2439,9 +2737,8 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
/* [cx cy [glyphs]] show_glyphs */
if (utf8 != NULL && clusters != NULL) {
- _cairo_output_stream_printf (surface->ctx->stream,
- "(%s) ",
- utf8);
+ _emit_string_literal (surface, utf8, utf8_len);
+ _cairo_output_stream_puts (surface->ctx->stream, " ");
}
matrix = surface->cr.current_ctm;
@@ -2597,24 +2894,41 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
}
ctx_inactive (surface->ctx);
+
+ if (_cairo_surface_wrapper_is_active (&surface->wrapper)){
+ return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper,
+ op, source,
+ utf8, utf8_len,
+ glyphs, num_glyphs,
+ clusters, num_clusters,
+ backward,
+ scaled_font,
+ clip);
+ }
+
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
+static cairo_bool_t
_cairo_script_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_script_surface_t *surface = abstract_surface;
+ if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
+ return _cairo_surface_wrapper_get_extents (&surface->wrapper,
+ rectangle);
+ }
+
if (surface->width < 0 || surface->height < 0)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return FALSE;
rectangle->x = 0;
rectangle->y = 0;
rectangle->width = surface->width;
rectangle->height = surface->height;
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
static const cairo_surface_backend_t
@@ -2622,8 +2936,8 @@ _cairo_script_surface_backend = {
CAIRO_SURFACE_TYPE_SCRIPT,
_cairo_script_surface_create_similar,
_cairo_script_surface_finish,
- NULL, //_cairo_script_surface_acquire_source_image,
- NULL, //_cairo_script_surface_release_source_image,
+ _cairo_script_surface_acquire_source_image,
+ _cairo_script_surface_release_source_image,
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
@@ -2634,8 +2948,6 @@ _cairo_script_surface_backend = {
NULL, /* check_span_renderer */
_cairo_script_surface_copy_page,
_cairo_script_surface_show_page,
- NULL, /* set_clip_region */
- _cairo_script_surface_intersect_clip_path,
_cairo_script_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -2651,10 +2963,10 @@ _cairo_script_surface_backend = {
_cairo_script_surface_fill,
NULL,
- NULL, //_cairo_script_surface_snapshot,
+ NULL, /* _cairo_script_surface_snapshot, */
NULL, /* is_similar */
- NULL, /* reset */
+ /* XXX need fill-stroke for passthrough */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
@@ -2686,6 +2998,8 @@ _cairo_script_vmcontext_create (cairo_output_stream_t *stream)
ctx->stream = stream;
ctx->mode = CAIRO_SCRIPT_MODE_ASCII;
+ cairo_list_init (&ctx->defines);
+
return ctx;
}
@@ -2711,7 +3025,8 @@ _cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr)
static cairo_script_surface_t *
_cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx,
double width,
- double height)
+ double height,
+ cairo_surface_t *passthrough)
{
cairo_script_surface_t *surface;
@@ -2726,6 +3041,11 @@ _cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx,
&_cairo_script_surface_backend,
CAIRO_CONTENT_COLOR_ALPHA);
+ _cairo_surface_wrapper_init (&surface->wrapper, passthrough);
+
+ _cairo_surface_clipper_init (&surface->clipper,
+ _cairo_script_surface_clipper_intersect_clip_path);
+
surface->ctx = ctx;
ctx->ref++;
@@ -2755,7 +3075,7 @@ cairo_script_surface_create (const char *filename,
surface = _cairo_script_surface_create_internal
- (_cairo_script_vmcontext_create (stream), width, height);
+ (_cairo_script_vmcontext_create (stream), width, height, NULL);
if (surface->base.status)
return &surface->base;
@@ -2776,7 +3096,64 @@ cairo_script_surface_create_for_stream (cairo_write_func_t write_func,
return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
return &_cairo_script_surface_create_internal
- (_cairo_script_vmcontext_create (stream), width, height)->base;
+ (_cairo_script_vmcontext_create (stream), width, height, NULL)->base;
+}
+
+cairo_surface_t *
+cairo_script_surface_create_for_target (cairo_surface_t *target,
+ cairo_write_func_t write_func,
+ void *closure)
+{
+ cairo_output_stream_t *stream;
+ cairo_script_surface_t *surface;
+ cairo_rectangle_int_t extents;
+
+ if (unlikely (target->status))
+ return _cairo_surface_create_in_error (target->status);
+
+ stream = _cairo_output_stream_create (write_func, NULL, closure);
+ if (_cairo_output_stream_get_status (stream))
+ return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
+
+ if (! _cairo_surface_get_extents (target, &extents))
+ extents.width = extents.height = -1;
+
+ surface = _cairo_script_surface_create_internal
+ (_cairo_script_vmcontext_create (stream),
+ extents.width, extents.height,
+ target);
+ if (unlikely (surface->base.status))
+ return &surface->base;
+
+ _cairo_output_stream_puts (surface->ctx->stream, "%!CairoScript\n");
+ return &surface->base;
+}
+
+void
+cairo_script_surface_write_comment (cairo_surface_t *abstract_surface,
+ const char *comment,
+ int len)
+{
+ cairo_script_surface_t *surface;
+ cairo_status_t status_ignored;
+
+ if (! _cairo_surface_is_script (abstract_surface)) {
+ status_ignored = _cairo_surface_set_error (abstract_surface,
+ CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return;
+ }
+
+ if (abstract_surface->status)
+ return;
+
+ surface = (cairo_script_surface_t *) abstract_surface;
+
+ if (len < 0)
+ len = strlen (comment);
+
+ _cairo_output_stream_puts (surface->ctx->stream, "% ");
+ _cairo_output_stream_write (surface->ctx->stream, comment, len);
+ _cairo_output_stream_puts (surface->ctx->stream, "\n");
}
void
diff --git a/src/cairo-script.h b/src/cairo-script.h
index 9c428e3b..397080bc 100644
--- a/src/cairo-script.h
+++ b/src/cairo-script.h
@@ -53,6 +53,16 @@ cairo_script_surface_create_for_stream (cairo_write_func_t write_func,
double width,
double height);
+cairo_public cairo_surface_t *
+cairo_script_surface_create_for_target (cairo_surface_t *surface,
+ cairo_write_func_t write_func,
+ void *closure);
+
+cairo_public void
+cairo_script_surface_write_comment (cairo_surface_t *abstract_surface,
+ const char *comment,
+ int len);
+
typedef enum {
CAIRO_SCRIPT_MODE_BINARY,
CAIRO_SCRIPT_MODE_ASCII
diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
index c285f949..c706b22a 100644
--- a/src/cairo-spans-private.h
+++ b/src/cairo-spans-private.h
@@ -132,13 +132,14 @@ _cairo_span_renderer_set_error (void *abstract_renderer,
cairo_status_t error);
cairo_private cairo_status_t
-_cairo_path_fixed_fill_using_spans (
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_path_fixed_t *path,
- cairo_surface_t *dst,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects);
+_cairo_path_fixed_fill_using_spans (cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_path_fixed_t *path,
+ cairo_surface_t *dst,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *rects,
+ cairo_region_t *clip_region);
+
#endif /* CAIRO_SPANS_PRIVATE_H */
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
index cf8f7677..48396b54 100644
--- a/src/cairo-spans.c
+++ b/src/cairo-spans.c
@@ -149,19 +149,19 @@ _create_scan_converter (cairo_fill_rule_t fill_rule,
}
cairo_status_t
-_cairo_path_fixed_fill_using_spans (
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_path_fixed_t *path,
- cairo_surface_t *dst,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects)
+_cairo_path_fixed_fill_using_spans (cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_path_fixed_t *path,
+ cairo_surface_t *dst,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *rects,
+ cairo_region_t *clip_region)
{
cairo_status_t status;
cairo_span_renderer_t *renderer = _cairo_surface_create_span_renderer (
- op, pattern, dst, antialias, rects);
+ op, pattern, dst, antialias, rects, clip_region);
cairo_scan_converter_t *converter = _create_scan_converter (
fill_rule, antialias, rects);
diff --git a/src/cairo-stroke-style.c b/src/cairo-stroke-style.c
index 9ab91e53..38518838 100644
--- a/src/cairo-stroke-style.c
+++ b/src/cairo-stroke-style.c
@@ -110,13 +110,13 @@ _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
style_expansion = M_SQRT1_2;
if (style->line_join == CAIRO_LINE_JOIN_MITER &&
- style_expansion < style->miter_limit)
+ style_expansion < M_SQRT2 * style->miter_limit)
{
- style_expansion = style->miter_limit;
+ style_expansion = M_SQRT2 * style->miter_limit;
}
style_expansion *= style->line_width;
- *dx = style_expansion * (fabs (ctm->xx) + fabs (ctm->xy));
- *dy = style_expansion * (fabs (ctm->yy) + fabs (ctm->yx));
+ *dx = style_expansion * hypot (ctm->xx, ctm->xy);
+ *dy = style_expansion * hypot (ctm->yy, ctm->yx);
}
diff --git a/src/cairo-surface-clipper-private.h b/src/cairo-surface-clipper-private.h
new file mode 100644
index 00000000..f3d9de18
--- /dev/null
+++ b/src/cairo-surface-clipper-private.h
@@ -0,0 +1,72 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.u>
+ */
+
+#ifndef CAIRO_SURFACE_CLIPPER_PRIVATE_H
+#define CAIRO_SURFACE_CLIPPER_PRIVATE_H
+
+#include "cairo-types-private.h"
+#include "cairo-clip-private.h"
+
+CAIRO_BEGIN_DECLS
+
+typedef struct _cairo_surface_clipper cairo_surface_clipper_t;
+
+typedef cairo_status_t
+(*cairo_surface_clipper_intersect_clip_path_func_t) (cairo_surface_clipper_t *,
+ cairo_path_fixed_t *,
+ cairo_fill_rule_t,
+ double,
+ cairo_antialias_t);
+struct _cairo_surface_clipper {
+ cairo_clip_t clip;
+ cairo_bool_t is_clipped;
+ cairo_surface_clipper_intersect_clip_path_func_t intersect_clip_path;
+};
+
+cairo_private cairo_status_t
+_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper,
+ cairo_clip_t *clip);
+
+cairo_private void
+_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper,
+ cairo_surface_clipper_intersect_clip_path_func_t intersect);
+
+cairo_private void
+_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_SURFACE_CLIPPER_PRIVATE_H */
diff --git a/src/cairo-surface-clipper.c b/src/cairo-surface-clipper.c
new file mode 100644
index 00000000..d536f0cb
--- /dev/null
+++ b/src/cairo-surface-clipper.c
@@ -0,0 +1,138 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-surface-clipper-private.h"
+
+/* A collection of routines to facilitate vector surface clipping */
+
+static cairo_status_t
+_cairo_surface_clipper_intersect_clip_path_recursive (cairo_surface_clipper_t *clipper,
+ cairo_clip_path_t *clip_path)
+{
+ cairo_status_t status;
+
+ if (clip_path->prev != NULL) {
+ status =
+ _cairo_surface_clipper_intersect_clip_path_recursive (clipper,
+ clip_path->prev);
+ if (unlikely (status))
+ return status;
+ }
+
+ return clipper->intersect_clip_path (clipper,
+ &clip_path->path,
+ clip_path->fill_rule,
+ clip_path->tolerance,
+ clip_path->antialias);
+}
+
+cairo_status_t
+_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_bool_t clear;
+
+ /* XXX as we cache a reference to the path, and compare every time,
+ * we may in future need to install a notification if the clip->path
+ * is every modified (e.g. cairo_clip_translate).
+ */
+
+ if (clip == NULL && clipper->clip.path == NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (clip != NULL && clip->path == clipper->clip.path)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (clip != NULL && clipper->clip.path != NULL &&
+ _cairo_path_fixed_equal (&clip->path->path, &clipper->clip.path->path))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ /* all clipped out state should never propagate this far */
+ assert (clip == NULL || clip->path != NULL);
+
+ /* Check whether this clip is a continuation of the previous.
+ * If not, we have to remove the current clip and rebuild.
+ */
+ clear = clip == NULL || clip->path->prev != clipper->clip.path;
+
+ _cairo_clip_reset (&clipper->clip);
+ _cairo_clip_init_copy (&clipper->clip, clip);
+
+ if (clear) {
+ clipper->is_clipped = FALSE;
+ status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0);
+ if (unlikely (status))
+ return status;
+
+ if (clip != NULL && clip->path != NULL) {
+ status =
+ _cairo_surface_clipper_intersect_clip_path_recursive (clipper,
+ clip->path);
+ clipper->is_clipped = TRUE;
+ }
+ } else {
+ cairo_clip_path_t *path = clip->path;
+
+ clipper->is_clipped = TRUE;
+ status = clipper->intersect_clip_path (clipper,
+ &path->path,
+ path->fill_rule,
+ path->tolerance,
+ path->antialias);
+ }
+
+ return status;
+}
+
+void
+_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper,
+ cairo_surface_clipper_intersect_clip_path_func_t func)
+{
+ _cairo_clip_init (&clipper->clip);
+ clipper->is_clipped = FALSE;
+ clipper->intersect_clip_path = func;
+}
+
+void
+_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper)
+{
+ _cairo_clip_reset (&clipper->clip);
+ clipper->is_clipped = FALSE;
+}
diff --git a/src/cairo-surface-fallback-private.h b/src/cairo-surface-fallback-private.h
index cd181780..236b7459 100644
--- a/src/cairo-surface-fallback-private.h
+++ b/src/cairo-surface-fallback-private.h
@@ -44,13 +44,15 @@
cairo_private cairo_status_t
_cairo_surface_fallback_paint (cairo_surface_t *surface,
cairo_operator_t op,
- const cairo_pattern_t *source);
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask);
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_stroke (cairo_surface_t *surface,
@@ -61,7 +63,8 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias);
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_fill (cairo_surface_t *surface,
@@ -70,7 +73,8 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias);
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
@@ -78,7 +82,8 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
- cairo_scaled_font_t *scaled_font);
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip);
cairo_private cairo_surface_t *
_cairo_surface_fallback_snapshot (cairo_surface_t *surface);
@@ -95,7 +100,8 @@ _cairo_surface_fallback_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height);
+ unsigned int height,
+ cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
@@ -116,7 +122,8 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps);
+ int num_traps,
+ cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 830c1b3d..9867eea8 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -40,6 +40,7 @@
#include "cairo-surface-fallback-private.h"
#include "cairo-clip-private.h"
+#include "cairo-region-private.h"
typedef struct {
cairo_surface_t *dst;
@@ -82,13 +83,13 @@ _fallback_init (fallback_state_t *state,
if (unlikely (status))
return status;
+
/* XXX: This NULL value tucked away in state->image is a rather
* ugly interface. Cleaner would be to push the
* CAIRO_INT_STATUS_NOTHING_TO_DO value down into
* _cairo_surface_acquire_dest_image and its backend
* counterparts. */
- if (state->image == NULL)
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ assert (state->image != NULL);
return CAIRO_STATUS_SUCCESS;
}
@@ -101,46 +102,85 @@ _fallback_fini (fallback_state_t *state)
state->image_extra);
}
-typedef cairo_status_t (*cairo_draw_func_t) (void *closure,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_surface_t *dst,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents);
+typedef cairo_status_t
+(*cairo_draw_func_t) (void *closure,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_surface_t *dst,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region);
static cairo_status_t
_create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
cairo_clip_t *clip,
- cairo_draw_func_t draw_func,
+ cairo_draw_func_t draw_func,
void *draw_closure,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
cairo_surface_t *mask;
+ cairo_region_t *clip_region = NULL;
+ cairo_solid_pattern_t solid;
cairo_status_t status;
+ cairo_bool_t clip_surface = FALSE;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (! _cairo_status_is_error (status));
+
+ clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (clip_region && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+ }
- mask = cairo_surface_create_similar (dst,
- CAIRO_CONTENT_ALPHA,
- extents->width,
- extents->height);
- if (mask->status)
+ /* We need to use solid here, because to use CAIRO_OPERATOR_SOURCE with
+ * a mask (as called via _cairo_surface_mask) triggers assertion failures.
+ */
+ mask = _cairo_surface_create_similar_solid (dst,
+ CAIRO_CONTENT_ALPHA,
+ extents->width,
+ extents->height,
+ CAIRO_COLOR_TRANSPARENT,
+ TRUE);
+ if (unlikely (mask->status))
return mask->status;
- status = (*draw_func) (draw_closure, CAIRO_OPERATOR_ADD,
- NULL, mask,
- extents->x, extents->y,
- extents);
+ _cairo_pattern_init_solid (&solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_ALPHA);
+ status = draw_func (draw_closure, CAIRO_OPERATOR_ADD,
+ &solid.base, mask,
+ extents->x, extents->y,
+ extents,
+ clip_region);
if (unlikely (status))
goto CLEANUP_SURFACE;
- if (clip && clip->surface)
- status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN,
- mask,
- extents->x, extents->y,
- extents);
- if (unlikely (status))
- goto CLEANUP_SURFACE;
+ if (clip_surface) {
+ cairo_surface_pattern_t pattern;
+ cairo_surface_t *surface;
+
+ surface = _cairo_clip_get_surface (clip, mask);
+ _cairo_pattern_init_for_surface (&pattern, surface);
+ cairo_surface_destroy (surface);
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ &pattern.base,
+ NULL,
+ mask,
+ extents->x - clip->path->extents.x,
+ extents->y - clip->path->extents.y,
+ 0, 0,
+ 0, 0,
+ extents->width, extents->height,
+ NULL);
+
+ _cairo_pattern_fini (&pattern.base);
+
+ if (unlikely (status))
+ goto CLEANUP_SURFACE;
+ }
_cairo_pattern_init_for_surface (mask_pattern, mask);
@@ -169,17 +209,17 @@ _clip_and_composite_with_mask (cairo_clip_t *clip,
clip,
draw_func, draw_closure,
dst, extents);
- if (unlikely (status))
- return status;
-
- status = _cairo_surface_composite (op,
- src, &mask_pattern.base, dst,
- extents->x, extents->y,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height);
-
- _cairo_pattern_fini (&mask_pattern.base);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _cairo_surface_composite (op,
+ src, &mask_pattern.base, dst,
+ extents->x, extents->y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height,
+ NULL);
+
+ _cairo_pattern_fini (&mask_pattern.base);
+ }
return status;
}
@@ -197,77 +237,95 @@ _clip_and_composite_combine (cairo_clip_t *clip,
const cairo_rectangle_int_t *extents)
{
cairo_surface_t *intermediate;
- cairo_surface_pattern_t dst_pattern;
- cairo_surface_pattern_t intermediate_pattern;
+ cairo_surface_pattern_t pattern;
+ cairo_surface_pattern_t clip_pattern;
+ cairo_surface_t *clip_surface;
cairo_status_t status;
/* We'd be better off here creating a surface identical in format
* to dst, but we have no way of getting that information.
* A CAIRO_CONTENT_CLONE or something might be useful.
- * cairo_surface_create_similar() also unnecessarily clears the surface.
*/
- intermediate = cairo_surface_create_similar (dst,
- CAIRO_CONTENT_COLOR_ALPHA,
- extents->width,
- extents->height);
- if (intermediate->status)
+ intermediate =
+ _cairo_surface_create_similar_scratch (dst,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ extents->width,
+ extents->height);
+ if (intermediate == NULL) {
+ intermediate =
+ _cairo_image_surface_create_with_content (CAIRO_CONTENT_COLOR_ALPHA,
+ extents->width,
+ extents->width);
+ }
+ if (unlikely (intermediate->status))
return intermediate->status;
- /* Initialize the intermediate surface from the destination surface
- */
- _cairo_pattern_init_for_surface (&dst_pattern, dst);
-
+ /* Initialize the intermediate surface from the destination surface */
+ _cairo_pattern_init_for_surface (&pattern, dst);
status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
- &dst_pattern.base, NULL, intermediate,
+ &pattern.base, NULL, intermediate,
extents->x, extents->y,
0, 0,
0, 0,
- extents->width, extents->height);
-
- _cairo_pattern_fini (&dst_pattern.base);
-
+ extents->width, extents->height,
+ NULL);
+ _cairo_pattern_fini (&pattern.base);
if (unlikely (status))
goto CLEANUP_SURFACE;
status = (*draw_func) (draw_closure, op,
src, intermediate,
extents->x, extents->y,
- extents);
+ extents,
+ NULL);
if (unlikely (status))
goto CLEANUP_SURFACE;
- /* Combine that with the clip
- */
- status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_IN,
- intermediate,
- extents->x, extents->y,
- extents);
- if (unlikely (status))
+ assert (clip->path != NULL);
+ clip_surface = _cairo_clip_get_surface (clip, dst);
+ if (unlikely (clip_surface->status))
goto CLEANUP_SURFACE;
- /* Punch the clip out of the destination
- */
- status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_OUT,
- dst,
- 0, 0,
- extents);
+ _cairo_pattern_init_for_surface (&clip_pattern, clip_surface);
+ cairo_surface_destroy (clip_surface);
+
+ /* Combine that with the clip */
+ status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_IN,
+ &clip_pattern.base, NULL, intermediate,
+ extents->x - clip->path->extents.x,
+ extents->y - clip->path->extents.y,
+ 0, 0,
+ 0, 0,
+ extents->width, extents->height,
+ NULL);
if (unlikely (status))
goto CLEANUP_SURFACE;
- /* Now add the two results together
- */
- _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+ /* Punch the clip out of the destination */
+ status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
+ &clip_pattern.base, NULL, dst,
+ extents->x - clip->path->extents.x,
+ extents->y - clip->path->extents.y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height,
+ NULL);
+ if (unlikely (status))
+ goto CLEANUP_SURFACE;
+ /* Now add the two results together */
+ _cairo_pattern_init_for_surface (&pattern, intermediate);
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
- &intermediate_pattern.base, NULL, dst,
+ &pattern.base, NULL, dst,
0, 0,
0, 0,
extents->x, extents->y,
- extents->width, extents->height);
-
- _cairo_pattern_fini (&intermediate_pattern.base);
+ extents->width, extents->height,
+ NULL);
+ _cairo_pattern_fini (&pattern.base);
CLEANUP_SURFACE:
+ _cairo_pattern_fini (&clip_pattern.base);
cairo_surface_destroy (intermediate);
return status;
@@ -285,10 +343,10 @@ _clip_and_composite_source (cairo_clip_t *clip,
const cairo_rectangle_int_t *extents)
{
cairo_surface_pattern_t mask_pattern;
+ cairo_region_t *clip_region = NULL;
cairo_status_t status;
- /* Create a surface that is mask IN clip
- */
+ /* Create a surface that is mask IN clip */
status = _create_composite_mask_pattern (&mask_pattern,
clip,
draw_func, draw_closure,
@@ -296,26 +354,35 @@ _clip_and_composite_source (cairo_clip_t *clip,
if (unlikely (status))
return status;
- /* Compute dest' = dest OUT (mask IN clip)
- */
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (! _cairo_status_is_error (status));
+
+ /* a solitary clip rectangle is already accommodated by extents */
+ if (clip_region && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+ }
+
+ /* Compute dest' = dest OUT (mask IN clip) */
status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
&mask_pattern.base, NULL, dst,
0, 0,
0, 0,
extents->x, extents->y,
- extents->width, extents->height);
+ extents->width, extents->height,
+ clip_region);
if (unlikely (status))
goto CLEANUP_MASK_PATTERN;
- /* Now compute (src IN (mask IN clip)) ADD dest'
- */
+ /* Now compute (src IN (mask IN clip)) ADD dest' */
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
src, &mask_pattern.base, dst,
extents->x, extents->y,
0, 0,
extents->x, extents->y,
- extents->width, extents->height);
+ extents->width, extents->height,
+ clip_region);
CLEANUP_MASK_PATTERN:
_cairo_pattern_fini (&mask_pattern.base);
@@ -372,30 +439,45 @@ _clip_and_composite (cairo_clip_t *clip,
op = CAIRO_OPERATOR_DEST_OUT;
}
- if ((clip && clip->surface) || op == CAIRO_OPERATOR_SOURCE)
- {
- if (op == CAIRO_OPERATOR_SOURCE)
- status = _clip_and_composite_source (clip,
- src,
- draw_func, draw_closure,
- dst, extents);
- else if (_cairo_operator_bounded_by_mask (op))
- status = _clip_and_composite_with_mask (clip, op,
- src,
- draw_func, draw_closure,
- dst, extents);
- else
- status = _clip_and_composite_combine (clip, op,
- src,
- draw_func, draw_closure,
- dst, extents);
- }
- else
- {
- status = (*draw_func) (draw_closure, op,
- src, dst,
- 0, 0,
- extents);
+ if (op == CAIRO_OPERATOR_SOURCE) {
+ status = _clip_and_composite_source (clip,
+ src,
+ draw_func, draw_closure,
+ dst, extents);
+ } else {
+ cairo_bool_t clip_surface = FALSE;
+ cairo_region_t *clip_region = NULL;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (! _cairo_status_is_error (status));
+
+ clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (clip_surface) {
+ if (_cairo_operator_bounded_by_mask (op)) {
+ status = _clip_and_composite_with_mask (clip, op,
+ src,
+ draw_func, draw_closure,
+ dst, extents);
+ } else {
+ status = _clip_and_composite_combine (clip, op,
+ src,
+ draw_func, draw_closure,
+ dst, extents);
+ }
+ } else {
+ /* a solitary clip rectangle is already accommodated by extents */
+ if (clip_region && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+
+ status = draw_func (draw_closure, op,
+ src, dst,
+ 0, 0,
+ extents,
+ clip_region);
+ }
}
return status;
@@ -409,59 +491,51 @@ _composite_trap_region (cairo_clip_t *clip,
cairo_operator_t op,
cairo_surface_t *dst,
cairo_region_t *trap_region,
- cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_solid_pattern_t solid_pattern;
- cairo_surface_pattern_t mask;
- int num_rects = cairo_region_num_rectangles (trap_region);
- unsigned int clip_serial;
- cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
+ cairo_surface_pattern_t mask_pattern;
+ cairo_pattern_t *mask = NULL;
+ int mask_x = 0, mask_y =0;
+
+ if (clip != NULL) {
+ cairo_surface_t *clip_surface = NULL;
+ const cairo_rectangle_int_t *clip_extents;
+
+ clip_surface = _cairo_clip_get_surface (clip, dst);
+ if (unlikely (clip_surface->status))
+ return clip_surface->status;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
+ CAIRO_CONTENT_COLOR);
+ src = &solid_pattern.base;
+ op = CAIRO_OPERATOR_DEST_OUT;
+ }
- if (num_rects == 0)
- return CAIRO_STATUS_SUCCESS;
+ _cairo_pattern_init_for_surface (&mask_pattern, clip_surface);
+ cairo_surface_destroy (clip_surface);
- if (clip_surface && op == CAIRO_OPERATOR_CLEAR) {
- _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
- src = &solid_pattern.base;
- op = CAIRO_OPERATOR_DEST_OUT;
+ clip_extents = _cairo_clip_get_extents (clip);
+ mask_x = extents->x - clip_extents->x;
+ mask_y = extents->y - clip_extents->y;
+ mask = &mask_pattern.base;
}
- if (num_rects > 1) {
- if (_cairo_surface_get_clip_mode (dst) != CAIRO_CLIP_MODE_REGION)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- clip_serial = _cairo_surface_allocate_clip_serial (dst);
- status = _cairo_surface_set_clip_region (dst,
- trap_region,
- clip_serial);
- if (unlikely (status))
- return status;
- }
+ /* reduce a solitary clipping region to the extents */
+ if (cairo_region_num_rectangles (trap_region) == 1)
+ trap_region = NULL;
- if (clip_surface)
- _cairo_pattern_init_for_surface (&mask, clip_surface);
-
- status = _cairo_surface_composite (op,
- src,
- clip_surface ? &mask.base : NULL,
- dst,
+ status = _cairo_surface_composite (op, src, mask, dst,
extents->x, extents->y,
- extents->x - (clip_surface ? clip->surface_rect.x : 0),
- extents->y - (clip_surface ? clip->surface_rect.y : 0),
+ mask_x, mask_y,
extents->x, extents->y,
- extents->width, extents->height);
-
- /* Restore the original clip if we modified it temporarily. */
- if (num_rects > 1) {
- cairo_status_t status2 = _cairo_surface_set_clip (dst, clip);
- if (status == CAIRO_STATUS_SUCCESS)
- status = status2;
- }
+ extents->width, extents->height,
+ trap_region);
- if (clip_surface)
- _cairo_pattern_fini (&mask.base);
+ if (mask != NULL)
+ _cairo_pattern_fini (mask);
return status;
}
@@ -478,183 +552,211 @@ _composite_traps_draw_func (void *closure,
cairo_surface_t *dst,
int dst_x,
int dst_y,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
{
cairo_composite_traps_info_t *info = closure;
- cairo_solid_pattern_t pattern;
if (dst_x != 0 || dst_y != 0)
_cairo_traps_translate (info->traps, - dst_x, - dst_y);
- if (src == NULL) {
- _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
- src = &pattern.base;
- }
-
return _cairo_surface_composite_trapezoids (op,
src, dst, info->antialias,
extents->x, extents->y,
extents->x - dst_x, extents->y - dst_y,
extents->width, extents->height,
info->traps->traps,
- info->traps->num_traps);
+ info->traps->num_traps,
+ clip_region);
}
-/* Warning: This call modifies the coordinates of traps */
+enum {
+ HAS_CLEAR_REGION = 0x1,
+};
+
static cairo_status_t
-_clip_and_composite_trapezoids (const cairo_pattern_t *src,
- cairo_operator_t op,
- cairo_surface_t *dst,
- cairo_traps_t *traps,
- cairo_clip_t *clip,
- cairo_antialias_t antialias)
+_clip_and_composite_region (const cairo_pattern_t *src,
+ cairo_operator_t op,
+ cairo_surface_t *dst,
+ cairo_region_t *trap_region,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents)
{
+ cairo_region_t clear_region;
+ cairo_bool_t clip_surface = FALSE;
+ unsigned int has_region = 0;
cairo_status_t status;
- cairo_region_t *trap_region = NULL;
- cairo_region_t *clear_region = NULL;
- cairo_rectangle_int_t extents;
- cairo_composite_traps_info_t traps_info;
- if (_cairo_operator_bounded_by_mask (op) && traps->num_traps == 0)
- return CAIRO_STATUS_SUCCESS;
+ if (clip != NULL) {
+ cairo_region_t *clip_region;
- status = _cairo_surface_get_extents (dst, &extents);
- if (unlikely (status))
- return status;
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (! _cairo_status_is_error (status));
- status = _cairo_traps_extract_region (traps, &trap_region);
- if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ }
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t trap_extents;
- if (trap_region) {
- status = _cairo_clip_intersect_to_region (clip, trap_region);
+ cairo_region_get_extents (trap_region, &trap_extents);
+ if (! _cairo_rectangle_intersect (extents, &trap_extents))
+ return CAIRO_STATUS_SUCCESS;
+ } else {
+ if (! clip_surface) {
+ /* If we optimize drawing with an unbounded operator to
+ * _cairo_surface_fill_rectangles() or to drawing with a
+ * clip region, then we have an additional region to clear.
+ */
+ _cairo_region_init_rectangle (&clear_region, extents);
+ status = cairo_region_subtract (&clear_region, trap_region);
if (unlikely (status))
- goto out;
+ return status;
- cairo_region_get_extents (trap_region, &trap_extents);
- } else {
- cairo_box_t trap_box;
- _cairo_traps_extents (traps, &trap_box);
- _cairo_box_round_to_rectangle (&trap_box, &trap_extents);
+ if (! cairo_region_is_empty (&clear_region))
+ has_region |= HAS_CLEAR_REGION;
}
+ }
- if (! _cairo_rectangle_intersect (&extents, &trap_extents)) {
- status = CAIRO_STATUS_SUCCESS;
- goto out;
- }
+ if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
+ ! clip_surface)
+ {
+ const cairo_color_t *color;
- status = _cairo_clip_intersect_to_rectangle (clip, &extents);
- if (unlikely (status))
- goto out;
+ if (op == CAIRO_OPERATOR_CLEAR)
+ color = CAIRO_COLOR_TRANSPARENT;
+ else
+ color = &((cairo_solid_pattern_t *)src)->color;
+
+ /* Solid rectangles special case */
+ status = _cairo_surface_fill_region (dst, op, color, trap_region);
} else {
- cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
+ /* For a simple rectangle, we can just use composite(), for more
+ * rectangles, we have to set a clip region. The cost of rasterizing
+ * trapezoids is pretty high for most backends currently, so it's
+ * worthwhile even if a region is needed.
+ *
+ * If we have a clip surface, we set it as the mask; this only works
+ * for bounded operators other than SOURCE; for unbounded operators,
+ * clip and mask cannot be interchanged. For SOURCE, the operator
+ * as implemented by the backends is different in its handling
+ * of the mask then what we want.
+ *
+ * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
+ * more than rectangle and the destination doesn't support clip
+ * regions. In that case, we fall through.
+ */
+ status = _composite_trap_region (clip_surface ? clip : NULL,
+ src, op, dst,
+ trap_region, extents);
+ }
- if (trap_region && !clip_surface) {
- /* If we optimize drawing with an unbounded operator to
- * _cairo_surface_fill_rectangles() or to drawing with a
- * clip region, then we have an additional region to clear.
- */
- clear_region = cairo_region_create_rectangle (&extents);
+ if (has_region & HAS_CLEAR_REGION) {
+ if (status == CAIRO_STATUS_SUCCESS) {
+ status = _cairo_surface_fill_region (dst,
+ CAIRO_OPERATOR_CLEAR,
+ CAIRO_COLOR_TRANSPARENT,
+ &clear_region);
+ }
+ _cairo_region_fini (&clear_region);
+ }
- status = cairo_region_status (clear_region);
- if (unlikely (status))
- goto out;
+ return status;
+}
- status = _cairo_clip_intersect_to_region (clip, clear_region);
- if (unlikely (status))
- goto out;
+/* Warning: This call modifies the coordinates of traps */
+static cairo_status_t
+_clip_and_composite_trapezoids (const cairo_pattern_t *src,
+ cairo_operator_t op,
+ cairo_surface_t *dst,
+ cairo_traps_t *traps,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_composite_traps_info_t traps_info;
+ cairo_region_t *clip_region = NULL;
+ cairo_bool_t clip_surface = FALSE;
+ cairo_status_t status;
- cairo_region_get_extents (clear_region, &extents);
+ if (_cairo_operator_bounded_by_mask (op) && traps->num_traps == 0)
+ return CAIRO_STATUS_SUCCESS;
- status = cairo_region_subtract (clear_region, trap_region);
- if (unlikely (status))
- goto out;
-
- if (cairo_region_is_empty (clear_region)) {
- cairo_region_destroy (clear_region);
- clear_region = NULL;
- }
- } else {
- status = _cairo_clip_intersect_to_rectangle (clip, &extents);
- }
- }
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ if (unlikely (_cairo_status_is_error (status)))
+ return status;
- if (unlikely (status))
- goto out;
+ /* The all-clipped state should not have been propagated this far. */
+ assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
+ clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ }
- if (trap_region) {
- cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
+ /* Use a fast path if the trapezoids consist of a simple region,
+ * but we can only do this if we do not have a clip surface, or can
+ * substitute the mask with the clip.
+ */
+ if (! clip_surface ||
+ (_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE))
+ {
+ cairo_region_t *trap_region = NULL;
- if ((src->type == CAIRO_PATTERN_TYPE_SOLID ||
- op == CAIRO_OPERATOR_CLEAR) && !clip_surface) {
- const cairo_color_t *color;
+ status = _cairo_traps_extract_region (traps, &trap_region);
+ if (unlikely (_cairo_status_is_error (status)))
+ return status;
- if (op == CAIRO_OPERATOR_CLEAR) {
- color = CAIRO_COLOR_TRANSPARENT;
- } else {
- color = &((cairo_solid_pattern_t *)src)->color;
- }
+ if (trap_region != NULL) {
+ status = cairo_region_intersect_rectangle (trap_region, extents);
+ if (unlikely (status)) {
+ cairo_region_destroy (trap_region);
+ return status;
+ }
- /* Solid rectangles special case */
- status = _cairo_surface_fill_region (dst, op, color, trap_region);
+ if (clip_region != NULL) {
+ status = cairo_region_intersect (trap_region, clip_region);
+ if (unlikely (status)) {
+ cairo_region_destroy (trap_region);
+ return status;
+ }
+ }
- if (!status && clear_region) {
- status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
- CAIRO_COLOR_TRANSPARENT,
- clear_region);
+ if (cairo_region_is_empty (trap_region) &&
+ _cairo_operator_bounded_by_mask (op))
+ {
+ cairo_region_destroy (trap_region);
+ return CAIRO_STATUS_SUCCESS;
}
- goto out;
- }
+ status = _clip_and_composite_region (src, op, dst,
+ trap_region,
+ antialias,
+ clip, extents);
+ cairo_region_destroy (trap_region);
- if ((_cairo_operator_bounded_by_mask (op) &&
- op != CAIRO_OPERATOR_SOURCE) || !clip_surface) {
- /* For a simple rectangle, we can just use composite(), for more
- * rectangles, we have to set a clip region. The cost of rasterizing
- * trapezoids is pretty high for most backends currently, so it's
- * worthwhile even if a region is needed.
- *
- * If we have a clip surface, we set it as the mask; this only works
- * for bounded operators other than SOURCE; for unbounded operators,
- * clip and mask cannot be interchanged. For SOURCE, the operator
- * as implemented by the backends is different in its handling
- * of the mask then what we want.
- *
- * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
- * more than rectangle and the destination doesn't support clip
- * regions. In that case, we fall through.
- */
- status = _composite_trap_region (clip, src, op, dst,
- trap_region, &extents);
-
- if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
- if (!status && clear_region)
- status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
- CAIRO_COLOR_TRANSPARENT,
- clear_region);
- goto out;
- }
- }
+ if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
+ return status;
+ }
}
- traps_info.traps = traps;
- traps_info.antialias = antialias;
-
- status = _clip_and_composite (clip, op, src,
- _composite_traps_draw_func,
- &traps_info, dst, &extents);
+ /* Otherwise we need to render the trapezoids to a mask and composite
+ * in the usual fashion.
+ */
+ if (_cairo_operator_bounded_by_mask (op)) {
+ cairo_rectangle_int_t trap_extents;
+ cairo_box_t trap_box;
-out:
- if (trap_region)
- cairo_region_destroy (trap_region);
- if (clear_region)
- cairo_region_destroy (clear_region);
+ _cairo_traps_extents (traps, &trap_box);
+ _cairo_box_round_to_rectangle (&trap_box, &trap_extents);
+ if (! _cairo_rectangle_intersect (extents, &trap_extents))
+ return CAIRO_STATUS_SUCCESS;
+ }
- return status;
+ traps_info.traps = traps;
+ traps_info.antialias = antialias;
+ return _clip_and_composite (clip, op, src,
+ _composite_traps_draw_func,
+ &traps_info, dst, extents);
}
typedef struct {
@@ -671,11 +773,11 @@ _composite_spans_fill_func (void *closure,
cairo_surface_t *dst,
int dst_x,
int dst_y,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
{
cairo_composite_rectangles_t rects;
cairo_composite_spans_fill_info_t *info = closure;
- cairo_solid_pattern_t pattern;
_cairo_composite_rectangles_init (
&rects, extents->x, extents->y,
@@ -687,60 +789,60 @@ _composite_spans_fill_func (void *closure,
rects.dst.x -= dst_x;
rects.dst.y -= dst_y;
- /* We're called without a source pattern from
- * _create_composite_mask_pattern(). */
- if (src == NULL) {
- _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
- src = &pattern.base;
+ return _cairo_path_fixed_fill_using_spans (op, src, info->path, dst,
+ info->fill_rule,
+ info->tolerance,
+ info->antialias,
+ &rects,
+ clip_region);
+}
+
+static cairo_bool_t
+_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
+{
+ if (clip != NULL) {
+ const cairo_rectangle_int_t *clip_extents;
+
+ clip_extents = _cairo_clip_get_extents (clip);
+ if (clip_extents != NULL)
+ return _cairo_rectangle_intersect (extents, clip_extents);
}
- return _cairo_path_fixed_fill_using_spans (
- op, src, info->path, dst,
- info->fill_rule, info->tolerance, info->antialias,
- &rects);
+ return ! _cairo_rectangle_empty (extents);
}
cairo_status_t
_cairo_surface_fallback_paint (cairo_surface_t *surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_rectangle_int_t extents;
cairo_box_t box;
cairo_traps_t traps;
+ cairo_bool_t is_bounded;
- status = _cairo_surface_get_extents (surface, &extents);
- if (unlikely (status))
- return status;
+ is_bounded = _cairo_surface_get_extents (surface, &extents);
+ assert (is_bounded || clip);
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
- status = _cairo_pattern_get_extents (source, &source_extents);
- if (unlikely (status))
- return status;
-
+ _cairo_pattern_get_extents (source, &source_extents);
if (! _cairo_rectangle_intersect (&extents, &source_extents))
return CAIRO_STATUS_SUCCESS;
}
- status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
- if (unlikely (status))
- return status;
+ if (! _rectangle_intersect_clip (&extents, clip))
+ return CAIRO_STATUS_SUCCESS;
_cairo_box_from_rectangle (&box, &extents);
_cairo_traps_init_box (&traps, &box);
-
- status = _clip_and_composite_trapezoids (source,
- op,
- surface,
- &traps,
- surface->clip,
- CAIRO_ANTIALIAS_NONE);
-
+ status = _clip_and_composite_trapezoids (source, op, surface,
+ &traps, CAIRO_ANTIALIAS_NONE,
+ clip, &extents);
_cairo_traps_fini (&traps);
return status;
@@ -753,69 +855,67 @@ _cairo_surface_mask_draw_func (void *closure,
cairo_surface_t *dst,
int dst_x,
int dst_y,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
{
cairo_pattern_t *mask = closure;
- if (src)
+ if (src) {
return _cairo_surface_composite (op,
src, mask, dst,
extents->x, extents->y,
extents->x, extents->y,
extents->x - dst_x, extents->y - dst_y,
- extents->width, extents->height);
- else
+ extents->width, extents->height,
+ clip_region);
+ } else {
return _cairo_surface_composite (op,
mask, NULL, dst,
extents->x, extents->y,
0, 0, /* unused */
extents->x - dst_x, extents->y - dst_y,
- extents->width, extents->height);
+ extents->width, extents->height,
+ clip_region);
+ }
}
+
cairo_status_t
_cairo_surface_fallback_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask)
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
{
- cairo_status_t status;
- cairo_rectangle_int_t extents, source_extents, mask_extents;
+ cairo_rectangle_int_t extents;
+ cairo_bool_t is_bounded;
- status = _cairo_surface_get_extents (surface, &extents);
- if (unlikely (status))
- return status;
+ is_bounded = _cairo_surface_get_extents (surface, &extents);
+ assert (is_bounded || clip);
if (_cairo_operator_bounded_by_source (op)) {
- status = _cairo_pattern_get_extents (source, &source_extents);
- if (unlikely (status))
- return status;
+ cairo_rectangle_int_t source_extents;
+ _cairo_pattern_get_extents (source, &source_extents);
if (! _cairo_rectangle_intersect (&extents, &source_extents))
return CAIRO_STATUS_SUCCESS;
}
if (_cairo_operator_bounded_by_mask (op)) {
- status = _cairo_pattern_get_extents (mask, &mask_extents);
- if (unlikely (status))
- return status;
+ cairo_rectangle_int_t mask_extents;
+ _cairo_pattern_get_extents (mask, &mask_extents);
if (! _cairo_rectangle_intersect (&extents, &mask_extents))
return CAIRO_STATUS_SUCCESS;
}
- status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
- if (unlikely (status))
- return status;
-
- status = _clip_and_composite (surface->clip, op,
- source,
- _cairo_surface_mask_draw_func,
- (void *) mask,
- surface,
- &extents);
+ if (! _rectangle_intersect_clip (&extents, clip))
+ return CAIRO_STATUS_SUCCESS;
- return status;
+ return _clip_and_composite (clip, op, source,
+ _cairo_surface_mask_draw_func,
+ (void *) mask,
+ surface, &extents);
}
cairo_status_t
@@ -827,32 +927,27 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_traps_t traps;
cairo_box_t box;
cairo_rectangle_int_t extents;
+ cairo_bool_t is_bounded;
- status = _cairo_surface_get_extents (surface, &extents);
- if (unlikely (status))
- return status;
+ is_bounded = _cairo_surface_get_extents (surface, &extents);
+ assert (is_bounded || clip);
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
- status = _cairo_pattern_get_extents (source, &source_extents);
- if (unlikely (status))
- return status;
+ _cairo_pattern_get_extents (source, &source_extents);
if (! _cairo_rectangle_intersect (&extents, &source_extents))
return CAIRO_STATUS_SUCCESS;
}
- status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
- if (unlikely (status))
- return status;
-
- if (extents.width == 0 || extents.height == 0)
+ if (! _rectangle_intersect_clip (&extents, clip))
return CAIRO_STATUS_SUCCESS;
_cairo_box_from_rectangle (&box, &extents);
@@ -868,14 +963,10 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
if (unlikely (status))
goto FAIL;
- status = _clip_and_composite_trapezoids (source,
- op,
- surface,
- &traps,
- surface->clip,
- antialias);
-
-FAIL:
+ status = _clip_and_composite_trapezoids (source, op,
+ surface, &traps, antialias,
+ clip, &extents);
+ FAIL:
_cairo_traps_fini (&traps);
return status;
@@ -888,35 +979,41 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_traps_t traps;
cairo_box_t box;
cairo_rectangle_int_t extents;
+ cairo_bool_t is_bounded;
- status = _cairo_surface_get_extents (surface, &extents);
- if (unlikely (status))
- return status;
+ is_bounded = _cairo_surface_get_extents (surface, &extents);
+ assert (is_bounded || clip);
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
- status = _cairo_pattern_get_extents (source, &source_extents);
- if (unlikely (status))
- return status;
-
+ _cairo_pattern_get_extents (source, &source_extents);
if (! _cairo_rectangle_intersect (&extents, &source_extents))
return CAIRO_STATUS_SUCCESS;
}
- status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
- if (unlikely (status))
- return status;
-
- if (extents.width == 0 || extents.height == 0)
+ if (! _rectangle_intersect_clip (&extents, clip))
return CAIRO_STATUS_SUCCESS;
+ /* XXX future direction:
+ status = _cairo_path_fixed_fill_to_region (path, fill_rule, &region);
+ if (status != CAIRO_STATUS_INT_UNSUPPORTED) {
+ if (unlikely (status))
+ return status;
+
+ status = _clip_and_composite_region ();
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+ */
+
/* Ask if the surface would like to render this combination of
* op/source/dst/antialias with spans or not, but don't actually
* make a renderer yet. We'll try to hit the region optimisations
@@ -927,9 +1024,7 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
/* TODO: The region filling code should be lifted from
* _clip_and_composite_trapezoids() and given first priority
* explicitly before deciding between spans and trapezoids. */
- if (antialias != CAIRO_ANTIALIAS_NONE &&
- !_cairo_path_fixed_is_box (path, &box) &&
- !_cairo_path_fixed_is_region (path) &&
+ if (antialias != CAIRO_ANTIALIAS_NONE && ! path->is_rectilinear &&
_cairo_surface_check_span_renderer (
op, source, surface, antialias, NULL))
{
@@ -948,12 +1043,11 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
- return _clip_and_composite (
- surface->clip, op, source,
- _composite_spans_fill_func,
- &info,
- surface,
- &extents);
+ return _clip_and_composite (clip, op, source,
+ _composite_spans_fill_func,
+ &info,
+ surface,
+ &extents);
}
/* Fall back to trapezoid fills. */
@@ -965,18 +1059,13 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
fill_rule,
tolerance,
&traps);
- if (unlikely (status)) {
- _cairo_traps_fini (&traps);
- return status;
- }
-
- status = _clip_and_composite_trapezoids (source,
- op,
- surface,
- &traps,
- surface->clip,
- antialias);
+ if (unlikely (status))
+ goto FAIL;
+ status = _clip_and_composite_trapezoids (source, op, surface,
+ &traps, antialias,
+ clip, &extents);
+ FAIL:
_cairo_traps_fini (&traps);
return status;
@@ -995,10 +1084,10 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure
cairo_surface_t *dst,
int dst_x,
int dst_y,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
{
cairo_show_glyphs_info_t *glyph_info = closure;
- cairo_solid_pattern_t pattern;
cairo_status_t status;
/* Modifying the glyph array is fine because we know that this function
@@ -1008,19 +1097,12 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure
if (dst_x != 0 || dst_y != 0) {
int i;
- for (i = 0; i < glyph_info->num_glyphs; ++i)
- {
+ for (i = 0; i < glyph_info->num_glyphs; ++i) {
((cairo_glyph_t *) glyph_info->glyphs)[i].x -= dst_x;
((cairo_glyph_t *) glyph_info->glyphs)[i].y -= dst_y;
}
}
- if (src == NULL) {
- _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
- src = &pattern.base;
- }
-
status = _cairo_surface_old_show_glyphs (glyph_info->font, op, src,
dst,
extents->x, extents->y,
@@ -1029,7 +1111,8 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure
extents->width,
extents->height,
glyph_info->glyphs,
- glyph_info->num_glyphs);
+ glyph_info->num_glyphs,
+ clip_region);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
@@ -1041,7 +1124,8 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure
extents->y - dst_y,
extents->width, extents->height,
glyph_info->glyphs,
- glyph_info->num_glyphs);
+ glyph_info->num_glyphs,
+ clip_region);
}
cairo_status_t
@@ -1050,15 +1134,16 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
- cairo_scaled_font_t *scaled_font)
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_rectangle_int_t extents;
cairo_show_glyphs_info_t glyph_info;
+ cairo_bool_t is_bounded;
- status = _cairo_surface_get_extents (surface, &extents);
- if (unlikely (status))
- return status;
+ is_bounded = _cairo_surface_get_extents (surface, &extents);
+ assert (is_bounded || clip);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t glyph_extents;
@@ -1074,23 +1159,18 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
- status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
- if (unlikely (status))
- return status;
+ if (! _rectangle_intersect_clip (&extents, clip))
+ return CAIRO_STATUS_SUCCESS;
glyph_info.font = scaled_font;
glyph_info.glyphs = glyphs;
glyph_info.num_glyphs = num_glyphs;
- status = _clip_and_composite (surface->clip,
- op,
- source,
- _cairo_surface_old_show_glyphs_draw_func,
- &glyph_info,
- surface,
- &extents);
-
- return status;
+ return _clip_and_composite (clip, op, source,
+ _cairo_surface_old_show_glyphs_draw_func,
+ &glyph_info,
+ surface,
+ &extents);
}
cairo_surface_t *
@@ -1124,15 +1204,10 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
}
_cairo_pattern_init_for_surface (&pattern, &image->base);
- status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
- &pattern.base,
- NULL,
- snapshot,
- 0, 0,
- 0, 0,
- 0, 0,
- image->width,
- image->height);
+ status = _cairo_surface_paint (snapshot,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base,
+ NULL);
_cairo_pattern_fini (&pattern.base);
_cairo_surface_release_source_image (surface, image, image_extra);
if (unlikely (status)) {
@@ -1155,15 +1230,17 @@ _cairo_surface_fallback_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
fallback_state_t state;
+ cairo_region_t *fallback_region = NULL;
cairo_status_t status;
status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- return CAIRO_STATUS_SUCCESS;
+ status = CAIRO_STATUS_SUCCESS;
return status;
}
@@ -1172,12 +1249,29 @@ _cairo_surface_fallback_composite (cairo_operator_t op,
* _cairo_surface_composite so that we get the correct device
* offset handling.
*/
+
+ if (clip_region != NULL && (state.image_rect.x || state.image_rect.y)) {
+ fallback_region = cairo_region_copy (clip_region);
+ status = fallback_region->status;
+ if (unlikely (status))
+ goto FAIL;
+
+ cairo_region_translate (fallback_region,
+ -state.image_rect.x,
+ -state.image_rect.y);
+ clip_region = fallback_region;
+ }
+
status = _cairo_surface_composite (op, src, mask,
&state.image->base,
src_x, src_y, mask_x, mask_y,
dst_x - state.image_rect.x,
dst_y - state.image_rect.y,
- width, height);
+ width, height,
+ clip_region);
+ FAIL:
+ if (fallback_region != NULL)
+ cairo_region_destroy (fallback_region);
_fallback_fini (&state);
return status;
@@ -1224,7 +1318,7 @@ _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- return CAIRO_STATUS_SUCCESS;
+ status = CAIRO_STATUS_SUCCESS;
return status;
}
@@ -1271,16 +1365,18 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps)
+ int num_traps,
+ cairo_region_t *clip_region)
{
fallback_state_t state;
+ cairo_region_t *fallback_region = NULL;
cairo_trapezoid_t *offset_traps = NULL;
cairo_status_t status;
status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- return CAIRO_STATUS_SUCCESS;
+ status = CAIRO_STATUS_SUCCESS;
return status;
}
@@ -1288,15 +1384,28 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
if (state.image_rect.x != 0 || state.image_rect.y != 0) {
offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t));
- if (!offset_traps) {
+ if (offset_traps == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto DONE;
+ goto FAIL;
}
_cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
- state.image_rect.x, - state.image_rect.y,
1.0, 1.0);
traps = offset_traps;
+
+ /* similarly we need to adjust the region */
+ if (clip_region != NULL) {
+ fallback_region = cairo_region_copy (clip_region);
+ status = fallback_region->status;
+ if (unlikely (status))
+ goto FAIL;
+
+ cairo_region_translate (fallback_region,
+ -state.image_rect.x,
+ -state.image_rect.y);
+ clip_region = fallback_region;
+ }
}
status = _cairo_surface_composite_trapezoids (op, pattern,
@@ -1306,11 +1415,14 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
dst_x - state.image_rect.x,
dst_y - state.image_rect.y,
width, height,
- traps, num_traps);
- if (offset_traps)
+ traps, num_traps,
+ clip_region);
+ if (offset_traps != NULL)
free (offset_traps);
- DONE:
+ FAIL:
+ if (fallback_region != NULL)
+ cairo_region_destroy (fallback_region);
_fallback_fini (&state);
return status;
@@ -1335,7 +1447,9 @@ _cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
new_surface = _cairo_surface_create_similar_scratch (surface,
src->content & content,
width, height);
- if (new_surface->status)
+ if (new_surface == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (unlikely (new_surface->status))
return new_surface->status;
/* We have to copy these here, so that the coordinate spaces are correct */
@@ -1348,7 +1462,8 @@ _cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
status = _cairo_surface_paint (new_surface,
CAIRO_OPERATOR_SOURCE,
- &pattern.base, NULL);
+ &pattern.base,
+ NULL);
_cairo_pattern_fini (&pattern.base);
if (unlikely (status)) {
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index c25b6dc8..5c80d43f 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -42,6 +42,7 @@
#include "cairo-types-private.h"
#include "cairo-reference-count-private.h"
+#include "cairo-clip-private.h"
typedef void (*cairo_surface_func_t) (cairo_surface_t *);
@@ -77,24 +78,6 @@ struct _cairo_surface {
double x_fallback_resolution;
double y_fallback_resolution;
- cairo_clip_t *clip;
-
- /*
- * Each time a clip region is modified, it gets the next value in this
- * sequence. This means that clip regions for this surface are uniquely
- * identified and updates to the clip can be readily identified
- */
- unsigned int next_clip_serial;
- /*
- * The serial number of the current clip. This is set when
- * the surface clipping is set. The gstate can then cheaply
- * check whether the surface clipping is already correct before
- * performing a rendering operation.
- *
- * The special value '0' is reserved for the unclipped case.
- */
- unsigned int current_clip_serial;
-
/* A "snapshot" surface is immutable. See _cairo_surface_snapshot. */
cairo_surface_t *snapshot_of;
cairo_surface_func_t snapshot_detach;
diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h
new file mode 100644
index 00000000..5ebcb860
--- /dev/null
+++ b/src/cairo-surface-wrapper-private.h
@@ -0,0 +1,156 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2009 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.u>
+ */
+
+#ifndef CAIRO_SURFACE_WRAPPER_PRIVATE_H
+#define CAIRO_SURFACE_WRAPPER_PRIVATE_H
+
+#include "cairo-types-private.h"
+
+CAIRO_BEGIN_DECLS
+
+struct _cairo_surface_wrapper {
+ cairo_surface_t *target;
+
+ /* any other information? */
+};
+
+cairo_private void
+_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
+ cairo_surface_t *target);
+
+cairo_private void
+_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper);
+
+cairo_private cairo_status_t
+_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
+ cairo_image_surface_t **image_out,
+ void **image_extra);
+
+cairo_private void
+_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
+ cairo_image_surface_t *image,
+ void *image_extra);
+
+
+cairo_private cairo_status_t
+_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *stroke_style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t fill_op,
+ const cairo_pattern_t *fill_source,
+ cairo_fill_rule_t fill_rule,
+ double fill_tolerance,
+ cairo_antialias_t fill_antialias,
+ cairo_path_fixed_t *path,
+ cairo_operator_t stroke_op,
+ const cairo_pattern_t *stroke_source,
+ cairo_stroke_style_t *stroke_style,
+ cairo_matrix_t *stroke_ctm,
+ cairo_matrix_t *stroke_ctm_inverse,
+ double stroke_tolerance,
+ cairo_antialias_t stroke_antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ const cairo_text_cluster_t *clusters,
+ int num_clusters,
+ cairo_text_cluster_flags_t cluster_flags,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip);
+
+cairo_private cairo_surface_t *
+_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
+ cairo_content_t content,
+ int width,
+ int height);
+cairo_private cairo_bool_t
+_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
+ cairo_rectangle_int_t *extents);
+
+cairo_private cairo_bool_t
+_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper);
+
+static inline cairo_bool_t
+_cairo_surface_wrapper_is_active (cairo_surface_wrapper_t *wrapper)
+{
+ return wrapper->target != (cairo_surface_t *) 0;
+}
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_SURFACE_WRAPPER_PRIVATE_H */
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
new file mode 100644
index 00000000..b21a32da
--- /dev/null
+++ b/src/cairo-surface-wrapper.c
@@ -0,0 +1,449 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2007 Adrian Johnson
+ * Copyright © 2009 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-surface-wrapper-private.h"
+
+/* A collection of routines to facilitate surface wrapping */
+
+static cairo_bool_t
+_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper,
+ cairo_matrix_t *matrix)
+{
+ if (_cairo_matrix_is_identity (&wrapper->target->device_transform))
+ return FALSE;
+
+ *matrix = wrapper->target->device_transform;
+ return TRUE;
+}
+
+cairo_status_t
+_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ if (unlikely (wrapper->target->status))
+ return wrapper->target->status;
+
+ return _cairo_surface_acquire_source_image (wrapper->target,
+ image_out, image_extra);
+}
+
+void
+_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ _cairo_surface_release_source_image (wrapper->target, image, image_extra);
+}
+
+cairo_status_t
+_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_matrix_t device_transform;
+ cairo_clip_t clip_copy, *dev_clip = clip;
+
+ if (unlikely (wrapper->target->status))
+ return wrapper->target->status;
+
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (clip != NULL &&
+ _cairo_surface_wrapper_needs_device_transform (wrapper,
+ &device_transform))
+ {
+ status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
+ &device_transform);
+ if (unlikely (status))
+ goto FINISH;
+
+ dev_clip = &clip_copy;
+ }
+
+ status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
+
+ FINISH:
+ if (dev_clip != clip)
+ _cairo_clip_reset (dev_clip);
+ return status;
+}
+
+cairo_status_t
+_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_matrix_t device_transform;
+ cairo_clip_t clip_copy, *dev_clip = clip;
+
+ if (unlikely (wrapper->target->status))
+ return wrapper->target->status;
+
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (clip != NULL &&
+ _cairo_surface_wrapper_needs_device_transform (wrapper,
+ &device_transform))
+ {
+ status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
+ &device_transform);
+ if (unlikely (status))
+ goto FINISH;
+
+ dev_clip = &clip_copy;
+ }
+
+ status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
+
+ FINISH:
+ if (dev_clip != clip)
+ _cairo_clip_reset (dev_clip);
+ return status;
+}
+
+cairo_status_t
+_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *stroke_style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_matrix_t device_transform;
+ cairo_path_fixed_t path_copy, *dev_path = path;
+ cairo_clip_t clip_copy, *dev_clip = clip;
+ cairo_matrix_t dev_ctm = *ctm;
+ cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
+
+ if (unlikely (wrapper->target->status))
+ return wrapper->target->status;
+
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (_cairo_surface_wrapper_needs_device_transform (wrapper,
+ &device_transform))
+ {
+ status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
+ if (unlikely (status))
+ goto FINISH;
+
+ _cairo_path_fixed_transform (&path_copy, &device_transform);
+ dev_path = &path_copy;
+
+ if (clip != NULL) {
+ status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
+ &device_transform);
+ if (unlikely (status))
+ goto FINISH;
+
+ dev_clip = &clip_copy;
+ }
+
+ cairo_matrix_multiply (&dev_ctm, &dev_ctm, &device_transform);
+ status = cairo_matrix_invert (&device_transform);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ cairo_matrix_multiply (&dev_ctm_inverse,
+ &device_transform,
+ &dev_ctm_inverse);
+ }
+
+ status = _cairo_surface_stroke (wrapper->target, op, source,
+ dev_path, stroke_style,
+ &dev_ctm, &dev_ctm_inverse,
+ tolerance, antialias,
+ dev_clip);
+
+ FINISH:
+ if (dev_path != path)
+ _cairo_path_fixed_fini (dev_path);
+ if (dev_clip != clip)
+ _cairo_clip_reset (dev_clip);
+ return status;
+}
+
+cairo_status_t
+_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t fill_op,
+ const cairo_pattern_t *fill_source,
+ cairo_fill_rule_t fill_rule,
+ double fill_tolerance,
+ cairo_antialias_t fill_antialias,
+ cairo_path_fixed_t *path,
+ cairo_operator_t stroke_op,
+ const cairo_pattern_t *stroke_source,
+ cairo_stroke_style_t *stroke_style,
+ cairo_matrix_t *stroke_ctm,
+ cairo_matrix_t *stroke_ctm_inverse,
+ double stroke_tolerance,
+ cairo_antialias_t stroke_antialias,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_matrix_t device_transform;
+ cairo_path_fixed_t path_copy, *dev_path = path;
+ cairo_clip_t clip_copy, *dev_clip = clip;
+ cairo_matrix_t dev_ctm = *stroke_ctm;
+ cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
+
+ if (unlikely (wrapper->target->status))
+ return wrapper->target->status;
+
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (_cairo_surface_wrapper_needs_device_transform (wrapper,
+ &device_transform))
+ {
+ status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
+ if (unlikely (status))
+ goto FINISH;
+
+ _cairo_path_fixed_transform (&path_copy, &device_transform);
+ dev_path = &path_copy;
+
+ if (clip != NULL) {
+ status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
+ &device_transform);
+ if (unlikely (status))
+ goto FINISH;
+
+ dev_clip = &clip_copy;
+ }
+
+ cairo_matrix_multiply (&dev_ctm, &dev_ctm, &device_transform);
+ status = cairo_matrix_invert (&device_transform);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ cairo_matrix_multiply (&dev_ctm_inverse,
+ &device_transform,
+ &dev_ctm_inverse);
+ }
+
+ status = _cairo_surface_fill_stroke (wrapper->target,
+ fill_op, fill_source, fill_rule,
+ fill_tolerance, fill_antialias,
+ dev_path,
+ stroke_op, stroke_source,
+ stroke_style,
+ &dev_ctm, &dev_ctm_inverse,
+ stroke_tolerance, stroke_antialias,
+ dev_clip);
+
+ FINISH:
+ if (dev_path != path)
+ _cairo_path_fixed_fini (dev_path);
+ if (dev_clip != clip)
+ _cairo_clip_reset (dev_clip);
+ return status;
+}
+
+cairo_status_t
+_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_matrix_t device_transform;
+ cairo_path_fixed_t path_copy, *dev_path = path;
+ cairo_clip_t clip_copy, *dev_clip = clip;
+
+ if (unlikely (wrapper->target->status))
+ return wrapper->target->status;
+
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (_cairo_surface_wrapper_needs_device_transform (wrapper,
+ &device_transform))
+ {
+ status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
+ if (unlikely (status))
+ goto FINISH;
+
+ _cairo_path_fixed_transform (&path_copy, &device_transform);
+ dev_path = &path_copy;
+
+ if (clip != NULL) {
+ status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
+ &device_transform);
+ if (unlikely (status))
+ goto FINISH;
+
+ dev_clip = &clip_copy;
+ }
+ }
+
+ status = _cairo_surface_fill (wrapper->target, op, source,
+ dev_path, fill_rule,
+ tolerance, antialias,
+ dev_clip);
+
+ FINISH:
+ if (dev_path != path)
+ _cairo_path_fixed_fini (dev_path);
+ if (dev_clip != clip)
+ _cairo_clip_reset (dev_clip);
+ return status;
+}
+
+cairo_status_t
+_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ const cairo_text_cluster_t *clusters,
+ int num_clusters,
+ cairo_text_cluster_flags_t cluster_flags,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_matrix_t device_transform;
+ cairo_clip_t clip_copy, *dev_clip = clip;
+ cairo_glyph_t *dev_glyphs = glyphs;
+
+ if (unlikely (wrapper->target->status))
+ return wrapper->target->status;
+
+ if (glyphs == NULL || num_glyphs == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (_cairo_surface_wrapper_needs_device_transform (wrapper,
+ &device_transform))
+ {
+ int i;
+
+ if (clip != NULL) {
+ dev_clip = &clip_copy;
+ status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
+ &device_transform);
+ if (unlikely (status))
+ goto FINISH;
+ }
+
+ dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
+ if (dev_glyphs == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto FINISH;
+ }
+
+ for (i = 0; i < num_glyphs; i++) {
+ dev_glyphs[i] = glyphs[i];
+ cairo_matrix_transform_point (&device_transform,
+ &dev_glyphs[i].x,
+ &dev_glyphs[i].y);
+ }
+ }
+
+ status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
+ utf8, utf8_len,
+ dev_glyphs, num_glyphs,
+ clusters, num_clusters,
+ cluster_flags,
+ scaled_font,
+ dev_clip);
+ FINISH:
+ if (dev_clip != clip)
+ _cairo_clip_reset (dev_clip);
+ if (dev_glyphs != glyphs)
+ free (dev_glyphs);
+ return status;
+}
+
+cairo_surface_t *
+_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ return _cairo_surface_create_similar_solid (wrapper->target,
+ content, width, height,
+ CAIRO_COLOR_TRANSPARENT,
+ TRUE);
+}
+
+cairo_bool_t
+_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
+ cairo_rectangle_int_t *extents)
+{
+ return _cairo_surface_get_extents (wrapper->target, extents);
+}
+
+cairo_bool_t
+_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper)
+{
+ return cairo_surface_has_show_text_glyphs (wrapper->target);
+}
+
+void
+_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
+ cairo_surface_t *target)
+{
+ wrapper->target = cairo_surface_reference (target);
+}
+
+void
+_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
+{
+ cairo_surface_destroy (wrapper->target);
+}
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 16e84921..f656ed5f 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -41,6 +41,7 @@
#include "cairo-surface-fallback-private.h"
#include "cairo-clip-private.h"
#include "cairo-meta-surface-private.h"
+#include "cairo-region-private.h"
#define DEFINE_NIL_SURFACE(status, name) \
const cairo_surface_t name = { \
@@ -59,9 +60,6 @@ const cairo_surface_t name = { \
0.0, /* y_resolution */ \
0.0, /* x_fallback_resolution */ \
0.0, /* y_fallback_resolution */ \
- NULL, /* clip */ \
- 0, /* next_clip_serial */ \
- 0, /* current_clip_serial */ \
NULL, /* snapshot_of */ \
NULL, /* snapshot_detach */ \
{ 0, /* size */ \
@@ -77,8 +75,11 @@ const cairo_surface_t name = { \
} /* font_options */ \
}
+/* XXX error object! */
+
static DEFINE_NIL_SURFACE(CAIRO_STATUS_NO_MEMORY, _cairo_surface_nil);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_SURFACE_TYPE_MISMATCH, _cairo_surface_nil_surface_type_mismatch);
+static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STATUS, _cairo_surface_nil_invalid_status);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_CONTENT, _cairo_surface_nil_invalid_content);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_FORMAT, _cairo_surface_nil_invalid_format);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_VISUAL, _cairo_surface_nil_invalid_visual);
@@ -89,7 +90,7 @@ static DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_err
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STRIDE, _cairo_surface_nil_invalid_stride);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_SIZE, _cairo_surface_nil_invalid_size);
-static cairo_status_t
+static void
_cairo_surface_copy_pattern_for_destination (const cairo_pattern_t **pattern,
cairo_surface_t *destination,
cairo_pattern_t *pattern_copy);
@@ -361,53 +362,48 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
- surface->clip = NULL;
- surface->next_clip_serial = 0;
- surface->current_clip_serial = 0;
-
_cairo_array_init (&surface->snapshots, sizeof (cairo_surface_t *));
surface->snapshot_of = NULL;
surface->has_font_options = FALSE;
}
+static void
+_cairo_surface_copy_similar_properties (cairo_surface_t *surface,
+ cairo_surface_t *other)
+{
+ if (other->has_font_options || other->backend != surface->backend) {
+ cairo_font_options_t options;
+
+ cairo_surface_get_font_options (other, &options);
+ _cairo_surface_set_font_options (surface, &options);
+ }
+
+ cairo_surface_set_fallback_resolution (surface,
+ other->x_fallback_resolution,
+ other->y_fallback_resolution);
+}
+
cairo_surface_t *
_cairo_surface_create_similar_scratch (cairo_surface_t *other,
cairo_content_t content,
int width,
int height)
{
- cairo_surface_t *surface = NULL;
+ cairo_surface_t *surface;
- if (other->status)
+ if (unlikely (other->status))
return _cairo_surface_create_in_error (other->status);
- if (other->backend->create_similar) {
- surface = other->backend->create_similar (other, content, width, height);
- if (surface != NULL && surface->status)
- return surface;
- }
-
- if (surface == NULL) {
- surface =
- cairo_image_surface_create (_cairo_format_from_content (content),
- width, height);
- }
+ if (other->backend->create_similar == NULL)
+ return NULL;
- /* If any error occurred, then return the nil surface we received. */
- if (unlikely (surface->status))
+ surface = other->backend->create_similar (other,
+ content, width, height);
+ if (surface == NULL || surface->status)
return surface;
- if (other->has_font_options || other->backend != surface->backend) {
- cairo_font_options_t options;
-
- cairo_surface_get_font_options (other, &options);
- _cairo_surface_set_font_options (surface, &options);
- }
-
- cairo_surface_set_fallback_resolution (surface,
- other->x_fallback_resolution,
- other->y_fallback_resolution);
+ _cairo_surface_copy_similar_properties (surface, other);
return surface;
}
@@ -443,46 +439,46 @@ cairo_surface_create_similar (cairo_surface_t *other,
int width,
int height)
{
- if (other->status)
+ if (unlikely (other->status))
return _cairo_surface_create_in_error (other->status);
- if (! CAIRO_CONTENT_VALID (content))
+ if (unlikely (! CAIRO_CONTENT_VALID (content)))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
- return _cairo_surface_create_similar_solid (other, content,
- width, height,
- CAIRO_COLOR_TRANSPARENT);
+ return _cairo_surface_create_similar_solid (other,
+ content, width, height,
+ CAIRO_COLOR_TRANSPARENT,
+ TRUE);
}
-slim_hidden_def (cairo_surface_create_similar);
cairo_surface_t *
_cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_content_t content,
int width,
int height,
- const cairo_color_t *color)
+ const cairo_color_t *color,
+ cairo_bool_t allow_fallback)
{
cairo_status_t status;
cairo_surface_t *surface;
- cairo_solid_pattern_t solid_pattern;
+ cairo_solid_pattern_t pattern;
surface = _cairo_surface_create_similar_scratch (other, content,
width, height);
- if (surface->status)
+ if (surface == NULL && allow_fallback)
+ surface = _cairo_image_surface_create_with_content (content,
+ width, height);
+ if (surface == NULL || surface->status)
return surface;
- _cairo_pattern_init_solid (&solid_pattern, color, content);
-
+ _cairo_pattern_init_solid (&pattern, color, content);
status = _cairo_surface_paint (surface,
color == CAIRO_COLOR_TRANSPARENT ?
CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
- &solid_pattern.base, NULL);
-
- _cairo_pattern_fini (&solid_pattern.base);
-
+ &pattern.base, NULL);
if (unlikely (status)) {
cairo_surface_destroy (surface);
- return _cairo_surface_create_in_error (status);
+ surface = _cairo_surface_create_in_error (status);
}
return surface;
@@ -504,7 +500,8 @@ _cairo_surface_create_solid_pattern_surface (cairo_surface_t *other,
return _cairo_surface_create_similar_solid (other,
solid_pattern->content,
1, 1,
- &solid_pattern->color);
+ &solid_pattern->color,
+ FALSE);
}
cairo_int_status_t
@@ -532,17 +529,6 @@ _cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other,
NULL);
}
-cairo_clip_mode_t
-_cairo_surface_get_clip_mode (cairo_surface_t *surface)
-{
- if (surface->backend->intersect_clip_path != NULL)
- return CAIRO_CLIP_MODE_PATH;
- else if (surface->backend->set_clip_region != NULL)
- return CAIRO_CLIP_MODE_REGION;
- else
- return CAIRO_CLIP_MODE_MASK;
-}
-
/**
* cairo_surface_reference:
* @surface: a #cairo_surface_t
@@ -605,36 +591,6 @@ cairo_surface_destroy (cairo_surface_t *surface)
slim_hidden_def(cairo_surface_destroy);
/**
- * _cairo_surface_reset:
- * @surface: a #cairo_surface_t
- *
- * Resets the surface back to defaults such that it may be reused in lieu
- * of creating a new surface.
- **/
-cairo_status_t
-_cairo_surface_reset (cairo_surface_t *surface)
-{
- if (surface == NULL ||
- CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
- return CAIRO_STATUS_SUCCESS;
-
- assert (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count) == 1);
-
- _cairo_user_data_array_fini (&surface->user_data);
- _cairo_user_data_array_fini (&surface->mime_data);
-
- if (surface->backend->reset != NULL) {
- cairo_status_t status = surface->backend->reset (surface);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
- }
-
- _cairo_surface_init (surface, surface->backend, surface->content);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
* cairo_surface_get_reference_count:
* @surface: a #cairo_surface_t
*
@@ -1078,14 +1034,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
* call mark_dirty()). */
assert (! _cairo_surface_has_snapshots (surface));
- /* Always reset the clip here, to avoid having external calls to
- * clip manipulation functions of the underlying device clip result
- * in a desync between the cairo clip and the backend clip, due to
- * the clip caching.
- */
- surface->current_clip_serial = -1;
-
- if (surface->backend->mark_dirty_rectangle) {
+ if (surface->backend->mark_dirty_rectangle != NULL) {
/* XXX: FRAGILE: We're ignoring the scaling component of
* device_transform here. I don't know what the right thing to
* do would actually be if there were some scaling here, but
@@ -1478,13 +1427,17 @@ _cairo_meta_surface_clone_similar (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
- if (width*height*8 < meta->extents.width*meta->extents.height) {
- similar = cairo_surface_create_similar (surface,
- src->content & content,
- width, height);
- status = similar->status;
- if (unlikely (status))
- return status;
+ if (meta->unbounded ||
+ width*height*8 < meta->extents.width*meta->extents.height)
+ {
+ /* XXX use _solid to perform an initial CLEAR? */
+ similar = _cairo_surface_create_similar_scratch (surface,
+ src->content & content,
+ width, height);
+ if (similar == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (unlikely (similar->status))
+ return similar->status;
cairo_surface_set_device_offset (similar, -src_x, -src_y);
@@ -1493,15 +1446,15 @@ _cairo_meta_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_destroy (similar);
return status;
}
-
} else {
- similar = cairo_surface_create_similar (surface,
- src->content & content,
- meta->extents.width,
- meta->extents.height);
- status = similar->status;
- if (unlikely (status))
- return status;
+ similar = _cairo_surface_create_similar_scratch (surface,
+ src->content & content,
+ meta->extents.width,
+ meta->extents.height);
+ if (similar == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (unlikely (similar->status))
+ return similar->status;
status = cairo_meta_surface_replay (src, similar);
if (unlikely (status)) {
@@ -1567,7 +1520,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
if (unlikely (surface->finished))
return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
- if (surface->backend->clone_similar) {
+ if (surface->backend->clone_similar != NULL) {
status = surface->backend->clone_similar (surface, src,
content,
src_x, src_y,
@@ -1575,7 +1528,6 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
clone_offset_x,
clone_offset_y,
clone_out);
-
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
if (_cairo_surface_is_image (src))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1620,7 +1572,6 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
clone_out);
}
- /* We should never get UNSUPPORTED here, so if we have an error, bail. */
if (unlikely (status))
return status;
@@ -1762,11 +1713,12 @@ _cairo_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_int_status_t status;
- if (dst->status)
+ if (unlikely (dst->status))
return dst->status;
assert (_cairo_surface_is_writable (dst));
@@ -1784,7 +1736,8 @@ _cairo_surface_composite (cairo_operator_t op,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
- width, height);
+ width, height,
+ clip_region);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_surface_set_error (dst, status);
}
@@ -1795,7 +1748,8 @@ _cairo_surface_composite (cairo_operator_t op,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
- width, height));
+ width, height,
+ clip_region));
}
/**
@@ -1883,8 +1837,8 @@ _cairo_surface_fill_region (cairo_surface_t *surface,
for (i = 0; i < num_rects; i++)
cairo_region_get_rectangle (region, i, &rects[i]);
- status = _cairo_surface_fill_rectangles (surface, op,
- color, rects, num_rects);
+ status = _cairo_surface_fill_rectangles (surface,
+ op, color, rects, num_rects);
if (rects != stack_rects)
free (rects);
@@ -1926,14 +1880,16 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
if (surface->backend->fill_rectangles) {
- status = surface->backend->fill_rectangles (surface, op, color,
+ status = surface->backend->fill_rectangles (surface,
+ op, color,
rects, num_rects);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_surface_set_error (surface, status);
}
return _cairo_surface_set_error (surface,
- _cairo_surface_fallback_fill_rectangles (surface, op, color,
+ _cairo_surface_fallback_fill_rectangles (surface,
+ op, color,
rects, num_rects));
}
@@ -1941,34 +1897,32 @@ cairo_status_t
_cairo_surface_paint (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
- if (surface->status)
+ if (unlikely (surface->status))
return surface->status;
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_surface_begin_modification (surface);
- status = _cairo_surface_copy_pattern_for_destination (&source,
- surface,
- &dev_source.base);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
+ _cairo_surface_copy_pattern_for_destination (&source,
+ surface,
+ &dev_source.base);
- if (surface->backend->paint) {
- status = surface->backend->paint (surface, op, source, extents);
+ if (surface->backend->paint != NULL) {
+ status = surface->backend->paint (surface, op, source, clip);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
}
- status = _cairo_surface_fallback_paint (surface, op, source);
+ status = _cairo_surface_fallback_paint (surface, op, source, clip);
FINISH:
- if (source == &dev_source.base)
- _cairo_pattern_fini (&dev_source.base);
-
return _cairo_surface_set_error (surface, status);
}
@@ -1977,45 +1931,34 @@ _cairo_surface_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
cairo_pattern_union_t dev_mask;
- if (surface->status)
+ if (unlikely (surface->status))
return surface->status;
- _cairo_surface_begin_modification (surface);
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
- status = _cairo_surface_copy_pattern_for_destination (&source,
- surface,
- &dev_source.base);
- if (unlikely (status))
- goto FINISH;
+ _cairo_surface_begin_modification (surface);
- status = _cairo_surface_copy_pattern_for_destination (&mask,
- surface,
- &dev_mask.base);
- if (unlikely (status))
- goto CLEANUP_SOURCE;
+ _cairo_surface_copy_pattern_for_destination (&source, surface,
+ &dev_source.base);
+ _cairo_surface_copy_pattern_for_destination (&mask, surface,
+ &dev_mask.base);
- if (surface->backend->mask) {
- status = surface->backend->mask (surface, op, source, mask, extents);
+ if (surface->backend->mask != NULL) {
+ status = surface->backend->mask (surface, op, source, mask, clip);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- goto CLEANUP_MASK;
+ goto FINISH;
}
- status = _cairo_surface_fallback_mask (surface, op, source, mask);
+ status = _cairo_surface_fallback_mask (surface, op, source, mask, clip);
- CLEANUP_MASK:
- if (mask == &dev_mask.base)
- _cairo_pattern_fini (&dev_mask.base);
- CLEANUP_SOURCE:
- if (source == &dev_source.base)
- _cairo_pattern_fini (&dev_source.base);
FINISH:
-
return _cairo_surface_set_error (surface, status);
}
@@ -2034,13 +1977,16 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
- if (surface->status)
+ if (unlikely (surface->status))
return surface->status;
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_surface_begin_modification (surface);
if (surface->backend->fill_stroke) {
@@ -2049,21 +1995,10 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_matrix_t dev_ctm = *stroke_ctm;
cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
- status = _cairo_surface_copy_pattern_for_destination (&stroke_source,
- surface,
- &dev_stroke_source.base);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
-
- status = _cairo_surface_copy_pattern_for_destination (&fill_source,
- surface,
- &dev_fill_source.base);
- if (unlikely (status)) {
- if (stroke_source == &dev_stroke_source.base)
- _cairo_pattern_fini (&dev_stroke_source.base);
-
- return _cairo_surface_set_error (surface, status);
- }
+ _cairo_surface_copy_pattern_for_destination (&stroke_source, surface,
+ &dev_stroke_source.base);
+ _cairo_surface_copy_pattern_for_destination (&fill_source, surface,
+ &dev_fill_source.base);
status = surface->backend->fill_stroke (surface,
fill_op, fill_source, fill_rule,
@@ -2073,26 +2008,22 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
stroke_style,
&dev_ctm, &dev_ctm_inverse,
stroke_tolerance, stroke_antialias,
- extents);
-
- if (stroke_source == &dev_stroke_source.base)
- _cairo_pattern_fini (&dev_stroke_source.base);
-
- if (fill_source == &dev_fill_source.base)
- _cairo_pattern_fini (&dev_fill_source.base);
+ clip);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_surface_set_error (surface, status);
}
status = _cairo_surface_fill (surface, fill_op, fill_source, path,
- fill_rule, fill_tolerance, fill_antialias, NULL);
+ fill_rule, fill_tolerance, fill_antialias,
+ clip);
if (unlikely (status))
return _cairo_surface_set_error (surface, status);
status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path,
stroke_style, stroke_ctm, stroke_ctm_inverse,
- stroke_tolerance, stroke_antialias, NULL);
+ stroke_tolerance, stroke_antialias,
+ clip);
if (unlikely (status))
return _cairo_surface_set_error (surface, status);
@@ -2109,31 +2040,28 @@ _cairo_surface_stroke (cairo_surface_t *surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
- cairo_path_fixed_t *dev_path = path;
- cairo_path_fixed_t real_dev_path;
- cairo_matrix_t dev_ctm = *ctm;
- cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
- if (surface->status)
+ if (unlikely (surface->status))
return surface->status;
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_surface_begin_modification (surface);
- status = _cairo_surface_copy_pattern_for_destination (&source,
- surface,
- &dev_source.base);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
+ _cairo_surface_copy_pattern_for_destination (&source, surface,
+ &dev_source.base);
- if (surface->backend->stroke) {
+ if (surface->backend->stroke != NULL) {
status = surface->backend->stroke (surface, op, source,
path, stroke_style,
- &dev_ctm, &dev_ctm_inverse,
- tolerance, antialias, extents);
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
@@ -2141,16 +2069,11 @@ _cairo_surface_stroke (cairo_surface_t *surface,
status = _cairo_surface_fallback_stroke (surface, op, source,
path, stroke_style,
- &dev_ctm, &dev_ctm_inverse,
- tolerance, antialias);
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
FINISH:
- if (dev_path == &real_dev_path)
- _cairo_path_fixed_fini (&real_dev_path);
-
- if (source == &dev_source.base)
- _cairo_pattern_fini (&dev_source.base);
-
return _cairo_surface_set_error (surface, status);
}
@@ -2162,26 +2085,26 @@ _cairo_surface_fill (cairo_surface_t *surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
- if (surface->status)
+ if (unlikely (surface->status))
return surface->status;
- _cairo_surface_begin_modification (surface);
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
- status = _cairo_surface_copy_pattern_for_destination (&source,
- surface,
- &dev_source.base);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
+ _cairo_surface_begin_modification (surface);
- if (surface->backend->fill) {
+ _cairo_surface_copy_pattern_for_destination (&source, surface,
+ &dev_source.base);
+ if (surface->backend->fill != NULL) {
status = surface->backend->fill (surface, op, source,
path, fill_rule,
- tolerance, antialias, extents);
+ tolerance, antialias,
+ clip);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
@@ -2189,12 +2112,10 @@ _cairo_surface_fill (cairo_surface_t *surface,
status = _cairo_surface_fallback_fill (surface, op, source,
path, fill_rule,
- tolerance, antialias);
+ tolerance, antialias,
+ clip);
FINISH:
- if (source == &dev_source.base)
- _cairo_pattern_fini (&dev_source.base);
-
return _cairo_surface_set_error (surface, status);
}
@@ -2210,7 +2131,8 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps)
+ int num_traps,
+ cairo_region_t *clip_region)
{
cairo_int_status_t status;
@@ -2231,7 +2153,8 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op,
src_x, src_y,
dst_x, dst_y,
width, height,
- traps, num_traps);
+ traps, num_traps,
+ clip_region);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_surface_set_error (dst, status);
}
@@ -2242,56 +2165,58 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op,
src_x, src_y,
dst_x, dst_y,
width, height,
- traps, num_traps));
+ traps, num_traps,
+ clip_region));
}
cairo_span_renderer_t *
-_cairo_surface_create_span_renderer (cairo_operator_t op,
- const cairo_pattern_t *pattern,
+_cairo_surface_create_span_renderer (cairo_operator_t op,
+ const cairo_pattern_t *pattern,
cairo_surface_t *dst,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects)
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *rects,
+ cairo_region_t *clip_region)
{
assert (dst->snapshot_of == NULL);
- if (dst->status)
+ if (unlikely (dst->status))
return _cairo_span_renderer_create_in_error (dst->status);
- if (dst->finished)
+ if (unlikely (dst->finished))
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
if (dst->backend->create_span_renderer) {
return dst->backend->create_span_renderer (op,
pattern, dst,
antialias,
- rects);
+ rects,
+ clip_region);
}
ASSERT_NOT_REACHED;
return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED);
}
cairo_bool_t
-_cairo_surface_check_span_renderer (cairo_operator_t op,
+_cairo_surface_check_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,
- cairo_antialias_t antialias,
+ cairo_antialias_t antialias,
const cairo_composite_rectangles_t *rects)
{
cairo_int_status_t status;
assert (dst->snapshot_of == NULL);
- if (dst->status)
+ if (unlikely (dst->status))
return FALSE;
- if (dst->finished) {
+ if (unlikely (dst->finished)) {
status = _cairo_surface_set_error (dst, CAIRO_STATUS_SURFACE_FINISHED);
return FALSE;
}
if (dst->backend->check_span_renderer) {
- return dst->backend->check_span_renderer (op,
- pattern, dst,
+ return dst->backend->check_span_renderer (op, pattern, dst,
antialias,
rects);
}
@@ -2375,329 +2300,6 @@ cairo_surface_show_page (cairo_surface_t *surface)
slim_hidden_def (cairo_surface_show_page);
/**
- * _cairo_surface_get_current_clip_serial:
- * @surface: the #cairo_surface_t to return the serial number for
- *
- * This space left intentionally blank.
- *
- * Returns: the serial number associated with the current
- * clip in the surface. All gstate functions must
- * verify that the correct clip is set in the surface before
- * invoking any surface drawing function.
- */
-unsigned int
-_cairo_surface_get_current_clip_serial (cairo_surface_t *surface)
-{
- return surface->current_clip_serial;
-}
-
-/**
- * _cairo_surface_allocate_clip_serial:
- * @surface: the #cairo_surface_t to allocate a serial number from
- *
- * Each surface has a separate set of clipping serial numbers, and
- * this function allocates one from the specified surface. As zero is
- * reserved for the special no-clipping case, this function will not
- * return that except for an in-error surface, (ie. surface->status !=
- * %CAIRO_STATUS_SUCCESS).
- */
-unsigned int
-_cairo_surface_allocate_clip_serial (cairo_surface_t *surface)
-{
- unsigned int serial;
-
- if (surface->status)
- return 0;
-
- if ((serial = ++(surface->next_clip_serial)) == 0)
- serial = ++(surface->next_clip_serial);
- return serial;
-}
-
-/**
- * _cairo_surface_reset_clip:
- * @surface: the #cairo_surface_t to reset the clip on
- *
- * This function sets the clipping for the surface to
- * None, which is to say that drawing is entirely
- * unclipped. It also sets the clip serial number
- * to zero.
- */
-cairo_status_t
-_cairo_surface_reset_clip (cairo_surface_t *surface)
-{
- cairo_status_t status;
-
- if (surface->status)
- return surface->status;
-
- if (surface->finished)
- return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
-
- surface->current_clip_serial = 0;
-
- if (surface->backend->intersect_clip_path) {
- status = surface->backend->intersect_clip_path (surface,
- NULL,
- CAIRO_FILL_RULE_WINDING,
- 0,
- CAIRO_ANTIALIAS_DEFAULT);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
- }
-
- if (surface->backend->set_clip_region != NULL) {
- status = surface->backend->set_clip_region (surface, NULL);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * _cairo_surface_set_clip_region:
- * @surface: the #cairo_surface_t to reset the clip on
- * @region: the #cairo_region_t to use for clipping
- * @serial: the clip serial number associated with the region
- *
- * This function sets the clipping for the surface to
- * the specified region and sets the surface clipping
- * serial number to the associated serial number.
- */
-cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t *surface,
- cairo_region_t *region,
- unsigned int serial)
-{
- cairo_status_t status;
-
- if (surface->status)
- return surface->status;
-
- if (surface->finished)
- return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
-
- assert (surface->backend->set_clip_region != NULL);
-
- status = surface->backend->set_clip_region (surface, region);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
-
- surface->current_clip_serial = serial;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_int_status_t
-_cairo_surface_intersect_clip_path (cairo_surface_t *surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_path_fixed_t *dev_path = path;
- cairo_status_t status;
-
- if (surface->status)
- return surface->status;
-
- if (surface->finished)
- return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
-
- assert (surface->backend->intersect_clip_path != NULL);
-
- status = surface->backend->intersect_clip_path (surface,
- dev_path,
- fill_rule,
- tolerance,
- antialias);
-
- return _cairo_surface_set_error (surface, status);
-}
-
-static cairo_status_t
-_cairo_surface_set_clip_path_recursive (cairo_surface_t *surface,
- cairo_clip_path_t *clip_path)
-{
- cairo_status_t status;
-
- if (surface->status)
- return surface->status;
-
- if (clip_path == NULL)
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_surface_set_clip_path_recursive (surface, clip_path->prev);
- if (unlikely (status))
- return status;
-
- return _cairo_surface_intersect_clip_path (surface,
- &clip_path->path,
- clip_path->fill_rule,
- clip_path->tolerance,
- clip_path->antialias);
-}
-
-/**
- * _cairo_surface_set_clip_path:
- * @surface: the #cairo_surface_t to set the clip on
- * @clip_path: the clip path to set
- * @serial: the clip serial number associated with the clip path
- *
- * Sets the given clipping path for the surface and assigns the
- * clipping serial to the surface.
- **/
-static cairo_status_t
-_cairo_surface_set_clip_path (cairo_surface_t *surface,
- cairo_clip_path_t *clip_path,
- unsigned int serial)
-{
- cairo_status_t status;
-
- if (surface->status)
- return surface->status;
-
- if (surface->finished)
- return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
-
- assert (surface->backend->intersect_clip_path != NULL);
-
- status = surface->backend->intersect_clip_path (surface,
- NULL,
- CAIRO_FILL_RULE_WINDING,
- 0,
- CAIRO_ANTIALIAS_DEFAULT);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
-
- status = _cairo_surface_set_clip_path_recursive (surface, clip_path);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
-
- surface->current_clip_serial = serial;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-/**
- * _cairo_surface_set_empty_clip_path:
- * @surface: the #cairo_surface_t to set the clip on
- * @serial: the clip serial number associated with the clip path
- *
- * Create an empty clip path, one that represents the entire surface clipped
- * out, and assigns the given clipping serial to the surface.
- **/
-static cairo_status_t
-_cairo_surface_set_empty_clip_path (cairo_surface_t *surface,
- unsigned int serial)
-{
- cairo_path_fixed_t path;
- cairo_status_t status;
-
- if (surface->status)
- return surface->status;
-
- _cairo_path_fixed_init (&path);
-
- status = surface->backend->intersect_clip_path (surface,
- &path,
- CAIRO_FILL_RULE_WINDING,
- 0,
- CAIRO_ANTIALIAS_DEFAULT);
-
- if (status == CAIRO_STATUS_SUCCESS)
- surface->current_clip_serial = serial;
-
- _cairo_path_fixed_fini (&path);
-
- return _cairo_surface_set_error (surface, status);
-}
-
-/**
- * _cairo_surface_set_empty_clip_region:
- * @surface: the #cairo_surface_t to set the clip on
- * @serial: the clip serial number associated with the clip path
- *
- * Create an empty clip region, one that represents the entire surface clipped
- * out, and assigns the given clipping serial to the surface.
- **/
-static cairo_status_t
-_cairo_surface_set_empty_clip_region (cairo_surface_t *surface,
- unsigned int serial)
-{
- cairo_region_t *region;
- cairo_status_t status;
-
- if (surface->status)
- return surface->status;
-
- region = cairo_region_create ();
- status = region->status;
-
- if (status == CAIRO_STATUS_SUCCESS)
- status = _cairo_surface_set_clip_region (surface, region, serial);
-
- cairo_region_destroy (region);
-
- return _cairo_surface_set_error (surface, status);
-}
-
-cairo_clip_t *
-_cairo_surface_get_clip (cairo_surface_t *surface)
-{
- return surface->clip;
-}
-
-cairo_status_t
-_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
-{
- unsigned int serial = 0;
-
- if (surface->status)
- return surface->status;
-
- if (surface->finished)
- return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
-
- if (clip) {
- serial = clip->serial;
- if (serial == 0)
- clip = NULL;
- }
-
- surface->clip = clip;
-
- if (serial == _cairo_surface_get_current_clip_serial (surface))
- return CAIRO_STATUS_SUCCESS;
-
- if (clip) {
- if (clip->all_clipped) {
- if (surface->backend->intersect_clip_path != NULL)
- return _cairo_surface_set_empty_clip_path (surface,
- clip->serial);
-
- if (surface->backend->set_clip_region != NULL)
- return _cairo_surface_set_empty_clip_region (surface,
- clip->serial);
- } else {
- if (clip->path)
- return _cairo_surface_set_clip_path (surface,
- clip->path,
- clip->serial);
-
- if (clip->region)
- return _cairo_surface_set_clip_region (surface,
- clip->region,
- clip->serial);
- }
- }
-
- return _cairo_surface_reset_clip (surface);
-}
-
-/**
* _cairo_surface_get_extents:
* @surface: the #cairo_surface_t to fetch extents for
*
@@ -2721,31 +2323,22 @@ _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
* This behavior would have to be changed is we ever exported a public
* variant of this function.
*/
-cairo_int_status_t
+cairo_bool_t
_cairo_surface_get_extents (cairo_surface_t *surface,
cairo_rectangle_int_t *extents)
{
- cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+ cairo_bool_t bounded = FALSE;
- if (surface->status)
- return surface->status;
+ if (unlikely (surface->status || surface->finished))
+ return TRUE;
- if (surface->finished)
- return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
+ if (surface->backend->get_extents != NULL)
+ bounded = surface->backend->get_extents (surface, extents);
- if (surface->backend->get_extents) {
- status = _cairo_surface_set_error (surface,
- surface->backend->get_extents (surface, extents));
- }
+ if (! bounded)
+ _cairo_unbounded_rectangle_init (extents);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- extents->x = CAIRO_RECT_INT_MIN;
- extents->y = CAIRO_RECT_INT_MIN;
- extents->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
- extents->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
- }
-
- return status;
+ return bounded;
}
/**
@@ -2817,25 +2410,25 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_scaled_font_t *dev_scaled_font = scaled_font;
cairo_pattern_union_t dev_source;
- if (surface->status)
+ if (unlikely (surface->status))
return surface->status;
if (num_glyphs == 0 && utf8_len == 0)
return CAIRO_STATUS_SUCCESS;
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_surface_begin_modification (surface);
- status = _cairo_surface_copy_pattern_for_destination (&source,
- surface,
- &dev_source.base);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
+ _cairo_surface_copy_pattern_for_destination (&source, surface,
+ &dev_source.base);
if (_cairo_surface_has_device_transform (surface) &&
! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL))
@@ -2853,12 +2446,8 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
&font_options);
}
status = cairo_scaled_font_status (dev_scaled_font);
- if (unlikely (status)) {
- if (source == &dev_source.base)
- _cairo_pattern_fini (&dev_source.base);
-
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
- }
status = CAIRO_INT_STATUS_UNSUPPORTED;
@@ -2867,21 +2456,25 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
if (clusters) {
/* A real show_text_glyphs call. Try show_text_glyphs backend
* method first */
- if (surface->backend->show_text_glyphs) {
+ if (surface->backend->show_text_glyphs != NULL) {
status = surface->backend->show_text_glyphs (surface, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
- dev_scaled_font, extents);
+ dev_scaled_font,
+ clip);
}
- if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->backend->show_glyphs) {
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
+ surface->backend->show_glyphs)
+ {
int remaining_glyphs = num_glyphs;
status = surface->backend->show_glyphs (surface, op,
source,
glyphs, num_glyphs,
dev_scaled_font,
- &remaining_glyphs, extents);
+ clip,
+ &remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0)
@@ -2889,18 +2482,19 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
}
} else {
/* A mere show_glyphs call. Try show_glyphs backend method first */
- if (surface->backend->show_glyphs) {
+ if (surface->backend->show_glyphs != NULL) {
int remaining_glyphs = num_glyphs;
status = surface->backend->show_glyphs (surface, op,
source,
glyphs, num_glyphs,
dev_scaled_font,
- &remaining_glyphs, extents);
+ clip,
+ &remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0)
status = CAIRO_STATUS_SUCCESS;
- } else if (surface->backend->show_text_glyphs) {
+ } else if (surface->backend->show_text_glyphs != NULL) {
/* Intentionally only try show_text_glyphs method for show_glyphs
* calls if backend does not have show_glyphs. If backend has
* both methods implemented, we don't fallback from show_glyphs to
@@ -2914,22 +2508,22 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
- dev_scaled_font, extents);
+ dev_scaled_font,
+ clip);
}
}
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
status = _cairo_surface_fallback_show_glyphs (surface, op,
source,
glyphs, num_glyphs,
- dev_scaled_font);
+ dev_scaled_font,
+ clip);
+ }
if (dev_scaled_font != scaled_font)
cairo_scaled_font_destroy (dev_scaled_font);
- if (source == &dev_source.base)
- _cairo_pattern_fini (&dev_source.base);
-
return _cairo_surface_set_error (surface, status);
}
@@ -2950,7 +2544,8 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
- int num_glyphs)
+ int num_glyphs,
+ cairo_region_t *clip_region)
{
cairo_status_t status;
@@ -2965,7 +2560,8 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
source_x, source_y,
dest_x, dest_y,
width, height,
- glyphs, num_glyphs);
+ glyphs, num_glyphs,
+ clip_region);
} else
status = CAIRO_INT_STATUS_UNSUPPORTED;
@@ -2979,7 +2575,8 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_rectangle_int_t dst_rectangle;
cairo_region_t clear_region;
@@ -2995,12 +2592,18 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst,
_cairo_region_init_rectangle (&clear_region, &dst_rectangle);
- if (src_rectangle) {
+ if (clip_region != NULL) {
+ status = cairo_region_intersect (&clear_region, clip_region);
+ if (unlikely (status))
+ goto CLEANUP_REGIONS;
+ }
+
+ if (src_rectangle != NULL) {
if (! _cairo_rectangle_intersect (&dst_rectangle, src_rectangle))
goto EMPTY;
}
- if (mask_rectangle) {
+ if (mask_rectangle != NULL) {
if (! _cairo_rectangle_intersect (&dst_rectangle, mask_rectangle))
goto EMPTY;
}
@@ -3011,7 +2614,7 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst,
goto CLEANUP_REGIONS;
EMPTY:
- status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_SOURCE,
+ status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
CAIRO_COLOR_TRANSPARENT,
&clear_region);
@@ -3060,13 +2663,14 @@ _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_rectangle_int_t src_tmp, mask_tmp;
cairo_rectangle_int_t *src_rectangle = NULL;
cairo_rectangle_int_t *mask_rectangle = NULL;
- if (dst->status)
+ if (unlikely (dst->status))
return dst->status;
assert (_cairo_surface_is_writable (dst));
@@ -3098,7 +2702,8 @@ _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
}
return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle,
- dst_x, dst_y, width, height);
+ dst_x, dst_y, width, height,
+ clip_region);
}
/**
@@ -3138,7 +2743,8 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_rectangle_int_t src_tmp, mask_tmp;
cairo_rectangle_int_t *src_rectangle = NULL;
@@ -3171,7 +2777,8 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
mask_rectangle = &mask_tmp;
return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle,
- dst_x, dst_y, width, height);
+ dst_x, dst_y, width, height,
+ clip_region);
}
/**
@@ -3183,26 +2790,19 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
* Copies the given pattern, taking into account device scale and offsets
* of the destination surface.
*/
-static cairo_status_t
+static void
_cairo_surface_copy_pattern_for_destination (const cairo_pattern_t **pattern,
cairo_surface_t *destination,
cairo_pattern_t *pattern_copy)
{
- cairo_status_t status;
-
if (! _cairo_surface_has_device_transform (destination))
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_pattern_init_copy (pattern_copy, *pattern);
- if (unlikely (status))
- return status;
+ return;
+ _cairo_pattern_init_static_copy (pattern_copy, *pattern);
_cairo_pattern_transform (pattern_copy,
&destination->device_transform_inverse);
-
*pattern = pattern_copy;
- return CAIRO_STATUS_SUCCESS;
}
/**
@@ -3235,6 +2835,8 @@ _cairo_surface_create_in_error (cairo_status_t status)
return (cairo_surface_t *) &_cairo_surface_nil;
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
return (cairo_surface_t *) &_cairo_surface_nil_surface_type_mismatch;
+ case CAIRO_STATUS_INVALID_STATUS:
+ return (cairo_surface_t *) &_cairo_surface_nil_invalid_status;
case CAIRO_STATUS_INVALID_CONTENT:
return (cairo_surface_t *) &_cairo_surface_nil_invalid_content;
case CAIRO_STATUS_INVALID_FORMAT:
@@ -3261,7 +2863,6 @@ _cairo_surface_create_in_error (cairo_status_t status)
case CAIRO_STATUS_INVALID_POP_GROUP:
case CAIRO_STATUS_NO_CURRENT_POINT:
case CAIRO_STATUS_INVALID_MATRIX:
- case CAIRO_STATUS_INVALID_STATUS:
case CAIRO_STATUS_NULL_POINTER:
case CAIRO_STATUS_INVALID_STRING:
case CAIRO_STATUS_INVALID_PATH_DATA:
diff --git a/src/cairo-svg-surface-private.h b/src/cairo-svg-surface-private.h
index e7cd4db8..64efe7f2 100644
--- a/src/cairo-svg-surface-private.h
+++ b/src/cairo-svg-surface-private.h
@@ -44,6 +44,7 @@
#include "cairo-svg.h"
#include "cairo-surface-private.h"
+#include "cairo-surface-clipper-private.h"
typedef struct cairo_svg_document cairo_svg_document_t;
@@ -52,8 +53,6 @@ typedef struct cairo_svg_surface {
cairo_content_t content;
- unsigned int id;
-
double width;
double height;
@@ -62,6 +61,7 @@ typedef struct cairo_svg_surface {
cairo_output_stream_t *xml_node;
cairo_array_t page_set;
+ cairo_surface_clipper_t clipper;
unsigned int clip_level;
unsigned int base_clip;
cairo_bool_t is_base_clip_emitted;
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 3a6b62df..08e4cfcb 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -49,6 +49,7 @@
#include "cairo-path-fixed-private.h"
#include "cairo-paginated-private.h"
#include "cairo-scaled-font-subsets-private.h"
+#include "cairo-surface-clipper-private.h"
#include "cairo-svg-surface-private.h"
typedef struct cairo_svg_page cairo_svg_page_t;
@@ -63,6 +64,11 @@ static const cairo_svg_version_t _cairo_svg_versions[] =
#define CAIRO_SVG_VERSION_LAST ARRAY_LENGTH (_cairo_svg_versions)
+static void
+_cairo_svg_surface_emit_path (cairo_output_stream_t *output,
+ cairo_path_fixed_t *path,
+ cairo_matrix_t *ctm_inverse);
+
static cairo_bool_t
_cairo_svg_version_has_page_set_support (cairo_svg_version_t version)
{
@@ -99,7 +105,6 @@ struct cairo_svg_document {
cairo_output_stream_t *xml_node_defs;
cairo_output_stream_t *xml_node_glyphs;
- unsigned int surface_id;
unsigned int linear_pattern_id;
unsigned int radial_pattern_id;
unsigned int pattern_id;
@@ -109,18 +114,11 @@ struct cairo_svg_document {
cairo_bool_t alpha_filter;
- cairo_array_t meta_snapshots;
-
cairo_svg_version_t svg_version;
cairo_scaled_font_subsets_t *font_subsets;
};
-typedef struct {
- unsigned int id;
- cairo_meta_surface_t *meta;
-} cairo_meta_snapshot_t;
-
static cairo_status_t
_cairo_svg_document_create (cairo_output_stream_t *stream,
double width,
@@ -278,8 +276,8 @@ _extract_svg_surface (cairo_surface_t *surface,
* Since: 1.2
**/
void
-cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface,
- cairo_svg_version_t version)
+cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface,
+ cairo_svg_version_t version)
{
cairo_svg_surface_t *surface = NULL; /* hide compiler warning */
cairo_status_t status;
@@ -306,7 +304,7 @@ cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface,
**/
void
cairo_svg_get_versions (cairo_svg_version_t const **versions,
- int *num_versions)
+ int *num_versions)
{
if (versions != NULL)
*versions = _cairo_svg_versions;
@@ -336,6 +334,73 @@ cairo_svg_version_to_string (cairo_svg_version_t version)
return _cairo_svg_version_strings[version];
}
+static cairo_bool_t
+_cliprect_covers_surface (cairo_svg_surface_t *surface,
+ cairo_path_fixed_t *path)
+{
+ cairo_box_t box;
+
+ if (_cairo_path_fixed_is_rectangle (path, &box)) {
+ if (box.p1.x <= 0 &&
+ box.p1.y <= 0 &&
+ _cairo_fixed_to_double (box.p2.x) >= surface->width &&
+ _cairo_fixed_to_double (box.p2.y) >= surface->height)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static cairo_status_t
+_cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_svg_surface_t *surface = cairo_container_of (clipper,
+ cairo_svg_surface_t,
+ clipper);
+ cairo_svg_document_t *document = surface->document;
+ unsigned int i;
+
+ if (path == NULL) {
+ for (i = 0; i < surface->clip_level; i++)
+ _cairo_output_stream_printf (surface->xml_node, "</g>\n");
+
+ surface->clip_level = 0;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ /* skip trivial whole-page clips */
+ if (_cliprect_covers_surface (surface, path))
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_output_stream_printf (document->xml_node_defs,
+ "<clipPath id=\"clip%d\">\n"
+ " <path ",
+ document->clip_id);
+ _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
+
+ _cairo_output_stream_printf (document->xml_node_defs,
+ "/>\n"
+ "</clipPath>\n");
+
+ _cairo_output_stream_printf (surface->xml_node,
+ "<g clip-path=\"url(#clip%d)\" "
+ "clip-rule=\"%s\">\n",
+ document->clip_id,
+ fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
+ "evenodd" : "nonzero");
+
+ document->clip_id++;
+ surface->clip_level++;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_surface_t *
_cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
cairo_content_t content,
@@ -359,8 +424,9 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
surface->document = _cairo_svg_document_reference (document);
surface->clip_level = 0;
+ _cairo_surface_clipper_init (&surface->clipper,
+ _cairo_svg_surface_clipper_intersect_clip_path);
- surface->id = document->surface_id++;
surface->base_clip = document->clip_id++;
surface->is_base_clip_emitted = FALSE;
@@ -388,8 +454,6 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
paginated = _cairo_paginated_surface_create (&surface->base,
surface->content,
- surface->width,
- surface->height,
&cairo_svg_surface_paginated_backend);
status = paginated->status;
if (status == CAIRO_STATUS_SUCCESS) {
@@ -457,7 +521,7 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface)
return NULL;
}
- page.surface_id = surface->id;
+ page.surface_id = surface->base.unique_id;
page.clip_level = surface->clip_level;
page.xml_node = surface->xml_node;
@@ -468,11 +532,13 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface)
surface->xml_node = stream;
surface->clip_level = 0;
-
for (i = 0; i < page.clip_level; i++)
_cairo_output_stream_printf (page.xml_node, "</g>\n");
- return _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1);
+ _cairo_surface_clipper_reset (&surface->clipper);
+
+ return _cairo_array_index (&surface->page_set,
+ surface->page_set.num_elements - 1);
}
static cairo_int_status_t
@@ -486,7 +552,6 @@ _cairo_svg_surface_copy_page (void *abstract_surface)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_memory_stream_copy (page->xml_node, surface->xml_node);
- surface->clip_level = page->clip_level;
return CAIRO_STATUS_SUCCESS;
}
@@ -596,7 +661,7 @@ _cairo_svg_path_close_path (void *closure)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
+static void
_cairo_svg_surface_emit_path (cairo_output_stream_t *output,
cairo_path_fixed_t *path,
cairo_matrix_t *ctm_inverse)
@@ -615,12 +680,9 @@ _cairo_svg_surface_emit_path (cairo_output_stream_t *output,
_cairo_svg_path_curve_to,
_cairo_svg_path_close_path,
&info);
- if (unlikely (status))
- return status;
+ assert (status == CAIRO_STATUS_SUCCESS);
_cairo_output_stream_printf (output, "\"");
-
- return status;
}
static cairo_int_status_t
@@ -642,9 +704,8 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document,
_cairo_output_stream_printf (document->xml_node_glyphs,
"<path style=\"stroke:none;\" ");
- status = _cairo_svg_surface_emit_path (document->xml_node_glyphs, scaled_glyph->path, NULL);
- if (unlikely (status))
- return status;
+ _cairo_svg_surface_emit_path (document->xml_node_glyphs,
+ scaled_glyph->path, NULL);
_cairo_output_stream_printf (document->xml_node_glyphs,
"/>\n");
@@ -847,22 +908,7 @@ _cairo_svg_surface_operation_supported (cairo_svg_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *pattern)
{
- if (_cairo_svg_surface_analyze_operation (surface, op, pattern)
- != CAIRO_INT_STATUS_UNSUPPORTED)
- {
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-static cairo_surface_t *
-_cairo_svg_surface_create_similar (void *abstract_src,
- cairo_content_t content,
- int width,
- int height)
-{
- return cairo_meta_surface_create (content, width, height);
+ return _cairo_svg_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_status_t
@@ -893,6 +939,8 @@ _cairo_svg_surface_finish (void *abstract_surface)
}
_cairo_array_fini (&surface->page_set);
+ _cairo_surface_clipper_reset (&surface->clipper);
+
status2 = _cairo_svg_document_destroy (document);
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
@@ -900,6 +948,7 @@ _cairo_svg_surface_finish (void *abstract_surface)
return status;
}
+
static void
_cairo_svg_surface_emit_alpha_filter (cairo_svg_document_t *document)
{
@@ -1120,112 +1169,139 @@ _cairo_svg_surface_emit_operator_for_style (cairo_output_stream_t *output,
}
static cairo_status_t
-_cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output,
- cairo_svg_surface_t *svg_surface,
- cairo_operator_t op,
- cairo_surface_pattern_t *pattern,
- int pattern_id,
- const cairo_matrix_t *parent_matrix,
- const char *extra_attributes)
+_cairo_svg_surface_emit_surface (cairo_svg_document_t *document,
+ cairo_surface_t *surface)
{
cairo_rectangle_int_t extents;
+ cairo_bool_t is_bounded;
cairo_status_t status;
- cairo_matrix_t p2u;
- status = _cairo_surface_get_extents (pattern->surface, &extents);
+ if (_cairo_user_data_array_get_data (&surface->user_data,
+ (cairo_user_data_key_t *) document))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ is_bounded = _cairo_surface_get_extents (surface, &extents);
+ assert (is_bounded);
+
+ _cairo_output_stream_printf (document->xml_node_defs,
+ "<image id=\"image%d\" width=\"%d\" height=\"%d\"",
+ surface->unique_id,
+ extents.width, extents.height);
+
+ _cairo_output_stream_printf (document->xml_node_defs, " xlink:href=\"");
+
+ status = _cairo_surface_base64_encode (surface,
+ document->xml_node_defs);
if (unlikely (status))
return status;
+ _cairo_output_stream_printf (document->xml_node_defs, "\"/>\n");
+
+ /* and tag it */
+ return _cairo_user_data_array_set_data (&surface->user_data,
+ (cairo_user_data_key_t *) document,
+ document, NULL);
+}
+
+static cairo_status_t
+_cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output,
+ cairo_svg_surface_t *svg_surface,
+ cairo_operator_t op,
+ cairo_surface_pattern_t *pattern,
+ int pattern_id,
+ const cairo_matrix_t *parent_matrix,
+ const char *extra_attributes)
+{
+ cairo_status_t status;
+ cairo_matrix_t p2u;
+
p2u = pattern->base.matrix;
status = cairo_matrix_invert (&p2u);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
+ status = _cairo_svg_surface_emit_surface (svg_surface->document,
+ pattern->surface);
+ if (unlikely (status))
+ return status;
+
if (pattern_id != invalid_pattern_id) {
+ cairo_rectangle_int_t extents;
+ cairo_bool_t is_bounded;
+
+ is_bounded = _cairo_surface_get_extents (pattern->surface, &extents);
+ assert (is_bounded);
+
_cairo_output_stream_printf (output,
"<pattern id=\"pattern%d\" "
"patternUnits=\"userSpaceOnUse\" "
- "width=\"%d\" height=\"%d\"",
+ "width=\"%d\" height=\"%d\" ",
pattern_id,
extents.width, extents.height);
- _cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix);
- _cairo_output_stream_printf (output, ">\n");
+ _cairo_svg_surface_emit_transform (output,
+ " patternTransform",
+ &p2u, parent_matrix);
+ _cairo_output_stream_printf (output, ">\n ");
}
_cairo_output_stream_printf (output,
- " <image width=\"%d\" height=\"%d\"",
- extents.width, extents.height);
+ "<use xlink:href=\"#image%d\"",
+ pattern->surface->unique_id);
+ if (extra_attributes)
+ _cairo_output_stream_printf (output, " %s", extra_attributes);
if (pattern_id == invalid_pattern_id) {
_cairo_svg_surface_emit_operator (output, svg_surface, op);
- _cairo_svg_surface_emit_transform (output, " transform", &p2u, parent_matrix);
+ _cairo_svg_surface_emit_transform (output,
+ " transform",
+ &p2u, parent_matrix);
}
+ _cairo_output_stream_printf (output, "/>\n");
- if (extra_attributes)
- _cairo_output_stream_printf (output, " %s", extra_attributes);
-
- _cairo_output_stream_printf (output, " xlink:href=\"");
-
- status = _cairo_surface_base64_encode (pattern->surface, output);
-
- _cairo_output_stream_printf (output, "\"/>\n");
if (pattern_id != invalid_pattern_id)
_cairo_output_stream_printf (output, "</pattern>\n");
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
- cairo_meta_surface_t *surface,
- int *id)
+ cairo_meta_surface_t *source)
{
cairo_status_t status;
cairo_surface_t *paginated_surface;
cairo_svg_surface_t *svg_surface;
- cairo_meta_snapshot_t new_snapshot;
cairo_array_t *page_set;
cairo_output_stream_t *contents;
- cairo_meta_surface_t *meta;
- cairo_meta_snapshot_t *snapshot;
- unsigned int num_elements;
- unsigned int i;
- /* search in already emitted meta snapshots */
- num_elements = document->meta_snapshots.num_elements;
- for (i = 0; i < num_elements; i++) {
- snapshot = _cairo_array_index (&document->meta_snapshots, i);
- meta = snapshot->meta;
- if (meta->commands.num_elements == surface->commands.num_elements &&
- _cairo_array_index (&meta->commands, 0) == _cairo_array_index (&surface->commands, 0)) {
- *id = snapshot->id;
- return CAIRO_STATUS_SUCCESS;
- }
+ if (_cairo_user_data_array_get_data (&source->base.user_data,
+ (cairo_user_data_key_t *) document))
+ {
+ return CAIRO_STATUS_SUCCESS;
}
- meta = (cairo_meta_surface_t *) _cairo_surface_snapshot (&surface->base);
- if (unlikely (meta->base.status))
- return meta->base.status;
-
paginated_surface = _cairo_svg_surface_create_for_document (document,
- meta->content,
- meta->width_pixels,
- meta->height_pixels);
- if (paginated_surface->status) {
- cairo_surface_destroy (&meta->base);
+ source->content,
+ source->extents_pixels.width,
+ source->extents_pixels.height);
+ if (unlikely (paginated_surface->status))
return paginated_surface->status;
- }
- svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface);
+ svg_surface = (cairo_svg_surface_t *)
+ _cairo_paginated_surface_get_target (paginated_surface);
cairo_surface_set_fallback_resolution (paginated_surface,
document->owner->x_fallback_resolution,
document->owner->y_fallback_resolution);
+ cairo_surface_set_device_offset (&svg_surface->base,
+ -source->extents_pixels.x,
+ -source->extents_pixels.y);
- status = cairo_meta_surface_replay (&meta->base, paginated_surface);
+ status = cairo_meta_surface_replay (&source->base, paginated_surface);
if (unlikely (status)) {
- cairo_surface_destroy (&meta->base);
cairo_surface_destroy (paginated_surface);
return status;
}
@@ -1233,21 +1309,11 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
cairo_surface_show_page (paginated_surface);
status = cairo_surface_status (paginated_surface);
if (unlikely (status)) {
- cairo_surface_destroy (&meta->base);
- cairo_surface_destroy (paginated_surface);
- return status;
- }
-
- new_snapshot.meta = meta;
- new_snapshot.id = svg_surface->id;
- status = _cairo_array_append (&document->meta_snapshots, &new_snapshot);
- if (unlikely (status)) {
- cairo_surface_destroy (&meta->base);
cairo_surface_destroy (paginated_surface);
return status;
}
- if (!svg_surface->is_base_clip_emitted) {
+ if (! svg_surface->is_base_clip_emitted) {
svg_surface->is_base_clip_emitted = TRUE;
_cairo_output_stream_printf (document->xml_node_defs,
"<clipPath id=\"clip%d\">\n"
@@ -1258,19 +1324,19 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
svg_surface->height);
}
- if (meta->content == CAIRO_CONTENT_ALPHA) {
+ if (source->content == CAIRO_CONTENT_ALPHA) {
_cairo_svg_surface_emit_alpha_filter (document);
_cairo_output_stream_printf (document->xml_node_defs,
"<g id=\"surface%d\" "
"clip-path=\"url(#clip%d)\" "
"filter=\"url(#alpha)\">\n",
- svg_surface->id,
+ source->base.unique_id,
svg_surface->base_clip);
} else {
_cairo_output_stream_printf (document->xml_node_defs,
"<g id=\"surface%d\" "
"clip-path=\"url(#clip%d)\">\n",
- svg_surface->id,
+ source->base.unique_id,
svg_surface->base_clip);
}
@@ -1293,19 +1359,16 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
- *id = new_snapshot.id;
-
status = cairo_surface_status (paginated_surface);
cairo_surface_destroy (paginated_surface);
- /* FIXME: cairo_paginated_surface doesn't take a ref to the
- * passed in target surface so we can't call destroy here.
- * cairo_paginated_surface should be fixed, but for now just
- * work around it. */
-
- /* cairo_surface_destroy (svg_surface); */
+ if (unlikely (status))
+ return status;
- return status;
+ /* and tag it */
+ return _cairo_user_data_array_set_data (&source->base.user_data,
+ (cairo_user_data_key_t *) document,
+ document, NULL);
}
static cairo_status_t
@@ -1321,7 +1384,6 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output,
cairo_meta_surface_t *meta_surface;
cairo_matrix_t p2u;
cairo_status_t status;
- int id = 0;
p2u = pattern->base.matrix;
status = cairo_matrix_invert (&p2u);
@@ -1329,8 +1391,7 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output,
assert (status == CAIRO_STATUS_SUCCESS);
meta_surface = (cairo_meta_surface_t *) pattern->surface;
-
- status = _cairo_svg_surface_emit_meta_surface (document, meta_surface, &id);
+ status = _cairo_svg_surface_emit_meta_surface (document, meta_surface);
if (unlikely (status))
return status;
@@ -1340,15 +1401,15 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output,
"patternUnits=\"userSpaceOnUse\" "
"width=\"%d\" height=\"%d\"",
pattern_id,
- (int) ceil (meta_surface->width_pixels),
- (int) ceil (meta_surface->height_pixels));
+ meta_surface->extents.width,
+ meta_surface->extents.height);
_cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix);
_cairo_output_stream_printf (output, ">\n");
}
_cairo_output_stream_printf (output,
"<use xlink:href=\"#surface%d\"",
- id);
+ meta_surface->base.unique_id);
if (pattern_id == invalid_pattern_id) {
_cairo_svg_surface_emit_operator (output, surface, op);
@@ -1377,12 +1438,18 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output,
{
if (_cairo_surface_is_meta (pattern->surface)) {
- return _cairo_svg_surface_emit_composite_meta_pattern (output, surface, op, pattern,
- pattern_id, parent_matrix, extra_attributes);
+ return _cairo_svg_surface_emit_composite_meta_pattern (output, surface,
+ op, pattern,
+ pattern_id,
+ parent_matrix,
+ extra_attributes);
}
- return _cairo_svg_surface_emit_composite_image_pattern (output, surface, op, pattern,
- pattern_id, parent_matrix, extra_attributes);
+ return _cairo_svg_surface_emit_composite_surface_pattern (output, surface,
+ op, pattern,
+ pattern_id,
+ parent_matrix,
+ extra_attributes);
}
static cairo_status_t
@@ -1716,7 +1783,9 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface,
document->radial_pattern_id,
x1, y1,
x1, y1, r1);
- _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
+ _cairo_svg_surface_emit_transform (document->xml_node_defs,
+ "gradientTransform",
+ &p2u, parent_matrix);
_cairo_output_stream_printf (document->xml_node_defs, ">\n");
if (extend == CAIRO_EXTEND_NONE || n_stops < 1)
@@ -1981,11 +2050,15 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_status_t status;
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
_cairo_output_stream_printf (surface->xml_node, "<path style=\"");
status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op,
fill_source, fill_rule, stroke_ctm_inverse);
@@ -1999,9 +2072,7 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
_cairo_output_stream_printf (surface->xml_node, "\" ");
- status = _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
- if (unlikely (status))
- return status;
+ _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
_cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm, NULL);
_cairo_output_stream_printf (surface->xml_node, "/>\n");
@@ -2017,7 +2088,7 @@ _cairo_svg_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -2027,6 +2098,10 @@ _cairo_svg_surface_fill (void *abstract_surface,
assert (_cairo_svg_surface_operation_supported (surface, op, source));
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
_cairo_output_stream_printf (surface->xml_node, "<path style=\" stroke:none;");
status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL);
if (unlikely (status))
@@ -2034,16 +2109,14 @@ _cairo_svg_surface_fill (void *abstract_surface,
_cairo_output_stream_printf (surface->xml_node, "\" ");
- status = _cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
- if (unlikely (status))
- return status;
+ _cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
_cairo_output_stream_printf (surface->xml_node, "/>\n");
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
+static cairo_bool_t
_cairo_svg_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -2053,13 +2126,13 @@ _cairo_svg_surface_get_extents (void *abstract_surface,
rectangle->y = 0;
/* XXX: The conversion to integers here is pretty bogus, (not to
- * mention the aribitray limitation of width to a short(!). We
+ * mention the arbitrary limitation of width to a short(!). We
* may need to come up with a better interface for get_size.
*/
rectangle->width = (int) ceil (surface->width);
rectangle->height = (int) ceil (surface->height);
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
static cairo_status_t
@@ -2106,52 +2179,63 @@ static cairo_int_status_t
_cairo_svg_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_svg_surface_t *surface = abstract_surface;
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_svg_surface_analyze_operation (surface, op, source);
-
- assert (_cairo_svg_surface_operation_supported (surface, op, source));
-
/* Emulation of clear and source operators, when no clipping region
* is defined. We just delete existing content of surface root node,
* and exit early if operator is clear.
- * XXX: optimization of SOURCE operator doesn't work, since analyze
- * above always return FALSE. In order to make it work, we need a way
- * to know if there's an active clipping path.
- * Optimization of CLEAR works because of a test in paginated surface,
- * and an optimization in meta surface. */
- if (surface->clip_level == 0 && op == CAIRO_OPERATOR_CLEAR) {
- status = _cairo_output_stream_destroy (surface->xml_node);
- if (unlikely (status)) {
- surface->xml_node = NULL;
- return status;
- }
+ */
+ if ((op == CAIRO_OPERATOR_CLEAR || op == CAIRO_OPERATOR_SOURCE) &&
+ clip == NULL)
+ {
+ switch (surface->paginated_mode) {
+ case CAIRO_PAGINATED_MODE_FALLBACK:
+ ASSERT_NOT_REACHED;
+ case CAIRO_PAGINATED_MODE_ANALYZE:
+ return CAIRO_STATUS_SUCCESS;
- surface->xml_node = _cairo_memory_stream_create ();
- if (_cairo_output_stream_get_status (surface->xml_node)) {
+ case CAIRO_PAGINATED_MODE_RENDER:
status = _cairo_output_stream_destroy (surface->xml_node);
- surface->xml_node = NULL;
- return status;
- }
+ if (unlikely (status)) {
+ surface->xml_node = NULL;
+ return status;
+ }
- if (op == CAIRO_OPERATOR_CLEAR) {
- if (surface->content == CAIRO_CONTENT_COLOR) {
- _cairo_output_stream_printf (surface->xml_node,
- "<rect "
- "width=\"%f\" height=\"%f\" "
- "style=\"opacity:1;"
- "stroke:none;"
- "fill:rgb(0,0,0);\"/>\n",
- surface->width, surface->height);
+ surface->xml_node = _cairo_memory_stream_create ();
+ if (_cairo_output_stream_get_status (surface->xml_node)) {
+ status = _cairo_output_stream_destroy (surface->xml_node);
+ surface->xml_node = NULL;
+ return status;
}
- return CAIRO_STATUS_SUCCESS;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ if (surface->content == CAIRO_CONTENT_COLOR) {
+ _cairo_output_stream_printf (surface->xml_node,
+ "<rect "
+ "width=\"%f\" height=\"%f\" "
+ "style=\"opacity:1;"
+ "stroke:none;"
+ "fill:rgb(0,0,0);\"/>\n",
+ surface->width, surface->height);
+ }
+ return CAIRO_STATUS_SUCCESS;
+ }
+ break;
}
+ } else {
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return _cairo_svg_surface_analyze_operation (surface, op, source);
+
+ assert (_cairo_svg_surface_operation_supported (surface, op, source));
}
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
return _cairo_svg_surface_emit_paint (surface->xml_node,
surface, op, source, 0, NULL);
}
@@ -2161,7 +2245,7 @@ _cairo_svg_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_svg_surface_t *surface = abstract_surface;
@@ -2189,6 +2273,10 @@ _cairo_svg_surface_mask (void *abstract_surface,
assert (_cairo_svg_surface_operation_supported (surface, op, source));
assert (_cairo_svg_surface_operation_supported (surface, CAIRO_OPERATOR_OVER, mask));
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
const cairo_surface_pattern_t *surface_pattern = (const cairo_surface_pattern_t*) mask;
cairo_content_t content = cairo_surface_get_content (surface_pattern->surface);
@@ -2249,7 +2337,7 @@ _cairo_svg_surface_stroke (void *abstract_dst,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_svg_surface_t *surface = abstract_dst;
cairo_status_t status;
@@ -2259,6 +2347,10 @@ _cairo_svg_surface_stroke (void *abstract_dst,
assert (_cairo_svg_surface_operation_supported (surface, op, source));
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
_cairo_output_stream_printf (surface->xml_node, "<path style=\"fill:none;");
status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, op,
source, stroke_style, ctm_inverse);
@@ -2267,9 +2359,7 @@ _cairo_svg_surface_stroke (void *abstract_dst,
_cairo_output_stream_printf (surface->xml_node, "\" ");
- status = _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse);
- if (unlikely (status))
- return status;
+ _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse);
_cairo_svg_surface_emit_transform (surface->xml_node, " transform", ctm, NULL);
_cairo_output_stream_printf (surface->xml_node, "/>\n");
@@ -2284,8 +2374,8 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_svg_document_t *document = surface->document;
@@ -2302,6 +2392,10 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
if (num_glyphs <= 0)
return CAIRO_STATUS_SUCCESS;
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
/* FIXME it's probably possible to apply a pattern of a gradient to
* a group of symbols, but I don't know how yet. Gradients or patterns
* are translated by x and y properties of use element. */
@@ -2349,7 +2443,9 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
FALLBACK:
_cairo_path_fixed_init (&path);
- status = _cairo_scaled_font_glyph_path (scaled_font,(cairo_glyph_t *) glyphs, num_glyphs, &path);
+ status = _cairo_scaled_font_glyph_path (scaled_font,
+ (cairo_glyph_t *) glyphs,
+ num_glyphs, &path);
if (unlikely (status)) {
_cairo_path_fixed_fini (&path);
@@ -2357,58 +2453,15 @@ FALLBACK:
}
status = _cairo_svg_surface_fill (abstract_surface, op, pattern,
- &path, CAIRO_FILL_RULE_WINDING, 0.0, CAIRO_ANTIALIAS_SUBPIXEL, NULL);
+ &path, CAIRO_FILL_RULE_WINDING,
+ 0.0, CAIRO_ANTIALIAS_SUBPIXEL,
+ clip);
_cairo_path_fixed_fini (&path);
return status;
}
-static cairo_int_status_t
-_cairo_svg_surface_intersect_clip_path (void *dst,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_svg_surface_t *surface = dst;
- cairo_svg_document_t *document = surface->document;
- cairo_status_t status;
- unsigned int i;
-
- if (path == NULL) {
- for (i = 0; i < surface->clip_level; i++)
- _cairo_output_stream_printf (surface->xml_node, "</g>\n");
-
- surface->clip_level = 0;
- return CAIRO_STATUS_SUCCESS;
- }
-
- _cairo_output_stream_printf (document->xml_node_defs,
- "<clipPath id=\"clip%d\">\n"
- " <path ",
- document->clip_id);
- status = _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
- if (unlikely (status))
- return status;
-
- _cairo_output_stream_printf (document->xml_node_defs,
- "/>\n"
- "</clipPath>\n");
-
- _cairo_output_stream_printf (surface->xml_node,
- "<g clip-path=\"url(#clip%d)\" "
- "clip-rule=\"%s\">\n",
- document->clip_id,
- fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
- "evenodd" : "nonzero");
-
- document->clip_id++;
- surface->clip_level++;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static void
_cairo_svg_surface_get_font_options (void *abstract_surface,
cairo_font_options_t *options)
@@ -2422,7 +2475,7 @@ _cairo_svg_surface_get_font_options (void *abstract_surface,
static const cairo_surface_backend_t cairo_svg_surface_backend = {
CAIRO_SURFACE_TYPE_SVG,
- _cairo_svg_surface_create_similar,
+ NULL, /* create_similar: handled by wrapper */
_cairo_svg_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
@@ -2436,8 +2489,6 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = {
NULL, /* check_span_renderer */
_cairo_svg_surface_copy_page,
_cairo_svg_surface_show_page,
- NULL, /* set_clip_region */
- _cairo_svg_surface_intersect_clip_path,
_cairo_svg_surface_get_extents,
NULL, /* _cairo_svg_surface_old_show_glyphs, */
_cairo_svg_surface_get_font_options,
@@ -2452,7 +2503,6 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = {
_cairo_svg_surface_show_glyphs,
NULL, /* snapshot */
NULL, /* is_similar */
- NULL, /* reset */
_cairo_svg_surface_fill_stroke
};
@@ -2487,7 +2537,6 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
document->width = width;
document->height = height;
- document->surface_id = 0;
document->linear_pattern_id = 0;
document->radial_pattern_id = 0;
document->pattern_id = 0;
@@ -2507,9 +2556,6 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
document->alpha_filter = FALSE;
- _cairo_array_init (&document->meta_snapshots,
- sizeof (cairo_meta_snapshot_t));
-
document->svg_version = version;
*document_out = document;
@@ -2560,7 +2606,6 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
{
cairo_status_t status, status2;
cairo_output_stream_t *output = document->output_stream;
- cairo_meta_snapshot_t *snapshot;
cairo_svg_page_t *page;
unsigned int i;
@@ -2662,16 +2707,6 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
- for (i = 0; i < document->meta_snapshots.num_elements; i++) {
- snapshot = _cairo_array_index (&document->meta_snapshots, i);
- cairo_surface_finish (&snapshot->meta->base);
- status2 = cairo_surface_status (&snapshot->meta->base);
- cairo_surface_destroy (&snapshot->meta->base);
- if (status == CAIRO_STATUS_SUCCESS)
- status = status2;
- }
- _cairo_array_fini (&document->meta_snapshots);
-
document->finished = TRUE;
return status;
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index d8464cc8..343d77fd 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -39,6 +39,8 @@
#include "cairoint.h"
+#include "cairo-region-private.h"
+
/* private functions */
static int
@@ -51,6 +53,8 @@ _cairo_traps_init (cairo_traps_t *traps)
traps->status = CAIRO_STATUS_SUCCESS;
+ traps->maybe_region = 1;
+
traps->num_traps = 0;
traps->traps_size = ARRAY_LENGTH (traps->traps_embedded);
@@ -83,6 +87,8 @@ _cairo_traps_clear (cairo_traps_t *traps)
{
traps->status = CAIRO_STATUS_SUCCESS;
+ traps->maybe_region = 1;
+
traps->num_traps = 0;
traps->extents.p1.x = traps->extents.p1.y = INT32_MAX;
traps->extents.p2.x = traps->extents.p2.y = INT32_MIN;
@@ -616,14 +622,18 @@ _cairo_traps_extents (const cairo_traps_t *traps,
* or %CAIRO_STATUS_NO_MEMORY
**/
cairo_int_status_t
-_cairo_traps_extract_region (const cairo_traps_t *traps,
- cairo_region_t **region)
+_cairo_traps_extract_region (cairo_traps_t *traps,
+ cairo_region_t **region)
{
cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
cairo_rectangle_int_t *rects = stack_rects;
cairo_int_status_t status;
int i, rect_count;
+ /* we only treat this a hint... */
+ if (! traps->maybe_region)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
for (i = 0; i < traps->num_traps; i++) {
if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
@@ -632,6 +642,7 @@ _cairo_traps_extract_region (const cairo_traps_t *traps,
! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
{
+ traps->maybe_region = FALSE;
return CAIRO_INT_STATUS_UNSUPPORTED;
}
}
@@ -655,7 +666,7 @@ _cairo_traps_extract_region (const cairo_traps_t *traps,
*/
if (x1 == x2 || y1 == y2)
continue;
-
+
rects[rect_count].x = x1;
rects[rect_count].y = y1;
rects[rect_count].width = x2 - x1;
@@ -663,18 +674,13 @@ _cairo_traps_extract_region (const cairo_traps_t *traps,
rect_count++;
}
-
+
*region = cairo_region_create_rectangles (rects, rect_count);
- status = cairo_region_status (*region);
+ status = (*region)->status;
if (rects != stack_rects)
free (rects);
- if (unlikely (status)) {
- cairo_region_destroy (*region);
- *region = NULL;
- }
-
return status;
}
diff --git a/src/cairo-type3-glyph-surface-private.h b/src/cairo-type3-glyph-surface-private.h
index 33314ae9..0b0010bc 100644
--- a/src/cairo-type3-glyph-surface-private.h
+++ b/src/cairo-type3-glyph-surface-private.h
@@ -42,6 +42,7 @@
#if CAIRO_HAS_FONT_SUBSET
#include "cairo-surface-private.h"
+#include "cairo-surface-clipper-private.h"
#include "cairo-pdf-operators-private.h"
typedef cairo_status_t (*cairo_type3_glyph_surface_emit_image_t) (cairo_image_surface_t *image,
@@ -55,16 +56,18 @@ typedef struct cairo_type3_glyph_surface {
cairo_pdf_operators_t pdf_operators;
cairo_matrix_t cairo_to_pdf;
cairo_type3_glyph_surface_emit_image_t emit_image;
+
+ cairo_surface_clipper_t clipper;
} cairo_type3_glyph_surface_t;
cairo_private cairo_surface_t *
-_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
+_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
cairo_output_stream_t *stream,
cairo_type3_glyph_surface_emit_image_t emit_image,
- cairo_scaled_font_subsets_t *font_subsets);
+ cairo_scaled_font_subsets_t *font_subsets);
cairo_private void
-_cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract_surface,
+_cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract_surface,
cairo_pdf_operators_use_font_subset_t use_font_subset,
void *closure);
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index 6e725960..f55b12ac 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -42,9 +42,31 @@
#include "cairo-output-stream-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-analysis-surface-private.h"
+#include "cairo-surface-clipper-private.h"
static const cairo_surface_backend_t cairo_type3_glyph_surface_backend;
+static cairo_status_t
+_cairo_type3_glyph_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_type3_glyph_surface_t *surface = cairo_container_of (clipper,
+ cairo_type3_glyph_surface_t,
+ clipper);
+
+ if (path == NULL) {
+ _cairo_output_stream_printf (surface->stream, "Q q\n");
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return _cairo_pdf_operators_clip (&surface->pdf_operators,
+ path,
+ fill_rule);
+}
+
cairo_surface_t *
_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
cairo_output_stream_t *stream,
@@ -81,6 +103,9 @@ _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
&surface->cairo_to_pdf,
font_subsets);
+ _cairo_surface_clipper_init (&surface->clipper,
+ _cairo_type3_glyph_surface_clipper_intersect_clip_path);
+
return &surface->base;
}
@@ -156,29 +181,10 @@ _cairo_type3_glyph_surface_finish (void *abstract_surface)
}
static cairo_int_status_t
-_cairo_type3_glyph_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_type3_glyph_surface_t *surface = abstract_surface;
-
- if (path == NULL) {
- _cairo_output_stream_printf (surface->stream, "Q q\n");
- return CAIRO_STATUS_SUCCESS;
- }
-
- return _cairo_pdf_operators_clip (&surface->pdf_operators,
- path,
- fill_rule);
-}
-
-static cairo_int_status_t
_cairo_type3_glyph_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
const cairo_surface_pattern_t *pattern;
@@ -189,8 +195,13 @@ _cairo_type3_glyph_surface_paint (void *abstract_surface,
if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
pattern = (const cairo_surface_pattern_t *) source;
- status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
+ status = _cairo_surface_acquire_source_image (pattern->surface,
+ &image, &image_extra);
if (unlikely (status))
goto fail;
@@ -209,9 +220,11 @@ _cairo_type3_glyph_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
- return _cairo_type3_glyph_surface_paint (abstract_surface, op, mask, extents);
+ return _cairo_type3_glyph_surface_paint (abstract_surface,
+ op, mask,
+ clip);
}
static cairo_int_status_t
@@ -224,9 +237,14 @@ _cairo_type3_glyph_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
+ cairo_int_status_t status;
+
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
return _cairo_pdf_operators_stroke (&surface->pdf_operators,
path,
@@ -243,16 +261,18 @@ _cairo_type3_glyph_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
cairo_int_status_t status;
- status = _cairo_pdf_operators_fill (&surface->pdf_operators,
- path,
- fill_rule);
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
- return status;
+ return _cairo_pdf_operators_fill (&surface->pdf_operators,
+ path,
+ fill_rule);
}
static cairo_int_status_t
@@ -262,8 +282,8 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@@ -271,8 +291,14 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface,
cairo_matrix_t new_ctm, ctm_inverse;
int i;
- for (i = 0; i < num_glyphs; i++)
- cairo_matrix_transform_point (&surface->cairo_to_pdf, &glyphs[i].x, &glyphs[i].y);
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status))
+ return status;
+
+ for (i = 0; i < num_glyphs; i++) {
+ cairo_matrix_transform_point (&surface->cairo_to_pdf,
+ &glyphs[i].x, &glyphs[i].y);
+ }
/* We require the matrix to be invertable. */
ctm_inverse = scaled_font->ctm;
@@ -316,8 +342,6 @@ static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* cairo_type3_glyph_surface_copy_page */
NULL, /* _cairo_type3_glyph_surface_show_page */
- NULL, /* set_clip_region */
- _cairo_type3_glyph_surface_intersect_clip_path,
NULL, /* _cairo_type3_glyph_surface_get_extents */
NULL, /* old_show_glyphs */
NULL, /* _cairo_type3_glyph_surface_get_font_options */
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 2ed3264b..a68fe500 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -41,6 +41,7 @@
#include "cairo.h"
#include "cairo-fixed-type-private.h"
+#include "cairo-list-private.h"
#include "cairo-reference-count-private.h"
typedef struct _cairo_array cairo_array_t;
@@ -63,6 +64,7 @@ typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t;
typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
typedef struct _cairo_solid_pattern cairo_solid_pattern_t;
typedef struct _cairo_surface_backend cairo_surface_backend_t;
+typedef struct _cairo_surface_wrapper cairo_surface_wrapper_t;
typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t;
typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t;
@@ -167,6 +169,7 @@ typedef enum _cairo_internal_surface_type {
CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH
} cairo_internal_surface_type_t;
@@ -237,12 +240,6 @@ typedef enum _cairo_direction {
CAIRO_DIRECTION_REVERSE
} cairo_direction_t;
-typedef enum _cairo_clip_mode {
- CAIRO_CLIP_MODE_PATH,
- CAIRO_CLIP_MODE_REGION,
- CAIRO_CLIP_MODE_MASK
-} cairo_clip_mode_t;
-
typedef struct _cairo_edge {
cairo_line_t edge;
int dir;
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index 1adfd7d6..42e8bae2 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -85,7 +85,7 @@ _cairo_user_scaled_font_create_meta_context (cairo_user_scaled_font_t *scaled_fo
CAIRO_CONTENT_COLOR_ALPHA :
CAIRO_CONTENT_ALPHA;
- meta_surface = cairo_meta_surface_create (content, -1, -1);
+ meta_surface = cairo_meta_surface_create (content, NULL);
cr = cairo_create (meta_surface);
cairo_surface_destroy (meta_surface);
@@ -114,11 +114,11 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
cr = _cairo_user_scaled_font_create_meta_context (scaled_font);
- if (face->scaled_font_methods.render_glyph)
+ if (face->scaled_font_methods.render_glyph) {
status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font,
_cairo_scaled_glyph_index(scaled_glyph),
cr, &extents);
- else
+ } else
status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
if (status == CAIRO_STATUS_SUCCESS)
@@ -141,27 +141,16 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
/* set metrics */
if (extents.width == 0.) {
- /* Compute extents.x/y/width/height from meta_surface, in font space */
-
cairo_box_t bbox;
double x1, y1, x2, y2;
double x_scale, y_scale;
- cairo_surface_t *null_surface;
- cairo_surface_t *analysis_surface;
-
- null_surface = _cairo_null_surface_create (cairo_surface_get_content (meta_surface));
- analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1);
- cairo_surface_destroy (null_surface);
- status = analysis_surface->status;
- if (unlikely (status))
- return status;
-
- _cairo_analysis_surface_set_ctm (analysis_surface,
- &scaled_font->extent_scale);
- status = cairo_meta_surface_replay (meta_surface, analysis_surface);
- _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox);
- cairo_surface_destroy (analysis_surface);
+ /* Compute extents.x/y/width/height from meta_surface,
+ * in font space.
+ */
+ status = _cairo_meta_surface_get_bbox ((cairo_meta_surface_t *) meta_surface,
+ &bbox,
+ &scaled_font->extent_scale);
if (unlikely (status))
return status;
@@ -231,7 +220,6 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_meta_surface_get_path (meta_surface, path);
-
if (unlikely (status)) {
_cairo_path_fixed_destroy (path);
return status;
diff --git a/src/cairo-vg-surface.c b/src/cairo-vg-surface.c
index de3d0c6f..232450d5 100644
--- a/src/cairo-vg-surface.c
+++ b/src/cairo-vg-surface.c
@@ -40,6 +40,7 @@
#include "cairo-path-fixed-private.h"
#include "cairo-meta-surface-private.h"
+#include "cairo-surface-clipper-private.h"
#include "cairo-cache-private.h"
#include <pixman.h>
@@ -94,7 +95,7 @@ struct _cairo_vg_surface {
cairo_cache_entry_t snapshot_cache_entry;
- cairo_bool_t clipped;
+ cairo_surface_clipper_t clipper;
unsigned long target_id;
};
@@ -397,21 +398,21 @@ _vg_surface_create_similar (void *abstract_surface,
return cairo_vg_surface_create (surface->context, content, width, height);
}
-static cairo_int_status_t
-_vg_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
+static cairo_status_t
+_vg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
{
- cairo_vg_surface_t *surface = abstract_surface;
+ cairo_vg_surface_t *surface = cairo_container_of (clipper,
+ cairo_vg_surface_t,
+ clipper);
cairo_vg_surface_t *mask;
- cairo_rectangle_int_t extents, clip_extents;
cairo_solid_pattern_t white;
cairo_status_t status;
if (path == NULL) {
- surface->clipped = FALSE;
vgMask (VG_INVALID_HANDLE,
VG_FILL_MASK, 0, 0, surface->width, surface->height);
vgSeti (VG_MASKING, VG_FALSE);
@@ -419,16 +420,6 @@ _vg_surface_intersect_clip_path (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
- extents.x = extents.y = 0;
- extents.width = surface->width;
- extents.height = surface->height;
- _cairo_path_fixed_approximate_clip_extents (path, &clip_extents);
- if (! _cairo_rectangle_intersect (&clip_extents, &extents))
- surface->clipped = TRUE;
-
- if (surface->clipped)
- return CAIRO_STATUS_SUCCESS;
-
mask = (cairo_vg_surface_t *)
_vg_surface_create_similar (surface, CAIRO_CONTENT_ALPHA,
surface->width, surface->height);
@@ -456,7 +447,7 @@ _vg_surface_intersect_clip_path (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
+static cairo_bool_t
_vg_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *extents)
{
@@ -467,7 +458,7 @@ _vg_surface_get_extents (void *abstract_surface,
extents->width = surface->width;
extents->height = surface->height;
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
#define MAX_SEG 16 /* max number of knots to upload in a batch */
@@ -589,7 +580,7 @@ _vg_close_path (void *closure)
static void
_vg_path_from_cairo (vg_path_t *vg_path,
- cairo_path_fixed_t *path)
+ const cairo_path_fixed_t *path)
{
cairo_status_t status;
@@ -805,7 +796,7 @@ _vg_setup_linear_source (cairo_vg_context_t *context,
static cairo_status_t
_vg_setup_radial_source (cairo_vg_context_t *context,
- cairo_radial_pattern_t *rpat)
+ const cairo_radial_pattern_t *rpat)
{
VGfloat radial[5];
@@ -832,7 +823,7 @@ _vg_setup_radial_source (cairo_vg_context_t *context,
static cairo_status_t
_vg_setup_solid_source (cairo_vg_context_t *context,
- cairo_solid_pattern_t *spat)
+ const cairo_solid_pattern_t *spat)
{
VGfloat color[] = {
spat->color.red,
@@ -960,7 +951,7 @@ _vg_surface_remove_from_cache (cairo_surface_t *abstract_surface)
static cairo_status_t
_vg_setup_surface_source (cairo_vg_context_t *context,
- cairo_surface_pattern_t *spat)
+ const cairo_surface_pattern_t *spat)
{
cairo_surface_t *snapshot;
cairo_vg_surface_t *clone;
@@ -1077,7 +1068,7 @@ _vg_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_vg_surface_t *surface = abstract_surface;
cairo_vg_context_t *context;
@@ -1086,9 +1077,6 @@ _vg_surface_stroke (void *abstract_surface,
VGfloat strokeTransform[9];
vg_path_t vg_path;
- if (surface->clipped)
- return CAIRO_STATUS_SUCCESS;
-
if (! _vg_is_supported_operator (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1105,6 +1093,12 @@ _vg_surface_stroke (void *abstract_surface,
return status;
}
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status)) {
+ _vg_context_unlock (context);
+ return status;
+ }
+
vg_path.path = vgCreatePath (VG_PATH_FORMAT_STANDARD,
VG_PATH_DATATYPE_F,
1, 0, 0, 0,
@@ -1148,16 +1142,13 @@ _vg_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_vg_surface_t *surface = abstract_surface;
cairo_vg_context_t *context;
cairo_status_t status;
vg_path_t vg_path;
- if (surface->clipped)
- return CAIRO_STATUS_SUCCESS;
-
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
@@ -1177,6 +1168,12 @@ _vg_surface_fill (void *abstract_surface,
return status;
}
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status)) {
+ _vg_context_unlock (context);
+ return status;
+ }
+
vg_path.path = vgCreatePath (VG_PATH_FORMAT_STANDARD,
VG_PATH_DATATYPE_F,
1, 0,
@@ -1208,15 +1205,12 @@ static cairo_int_status_t
_vg_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_vg_surface_t *surface = abstract_surface;
cairo_vg_context_t *context;
cairo_status_t status;
- if (surface->clipped)
- return CAIRO_STATUS_SUCCESS;
-
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
@@ -1236,6 +1230,12 @@ _vg_surface_paint (void *abstract_surface,
return status;
}
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (unlikely (status)) {
+ _vg_context_unlock (context);
+ return status;
+ }
+
vgSeti (VG_BLEND_MODE, _vg_operator (op));
vgSetPaint (context->paint, VG_FILL_PATH);
@@ -1273,14 +1273,11 @@ _vg_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_vg_surface_t *surface = abstract_surface;
cairo_status_t status;
- if (surface->clipped)
- return CAIRO_STATUS_SUCCESS;
-
if (! _vg_is_supported_operator (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1291,7 +1288,7 @@ _vg_surface_mask (void *abstract_surface,
double alpha = context->alpha;
context->alpha = solid->color.alpha;
- status = _vg_surface_paint (abstract_surface, op, source, extents);
+ status = _vg_surface_paint (abstract_surface, op, source, clip);
context->alpha = alpha;
_vg_context_unlock (context);
@@ -1312,14 +1309,14 @@ _vg_surface_get_font_options (void *abstract_surface,
}
static cairo_int_status_t
-_vg_surface_show_glyphs (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+_vg_surface_show_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_path_fixed_t path;
@@ -1342,7 +1339,7 @@ _vg_surface_show_glyphs (void *abstract_surface,
CAIRO_FILL_RULE_WINDING,
CAIRO_GSTATE_TOLERANCE_DEFAULT,
CAIRO_ANTIALIAS_SUBPIXEL,
- extents);
+ clip);
BAIL:
_cairo_path_fixed_fini (&path);
return status;
@@ -1510,12 +1507,6 @@ _vg_surface_release_dest_image (void *abstract_surface,
cairo_vg_surface_t *surface = abstract_surface;
cairo_bool_t needs_unpremultiply;
- /* XXX clipping is incorrect
- * We can either composite through the current clip mask using fill,
- * or what for the clipping overhaul patches, due to land any time
- * soon now...
- */
-
_vg_format_to_pixman (surface->format, &needs_unpremultiply);
if (needs_unpremultiply) {
unpremultiply_argb (image->data,
@@ -1545,6 +1536,8 @@ _vg_surface_finish (void *abstract_surface)
surface->snapshot_cache_entry.hash = 0;
}
+ _cairo_surface_clipper_reset (&surface->clipper);
+
if (surface->own_image)
vgDestroyImage (surface->image);
@@ -1561,20 +1554,21 @@ static const cairo_surface_backend_t cairo_vg_surface_backend = {
CAIRO_SURFACE_TYPE_VG,
_vg_surface_create_similar,
_vg_surface_finish,
+
_vg_surface_acquire_source_image,
_vg_surface_release_source_image,
_vg_surface_acquire_dest_image,
_vg_surface_release_dest_image,
+
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
+
NULL, /* copy_page */
NULL, /* show_page */
- NULL, /* set_clip_region */
- _vg_surface_intersect_clip_path,
_vg_surface_get_extents,
NULL, /* old_show_glyphs */
_vg_surface_get_font_options, /* get_font_options */
@@ -1591,7 +1585,6 @@ static const cairo_surface_backend_t cairo_vg_surface_backend = {
NULL, /* snapshot */
NULL, /* is_similar */
- NULL, /* reset */
};
static cairo_surface_t *
@@ -1617,15 +1610,14 @@ _vg_surface_create_internal (cairo_vg_context_t *context,
surface->width = width;
surface->height = height;
- surface->clipped = FALSE;
+
+ _cairo_surface_clipper_init (&surface->clipper,
+ _vg_surface_clipper_intersect_clip_path);
surface->snapshot_cache_entry.hash = 0;
surface->target_id = 0;
- /* Force an initial "clip", that resets the mask */
- _vg_surface_intersect_clip_path (surface, NULL, 0, 0.0, 0);
-
CHECK_VG_ERRORS();
return &surface->base;
}
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index e62e8816..2f1127c2 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -1360,6 +1360,7 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font,
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
+ cairo_region_t *clip_region,
int *remaining_glyphs)
{
cairo_win32_scaled_font_t *scaled_font = abstract_font;
@@ -1381,15 +1382,17 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font,
*/
COLORREF new_color;
+ status = _cairo_win32_surface_set_clip_region (surface, clip_region);
+ if (unlikely (status))
+ return status;
+
new_color = RGB (((int)solid_pattern->color.red_short) >> 8,
((int)solid_pattern->color.green_short) >> 8,
((int)solid_pattern->color.blue_short) >> 8);
- status = _draw_glyphs_on_surface (surface, scaled_font, new_color,
- 0, 0,
- glyphs, num_glyphs);
-
- return status;
+ return _draw_glyphs_on_surface (surface, scaled_font, new_color,
+ 0, 0,
+ glyphs, num_glyphs);
} else {
/* Otherwise, we need to draw using software fallbacks. We create a mask
* surface by drawing the the glyphs onto a DIB, black-on-white then
@@ -1458,7 +1461,8 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font,
source_x, source_y,
0, 0,
dest_x, dest_y,
- width, height);
+ width, height,
+ clip_region);
_cairo_pattern_fini (&mask.base);
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 9025bfa7..17a7b39c 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -53,6 +53,7 @@
#include "cairo-meta-surface-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-image-info-private.h"
+#include "cairo-surface-clipper-private.h"
#include <windows.h>
@@ -128,7 +129,7 @@ analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern)
cairo_image_surface_t *image;
void *image_extra;
cairo_int_status_t status;
- int x, y;
+ cairo_image_transparency_t transparency;
status = _cairo_surface_acquire_source_image (pattern->surface,
&image,
@@ -136,38 +137,20 @@ analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern)
if (status)
return status;
- if (image->base.status)
- return image->base.status;
-
- if (image->format == CAIRO_FORMAT_RGB24) {
+ transparency = _cairo_image_analyze_transparency (image);
+ switch (transparency) {
+ case CAIRO_IMAGE_UNKNOWN:
+ ASSERT_NOT_REACHED;
+ case CAIRO_IMAGE_IS_OPAQUE:
status = CAIRO_STATUS_SUCCESS;
- goto RELEASE_SOURCE;
- }
+ break;
- if (image->format != CAIRO_FORMAT_ARGB32) {
- /* If the surface does not support the image format, assume
- * that it does have alpha. The image will be converted to
- * rgb24 when the surface blends the image into the page
- * color to remove the transparency. */
+ case CAIRO_IMAGE_HAS_BILEVEL_ALPHA:
+ case CAIRO_IMAGE_HAS_ALPHA:
status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
- goto RELEASE_SOURCE;
- }
-
- for (y = 0; y < image->height; y++) {
- int a;
- uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
-
- for (x = 0; x < image->width; x++, pixel++) {
- a = (*pixel & 0xff000000) >> 24;
- if (a != 255) {
- status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
- goto RELEASE_SOURCE;
- }
- }
+ break;
}
- status = CAIRO_STATUS_SUCCESS;
-RELEASE_SOURCE:
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
return status;
@@ -176,8 +159,6 @@ RELEASE_SOURCE:
static cairo_bool_t
surface_pattern_supported (const cairo_surface_pattern_t *pattern)
{
- cairo_extend_t extend;
-
if (_cairo_surface_is_meta (pattern->surface))
return TRUE;
@@ -187,19 +168,7 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern)
return FALSE;
}
- extend = cairo_pattern_get_extend ((cairo_pattern_t*)&pattern->base);
- switch (extend) {
- case CAIRO_EXTEND_NONE:
- case CAIRO_EXTEND_REPEAT:
- case CAIRO_EXTEND_REFLECT:
- /* There's no point returning FALSE for EXTEND_PAD, as the image
- * surface does not currently implement it either */
- case CAIRO_EXTEND_PAD:
- return TRUE;
- }
-
- ASSERT_NOT_REACHED;
- return FALSE;
+ return TRUE;
}
static cairo_bool_t
@@ -390,7 +359,8 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa
XFORM xform;
int x_tile, y_tile, left, right, top, bottom;
RECT clip;
- cairo_surface_t *meta_surface = pattern->surface;
+ cairo_meta_surface_t *meta_surface = (cairo_meta_surface_t *) pattern->surface;
+ cairo_box_t bbox;
extend = cairo_pattern_get_extend (&pattern->base);
@@ -406,7 +376,7 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa
SaveDC (surface->dc);
_cairo_matrix_to_win32_xform (&p2d, &xform);
- status = _cairo_surface_get_extents (meta_surface, &meta_extents);
+ status = _cairo_meta_surface_get_bbox (meta_surface, &bbox, NULL);
if (status)
return status;
@@ -415,10 +385,10 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa
return status;
if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
- left = (int) floor((double)clip.left/meta_extents.width);
- right = (int) ceil((double)clip.right/meta_extents.width);
- top = (int) floor((double)clip.top/meta_extents.height);
- bottom = (int) ceil((double)clip.bottom/meta_extents.height);
+ left = (int) floor (clip.left / _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x));
+ right = (int) ceil (clip.right / _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x));
+ top = (int) floor (clip.top / _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y));
+ bottom = (int) ceil (clip.bottom / _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y));
} else {
left = 0;
right = 1;
@@ -427,7 +397,7 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa
}
old_content = surface->content;
- if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
+ if (meta_surface->base.content == CAIRO_CONTENT_COLOR) {
cairo_pattern_t *source;
cairo_solid_pattern_t black;
@@ -490,7 +460,8 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa
SelectClipPath (surface->dc, RGN_AND);
SaveDC (surface->dc); /* Allow clip path to be reset during replay */
- status = _cairo_meta_surface_replay_region (meta_surface, &surface->base,
+ status = _cairo_meta_surface_replay_region (&meta_surface->base,
+ &surface->base,
CAIRO_META_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
/* Restore both the clip save and our earlier path SaveDC */
@@ -594,7 +565,6 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
cairo_extend_t extend;
cairo_image_surface_t *image;
void *image_extra;
- cairo_surface_t *opaque_surface;
cairo_image_surface_t *opaque_image = NULL;
BITMAPINFO bi;
cairo_matrix_t m;
@@ -651,13 +621,15 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
&mime_size,
&mime_info);
}
- if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
+ if (_cairo_status_is_error (status))
return status;
use_mime = (status == CAIRO_STATUS_SUCCESS);
if (!use_mime && image->format != CAIRO_FORMAT_RGB24) {
- cairo_surface_pattern_t opaque_pattern;
+ cairo_surface_t *opaque_surface;
+ cairo_surface_pattern_t image_pattern;
+ cairo_solid_pattern_t background_pattern;
opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
image->width,
@@ -667,36 +639,27 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
goto CLEANUP_OPAQUE_IMAGE;
}
- _cairo_pattern_init_for_surface (&opaque_pattern, &image->base);
-
- status = _cairo_surface_fill_rectangle (opaque_surface,
- CAIRO_OPERATOR_SOURCE,
- background_color,
- 0, 0,
- image->width, image->height);
- if (status) {
- _cairo_pattern_fini (&opaque_pattern.base);
+ _cairo_pattern_init_solid (&background_pattern,
+ background_color,
+ CAIRO_CONTENT_COLOR);
+ status = _cairo_surface_paint (opaque_surface,
+ CAIRO_OPERATOR_SOURCE,
+ &background_pattern.base,
+ NULL);
+ if (status)
goto CLEANUP_OPAQUE_IMAGE;
- }
- status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
- &opaque_pattern.base,
- NULL,
- opaque_surface,
- 0, 0,
- 0, 0,
- 0, 0,
- image->width,
- image->height);
- if (status) {
- _cairo_pattern_fini (&opaque_pattern.base);
+ _cairo_pattern_init_for_surface (&image_pattern, &image->base);
+ status = _cairo_surface_paint (opaque_surface,
+ CAIRO_OPERATOR_OVER,
+ &image_pattern.base,
+ NULL);
+ _cairo_pattern_fini (&image_pattern.base);
+ if (status)
goto CLEANUP_OPAQUE_IMAGE;
- }
- _cairo_pattern_fini (&opaque_pattern.base);
opaque_image = (cairo_image_surface_t *) opaque_surface;
} else {
- opaque_surface = &image->base;
opaque_image = image;
}
@@ -767,7 +730,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
CLEANUP_OPAQUE_IMAGE:
if (opaque_image != image)
- cairo_surface_destroy (opaque_surface);
+ cairo_surface_destroy (&opaque_image->base);
CLEANUP_IMAGE:
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
@@ -1085,17 +1048,15 @@ _cairo_win32_printing_surface_emit_path (cairo_win32_surface_t *surface,
cairo_path_fixed_t *path)
{
win32_path_info_t path_info;
- cairo_status_t status;
path_info.surface = surface;
- status = _cairo_path_fixed_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_win32_printing_surface_path_move_to,
- _cairo_win32_printing_surface_path_line_to,
- _cairo_win32_printing_surface_path_curve_to,
- _cairo_win32_printing_surface_path_close_path,
- &path_info);
- return status;
+ return _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_win32_printing_surface_path_move_to,
+ _cairo_win32_printing_surface_path_line_to,
+ _cairo_win32_printing_surface_path_curve_to,
+ _cairo_win32_printing_surface_path_close_path,
+ &path_info);
}
static cairo_int_status_t
@@ -1109,14 +1070,16 @@ _cairo_win32_printing_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_win32_printing_surface_intersect_clip_path (void *abstract_surface,
+static cairo_status_t
+_cairo_win32_printing_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
- cairo_win32_surface_t *surface = abstract_surface;
+ cairo_win32_surface_t *surface = cairo_container_of (clipper,
+ cairo_win32_surface_t,
+ clipper);
cairo_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
@@ -1164,10 +1127,15 @@ static cairo_int_status_t
_cairo_win32_printing_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_solid_pattern_t clear;
+ cairo_status_t status;
+
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (status)
+ return status;
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_win32_printing_surface_init_clear_color (surface, &clear);
@@ -1242,7 +1210,7 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
cairo_matrix_t *stroke_ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@@ -1258,6 +1226,10 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
cairo_matrix_t mat;
double scale;
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (status)
+ return status;
+
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_win32_printing_surface_init_clear_color (surface, &clear);
source = (cairo_pattern_t*) &clear;
@@ -1364,12 +1336,16 @@ _cairo_win32_printing_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_int_status_t status;
cairo_solid_pattern_t clear;
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (status)
+ return status;
+
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_win32_printing_surface_init_clear_color (surface, &clear);
source = (cairo_pattern_t*) &clear;
@@ -1423,8 +1399,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
@@ -1435,6 +1411,10 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
cairo_bool_t old_has_ctm;
cairo_solid_pattern_t clear;
+ status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+ if (status)
+ return status;
+
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_win32_printing_surface_init_clear_color (surface, &clear);
source = (cairo_pattern_t*) &clear;
@@ -1547,8 +1527,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
status = _cairo_win32_surface_show_glyphs (surface, op,
source, glyphs,
num_glyphs, scaled_font,
- remaining_glyphs,
- extents);
+ clip,
+ remaining_glyphs);
if (surface->has_ctm)
cairo_scaled_font_destroy (scaled_font);
@@ -1607,7 +1587,12 @@ _cairo_win32_printing_surface_create_similar (void *abstract_surface,
int width,
int height)
{
- return cairo_meta_surface_create (content, width, height);
+ cairo_rectangle_t extents;
+
+ extents.x = extents.y = 0;
+ extents.width = width;
+ extents.height = height;
+ return cairo_meta_surface_create (content, &extents);
}
static cairo_int_status_t
@@ -1698,6 +1683,9 @@ cairo_win32_printing_surface_create (HDC hdc)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
+ _cairo_surface_clipper_init (&surface->clipper,
+ _cairo_win32_printing_surface_clipper_intersect_clip_path);
+
surface->image = NULL;
surface->format = CAIRO_FORMAT_RGB24;
surface->content = CAIRO_CONTENT_COLOR_ALPHA;
@@ -1725,13 +1713,12 @@ cairo_win32_printing_surface_create (HDC hdc)
_cairo_win32_printing_surface_init_ps_mode (surface);
_cairo_win32_printing_surface_init_image_support (surface);
- _cairo_surface_init (&surface->base, &cairo_win32_printing_surface_backend,
+ _cairo_surface_init (&surface->base,
+ &cairo_win32_printing_surface_backend,
CAIRO_CONTENT_COLOR_ALPHA);
paginated = _cairo_paginated_surface_create (&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
- surface->extents.width,
- surface->extents.height,
&cairo_win32_surface_paginated_backend);
/* paginated keeps the only reference to surface now, drop ours */
@@ -1762,8 +1749,6 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
_cairo_win32_printing_surface_show_page,
- NULL, /* set_clip_region */
- _cairo_win32_printing_surface_intersect_clip_path,
_cairo_win32_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_win32_printing_surface_get_font_options,
@@ -1779,7 +1764,6 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
_cairo_win32_printing_surface_show_glyphs,
NULL, /* snapshot */
NULL, /* is_similar */
- NULL, /* reset */
NULL, /* fill_stroke */
};
diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
index 40ed20ef..c1040e83 100644
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -38,6 +38,7 @@
#include "cairo-win32.h"
#include "cairoint.h"
+#include "cairo-surface-clipper-private.h"
#ifndef SHADEBLENDCAPS
#define SHADEBLENDCAPS 120
@@ -81,6 +82,10 @@ typedef struct _cairo_win32_surface {
cairo_rectangle_int_t clip_rect;
HRGN initial_clip_rgn;
cairo_bool_t had_simple_clip;
+ cairo_region_t *clip_region;
+
+ /* For path clipping to the printing-surface */
+ cairo_surface_clipper_t clipper;
/* Surface DC flags */
uint32_t flags;
@@ -137,13 +142,17 @@ _cairo_surface_is_win32_printing (cairo_surface_t *surface);
cairo_status_t
_cairo_win32_surface_finish (void *abstract_surface);
-cairo_int_status_t
+cairo_bool_t
_cairo_win32_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle);
uint32_t
_cairo_win32_flags_for_dc (HDC dc);
+cairo_status_t
+_cairo_win32_surface_set_clip_region (void *abstract_surface,
+ cairo_region_t *region);
+
cairo_int_status_t
_cairo_win32_surface_show_glyphs (void *surface,
cairo_operator_t op,
@@ -151,8 +160,8 @@ _cairo_win32_surface_show_glyphs (void *surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip,
+ int *remaining_glyphs);
cairo_surface_t *
_cairo_win32_surface_create_similar (void *abstract_src,
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 5bbc8f86..12219e95 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -468,7 +468,8 @@ _cairo_win32_surface_clone_similar (void *abstract_surface,
src_x, src_y,
0, 0,
0, 0,
- width, height);
+ width, height,
+ NULL);
_cairo_pattern_fini (&pattern.base);
@@ -693,6 +694,91 @@ _cairo_win32_surface_release_dest_image (void *abstract_surfa
cairo_surface_destroy ((cairo_surface_t *)local);
}
+cairo_status_t
+_cairo_win32_surface_set_clip_region (void *abstract_surface,
+ cairo_region_t *region)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ if (surface->clip_region == region)
+ return CAIRO_STATUS_SUCCESS;
+
+ cairo_region_destroy (surface->clip_region);
+ surface->clip_region = cairo_region_reference (region);
+
+ /* The semantics we want is that any clip set by cairo combines
+ * is intersected with the clip on device context that the
+ * surface was created for. To implement this, we need to
+ * save the original clip when first setting a clip on surface.
+ */
+
+ /* Clear any clip set by cairo, return to the original first */
+ status = _cairo_win32_restore_initial_clip (surface);
+
+ /* Then combine any new region with it */
+ if (region) {
+ cairo_rectangle_int_t extents;
+ int num_rects;
+ RGNDATA *data;
+ size_t data_size;
+ RECT *rects;
+ int i;
+ HRGN gdi_region;
+
+ /* Create a GDI region for the cairo region */
+
+ cairo_region_get_extents (region, &extents);
+ num_rects = cairo_region_num_rectangles (region);
+ /* XXX see notes in _cairo_win32_save_initial_clip --
+ * this code will interact badly with a HDC which had an initial
+ * world transform -- we should probably manually transform the
+ * region rects, because SelectClipRgn takes device units, not
+ * logical units (unlike IntersectClipRect).
+ */
+
+ data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
+ data = malloc (data_size);
+ if (!data)
+ return _cairo_error(CAIRO_STATUS_NO_MEMORY);
+ rects = (RECT *)data->Buffer;
+
+ data->rdh.dwSize = sizeof (RGNDATAHEADER);
+ data->rdh.iType = RDH_RECTANGLES;
+ data->rdh.nCount = num_rects;
+ data->rdh.nRgnSize = num_rects * sizeof (RECT);
+ data->rdh.rcBound.left = extents.x;
+ data->rdh.rcBound.top = extents.y;
+ data->rdh.rcBound.right = extents.x + extents.width;
+ data->rdh.rcBound.bottom = extents.y + extents.height;
+
+ for (i = 0; i < num_rects; i++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (region, i, &rect);
+
+ rects[i].left = rect.x;
+ rects[i].top = rect.y;
+ rects[i].right = rect.x + rect.width;
+ rects[i].bottom = rect.y + rect.height;
+ }
+
+ gdi_region = ExtCreateRegion (NULL, data_size, data);
+ free (data);
+
+ if (!gdi_region)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ /* AND the new region into our DC */
+ if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
+
+ DeleteObject (gdi_region);
+ }
+
+ return status;
+}
+
#if !defined(AC_SRC_OVER)
#define AC_SRC_OVER 0x00
#pragma pack(1)
@@ -889,7 +975,8 @@ _cairo_win32_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_win32_surface_t *dst = abstract_dst;
cairo_win32_surface_t *src;
@@ -1030,7 +1117,7 @@ _cairo_win32_surface_composite (cairo_operator_t op,
fflush (stderr);
#endif
- /* If the src recangle doesn't wholly lie within the src extents,
+ /* If the src rectangle doesn't wholly lie within the src extents,
* fudge things. We really need to do fixup on the unpainted
* region -- e.g. the SOURCE operator is broken for areas outside
* of the extents, because it won't clear that area to transparent
@@ -1150,6 +1237,10 @@ _cairo_win32_surface_composite (cairo_operator_t op,
fflush (stderr);
#endif
+ status = _cairo_win32_surface_set_clip_region (dst, clip_region);
+ if (status)
+ return status;
+
/* If we need to repeat, we turn the repeated blit into
* a bunch of piece-by-piece blits.
*/
@@ -1283,7 +1374,8 @@ UNSUPPORTED:
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
- width, height);
+ width, height,
+ clip_region);
}
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1387,6 +1479,10 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
if (surface->format != CAIRO_FORMAT_RGB24)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ status = _cairo_win32_surface_set_clip_region (surface, NULL);
+ if (status)
+ return status;
+
/* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
* surfaces with alpha.)
*/
@@ -1432,133 +1528,20 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
return status;
}
-static cairo_int_status_t
-_cairo_win32_surface_set_clip_region (void *abstract_surface,
- cairo_region_t *region)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- /* If we are in-memory, then we set the clip on the image surface
- * as well as on the underlying GDI surface.
- */
- if (surface->image) {
- unsigned int serial;
-
- serial = _cairo_surface_allocate_clip_serial (surface->image);
- status = _cairo_surface_set_clip_region (surface->image, region, serial);
- if (status)
- return status;
- }
-
- /* The semantics we want is that any clip set by cairo combines
- * is intersected with the clip on device context that the
- * surface was created for. To implement this, we need to
- * save the original clip when first setting a clip on surface.
- */
-
- /* Clear any clip set by cairo, return to the original first */
- status = _cairo_win32_restore_initial_clip (surface);
-
- /* Then combine any new region with it */
- if (region) {
- cairo_rectangle_int_t extents;
- int num_rects;
- RGNDATA *data;
- size_t data_size;
- RECT *rects;
- int i;
- HRGN gdi_region;
- cairo_rectangle_int_t rect0;
-
- /* Create a GDI region for the cairo region */
-
- cairo_region_get_extents (region, &extents);
- num_rects = cairo_region_num_rectangles (region);
-
- if (num_rects == 1)
- cairo_region_get_rectangle (region, 0, &rect0);
-
- if (num_rects == 1 &&
- rect0.x == 0 &&
- rect0.y == 0 &&
- rect0.width == surface->extents.width &&
- rect0.width == surface->extents.height)
- {
- gdi_region = NULL;
-
- SelectClipRgn (surface->dc, NULL);
- IntersectClipRect (surface->dc,
- rect0.x,
- rect0.y,
- rect0.x + rect0.width,
- rect0.y + rect0.height);
- } else {
- /* XXX see notes in _cairo_win32_save_initial_clip --
- * this code will interact badly with a HDC which had an initial
- * world transform -- we should probably manually transform the
- * region rects, because SelectClipRgn takes device units, not
- * logical units (unlike IntersectClipRect).
- */
-
- data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
- data = malloc (data_size);
- if (!data)
- return _cairo_error(CAIRO_STATUS_NO_MEMORY);
- rects = (RECT *)data->Buffer;
-
- data->rdh.dwSize = sizeof (RGNDATAHEADER);
- data->rdh.iType = RDH_RECTANGLES;
- data->rdh.nCount = num_rects;
- data->rdh.nRgnSize = num_rects * sizeof (RECT);
- data->rdh.rcBound.left = extents.x;
- data->rdh.rcBound.top = extents.y;
- data->rdh.rcBound.right = extents.x + extents.width;
- data->rdh.rcBound.bottom = extents.y + extents.height;
-
- for (i = 0; i < num_rects; i++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (region, i, &rect);
-
- rects[i].left = rect.x;
- rects[i].top = rect.y;
- rects[i].right = rect.x + rect.width;
- rects[i].bottom = rect.y + rect.height;
- }
-
- gdi_region = ExtCreateRegion (NULL, data_size, data);
- free (data);
-
- if (!gdi_region)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- /* AND the new region into our DC */
- if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
- status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
-
- DeleteObject (gdi_region);
- }
- }
-
- return status;
-}
-
-cairo_int_status_t
+cairo_bool_t
_cairo_win32_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_win32_surface_t *surface = abstract_surface;
*rectangle = surface->extents;
-
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
static cairo_status_t
_cairo_win32_surface_flush (void *abstract_surface)
{
- return _cairo_surface_reset_clip (abstract_surface);
+ return _cairo_win32_surface_set_clip_region (abstract_surface, NULL);
}
#define STACK_GLYPH_SIZE 256
@@ -1570,8 +1553,8 @@ _cairo_win32_surface_show_glyphs (void *surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
#if CAIRO_HAS_WIN32_FONT
cairo_win32_surface_t *dst = surface;
@@ -1611,11 +1594,19 @@ _cairo_win32_surface_show_glyphs (void *surface,
/* If we have a fallback mask clip set on the dst, we have
* to go through the fallback path, but only if we're not
* doing this for printing */
- if (dst->base.clip &&
- !(dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) &&
- (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
- dst->base.clip->surface != NULL))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (clip != NULL) {
+ if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) == 0) {
+ cairo_region_t *clip_region;
+ cairo_status_t status;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
+ if (status)
+ return status;
+
+ _cairo_win32_surface_set_clip_region (surface, clip_region);
+ }
+ }
solid_pattern = (cairo_solid_pattern_t *)source;
color = RGB(((int)solid_pattern->color.red_short) >> 8,
@@ -1957,19 +1948,6 @@ _cairo_win32_surface_is_similar (void *surface_a,
return a->dc == b->dc;
}
-static cairo_status_t
-_cairo_win32_surface_reset (void *abstract_surface)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
- status = _cairo_win32_surface_set_clip_region (surface, NULL);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
typedef struct _cairo_win32_surface_span_renderer {
cairo_span_renderer_t base;
@@ -1979,6 +1957,7 @@ typedef struct _cairo_win32_surface_span_renderer {
cairo_image_surface_t *mask;
cairo_win32_surface_t *dst;
+ cairo_region_t *clip_region;
cairo_composite_rectangles_t composite_rectangles;
} cairo_win32_surface_span_renderer_t;
@@ -2031,18 +2010,20 @@ _cairo_win32_surface_span_renderer_finish (void *abstract_renderer)
rects->src.y,
0, 0, /* mask.x, mask.y */
rects->dst.x, rects->dst.y,
- rects->width, rects->height);
+ rects->width, rects->height,
+ renderer->clip_region);
} else {
/* otherwise go through the fallback_composite path which
* will do the appropriate surface acquisition */
status = _cairo_surface_fallback_composite (
renderer->op,
- renderer->pattern, mask_pattern, dst,
+ renderer->pattern, mask_pattern, &dst->base,
rects->src.x,
rects->src.y,
0, 0, /* mask.x, mask.y */
rects->dst.x, rects->dst.y,
- rects->width, rects->height);
+ rects->width, rects->height,
+ renderer->clip_region);
}
cairo_pattern_destroy (mask_pattern);
@@ -2073,15 +2054,16 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *abstract_dst,
cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects)
+ const cairo_composite_rectangles_t *rects,
+ cairo_region_t *clip_region)
{
cairo_win32_surface_t *dst = abstract_dst;
- cairo_win32_surface_span_renderer_t *renderer
- = calloc(1, sizeof(*renderer));
+ cairo_win32_surface_span_renderer_t *renderer;
cairo_status_t status;
int width = rects->width;
int height = rects->height;
+ renderer = calloc(1, sizeof(*renderer));
if (renderer == NULL)
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
@@ -2093,6 +2075,7 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op,
renderer->pattern = pattern;
renderer->antialias = antialias;
renderer->dst = dst;
+ renderer->clip_region = clip_region;
renderer->composite_rectangles = *rects;
@@ -2128,8 +2111,6 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = {
_cairo_win32_surface_check_span_renderer,
NULL, /* copy_page */
NULL, /* show_page */
- _cairo_win32_surface_set_clip_region,
- NULL, /* intersect_clip_path */
_cairo_win32_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -2146,8 +2127,6 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = {
NULL, /* snapshot */
_cairo_win32_surface_is_similar,
-
- _cairo_win32_surface_reset
};
/* Notes:
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index a7340cf9..0650f8f6 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -75,6 +75,7 @@ typedef struct cairo_xcb_surface {
cairo_bool_t have_clip_rects;
xcb_rectangle_t *clip_rects;
int num_clip_rects;
+ cairo_region_t *clip_region;
xcb_render_picture_t src_picture, dst_picture;
xcb_render_pictforminfo_t xrender_format;
@@ -166,6 +167,93 @@ _xcb_render_format_to_content (xcb_render_pictforminfo_t *xrender_format)
return CAIRO_CONTENT_COLOR;
}
+static void
+_cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface)
+{
+ if (surface->have_clip_rects)
+ xcb_set_clip_rectangles(surface->dpy, XCB_CLIP_ORDERING_YX_SORTED, surface->gc,
+ 0, 0,
+ surface->num_clip_rects,
+ surface->clip_rects );
+}
+
+static void
+_cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface)
+{
+ if (surface->have_clip_rects)
+ xcb_render_set_picture_clip_rectangles (surface->dpy, surface->dst_picture,
+ 0, 0,
+ surface->num_clip_rects,
+ surface->clip_rects);
+}
+
+static cairo_status_t
+_cairo_xcb_surface_set_clip_region (void *abstract_surface,
+ cairo_region_t *region)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+
+ if (region == surface->clip_region)
+ return CAIRO_STATUS_SUCCESS;
+
+ cairo_region_destroy (surface->clip_region);
+ region = cairo_region_reference (region);
+
+ if (surface->clip_rects) {
+ free (surface->clip_rects);
+ surface->clip_rects = NULL;
+ }
+
+ surface->have_clip_rects = FALSE;
+ surface->num_clip_rects = 0;
+
+ if (region == NULL) {
+ uint32_t none[] = { XCB_NONE };
+ if (surface->gc)
+ xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none);
+
+ if (surface->xrender_format.id != XCB_NONE && surface->dst_picture)
+ xcb_render_change_picture (surface->dpy, surface->dst_picture,
+ XCB_RENDER_CP_CLIP_MASK, none);
+ } else {
+ xcb_rectangle_t *rects = NULL;
+ int n_rects, i;
+
+ n_rects = cairo_region_num_rectangles (region);
+
+ if (n_rects > 0) {
+ rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t));
+ if (rects == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ } else {
+ rects = NULL;
+ }
+
+ for (i = 0; i < n_rects; i++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (region, i, &rect);
+
+ rects[i].x = rect.x;
+ rects[i].y = rect.y;
+ rects[i].width = rect.width;
+ rects[i].height = rect.height;
+ }
+
+ surface->have_clip_rects = TRUE;
+ surface->clip_rects = rects;
+ surface->num_clip_rects = n_rects;
+
+ if (surface->gc)
+ _cairo_xcb_surface_set_gc_clip_rects (surface);
+
+ if (surface->dst_picture)
+ _cairo_xcb_surface_set_picture_clip_rects (surface);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_surface_t *
_cairo_xcb_surface_create_similar (void *abstract_src,
cairo_content_t content,
@@ -223,6 +311,7 @@ _cairo_xcb_surface_finish (void *abstract_surface)
xcb_free_gc (surface->dpy, surface->gc);
free (surface->clip_rects);
+ cairo_region_destroy (surface->clip_region);
surface->dpy = NULL;
@@ -476,26 +565,6 @@ _cairo_xcb_surface_ensure_src_picture (cairo_xcb_surface_t *surface)
}
static void
-_cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface)
-{
- if (surface->have_clip_rects)
- xcb_render_set_picture_clip_rectangles (surface->dpy, surface->dst_picture,
- 0, 0,
- surface->num_clip_rects,
- surface->clip_rects);
-}
-
-static void
-_cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface)
-{
- if (surface->have_clip_rects)
- xcb_set_clip_rectangles(surface->dpy, XCB_CLIP_ORDERING_YX_SORTED, surface->gc,
- 0, 0,
- surface->num_clip_rects,
- surface->clip_rects );
-}
-
-static void
_cairo_xcb_surface_ensure_dst_picture (cairo_xcb_surface_t *surface)
{
if (!surface->dst_picture) {
@@ -1124,7 +1193,8 @@ _cairo_xcb_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_surface_attributes_t src_attr, mask_attr;
cairo_xcb_surface_t *dst = abstract_dst;
@@ -1163,6 +1233,10 @@ _cairo_xcb_surface_composite (cairo_operator_t op,
goto BAIL;
}
+ status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ goto BAIL;
+
status = _cairo_xcb_surface_set_attributes (src, &src_attr);
if (status)
goto BAIL;
@@ -1257,7 +1331,8 @@ _cairo_xcb_surface_composite (cairo_operator_t op,
mask ? mask->height : 0,
src_x, src_y,
mask_x, mask_y,
- dst_x, dst_y, width, height);
+ dst_x, dst_y, width, height,
+ clip_region);
BAIL:
if (mask)
@@ -1279,6 +1354,7 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface,
xcb_render_color_t render_color;
xcb_rectangle_t static_xrects[16];
xcb_rectangle_t *xrects = static_xrects;
+ cairo_status_t status;
int i;
if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
@@ -1289,6 +1365,9 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface,
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
+ status = _cairo_xcb_surface_set_clip_region (surface, NULL);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
if (num_rects > ARRAY_LENGTH(static_xrects)) {
xrects = _cairo_malloc_ab (num_rects, sizeof(xcb_rectangle_t));
if (xrects == NULL)
@@ -1415,7 +1494,8 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps)
+ int num_traps,
+ cairo_region_t *clip_region)
{
cairo_surface_attributes_t attributes;
cairo_xcb_surface_t *dst = abstract_dst;
@@ -1475,6 +1555,11 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
render_src_y = src_y + render_reference_y - dst_y;
_cairo_xcb_surface_ensure_dst_picture (dst);
+
+ status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ goto BAIL;
+
status = _cairo_xcb_surface_set_attributes (src, &attributes);
if (status)
goto BAIL;
@@ -1516,7 +1601,8 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
width, height,
src_x, src_y,
0, 0,
- dst_x, dst_y, width, height);
+ dst_x, dst_y, width, height,
+ clip_region);
} else {
xcb_render_trapezoid_t xtraps_stack[16];
@@ -1562,68 +1648,7 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
return status;
}
-static cairo_int_status_t
-_cairo_xcb_surface_set_clip_region (void *abstract_surface,
- cairo_region_t *region)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
-
- if (surface->clip_rects) {
- free (surface->clip_rects);
- surface->clip_rects = NULL;
- }
-
- surface->have_clip_rects = FALSE;
- surface->num_clip_rects = 0;
-
- if (region == NULL) {
- uint32_t none[] = { XCB_NONE };
- if (surface->gc)
- xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none);
-
- if (surface->xrender_format.id != XCB_NONE && surface->dst_picture)
- xcb_render_change_picture (surface->dpy, surface->dst_picture,
- XCB_RENDER_CP_CLIP_MASK, none);
- } else {
- xcb_rectangle_t *rects = NULL;
- int n_rects, i;
-
- n_rects = cairo_region_num_rectangles (region);
-
- if (n_rects > 0) {
- rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t));
- if (rects == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- } else {
- rects = NULL;
- }
-
- for (i = 0; i < n_rects; i++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (region, i, &rect);
-
- rects[i].x = rect.x;
- rects[i].y = rect.y;
- rects[i].width = rect.width;
- rects[i].height = rect.height;
- }
-
- surface->have_clip_rects = TRUE;
- surface->clip_rects = rects;
- surface->num_clip_rects = n_rects;
-
- if (surface->gc)
- _cairo_xcb_surface_set_gc_clip_rects (surface);
-
- if (surface->dst_picture)
- _cairo_xcb_surface_set_picture_clip_rects (surface);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
+static cairo_bool_t
_cairo_xcb_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -1635,7 +1660,7 @@ _cairo_xcb_surface_get_extents (void *abstract_surface,
rectangle->width = surface->width;
rectangle->height = surface->height;
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
/* XXX: _cairo_xcb_surface_get_font_options */
@@ -1654,8 +1679,8 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip,
+ int *remaining_glyphs);
static cairo_bool_t
_cairo_xcb_surface_is_similar (void *surface_a,
@@ -1682,40 +1707,29 @@ _cairo_xcb_surface_is_similar (void *surface_a,
return a->xrender_format.id == xrender_format->id;
}
-static cairo_status_t
-_cairo_xcb_surface_reset (void *abstract_surface)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
- status = _cairo_xcb_surface_set_clip_region (surface, NULL);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
/* XXX: move this to the bottom of the file, XCB and Xlib */
static const cairo_surface_backend_t cairo_xcb_surface_backend = {
CAIRO_SURFACE_TYPE_XCB,
+
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_finish,
_cairo_xcb_surface_acquire_source_image,
_cairo_xcb_surface_release_source_image,
+
_cairo_xcb_surface_acquire_dest_image,
_cairo_xcb_surface_release_dest_image,
+
_cairo_xcb_surface_clone_similar,
_cairo_xcb_surface_composite,
_cairo_xcb_surface_fill_rectangles,
_cairo_xcb_surface_composite_trapezoids,
NULL, /* create_span_renderer */
NULL, /* check_span_renderer */
+
NULL, /* copy_page */
NULL, /* show_page */
- _cairo_xcb_surface_set_clip_region,
- NULL, /* intersect_clip_path */
+
_cairo_xcb_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -1733,8 +1747,6 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_snapshot,
_cairo_xcb_surface_is_similar,
-
- _cairo_xcb_surface_reset
};
/**
@@ -1853,8 +1865,9 @@ _cairo_xcb_surface_create_internal (xcb_connection_t *dpy,
surface->have_clip_rects = FALSE;
surface->clip_rects = NULL;
surface->num_clip_rects = 0;
+ surface->clip_region = NULL;
- return (cairo_surface_t *) surface;
+ return &surface->base;
}
static xcb_screen_t *
@@ -2463,8 +2476,8 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_xcb_surface_t *dst = abstract_dst;
@@ -2474,6 +2487,7 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
cairo_xcb_surface_t *src = NULL;
cairo_solid_pattern_t solid_pattern;
+ cairo_region_t *clip_region = NULL;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -2497,10 +2511,12 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
* fallback clip masking, we have to go through the full
* fallback path.
*/
- if (dst->base.clip &&
- (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
- dst->base.clip->surface != NULL))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
+ if (status)
+ return status;
+ }
operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
if (operation == DO_UNSUPPORTED)
@@ -2564,6 +2580,10 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
goto BAIL;
}
+ status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ goto BAIL;
+
status = _cairo_xcb_surface_set_attributes (src, &attributes);
if (status)
goto BAIL;
diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h
index 164fe15f..53701e24 100644
--- a/src/cairo-xlib-surface-private.h
+++ b/src/cairo-xlib-surface-private.h
@@ -85,11 +85,11 @@ struct _cairo_xlib_surface {
Picture dst_picture, src_picture;
unsigned int clip_dirty;
- cairo_bool_t have_clip_rects;
cairo_bool_t gc_has_clip_rects;
XRectangle embedded_clip_rects[8];
XRectangle *clip_rects;
int num_clip_rects;
+ cairo_region_t *clip_region;
XRenderPictFormat *xrender_format;
cairo_filter_t filter;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 1aae2885..647e61fb 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -45,11 +45,25 @@
#include "cairo-xlib-surface-private.h"
#include "cairo-clip-private.h"
#include "cairo-scaled-font-private.h"
+#include "cairo-region-private.h"
#include <X11/Xutil.h> /* for XDestroyImage */
#define XLIB_COORD_MAX 32767
+#define DEBUG 0
+
+#if DEBUG
+#define UNSUPPORTED(reason) ({ \
+ fprintf (stderr, \
+ "cairo-xlib: hit unsupported operation %s(), line %d: %s\n", \
+ __FUNCTION__, __LINE__, reason); \
+ CAIRO_INT_STATUS_UNSUPPORTED; \
+})
+#else
+#define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
+#endif
+
/* Xlib doesn't define a typedef, so define one ourselves */
typedef int (*cairo_xlib_error_func_t) (Display *display,
XErrorEvent *event);
@@ -65,7 +79,8 @@ _cairo_xlib_surface_create_internal (Display *dpy,
int depth);
static cairo_status_t
-_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
+_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface,
+ cairo_bool_t set_clip);
static void
_cairo_xlib_surface_maybe_put_gc (cairo_xlib_surface_t *surface);
@@ -89,8 +104,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip,
+ int *remaining_glyphs);
/* XXX temporarily used by cairo-qt-surface.c */
slim_hidden_proto (cairo_xlib_surface_create);
@@ -135,12 +150,68 @@ static const XTransform identity = { {
#if RENDER_MAJOR > 0 || RENDER_MINOR >= 11
#define CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR(surface, op) \
- (CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS (surface) ? (op) <= CAIRO_OPERATOR_HSL_LUMINOSITY : (op) <= CAIRO_OPERATOR_SATURATE)
+ (((op) <= CAIRO_OPERATOR_SATURATE) ? TRUE : (CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS (surface) ? (op) <= CAIRO_OPERATOR_HSL_LUMINOSITY : FALSE))
#else
#define CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR(surface, op) \
((op) <= CAIRO_OPERATOR_SATURATE)
#endif
+static cairo_status_t
+_cairo_xlib_surface_set_clip_region (cairo_xlib_surface_t *surface,
+ cairo_region_t *region)
+{
+ cairo_bool_t had_clip_rects = surface->clip_region != NULL;
+
+ if (had_clip_rects == FALSE && region == NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (surface->clip_region == region)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (cairo_region_equal (surface->clip_region, region))
+ return CAIRO_STATUS_SUCCESS;
+
+ cairo_region_destroy (surface->clip_region);
+ surface->clip_region = cairo_region_reference (region);
+
+ if (surface->clip_rects != surface->embedded_clip_rects) {
+ free (surface->clip_rects);
+ surface->clip_rects = surface->embedded_clip_rects;
+ }
+ surface->num_clip_rects = 0;
+
+ if (region != NULL) {
+ XRectangle *rects = NULL;
+ int n_rects, i;
+
+ n_rects = cairo_region_num_rectangles (region);
+ if (n_rects > ARRAY_LENGTH (surface->embedded_clip_rects)) {
+ rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
+ if (unlikely (rects == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ } else {
+ rects = surface->embedded_clip_rects;
+ }
+
+ for (i = 0; i < n_rects; i++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (region, i, &rect);
+
+ rects[i].x = rect.x;
+ rects[i].y = rect.y;
+ rects[i].width = rect.width;
+ rects[i].height = rect.height;
+ }
+
+ surface->clip_rects = rects;
+ surface->num_clip_rects = n_rects;
+ }
+
+ surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL;
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_surface_t *
_cairo_xlib_surface_create_similar_with_format (void *abstract_src,
cairo_format_t format,
@@ -178,7 +249,7 @@ _cairo_xlib_surface_create_similar_with_format (void *abstract_src,
xrender_format,
width, height,
xrender_format->depth);
- if (surface->base.status) {
+ if (unlikely (surface->base.status)) {
XFreePixmap (dpy, pix);
return &surface->base;
}
@@ -256,7 +327,7 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
xrender_format,
width, height,
xrender_format->depth);
- if (surface->base.status != CAIRO_STATUS_SUCCESS) {
+ if (unlikely (surface->base.status)) {
XFreePixmap (src->dpy, pix);
return &surface->base;
}
@@ -280,9 +351,7 @@ _cairo_xlib_surface_finish (void *abstract_surface)
status2 = _cairo_xlib_display_queue_resource (display,
XRenderFreePicture,
surface->dst_picture);
- if (status2 == CAIRO_STATUS_SUCCESS)
- surface->dst_picture = None;
- else if (status == CAIRO_STATUS_SUCCESS)
+ if (status == CAIRO_STATUS_SUCCESS)
status = status2;
}
@@ -290,19 +359,14 @@ _cairo_xlib_surface_finish (void *abstract_surface)
status2 = _cairo_xlib_display_queue_resource (display,
XRenderFreePicture,
surface->src_picture);
- if (status2 == CAIRO_STATUS_SUCCESS)
- surface->src_picture = None;
- else if (status == CAIRO_STATUS_SUCCESS)
+ if (status == CAIRO_STATUS_SUCCESS)
status = status2;
}
status2 = _cairo_xlib_display_queue_resource (display,
(cairo_xlib_notify_resource_func) XFreePixmap,
surface->drawable);
- if (status2 == CAIRO_STATUS_SUCCESS) {
- surface->owns_pixmap = FALSE;
- surface->drawable = None;
- } else if (status == CAIRO_STATUS_SUCCESS)
+ if (status == CAIRO_STATUS_SUCCESS)
status = status2;
} else {
if (surface->dst_picture != None)
@@ -332,6 +396,7 @@ _cairo_xlib_surface_finish (void *abstract_surface)
_cairo_xlib_display_destroy (surface->display);
}
+ cairo_region_destroy (surface->clip_region);
surface->dpy = NULL;
return status;
@@ -667,8 +732,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
ximage = NULL;
}
- if (!ximage) {
-
+ if (ximage == NULL) {
/* XGetImage from a window is dangerous because it can
* produce errors if the window is unmapped or partially
* outside the screen. We could check for errors and
@@ -677,7 +741,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
*/
Pixmap pixmap;
- status = _cairo_xlib_surface_ensure_gc (surface);
+ status = _cairo_xlib_surface_ensure_gc (surface, FALSE);
if (unlikely (status))
return status;
@@ -700,7 +764,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
XFreePixmap (surface->dpy, pixmap);
}
- if (!ximage)
+ if (ximage == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_xlib_surface_maybe_put_gc (surface);
@@ -714,10 +778,14 @@ _get_image_surface (cairo_xlib_surface_t *surface,
xlib_masks.green_mask = surface->g_mask;
xlib_masks.blue_mask = surface->b_mask;
- if (_pixman_format_from_masks (&xlib_masks, &pixman_format) &&
- xlib_masks.bpp >= 24 &&
- ximage->bitmap_unit == 32 &&
- ximage->bitmap_pad == 32)
+ /* We can't use pixman to simply write to image if:
+ * (a) the pixels are not appropriately aligned,
+ * (b) pixman does not the pixel format, or
+ * (c) if the image is palettized and we need to convert.
+ */
+ if (ximage->bitmap_unit == 32 && ximage->bitmap_pad == 32 &&
+ _pixman_format_from_masks (&xlib_masks, &pixman_format) &&
+ (surface->visual == NULL || surface->visual->class == TrueColor))
{
image = (cairo_image_surface_t*)
_cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data,
@@ -861,7 +929,7 @@ _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface)
static void
_cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface)
{
- if (surface->have_clip_rects) {
+ if (surface->clip_region != NULL) {
XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture,
0, 0,
surface->clip_rects,
@@ -879,8 +947,8 @@ _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface)
static void
_cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface)
{
- surface->gc_has_clip_rects = surface->have_clip_rects;
- if (surface->have_clip_rects) {
+ surface->gc_has_clip_rects = surface->clip_region != NULL;
+ if (surface->clip_region != NULL) {
XSetClipRectangles(surface->dpy, surface->gc,
0, 0,
surface->clip_rects,
@@ -906,7 +974,8 @@ _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface)
}
static cairo_status_t
-_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
+_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface,
+ cairo_bool_t set_clip)
{
if (surface->gc == NULL) {
@@ -916,10 +985,22 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
&surface->clip_dirty);
if (unlikely (surface->gc == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ surface->gc_has_clip_rects =
+ surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC;
}
- if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC)
- _cairo_xlib_surface_set_gc_clip_rects (surface);
+ if (set_clip) {
+ if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC)
+ _cairo_xlib_surface_set_gc_clip_rects (surface);
+ } else {
+ if (surface->gc_has_clip_rects) {
+ surface->gc_has_clip_rects = FALSE;
+ XSetClipMask (surface->dpy, surface->gc, None);
+
+ surface->clip_dirty |= CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC;
+ }
+ }
return CAIRO_STATUS_SUCCESS;
}
@@ -928,7 +1009,6 @@ static void
_cairo_xlib_surface_maybe_put_gc (cairo_xlib_surface_t *surface)
{
/* return the GC back to the common pool if clean */
-
if (surface->gc_has_clip_rects)
return;
@@ -984,7 +1064,9 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
ret = XInitImage (&ximage);
assert (ret != 0);
- } else {
+ }
+ else
+ {
unsigned int stride, rowstride;
int x, y, x0, y0, x_off, y_off;
uint32_t in_pixel, out_pixel, *row;
@@ -1089,13 +1171,14 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
}
}
- status = _cairo_xlib_surface_ensure_gc (surface);
+ /* XXX set clip? */
+ status = _cairo_xlib_surface_ensure_gc (surface, FALSE);
if (unlikely (status))
goto BAIL;
- XPutImage(surface->dpy, surface->drawable, surface->gc,
- &ximage, src_x, src_y, dst_x, dst_y,
- width, height);
+ XPutImage (surface->dpy, surface->drawable, surface->gc,
+ &ximage, src_x, src_y, dst_x, dst_y,
+ width, height);
_cairo_xlib_surface_maybe_put_gc (surface);
@@ -1103,7 +1186,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
if (own_data)
free (ximage.data);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -1197,11 +1280,11 @@ _cairo_xlib_surface_release_dest_image (void *abstract_surfac
* screen. Both core and Render drawing require this
* when using multiple drawables in an operation.
*/
-static cairo_bool_t
+static inline cairo_bool_t
_cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
cairo_xlib_surface_t *src)
{
- return dst->dpy == src->dpy && dst->screen == src->screen;
+ return dst->screen_info == src->screen_info;
}
static cairo_status_t
@@ -1237,7 +1320,7 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface,
cairo_format_t format;
if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("roi too large for xlib");
format = image_src->format;
if (format == CAIRO_FORMAT_INVALID ||
@@ -1250,9 +1333,9 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface,
format,
width, height);
if (clone == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("unhandled image format, no similar surface");
- if (clone->base.status)
+ if (unlikely (clone->base.status))
return clone->base.status;
status = _draw_image_surface (clone, image_src,
@@ -1299,9 +1382,6 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac
if (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other))
return NULL;
- if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
- return NULL;
-
image = (cairo_image_surface_t *)
_cairo_image_surface_create_with_content (solid_pattern->content,
width, height);
@@ -1327,7 +1407,8 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac
status = _cairo_surface_paint (&image->base,
CAIRO_OPERATOR_SOURCE,
- &solid_pattern->base, NULL);
+ &solid_pattern->base,
+ NULL);
if (unlikely (status))
goto BAIL;
@@ -1361,7 +1442,6 @@ _cairo_xlib_surface_can_repaint_solid_pattern_surface (void *abstract_surface,
return CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other);
}
-
static cairo_status_t
_cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
cairo_matrix_t *matrix,
@@ -1380,8 +1460,8 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0)
return CAIRO_STATUS_SUCCESS;
- if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (! CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
+ return UNSUPPORTED ("XRender does not support picture transforms");
XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform);
surface->xtransform = xtransform;
@@ -1398,12 +1478,11 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
if (surface->filter == filter)
return CAIRO_STATUS_SUCCESS;
- if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
- {
+ if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) {
if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
return CAIRO_STATUS_SUCCESS;
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("XRender does not support filter");
}
switch (filter) {
@@ -1463,6 +1542,7 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
double yc)
{
cairo_int_status_t status;
+ int repeat;
_cairo_xlib_surface_ensure_src_picture (surface);
@@ -1473,24 +1553,28 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
switch (attributes->extend) {
case CAIRO_EXTEND_NONE:
- _cairo_xlib_surface_set_repeat (surface, RepeatNone);
+ repeat = RepeatNone;
break;
case CAIRO_EXTEND_REPEAT:
- _cairo_xlib_surface_set_repeat (surface, RepeatNormal);
+ repeat = RepeatNormal;
break;
case CAIRO_EXTEND_REFLECT:
if (surface->buggy_pad_reflect)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- _cairo_xlib_surface_set_repeat (surface, RepeatReflect);
+ return UNSUPPORTED ("buggy reflect");
+
+ repeat = RepeatReflect;
break;
case CAIRO_EXTEND_PAD:
if (surface->buggy_pad_reflect)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- _cairo_xlib_surface_set_repeat (surface, RepeatPad);
+ return UNSUPPORTED ("buggy reflect");
+
+ repeat = RepeatPad;
break;
default:
+ ASSERT_NOT_REACHED;
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+ _cairo_xlib_surface_set_repeat (surface, repeat);
status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
if (unlikely (status))
@@ -1508,7 +1592,7 @@ _surfaces_compatible (cairo_xlib_surface_t *dst,
cairo_xlib_surface_t *src)
{
/* same screen */
- if (!_cairo_xlib_surface_same_screen (dst, src))
+ if (! _cairo_xlib_surface_same_screen (dst, src))
return FALSE;
/* same depth (for core) */
@@ -1538,7 +1622,6 @@ _surface_has_alpha (cairo_xlib_surface_t *surface)
else
return FALSE;
} else {
-
/* In the no-render case, we never have alpha */
return FALSE;
}
@@ -1601,7 +1684,7 @@ _categorize_composite_operation (cairo_xlib_surface_t *dst,
if (!CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR (dst, op))
return DO_UNSUPPORTED;
- if (!dst->buggy_repeat)
+ if (! dst->buggy_repeat)
return DO_RENDER;
if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
@@ -1665,9 +1748,6 @@ _recategorize_composite_operation (cairo_xlib_surface_t *dst,
_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
cairo_bool_t needs_alpha_composite;
- if (! _cairo_surface_is_xlib (&src->base))
- return DO_UNSUPPORTED;
-
needs_alpha_composite =
_operator_needs_alpha_composite (op,
_surface_has_alpha (dst),
@@ -1810,7 +1890,8 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_surface_attributes_t src_attr, mask_attr;
cairo_xlib_surface_t *dst = abstract_dst;
@@ -1823,12 +1904,13 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
cairo_bool_t needs_alpha_composite;
cairo_content_t src_content;
- _cairo_xlib_display_notify (dst->display);
+ if (mask_pattern != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
+ return UNSUPPORTED ("no support for masks");
operation = _categorize_composite_operation (dst, op, src_pattern,
mask_pattern != NULL);
if (operation == DO_UNSUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("unsupported operation");
needs_alpha_composite =
_operator_needs_alpha_composite (op,
@@ -1838,6 +1920,8 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
if (! needs_alpha_composite)
src_content &= ~CAIRO_CONTENT_ALPHA;
+ _cairo_xlib_display_notify (dst->display);
+
status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
&dst->base,
src_content,
@@ -1854,25 +1938,25 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
return status;
/* check for fallback surfaces that we cannot handle ... */
- if (!_cairo_surface_is_xlib (&src->base)) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto BAIL;
- }
- if (mask != NULL &&
- (! _cairo_surface_is_xlib (&mask->base) ||
- ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)))
- {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ assert (_cairo_surface_is_xlib (&src->base));
+ assert (mask == NULL || _cairo_surface_is_xlib (&mask->base));
+
+ if (mask != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (mask)) {
+ status = UNSUPPORTED ("unsupported mask");
goto BAIL;
}
operation = _recategorize_composite_operation (dst, op, src, &src_attr,
mask_pattern != NULL);
if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ status = UNSUPPORTED ("unsupported operation");
goto BAIL;
}
+ status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ goto BAIL;
+
switch (operation)
{
case DO_RENDER:
@@ -1917,7 +2001,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
break;
case DO_XCOPYAREA:
- status = _cairo_xlib_surface_ensure_gc (dst);
+ status = _cairo_xlib_surface_ensure_gc (dst, TRUE);
if (unlikely (status))
goto BAIL;
@@ -1947,7 +2031,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
* _recategorize_composite_operation.
*/
- status = _cairo_xlib_surface_ensure_gc (dst);
+ status = _cairo_xlib_surface_ensure_gc (dst, TRUE);
if (unlikely (status))
goto BAIL;
is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
@@ -1979,7 +2063,8 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
mask ? mask->height : 0,
src_x, src_y,
mask_x, mask_y,
- dst_x, dst_y, width, height);
+ dst_x, dst_y, width, height,
+ clip_region);
BAIL:
if (mask)
@@ -2004,7 +2089,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
_cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR);
- status = _cairo_xlib_surface_ensure_gc (surface);
+ status = _cairo_xlib_surface_ensure_gc (surface, FALSE);
if (unlikely (status))
return status;
@@ -2019,10 +2104,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
if (unlikely (status))
return status;
- if (! _cairo_surface_is_xlib (solid_surface)) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto BAIL;
- }
+ assert (_cairo_surface_is_xlib (solid_surface));
XSetTSOrigin (surface->dpy, surface->gc,
- (surface->base.device_transform.x0 + attrs.x_offset),
@@ -2039,10 +2121,9 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
_cairo_xlib_surface_maybe_put_gc (surface);
- BAIL:
_cairo_pattern_release_surface (&solid.base, solid_surface, &attrs);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@@ -2054,6 +2135,7 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
{
cairo_xlib_surface_t *surface = abstract_surface;
XRenderColor render_color;
+ cairo_status_t status;
int i;
_cairo_xlib_display_notify (surface->display);
@@ -2070,7 +2152,7 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
rects, num_rects);
}
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("no support for FillRectangles with this op");
}
render_color.red = color->red_short;
@@ -2078,6 +2160,9 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
+ status = _cairo_xlib_surface_set_clip_region (surface, NULL);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
_cairo_xlib_surface_ensure_dst_picture (surface);
if (num_rects == 1) {
/* Take advantage of the protocol compaction that libXrender performs
@@ -2245,7 +2330,8 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps)
+ int num_traps,
+ cairo_region_t *clip_region)
{
cairo_surface_attributes_t attributes;
cairo_xlib_surface_t *dst = abstract_dst;
@@ -2258,12 +2344,12 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
_cairo_xlib_display_notify (dst->display);
- if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (! CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
+ return UNSUPPORTED ("XRender does not support CompositeTrapezoids");
operation = _categorize_composite_operation (dst, op, pattern, TRUE);
if (operation == DO_UNSUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("unsupported operation");
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
@@ -2279,7 +2365,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
operation = _recategorize_composite_operation (dst, op, src,
&attributes, TRUE);
if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ status = UNSUPPORTED ("unsupported operation");
goto BAIL;
}
@@ -2310,7 +2396,12 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
render_src_x = src_x + render_reference_x - dst_x;
render_src_y = src_y + render_reference_y - dst_y;
+ status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ goto BAIL;
+
_cairo_xlib_surface_ensure_dst_picture (dst);
+
status = _cairo_xlib_surface_set_attributes (src, &attributes,
dst_x + width / 2.,
dst_y + height / 2.);
@@ -2353,7 +2444,8 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
width, height,
src_x, src_y,
0, 0,
- dst_x, dst_y, width, height);
+ dst_x, dst_y, width, height,
+ clip_region);
} else {
XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
@@ -2399,115 +2491,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
return status;
}
-static cairo_region_t *
-_surface_maybe_clip_region (cairo_xlib_surface_t *surface,
- cairo_region_t *clip,
- cairo_region_t *bounded)
-{
- cairo_rectangle_int_t rect;
-
- cairo_region_get_extents (clip, &rect);
- if (rect.x >= 0 &&
- rect.y >= 0 &&
- rect.x + rect.width <= surface->width &&
- rect.y + rect.height <= surface->height)
- {
- return clip;
- }
-
- rect.x = rect.y = 0;
- rect.width = surface->width;
- rect.height = surface->height;
- _cairo_region_init_rectangle (bounded, &rect);
-
- bounded->status = cairo_region_intersect (bounded, clip);
-
- return bounded;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_set_clip_region (void *abstract_surface,
- cairo_region_t *region)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_bool_t had_clip_rects = surface->have_clip_rects;
-
- if (had_clip_rects == FALSE && region == NULL)
- return CAIRO_STATUS_SUCCESS;
-
- if (surface->clip_rects != surface->embedded_clip_rects) {
- free (surface->clip_rects);
- surface->clip_rects = surface->embedded_clip_rects;
- }
-
- surface->have_clip_rects = FALSE;
- surface->num_clip_rects = 0;
-
- if (region != NULL) {
- XRectangle *rects = NULL;
- int n_rects, i;
- cairo_region_t bounded;
-
- /* Intersect the region with the bounds of the surface. This
- * is necessary so we don't wrap around when we convert cairo's
- * 32 bit region into 16 bit rectangles.
- */
- region = _surface_maybe_clip_region (surface, region, &bounded);
- if (unlikely (region->status))
- return region->status;
-
- n_rects = cairo_region_num_rectangles (region);
- if (n_rects > ARRAY_LENGTH (surface->embedded_clip_rects)) {
- rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
- if (unlikely (rects == NULL)) {
- if (unlikely (region == &bounded))
- _cairo_region_fini (&bounded);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
- } else {
- rects = surface->embedded_clip_rects;
- }
-
- for (i = 0; i < n_rects; i++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (region, i, &rect);
-
- rects[i].x = rect.x;
- rects[i].y = rect.y;
- rects[i].width = rect.width;
- rects[i].height = rect.height;
- }
-
- if (unlikely (region == &bounded))
- _cairo_region_fini (&bounded);
-
- surface->have_clip_rects = TRUE;
- surface->clip_rects = rects;
- surface->num_clip_rects = n_rects;
-
- /* Discard the trivial clip rectangle that covers the entire surface */
- if (n_rects == 1 &&
- rects[0].x == 0 &&
- rects[0].y == 0 &&
- rects[0].width == surface->width &&
- rects[0].height == surface->height)
- {
- surface->have_clip_rects = FALSE;
- surface->num_clip_rects = 0;
-
- if (! had_clip_rects)
- goto DONE;
- }
- }
-
- surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL;
- DONE:
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
+static cairo_bool_t
_cairo_xlib_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -2519,7 +2503,7 @@ _cairo_xlib_surface_get_extents (void *abstract_surface,
rectangle->width = surface->width;
rectangle->height = surface->height;
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
static void
@@ -2547,7 +2531,7 @@ _cairo_xlib_surface_is_similar (void *surface_a,
cairo_xlib_surface_t *b = surface_b;
XRenderPictFormat *xrender_format = b->xrender_format;
- if (!_cairo_xlib_surface_same_screen (a, b))
+ if (! _cairo_xlib_surface_same_screen (a, b))
return FALSE;
/* now inspect the content to check that a is similar to b */
@@ -2566,19 +2550,6 @@ _cairo_xlib_surface_is_similar (void *surface_a,
return a->xrender_format == xrender_format;
}
-static cairo_status_t
-_cairo_xlib_surface_reset (void *abstract_surface)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
- status = _cairo_xlib_surface_set_clip_region (surface, NULL);
- if (unlikely (status))
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static const cairo_surface_backend_t cairo_xlib_surface_backend = {
CAIRO_SURFACE_TYPE_XLIB,
_cairo_xlib_surface_create_similar,
@@ -2595,8 +2566,6 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- _cairo_xlib_surface_set_clip_region,
- NULL, /* intersect_clip_path */
_cairo_xlib_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_xlib_surface_get_font_options,
@@ -2612,10 +2581,10 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_show_glyphs,
_cairo_xlib_surface_snapshot,
-
_cairo_xlib_surface_is_similar,
- _cairo_xlib_surface_reset,
+
NULL, /* fill_stroke */
+
_cairo_xlib_surface_create_solid_pattern_surface,
_cairo_xlib_surface_can_repaint_solid_pattern_surface
};
@@ -2771,7 +2740,7 @@ _cairo_xlib_surface_create_internal (Display *dpy,
surface->height = height;
surface->buggy_repeat = screen_info->display->buggy_repeat;
- if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
+ if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
/* so we can use the XTile fallback */
surface->buggy_repeat = TRUE;
}
@@ -2787,7 +2756,7 @@ _cairo_xlib_surface_create_internal (Display *dpy,
surface->repeat = FALSE;
surface->xtransform = identity;
- surface->have_clip_rects = FALSE;
+ surface->clip_region = NULL;
surface->gc_has_clip_rects = FALSE;
surface->clip_rects = surface->embedded_clip_rects;
surface->num_clip_rects = 0;
@@ -2833,23 +2802,25 @@ _cairo_xlib_surface_create_internal (Display *dpy,
static Screen *
_cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
{
- int s;
- int d;
- int v;
- Screen *screen;
- Depth *depth;
+ int s, d, v;
for (s = 0; s < ScreenCount (dpy); s++) {
+ Screen *screen;
+
screen = ScreenOfDisplay (dpy, s);
if (visual == DefaultVisualOfScreen (screen))
return screen;
+
for (d = 0; d < screen->ndepths; d++) {
+ Depth *depth;
+
depth = &screen->depths[d];
for (v = 0; v < depth->nvisuals; v++)
if (visual == &depth->visuals[v])
return screen;
}
}
+
return NULL;
}
@@ -3624,7 +3595,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
sz_xGlyphInfo -
8;
if (len >= max_request_size)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("glyph too large for XRequest");
}
/* If the glyph surface has zero height or width, we create
@@ -3975,7 +3946,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
- if (status != CAIRO_STATUS_SUCCESS)
+ if (unlikely (status))
return status;
this_x = _cairo_lround (glyphs[i].d.x);
@@ -4055,7 +4026,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
status = _emit_glyphs_chunk (dst, glyphs, i,
scaled_font, op, src, attributes,
num_elts, old_width, glyphset_info);
- if (status != CAIRO_STATUS_SUCCESS)
+ if (unlikely (status))
return status;
glyphs += i;
@@ -4094,13 +4065,14 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
request_size += width;
}
- if (num_elts)
+ if (num_elts) {
status = _emit_glyphs_chunk (dst, glyphs, i,
scaled_font, op, src, attributes,
num_elts, width, glyphset_info);
+ }
*remaining_glyphs = num_glyphs - i;
- if (*remaining_glyphs && status == CAIRO_STATUS_SUCCESS)
+ if (*remaining_glyphs != 0 && status == CAIRO_STATUS_SUCCESS)
status = CAIRO_INT_STATUS_UNSUPPORTED;
return status;
@@ -4130,8 +4102,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_xlib_surface_t *dst = (cairo_xlib_surface_t*) abstract_dst;
@@ -4139,16 +4111,17 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
composite_operation_t operation;
cairo_surface_attributes_t attributes;
cairo_xlib_surface_t *src = NULL;
+ cairo_region_t *clip_region = NULL;
cairo_solid_pattern_t solid_pattern;
if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("XRender does not support CompositeText");
/* Just let unbounded operators go through the fallback code
* instead of trying to do the fixups here */
- if (!_cairo_operator_bounded_by_mask (op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (! _cairo_operator_bounded_by_mask (op))
+ return UNSUPPORTED ("unsupported unbounded op");
/* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs --
* the solid source seems to be multiplied by the glyph mask, and
@@ -4156,25 +4129,33 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
* including the fully transparent "background" of the rectangular
* glyph surface. */
if (op == CAIRO_OPERATOR_SOURCE &&
- !CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ ! CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
+ {
+ return UNSUPPORTED ("known bug in Render");
+ }
/* We can only use our code if we either have no clip or
* have a real native clip region set. If we're using
* fallback clip masking, we have to go through the full
* fallback path.
*/
- if (dst->base.clip &&
- (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
- dst->base.clip->surface != NULL))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
+ if (status)
+ return status;
+ }
operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
if (operation == DO_UNSUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("unsupported op");
if (! _cairo_xlib_surface_owns_font (dst, scaled_font))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("unowned font");
+
+ status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ return status;
/* After passing all those tests, we're now committed to rendering
* these glyphs or to fail trying. We first upload any glyphs to
@@ -4213,6 +4194,14 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
if (unlikely (status))
goto BAIL0;
+ if (clip != NULL) {
+ if (! _cairo_rectangle_intersect (&glyph_extents,
+ _cairo_clip_get_extents (clip)))
+ {
+ goto BAIL0;
+ }
+ }
+
status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
glyph_extents.x, glyph_extents.y,
@@ -4229,7 +4218,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
operation = _recategorize_composite_operation (dst, op, src,
&attributes, TRUE);
if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ status = UNSUPPORTED ("unsupported op");
goto BAIL1;
}
@@ -4247,15 +4236,14 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
src,
&attributes,
remaining_glyphs);
- } else
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ } else {
+ status = UNSUPPORTED ("unowned font");
+ }
_cairo_scaled_font_thaw_cache (scaled_font);
BAIL1:
if (src)
_cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
- if (src_pattern == &solid_pattern.base)
- _cairo_pattern_fini (&solid_pattern.base);
BAIL0:
_cairo_xlib_display_notify (dst->display);
diff --git a/src/cairo.c b/src/cairo.c
index 3e590496..2470b0d6 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -44,6 +44,10 @@
#define CAIRO_TOLERANCE_MINIMUM _cairo_fixed_to_double(1)
+#if !defined(INFINITY)
+#define INFINITY HUGE_VAL
+#endif
+
static const cairo_t _cairo_nil = {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
@@ -57,7 +61,8 @@ static const cairo_t _cairo_nil = {
FALSE, /* has_current_point */
FALSE, /* has_curve_to */
FALSE, /* is_box */
- FALSE, /* is_region */
+ FALSE, /* maybe_fill_region */
+ TRUE, /* is_empty_fill */
{{{NULL,NULL}}} /* link */
}}
};
@@ -496,25 +501,28 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content)
{
cairo_status_t status;
cairo_rectangle_int_t extents;
+ const cairo_rectangle_int_t *clip_extents;
cairo_surface_t *parent_surface, *group_surface = NULL;
+ cairo_bool_t is_empty;
if (unlikely (cr->status))
return;
parent_surface = _cairo_gstate_get_target (cr->gstate);
- /* Get the extents that we'll use in creating our new group surface */
- status = _cairo_surface_get_extents (parent_surface, &extents);
- if (unlikely (status))
- goto bail;
- status = _cairo_clip_intersect_to_rectangle (_cairo_gstate_get_clip (cr->gstate), &extents);
- if (unlikely (status))
- goto bail;
- group_surface = cairo_surface_create_similar (parent_surface,
- content,
- extents.width,
- extents.height);
- status = cairo_surface_status (group_surface);
+ /* Get the extents that we'll use in creating our new group surface */
+ is_empty = _cairo_surface_get_extents (parent_surface, &extents);
+ clip_extents = _cairo_clip_get_extents (_cairo_gstate_get_clip (cr->gstate));
+ if (clip_extents != NULL)
+ is_empty = _cairo_rectangle_intersect (&extents, clip_extents);
+
+ group_surface = _cairo_surface_create_similar_solid (parent_surface,
+ content,
+ extents.width,
+ extents.height,
+ CAIRO_COLOR_TRANSPARENT,
+ TRUE);
+ status = group_surface->status;
if (unlikely (status))
goto bail;
@@ -2340,7 +2348,7 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
cairo_bool_t inside = FALSE;
if (unlikely (cr->status))
- return 0;
+ return FALSE;
status = _cairo_gstate_in_stroke (cr->gstate,
cr->path,
@@ -2370,16 +2378,10 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
cairo_bool_t
cairo_in_fill (cairo_t *cr, double x, double y)
{
- cairo_bool_t inside;
-
if (unlikely (cr->status))
- return 0;
-
- _cairo_gstate_in_fill (cr->gstate,
- cr->path,
- x, y, &inside);
+ return FALSE;
- return inside;
+ return _cairo_gstate_in_fill (cr->gstate, cr->path, x, y);
}
/**
@@ -2600,8 +2602,6 @@ cairo_clip_extents (cairo_t *cr,
double *x1, double *y1,
double *x2, double *y2)
{
- cairo_status_t status;
-
if (unlikely (cr->status)) {
if (x1)
*x1 = 0.0;
@@ -2615,9 +2615,38 @@ cairo_clip_extents (cairo_t *cr,
return;
}
- status = _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2);
- if (unlikely (status))
- _cairo_set_error (cr, status);
+ if (! _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2)) {
+ *x1 = -INFINITY;
+ *y1 = -INFINITY;
+ *x2 = +INFINITY;
+ *y2 = +INFINITY;
+ }
+}
+
+/**
+ * cairo_in_clip:
+ * @cr: a cairo context
+ * @x: X coordinate of the point to test
+ * @y: Y coordinate of the point to test
+ *
+ * Tests whether the given point is inside the area that would be
+ * visible through the current clip, i.e. the area that would be filled by
+ * a cairo_paint() operation.
+ *
+ * See cairo_clip(), and cairo_clip_preserve().
+ *
+ * Return value: A non-zero value if the point is inside, or zero if
+ * outside.
+ *
+ * Since: 1.10
+ **/
+cairo_bool_t
+cairo_in_clip (cairo_t *cr, double x, double y)
+{
+ if (unlikely (cr->status))
+ return FALSE;
+
+ return _cairo_gstate_in_clip (cr->gstate, x, y);
}
static cairo_rectangle_list_t *
diff --git a/src/cairo.h b/src/cairo.h
index bd4eb661..4e930604 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -788,6 +788,9 @@ cairo_in_stroke (cairo_t *cr, double x, double y);
cairo_public cairo_bool_t
cairo_in_fill (cairo_t *cr, double x, double y);
+cairo_public cairo_bool_t
+cairo_in_clip (cairo_t *cr, double x, double y);
+
/* Rectangular extents */
cairo_public void
cairo_stroke_extents (cairo_t *cr,
@@ -2169,8 +2172,7 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
cairo_public cairo_surface_t *
cairo_meta_surface_create (cairo_content_t content,
- double width_pixels,
- double height_pixels);
+ const cairo_rectangle_t *extents);
cairo_public void
cairo_meta_surface_ink_extents (cairo_surface_t *surface,
@@ -2451,39 +2453,45 @@ cairo_public cairo_region_t *
cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle);
cairo_public cairo_region_t *
-cairo_region_create_rectangles (cairo_rectangle_int_t *rects,
+cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
int count);
cairo_public cairo_region_t *
-cairo_region_copy (cairo_region_t *original);
+cairo_region_copy (const cairo_region_t *original);
+
+cairo_public cairo_region_t *
+cairo_region_reference (cairo_region_t *);
cairo_public void
cairo_region_destroy (cairo_region_t *region);
+cairo_public cairo_bool_t
+cairo_region_equal (const cairo_region_t *a, const cairo_region_t *b);
+
cairo_public cairo_status_t
-cairo_region_status (cairo_region_t *region);
+cairo_region_status (const cairo_region_t *region);
cairo_public void
-cairo_region_get_extents (cairo_region_t *region,
+cairo_region_get_extents (const cairo_region_t *region,
cairo_rectangle_int_t *extents);
cairo_public int
-cairo_region_num_rectangles (cairo_region_t *region);
+cairo_region_num_rectangles (const cairo_region_t *region);
cairo_public void
-cairo_region_get_rectangle (cairo_region_t *region,
+cairo_region_get_rectangle (const cairo_region_t *region,
int nth_rectangle,
cairo_rectangle_int_t *rectangle);
cairo_public cairo_bool_t
-cairo_region_is_empty (cairo_region_t *region);
+cairo_region_is_empty (const cairo_region_t *region);
cairo_public cairo_region_overlap_t
-cairo_region_contains_rectangle (cairo_region_t *region,
+cairo_region_contains_rectangle (const cairo_region_t *region,
const cairo_rectangle_int_t *rectangle);
cairo_public cairo_bool_t
-cairo_region_contains_point (cairo_region_t *region, int x, int y);
+cairo_region_contains_point (const cairo_region_t *region, int x, int y);
cairo_public void
cairo_region_translate (cairo_region_t *region, int dx, int dy);
diff --git a/src/cairoint.h b/src/cairoint.h
index cb30f6de..5782f071 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -125,7 +125,7 @@ _cairo_win32_tmpfile (void);
#define STRINGIFY(macro_or_string) STRINGIFY_ARG (macro_or_string)
#define STRINGIFY_ARG(contents) #contents
-#ifdef __GNUC__
+#if defined (__GNUC__)
#define cairo_container_of(ptr, type, member) ({ \
const __typeof__ (((type *) 0)->member) *mptr__ = (ptr); \
(type *) ((char *) mptr__ - offsetof (type, member)); \
@@ -252,6 +252,15 @@ cairo_private void
_cairo_box_round_to_rectangle (const cairo_box_t *box,
cairo_rectangle_int_t *rectangle);
+static inline void
+_cairo_unbounded_rectangle_init (cairo_rectangle_int_t *rect)
+{
+ rect->x = CAIRO_RECT_INT_MIN;
+ rect->y = CAIRO_RECT_INT_MIN;
+ rect->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
+ rect->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
+}
+
cairo_private cairo_bool_t
_cairo_rectangle_intersect (cairo_rectangle_int_t *dst,
const cairo_rectangle_int_t *src);
@@ -489,6 +498,7 @@ struct _cairo_scaled_font_backend {
unsigned int height,
cairo_glyph_t *glyphs,
int num_glyphs,
+ cairo_region_t *clip_region,
int *remaining_glyphs);
cairo_warn cairo_int_status_t
@@ -615,6 +625,7 @@ struct _cairo_surface_backend {
int *clone_offset_y,
cairo_surface_t **clone_out);
+ /* XXX remove to a separate cairo_surface_compositor_t */
/* XXX: dst should be the first argument for consistency */
cairo_warn cairo_int_status_t
(*composite) (cairo_operator_t op,
@@ -628,7 +639,8 @@ struct _cairo_surface_backend {
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height);
+ unsigned int height,
+ cairo_region_t *clip_region);
cairo_warn cairo_int_status_t
(*fill_rectangles) (void *surface,
@@ -650,14 +662,16 @@ struct _cairo_surface_backend {
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps);
+ int num_traps,
+ cairo_region_t *region);
cairo_warn cairo_span_renderer_t *
(*create_span_renderer) (cairo_operator_t op,
const cairo_pattern_t *pattern,
void *dst,
cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects);
+ const cairo_composite_rectangles_t *rects,
+ cairo_region_t *clip_region);
cairo_warn cairo_bool_t
(*check_span_renderer) (cairo_operator_t op,
@@ -672,59 +686,15 @@ struct _cairo_surface_backend {
cairo_warn cairo_int_status_t
(*show_page) (void *surface);
- /* Set given region as the clip region for the surface, replacing
- * any previously set clip region. Passing in a NULL region will
- * clear the surface clip region.
- *
- * The surface is expected to store the clip region and clip all
- * following drawing operations against it until the clip region
- * is cleared of replaced by another clip region.
- *
- * Cairo will call this function whenever a clip path can be
- * represented as a device pixel aligned set of rectangles. When
- * this is not possible, cairo will use mask surfaces for
- * clipping.
- */
- cairo_warn cairo_int_status_t
- (*set_clip_region) (void *surface,
- cairo_region_t *region);
-
- /* Intersect the given path against the clip path currently set in
- * the surface, using the given fill_rule and tolerance, and set
- * the result as the new clipping path for the surface. Passing
- * in a NULL path will clear the surface clipping path.
- *
- * The surface is expected to store the resulting clip path and
- * clip all following drawing operations against it until the clip
- * path cleared or intersected with a new path.
- *
- * If a surface implements this function, set_clip_region() will
- * never be called and should not be implemented. If this
- * function is not implemented cairo will use set_clip_region()
- * (if available) and mask surfaces for clipping.
- */
- cairo_warn cairo_int_status_t
- (*intersect_clip_path) (void *dst,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias);
-
/* Get the extents of the current surface. For many surface types
* this will be as simple as { x=0, y=0, width=surface->width,
* height=surface->height}.
*
- * This function need not take account of any clipping from
- * set_clip_region since the generic version of set_clip_region
- * saves those, and the generic get_clip_extents will only call
- * into the specific surface->get_extents if there is no current
- * clip.
- *
* If this function is not implemented, or if it returns
- * %CAIRO_INT_STATUS_UNSUPPORTED, the surface is considered to be
- * boundless and inifnite bounds are used for it.
+ * FALSE the surface is considered to be
+ * boundless and infinite bounds are used for it.
*/
- cairo_warn cairo_int_status_t
+ cairo_warn cairo_bool_t
(*get_extents) (void *surface,
cairo_rectangle_int_t *extents);
@@ -745,7 +715,8 @@ struct _cairo_surface_backend {
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
- int num_glyphs);
+ int num_glyphs,
+ cairo_region_t *clip_region);
void
(*get_font_options) (void *surface,
@@ -775,14 +746,14 @@ struct _cairo_surface_backend {
(*paint) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
cairo_warn cairo_int_status_t
(*mask) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
cairo_warn cairo_int_status_t
(*stroke) (void *surface,
@@ -794,7 +765,7 @@ struct _cairo_surface_backend {
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
cairo_warn cairo_int_status_t
(*fill) (void *surface,
@@ -804,7 +775,7 @@ struct _cairo_surface_backend {
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
cairo_warn cairo_int_status_t
(*show_glyphs) (void *surface,
@@ -813,8 +784,8 @@ struct _cairo_surface_backend {
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip,
+ int *remaining_glyphs);
cairo_surface_t *
(*snapshot) (void *surface);
@@ -824,9 +795,6 @@ struct _cairo_surface_backend {
void *surface_b,
cairo_content_t content);
- cairo_warn cairo_status_t
- (*reset) (void *surface);
-
cairo_warn cairo_int_status_t
(*fill_stroke) (void *surface,
cairo_operator_t fill_op,
@@ -842,7 +810,7 @@ struct _cairo_surface_backend {
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
cairo_surface_t *
(*create_solid_pattern_surface)
@@ -869,7 +837,7 @@ struct _cairo_surface_backend {
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
};
#include "cairo-surface-private.h"
@@ -887,9 +855,9 @@ struct _cairo_image_surface {
int depth;
pixman_image_t *pixman_image;
+ cairo_region_t *clip_region;
unsigned owns_data : 1;
- unsigned has_clip : 1;
unsigned transparency : 2;
};
@@ -983,6 +951,8 @@ typedef struct _cairo_traps {
cairo_box_t extents;
+ unsigned int maybe_region : 1; /* hint: 0 implies that it cannot be */
+
int num_traps;
int traps_size;
cairo_trapezoid_t *traps;
@@ -1245,12 +1215,16 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double y,
cairo_bool_t *inside_ret);
-cairo_private void
+cairo_private cairo_bool_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
- double y,
- cairo_bool_t *inside_ret);
+ double y);
+
+cairo_private cairo_bool_t
+_cairo_gstate_in_clip (cairo_gstate_t *gstate,
+ double x,
+ double y);
cairo_private cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
@@ -1258,12 +1232,12 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_gstate_reset_clip (cairo_gstate_t *gstate);
-cairo_private cairo_status_t
+cairo_private cairo_bool_t
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
double *x1,
double *y1,
- double *x2,
- double *y2);
+ double *x2,
+ double *y2);
cairo_private cairo_rectangle_list_t*
_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate);
@@ -1480,19 +1454,19 @@ cairo_private void
_cairo_intern_string_reset_static_data (void);
/* cairo-path-fixed.c */
+cairo_private cairo_path_fixed_t *
+_cairo_path_fixed_create (void);
+
cairo_private void
_cairo_path_fixed_init (cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
- cairo_path_fixed_t *other);
+ const cairo_path_fixed_t *other);
cairo_private cairo_bool_t
-_cairo_path_fixed_is_equal (cairo_path_fixed_t *path,
- cairo_path_fixed_t *other);
-
-cairo_private cairo_path_fixed_t *
-_cairo_path_fixed_create (void);
+_cairo_path_fixed_is_equal (const cairo_path_fixed_t *path,
+ const cairo_path_fixed_t *other);
cairo_private void
_cairo_path_fixed_fini (cairo_path_fixed_t *path);
@@ -1578,64 +1552,69 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
void *closure,
double tolerance);
-cairo_private cairo_status_t
-_cairo_path_fixed_append (cairo_path_fixed_t *path,
- const cairo_path_fixed_t *other,
- cairo_direction_t dir);
-
cairo_private void
-_cairo_path_fixed_approximate_clip_extents (cairo_path_fixed_t *path,
+_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents);
cairo_private void
-_cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path,
+_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents);
cairo_private void
-_cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path,
+_cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_rectangle_int_t *extents);
+
+cairo_private void
+_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents);
+cairo_private cairo_status_t
+_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
+ cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_rectangle_int_t *extents);
+
cairo_private void
-_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
+_cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
cairo_private void
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
- cairo_matrix_t *matrix);
-
-cairo_private cairo_bool_t
-_cairo_path_fixed_is_empty (cairo_path_fixed_t *path);
+ const cairo_matrix_t *matrix);
cairo_private cairo_bool_t
-_cairo_path_fixed_is_box (cairo_path_fixed_t *path,
+_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
cairo_box_t *box);
cairo_private cairo_bool_t
-_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
+_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path,
cairo_box_t *box);
/* cairo-path-in-fill.c */
-cairo_private void
-_cairo_path_fixed_in_fill (cairo_path_fixed_t *path,
+cairo_private cairo_bool_t
+_cairo_path_fixed_in_fill (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
double x,
- double y,
- cairo_bool_t *is_inside);
+ double y);
/* cairo-path-fill.c */
cairo_private cairo_status_t
-_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
+_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_traps_t *traps);
/* cairo-path-stroke.c */
cairo_private cairo_status_t
-_cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
+_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
@@ -1707,7 +1686,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
- int num_glyphs);
+ int num_glyphs,
+ cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
@@ -1789,11 +1769,12 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other,
int height);
cairo_private cairo_surface_t *
-_cairo_surface_create_similar_solid (cairo_surface_t *other,
- cairo_content_t content,
- int width,
- int height,
- const cairo_color_t *color);
+_cairo_surface_create_similar_solid (cairo_surface_t *other,
+ cairo_content_t content,
+ int width,
+ int height,
+ const cairo_color_t *color,
+ cairo_bool_t allow_fallback);
cairo_private cairo_surface_t *
_cairo_surface_create_solid_pattern_surface (cairo_surface_t *other,
@@ -1813,22 +1794,20 @@ cairo_private void
_cairo_surface_set_font_options (cairo_surface_t *surface,
cairo_font_options_t *options);
-cairo_private cairo_clip_mode_t
-_cairo_surface_get_clip_mode (cairo_surface_t *surface);
-
cairo_private cairo_status_t
_cairo_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src,
const cairo_pattern_t *mask,
cairo_surface_t *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height);
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
@@ -1856,14 +1835,14 @@ cairo_private cairo_status_t
_cairo_surface_paint (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fill_stroke (cairo_surface_t *surface,
@@ -1880,7 +1859,7 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_stroke (cairo_surface_t *surface,
@@ -1892,7 +1871,7 @@ _cairo_surface_stroke (cairo_surface_t *surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_fill (cairo_surface_t *surface,
@@ -1902,7 +1881,7 @@ _cairo_surface_fill (cairo_surface_t *surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_show_text_glyphs (cairo_surface_t *surface,
@@ -1916,7 +1895,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t op,
@@ -1930,23 +1909,23 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int ntraps);
+ int ntraps,
+ cairo_region_t *clip_region);
cairo_private cairo_span_renderer_t *
-_cairo_surface_create_span_renderer (
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects);
+_cairo_surface_create_span_renderer (cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *rects,
+ cairo_region_t *clip_region);
cairo_private cairo_bool_t
-_cairo_surface_check_span_renderer (
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects);
+_cairo_surface_check_span_renderer (cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *rects);
cairo_private cairo_status_t
_cairo_surface_acquire_source_image (cairo_surface_t *surface,
@@ -2005,37 +1984,7 @@ _cairo_surface_is_similar (cairo_surface_t *surface_a,
cairo_surface_t *surface_b,
cairo_content_t content);
-cairo_private cairo_status_t
-_cairo_surface_reset (cairo_surface_t *surface);
-
-cairo_private unsigned int
-_cairo_surface_get_current_clip_serial (cairo_surface_t *surface);
-
-cairo_private unsigned int
-_cairo_surface_allocate_clip_serial (cairo_surface_t *surface);
-
-cairo_private cairo_status_t
-_cairo_surface_reset_clip (cairo_surface_t *surface);
-
-cairo_private cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t *surface,
- cairo_region_t *region,
- unsigned int serial);
-
-cairo_private cairo_int_status_t
-_cairo_surface_intersect_clip_path (cairo_surface_t *surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias);
-
-cairo_private cairo_clip_t *
-_cairo_surface_get_clip (cairo_surface_t *surface);
-
-cairo_private cairo_status_t
-_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip);
-
-cairo_private cairo_int_status_t
+cairo_private cairo_bool_t
_cairo_surface_get_extents (cairo_surface_t *surface,
cairo_rectangle_int_t *extents);
@@ -2051,7 +2000,8 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
unsigned int width,
unsigned int height,
cairo_glyph_t *glyphs,
- int num_glyphs);
+ int num_glyphs,
+ cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
@@ -2068,7 +2018,8 @@ _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height);
+ unsigned int height,
+ cairo_region_t *clip_region);
cairo_private cairo_status_t
_cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
@@ -2084,7 +2035,8 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height);
+ unsigned int height,
+ cairo_region_t *clip_region);
cairo_private cairo_bool_t
_cairo_surface_is_opaque (const cairo_surface_t *surface);
@@ -2193,19 +2145,6 @@ _cairo_image_surface_create_for_data_with_content (unsigned char *data,
cairo_private void
_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface);
-/* XXX: It's a nasty kludge that this appears here. Backend functions
- * like this should really be static. But we're doing this to work
- * around some general defects in the backend clipping interfaces,
- * (see some notes in test-paginated-surface.c).
- *
- * I want to fix the real defects, but it's "hard" as they touch many
- * backends, so doing that will require synchronizing several backend
- * maintainers.
- */
-cairo_private cairo_int_status_t
-_cairo_image_surface_set_clip_region (void *abstract_surface,
- cairo_region_t *region);
-
cairo_private cairo_image_surface_t *
_cairo_image_surface_coerce (cairo_image_surface_t *surface,
cairo_format_t format);
@@ -2439,8 +2378,8 @@ _cairo_traps_extents (const cairo_traps_t *traps,
cairo_box_t *extents);
cairo_private cairo_int_status_t
-_cairo_traps_extract_region (const cairo_traps_t *tr,
- cairo_region_t **region);
+_cairo_traps_extract_region (cairo_traps_t *traps,
+ cairo_region_t **region);
cairo_private cairo_status_t
_cairo_traps_path (const cairo_traps_t *traps,
@@ -2560,7 +2499,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
cairo_surface_attributes_t *src_attributes,
cairo_surface_attributes_t *mask_attributes);
-cairo_private cairo_status_t
+cairo_private void
_cairo_pattern_get_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents);
@@ -2577,23 +2516,8 @@ _cairo_pattern_equal (const cairo_pattern_t *a,
cairo_private void
_cairo_pattern_reset_static_data (void);
-/* cairo-region.c */
-
-struct _cairo_region {
- cairo_status_t status;
-
- pixman_region32_t rgn;
-};
-
-cairo_private void
-_cairo_region_init (cairo_region_t *region);
-
-cairo_private void
-_cairo_region_init_rectangle (cairo_region_t *region,
- const cairo_rectangle_int_t *rectangle);
-
cairo_private void
-_cairo_region_fini (cairo_region_t *region);
+_cairo_clip_reset_static_data (void);
/* cairo-unicode.c */
@@ -2725,7 +2649,6 @@ slim_hidden_proto (cairo_status);
slim_hidden_proto (cairo_stroke);
slim_hidden_proto (cairo_stroke_preserve);
slim_hidden_proto (cairo_surface_copy_page);
-slim_hidden_proto (cairo_surface_create_similar);
slim_hidden_proto (cairo_surface_destroy);
slim_hidden_proto (cairo_surface_finish);
slim_hidden_proto (cairo_surface_flush);
@@ -2760,7 +2683,9 @@ slim_hidden_proto (cairo_region_create);
slim_hidden_proto (cairo_region_create_rectangle);
slim_hidden_proto (cairo_region_create_rectangles);
slim_hidden_proto (cairo_region_copy);
+slim_hidden_proto (cairo_region_reference);
slim_hidden_proto (cairo_region_destroy);
+slim_hidden_proto (cairo_region_equal);
slim_hidden_proto (cairo_region_status);
slim_hidden_proto (cairo_region_get_extents);
slim_hidden_proto (cairo_region_num_rectangles);
diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c
index 2a7f1489..f331cf25 100644
--- a/src/test-fallback-surface.c
+++ b/src/test-fallback-surface.c
@@ -194,7 +194,7 @@ _test_fallback_surface_clone_similar (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_int_status_t
+static cairo_bool_t
_test_fallback_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -219,8 +219,6 @@ static const cairo_surface_backend_t test_fallback_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- NULL, /* set_clip_region */
- NULL, /* intersect_clip_path */
_test_fallback_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
diff --git a/src/test-fallback16-surface.c b/src/test-fallback16-surface.c
index 07c06105..5f6bee4a 100644
--- a/src/test-fallback16-surface.c
+++ b/src/test-fallback16-surface.c
@@ -193,7 +193,7 @@ _test_fallback16_surface_clone_similar (void *abstract_surface,
}
}
-static cairo_int_status_t
+static cairo_bool_t
_test_fallback16_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -218,8 +218,6 @@ static const cairo_surface_backend_t test_fallback16_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- NULL, /* set_clip_region */
- NULL, /* intersect_clip_path */
_test_fallback16_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
diff --git a/src/test-null-surface.c b/src/test-null-surface.c
index 2c71f853..59761a39 100644
--- a/src/test-null-surface.c
+++ b/src/test-null-surface.c
@@ -50,26 +50,17 @@ _return_success (void)
/* These typedefs are just to silence the compiler... */
typedef cairo_int_status_t
-(*_set_clip_region_func) (void *surface,
- cairo_region_t *region);
-typedef cairo_int_status_t
-(*_intersect_clip_path_func) (void *dst,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias);
-typedef cairo_int_status_t
(*_paint_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
typedef cairo_int_status_t
(*_mask_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
typedef cairo_int_status_t
(*_stroke_func) (void *surface,
@@ -81,7 +72,7 @@ typedef cairo_int_status_t
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
typedef cairo_int_status_t
(*_fill_func) (void *surface,
@@ -91,7 +82,7 @@ typedef cairo_int_status_t
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
typedef cairo_int_status_t
(*_show_glyphs_func) (void *surface,
@@ -100,8 +91,8 @@ typedef cairo_int_status_t
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip,
+ int *remaining_glyphs);
typedef cairo_int_status_t
(*_show_text_glyphs_func) (void *surface,
@@ -115,7 +106,7 @@ typedef cairo_int_status_t
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip);
static cairo_surface_t *
_cairo_null_surface_create_similar (void *other,
@@ -125,16 +116,11 @@ _cairo_null_surface_create_similar (void *other,
return _cairo_test_null_surface_create (content);
}
-static cairo_int_status_t
+static cairo_bool_t
_cairo_null_surface_get_extents (void *surface,
cairo_rectangle_int_t *extents)
{
- extents->x = 0;
- extents->y = 0;
- extents->width = 0;
- extents->height = 0;
-
- return CAIRO_STATUS_SUCCESS;
+ return FALSE;
}
static cairo_bool_t
@@ -160,8 +146,6 @@ static const cairo_surface_backend_t null_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- (_set_clip_region_func) _return_success, /* set_clip_region */
- (_intersect_clip_path_func) _return_success, /* intersect_clip_path */
_cairo_null_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -176,7 +160,6 @@ static const cairo_surface_backend_t null_surface_backend = {
(_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
- NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c
index d42700c8..164d4a71 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -61,37 +61,27 @@ static const cairo_surface_backend_t test_paginated_surface_backend;
static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend;
cairo_surface_t *
-_cairo_test_paginated_surface_create_for_data (unsigned char *data,
- cairo_content_t content,
- int width,
- int height,
- int stride)
+_cairo_test_paginated_surface_create (cairo_surface_t *target)
{
cairo_status_t status;
- cairo_surface_t *target;
cairo_surface_t *paginated;
test_paginated_surface_t *surface;
- target = _cairo_image_surface_create_for_data_with_content (data, content,
- width, height,
- stride);
status = cairo_surface_status (target);
- if (status)
- return target;
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
surface = malloc (sizeof (test_paginated_surface_t));
- if (unlikely (surface == NULL)) {
- cairo_surface_destroy (target);
+ if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- }
_cairo_surface_init (&surface->base, &test_paginated_surface_backend,
- content);
+ target->content);
- surface->target = target;
+ surface->target = cairo_surface_reference (target);
paginated = _cairo_paginated_surface_create (&surface->base,
- content, width, height,
+ target->content,
&test_paginated_surface_paginated_backend);
status = paginated->status;
if (status == CAIRO_STATUS_SUCCESS) {
@@ -115,49 +105,7 @@ _test_paginated_surface_finish (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_test_paginated_surface_set_clip_region (void *abstract_surface,
- cairo_region_t *region)
-{
- test_paginated_surface_t *surface = abstract_surface;
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return CAIRO_STATUS_SUCCESS;
-
- /* XXX: The whole surface backend clipping interface is a giant
- * disaster right now. In particular, its uncleanness shows up
- * when trying to implement one surface that wraps another one (as
- * we are doing here).
- *
- * Here are two of the problems that show up:
- *
- * 1. The most critical piece of information in all this stuff,
- * the "clip" isn't getting passed to the backend
- * functions. Instead the generic surface layer is caching that as
- * surface->clip. This is a problem for surfaces like this one
- * that do wrapping. Our base surface will have the clip set, but
- * our target's surface will not.
- *
- * 2. We're here in our backend's set_clip_region function, and we
- * want to call into our target surface's set_clip_region.
- * Generally, we would do this by calling an equivalent
- * _cairo_surface function, but _cairo_surface_set_clip_region
- * does not have the same signature/semantics, (it has the
- * clip_serial stuff as well).
- *
- * We kludge around each of these by manually copying the clip
- * object from our base surface into the target's base surface
- * (yuck!) and by reaching directly into the image surface's
- * set_clip_region instead of calling into the generic
- * _cairo_surface_set_clip_region (double yuck!).
- */
-
- surface->target->clip = surface->base.clip;
-
- return _cairo_image_surface_set_clip_region (surface->target, region);
-}
-
-static cairo_int_status_t
+static cairo_bool_t
_test_paginated_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -170,14 +118,14 @@ static cairo_int_status_t
_test_paginated_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
test_paginated_surface_t *surface = abstract_surface;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
- return _cairo_surface_paint (surface->target, op, source, extents);
+ return _cairo_surface_paint (surface->target, op, source, clip);
}
static cairo_int_status_t
@@ -185,14 +133,15 @@ _test_paginated_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
test_paginated_surface_t *surface = abstract_surface;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
- return _cairo_surface_mask (surface->target, op, source, mask, extents);
+ return _cairo_surface_mask (surface->target,
+ op, source, mask, clip);
}
static cairo_int_status_t
@@ -205,7 +154,7 @@ _test_paginated_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
test_paginated_surface_t *surface = abstract_surface;
@@ -215,7 +164,8 @@ _test_paginated_surface_stroke (void *abstract_surface,
return _cairo_surface_stroke (surface->target, op, source,
path, style,
ctm, ctm_inverse,
- tolerance, antialias, extents);
+ tolerance, antialias,
+ clip);
}
static cairo_int_status_t
@@ -226,7 +176,7 @@ _test_paginated_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
test_paginated_surface_t *surface = abstract_surface;
@@ -235,7 +185,8 @@ _test_paginated_surface_fill (void *abstract_surface,
return _cairo_surface_fill (surface->target, op, source,
path, fill_rule,
- tolerance, antialias, extents);
+ tolerance, antialias,
+ clip);
}
static cairo_bool_t
@@ -258,7 +209,7 @@ _test_paginated_surface_show_text_glyphs (void *abstract_surface,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
test_paginated_surface_t *surface = abstract_surface;
@@ -268,8 +219,10 @@ _test_paginated_surface_show_text_glyphs (void *abstract_surface,
return _cairo_surface_show_text_glyphs (surface->target, op, source,
utf8, utf8_len,
glyphs, num_glyphs,
- clusters, num_clusters, cluster_flags,
- scaled_font, extents);
+ clusters, num_clusters,
+ cluster_flags,
+ scaled_font,
+ clip);
}
@@ -302,8 +255,6 @@ static const cairo_surface_backend_t test_paginated_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- _test_paginated_surface_set_clip_region,
- NULL, /* intersect_clip_path */
_test_paginated_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -319,11 +270,10 @@ static const cairo_surface_backend_t test_paginated_surface_backend = {
_test_paginated_surface_mask,
_test_paginated_surface_stroke,
_test_paginated_surface_fill,
- NULL, /* show_glyphs */
+ NULL, /* replaced by show_text_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
- NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
diff --git a/src/test-paginated-surface.h b/src/test-paginated-surface.h
index 4879cfcd..76ce6890 100644
--- a/src/test-paginated-surface.h
+++ b/src/test-paginated-surface.h
@@ -41,11 +41,7 @@
CAIRO_BEGIN_DECLS
cairo_surface_t *
-_cairo_test_paginated_surface_create_for_data (unsigned char *data,
- cairo_content_t content,
- int width,
- int height,
- int stride);
+_cairo_test_paginated_surface_create (cairo_surface_t *target);
CAIRO_END_DECLS
diff --git a/src/test-wrapping-surface.c b/src/test-wrapping-surface.c
new file mode 100644
index 00000000..a634b48a
--- /dev/null
+++ b/src/test-wrapping-surface.c
@@ -0,0 +1,272 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc
+ * Copyright © Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/* Another mythical surface that exists to simply wrap another - do nothing
+ * itself but forward the calls onto a target surface.
+ */
+
+#include "cairoint.h"
+
+#include "test-wrapping-surface.h"
+
+#include "cairo-surface-wrapper-private.h"
+
+typedef struct _test_wrapping_surface {
+ cairo_surface_t base;
+ cairo_surface_wrapper_t wrapper;
+} test_wrapping_surface_t;
+
+static const cairo_surface_backend_t test_wrapping_surface_backend;
+
+slim_hidden_proto (_cairo_test_wrapping_surface_create);
+
+cairo_surface_t *
+_cairo_test_wrapping_surface_create (cairo_surface_t *target)
+{
+ test_wrapping_surface_t *surface;
+
+ if (unlikely (target->status))
+ return _cairo_surface_create_in_error (target->status);
+
+ surface = malloc (sizeof (test_wrapping_surface_t));
+ if (unlikely (surface == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&surface->base,
+ &test_wrapping_surface_backend,
+ target->content);
+
+ _cairo_surface_wrapper_init (&surface->wrapper, target);
+
+ return &surface->base;
+}
+slim_hidden_def (_cairo_test_wrapping_surface_create);
+
+static cairo_surface_t *
+_test_wrapping_surface_create_similar (void *abstract_surface,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+
+ test_wrapping_surface_t *surface = abstract_surface;
+
+ return _cairo_test_wrapping_surface_create (
+ _cairo_surface_wrapper_create_similar (&surface->wrapper,
+ content, width, height));
+}
+
+static cairo_status_t
+_test_wrapping_surface_finish (void *abstract_surface)
+{
+ test_wrapping_surface_t *surface = abstract_surface;
+
+ _cairo_surface_wrapper_fini (&surface->wrapper);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_test_wrapping_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ test_wrapping_surface_t *surface = abstract_surface;
+
+ return _cairo_surface_wrapper_acquire_source_image (&surface->wrapper,
+ image_out, image_extra);
+}
+
+static void
+_test_wrapping_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ test_wrapping_surface_t *surface = abstract_surface;
+
+ _cairo_surface_wrapper_release_source_image (&surface->wrapper,
+ image, image_extra);
+}
+
+static cairo_bool_t
+_test_wrapping_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *rectangle)
+{
+ test_wrapping_surface_t *surface = abstract_surface;
+
+ return _cairo_surface_wrapper_get_extents (&surface->wrapper, rectangle);
+}
+
+static cairo_int_status_t
+_test_wrapping_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ test_wrapping_surface_t *surface = abstract_surface;
+
+ return _cairo_surface_wrapper_paint (&surface->wrapper, op, source, clip);
+}
+
+static cairo_int_status_t
+_test_wrapping_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ test_wrapping_surface_t *surface = abstract_surface;
+
+ return _cairo_surface_wrapper_mask (&surface->wrapper,
+ op, source, mask, clip);
+}
+
+static cairo_int_status_t
+_test_wrapping_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ test_wrapping_surface_t *surface = abstract_surface;
+
+ return _cairo_surface_wrapper_stroke (&surface->wrapper,
+ op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
+}
+
+static cairo_int_status_t
+_test_wrapping_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ test_wrapping_surface_t *surface = abstract_surface;
+
+ return _cairo_surface_wrapper_fill (&surface->wrapper,
+ op, source,
+ path, fill_rule,
+ tolerance, antialias,
+ clip);
+}
+
+static cairo_bool_t
+_test_wrapping_surface_has_show_text_glyphs (void *abstract_surface)
+{
+ test_wrapping_surface_t *surface = abstract_surface;
+
+ return _cairo_surface_wrapper_has_show_text_glyphs (&surface->wrapper);
+}
+
+static cairo_int_status_t
+_test_wrapping_surface_show_text_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ const cairo_text_cluster_t *clusters,
+ int num_clusters,
+ cairo_text_cluster_flags_t cluster_flags,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip)
+{
+ test_wrapping_surface_t *surface = abstract_surface;
+
+ return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper,
+ op, source,
+ utf8, utf8_len,
+ glyphs, num_glyphs,
+ clusters, num_clusters,
+ cluster_flags,
+ scaled_font,
+ clip);
+}
+
+static const cairo_surface_backend_t test_wrapping_surface_backend = {
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
+ _test_wrapping_surface_create_similar,
+ _test_wrapping_surface_finish,
+ _test_wrapping_surface_acquire_source_image,
+ _test_wrapping_surface_release_source_image,
+ NULL, NULL, /* dest_image */
+ NULL, /* clone_similar */
+ NULL, /* composite */
+ NULL, /* fill_rectangles */
+ NULL, /* composite_trapezoids */
+ NULL, /* create_span_renderer */
+ NULL, /* check_span_renderer */
+ NULL, /* copy_page */
+ NULL, /* show_page */
+ _test_wrapping_surface_get_extents,
+ NULL, /* old_show_glyphs */
+ NULL, /* get_font_options */
+ NULL, /* flush */
+ NULL, /* mark_dirty_rectangle */
+ NULL, /* scaled_font_fini */
+ NULL, /* scaled_glyph_fini */
+
+ _test_wrapping_surface_paint,
+ _test_wrapping_surface_mask,
+ _test_wrapping_surface_stroke,
+ _test_wrapping_surface_fill,
+ NULL, /* replaced by show_text_glyphs */
+
+ NULL, /* snapshot */
+ NULL, /* is_similar */
+ NULL, /* fill_stroke */
+ NULL, /* create_solid_pattern_surface */
+ NULL, /* can_repaint_solid_pattern_surface */
+
+ _test_wrapping_surface_has_show_text_glyphs,
+ _test_wrapping_surface_show_text_glyphs
+
+ /* XXX wrap fill-stroke and show_glyphs */
+};
diff --git a/src/test-wrapping-surface.h b/src/test-wrapping-surface.h
new file mode 100644
index 00000000..32d2ca3a
--- /dev/null
+++ b/src/test-wrapping-surface.h
@@ -0,0 +1,51 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2009 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#ifndef TEST_WRAPPING_SURFACE_H
+#define TEST_WRAPPING_SURFACE_H
+
+#include "cairo.h"
+
+CAIRO_BEGIN_DECLS
+
+cairo_surface_t *
+_cairo_test_wrapping_surface_create (cairo_surface_t *target);
+
+CAIRO_END_DECLS
+
+#endif /* TEST_WRAPPING_SURFACE_H */
+
diff --git a/test/Makefile.am b/test/Makefile.am
index 2e0eb106..ec5dfac9 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -185,8 +185,8 @@ REFERENCE_IMAGES = \
clip-nesting.rgb24.ref.png \
clip-nesting.test-paginated.rgb24.ref.png \
clip-nesting.xlib.rgb24.ref.png \
- clip-operator.pdf.argb32.xfail.png \
- clip-operator.pdf.rgb24.xfail.png \
+ clip-operator.pdf.argb32.ref.png \
+ clip-operator.pdf.rgb24.ref.png \
clip-operator.ps2.rgb24.ref.png \
clip-operator.ps3.argb32.ref.png \
clip-operator.ps3.ref.png \
@@ -198,15 +198,21 @@ REFERENCE_IMAGES = \
clip-operator.svg12.argb32.xfail.png \
clip-operator.svg12.rgb24.xfail.png \
clip-operator.test-paginated.argb32.ref.png \
- clip-operator.xlib-fallback.rgb24.ref.png \
+ clip-operator.xlib-fallback.ref.png \
clip-operator.xlib.ref.png \
clip-operator.xlib.rgb24.ref.png \
+ clip-unbounded.ref.png \
+ clip-unbounded.rgb24.ref.png \
+ clip-unbounded.svg12.rgb24.xfail.png \
+ clipped-surface.ref.png \
+ clip-push-group.pdf.ref.png \
clip-push-group.ps2.argb32.ref.png \
clip-push-group.ps2.rgb24.ref.png \
clip-push-group.ps3.argb32.ref.png \
clip-push-group.ps3.rgb24.ref.png \
clip-push-group.quartz.ref.png \
clip-push-group.ref.png \
+ clip-push-group.xlib.ref.png \
clip-twice.pdf.argb32.ref.png \
clip-twice.ps2.argb32.ref.png \
clip-twice.ps2.rgb24.ref.png \
@@ -220,8 +226,7 @@ REFERENCE_IMAGES = \
clip-twice.test-paginated.rgb24.ref.png \
clip-twice.xlib.ref.png \
clip-twice.xlib.rgb24.ref.png \
- clipped-group.pdf.argb32.ref.png \
- clipped-group.pdf.rgb24.ref.png \
+ clipped-group.pdf.ref.png \
clipped-group.ps2.ref.png \
clipped-group.ps3.ref.png \
clipped-group.ref.png \
@@ -240,6 +245,8 @@ REFERENCE_IMAGES = \
composite-integer-translate-source.ps2.ref.png \
composite-integer-translate-source.ps3.ref.png \
composite-integer-translate-source.ref.png \
+ composite-integer-translate-source.svg12.argb32.xfail.png \
+ composite-integer-translate-source.svg12.rgb24.xfail.png \
copy-path.ps2.ref.png \
copy-path.ps3.ref.png \
copy-path.ref.png \
@@ -299,7 +306,7 @@ REFERENCE_IMAGES = \
device-offset-fractional.gl.xfail.png \
device-offset-fractional.pdf.argb32.ref.png \
device-offset-fractional.pdf.ref.png \
- device-offset-fractional.pdf.rgb24.ref.png \
+ device-offset-fractional.pdf.xfail.png \
device-offset-fractional.ps2.ref.png \
device-offset-fractional.ps3.ref.png \
device-offset-fractional.ref.png \
@@ -311,8 +318,12 @@ REFERENCE_IMAGES = \
device-offset.rgb24.ref.png \
extended-blend.argb32.ref.png \
extended-blend.rgb24.ref.png \
+ extended-blend.svg12.argb32.xfail.png \
+ extended-blend.svg12.rgb24.xfail.png \
extended-blend-alpha.argb32.ref.png \
extended-blend-alpha.rgb24.ref.png \
+ extended-blend-alpha.svg12.argb32.xfail.png \
+ extended-blend-alpha.svg12.rgb24.xfail.png \
extend-pad-border.ps.ref.png \
extend-pad-border.ref.png \
extend-pad-border.svg.xfail.png \
@@ -377,6 +388,9 @@ REFERENCE_IMAGES = \
fill-degenerate-sort-order.rgb24.ref.png \
fill-degenerate-sort-order.xlib.ref.png \
fill-degenerate-sort-order.xlib.rgb24.ref.png \
+ fill-empty.argb32.ref.png \
+ fill-empty.rgb24.ref.png \
+ fill-empty.svg12.rgb24.xfail.png \
fill-image.ps.ref.png \
fill-image.ref.png \
fill-image.xlib.ref.png \
@@ -443,17 +457,13 @@ REFERENCE_IMAGES = \
ft-text-antialias-none.ps2.argb32.ref.png \
ft-text-antialias-none.ps3.argb32.ref.png \
ft-text-antialias-none.ref.png \
- ft-text-vertical-layout-type1.pdf.argb32.ref.png \
ft-text-vertical-layout-type1.pdf.ref.png \
- ft-text-vertical-layout-type1.pdf.rgb24.ref.png \
ft-text-vertical-layout-type1.ps2.ref.png \
ft-text-vertical-layout-type1.ps3.ref.png \
ft-text-vertical-layout-type1.ref.png \
ft-text-vertical-layout-type1.svg.ref.png \
ft-text-vertical-layout-type1.xlib.ref.png \
- ft-text-vertical-layout-type3.pdf.argb32.ref.png \
ft-text-vertical-layout-type3.pdf.ref.png \
- ft-text-vertical-layout-type3.pdf.rgb24.ref.png \
ft-text-vertical-layout-type3.ps2.ref.png \
ft-text-vertical-layout-type3.ps3.ref.png \
ft-text-vertical-layout-type3.ref.png \
@@ -498,6 +508,8 @@ REFERENCE_IMAGES = \
image-surface-source.ps2.ref.png \
image-surface-source.ps3.ref.png \
image-surface-source.ref.png \
+ image-surface-source.svg12.argb32.xfail.png \
+ image-surface-source.svg12.rgb24.xfail.png \
infinite-join.ps2.ref.png \
infinite-join.ps3.ref.png \
infinite-join.ref.png \
@@ -558,15 +570,14 @@ REFERENCE_IMAGES = \
mask-transformed-similar.pdf.ref.png \
mask-transformed-similar.ref.png \
mask-transformed-similar.svg.ref.png \
- mask.pdf.argb32.xfail.png \
- mask.pdf.rgb24.xfail.png \
+ mask.pdf.argb32.ref.png \
+ mask.pdf.rgb24.ref.png \
mask.quartz.ref.png \
mask.quartz.rgb24.ref.png \
mask.ref.png \
mask.rgb24.ref.png \
mask.svg.argb32.xfail.png \
mask.svg.rgb24.xfail.png \
- mask.xlib-fallback.rgb24.ref.png \
mask.xlib.ref.png \
mask.xlib.rgb24.ref.png \
meta-surface-pattern.gl.argb32.ref.png \
@@ -613,15 +624,16 @@ REFERENCE_IMAGES = \
operator-clear.rgb24.ref.png \
operator-clear.svg12.argb32.xfail.png \
operator-clear.svg12.rgb24.xfail.png \
- operator-clear.xlib.ref.png \
- operator-source.pdf.rgb24.xfail.png \
+ operator-clear.xlib.argb32.ref.png \
+ operator-clear.xlib.rgb24.ref.png \
+ operator-source.pdf.rgb24.ref.png \
operator-source.quartz.ref.png \
operator-source.quartz.rgb24.ref.png \
operator-source.ref.png \
operator-source.rgb24.ref.png \
operator-source.svg12.argb32.xfail.png \
operator-source.svg12.rgb24.xfail.png \
- operator-source.xlib-fallback.rgb24.ref.png \
+ operator-source.xlib-fallback.ref.png \
operator-source.xlib.ref.png \
operator-source.xlib.rgb24.ref.png \
operator.ref.png \
@@ -682,12 +694,15 @@ REFERENCE_IMAGES = \
path-append.xlib.ref.png \
pattern-getters.ref.png \
pdf-surface-source.ref.png \
+ pdf-surface-source.svg12.argb32.xfail.png \
+ pdf-surface-source.svg12.rgb24.xfail.png \
pixman-rotate.ref.png \
pixman-rotate.rgb24.ref.png \
ps-surface-source.ref.png \
+ ps-surface-source.svg12.argb32.xfail.png \
+ ps-surface-source.svg12.rgb24.xfail.png \
push-group.ref.png \
push-group.rgb24.ref.png \
- push-group.xlib-fallback.rgb24.ref.png \
push-group.xlib.ref.png \
push-group.xlib.rgb24.ref.png \
quartz-surface-source.ps2.ref.png \
@@ -727,19 +742,21 @@ REFERENCE_IMAGES = \
rotate-image-surface-paint.svg.ref.png \
scale-down-source-surface-paint.ref.png \
scale-offset-image.gl.ref.png \
- scale-offset-image.pdf.argb32.ref.png \
- scale-offset-image.pdf.rgb24.ref.png \
+ scale-offset-image.pdf.xfail.png \
scale-offset-image.ps.ref.png \
scale-offset-image.ref.png \
scale-offset-image.xfail.png \
+ scale-offset-image.meta.xfail.png \
scale-offset-image.xlib.xfail.png \
+ scale-offset-image.xlib-fallback.xfail.png \
scale-offset-similar.gl.ref.png \
- scale-offset-similar.pdf.argb32.ref.png \
- scale-offset-similar.pdf.rgb24.ref.png \
+ scale-offset-similar.pdf.xfail.png \
scale-offset-similar.ps.ref.png \
scale-offset-similar.ref.png \
scale-offset-similar.xfail.png \
+ scale-offset-similar.meta.xfail.png \
scale-offset-similar.xlib.xfail.png \
+ scale-offset-similar.xlib-fallback.xfail.png \
scale-source-surface-paint.ref.png \
scale-source-surface-paint.rgb24.ref.png \
scale-source-surface-paint.svg.argb32.xfail.png \
@@ -773,7 +790,6 @@ REFERENCE_IMAGES = \
skew-extreme.ref.png \
smask-fill.ref.png \
smask-fill.svg.ref.png \
- smask-fill.xlib-fallback.ref.png \
smask-fill.xlib.ref.png \
smask-image-mask.ref.png \
smask-mask.pdf.xfail.png \
@@ -789,11 +805,13 @@ REFERENCE_IMAGES = \
smask-text.ps3.ref.png \
smask-text.ref.png \
smask-text.svg.ref.png \
+ smask-text.xlib.ref.png \
smask.pdf.xfail.png \
smask.ps2.ref.png \
smask.ps3.ref.png \
smask.ref.png \
smask.svg.ref.png \
+ smask.xlib.ref.png \
solid-pattern-cache-stress.ref.png \
source-clip-scale.gl.ref.png \
source-clip-scale.pdf.ref.png \
@@ -821,6 +839,7 @@ REFERENCE_IMAGES = \
stroke-image.quartz.ref.png \
stroke-image.ref.png \
surface-pattern-big-scale-down.ref.png \
+ surface-pattern-big-scale-down.ps.xfail.png \
surface-pattern-scale-down.pdf.ref.png \
surface-pattern-scale-down.ps2.ref.png \
surface-pattern-scale-down.ps3.ref.png \
@@ -835,8 +854,12 @@ REFERENCE_IMAGES = \
surface-pattern.ref.png \
surface-pattern.svg.xfail.png \
svg-surface-source.ref.png \
+ svg-surface-source.svg12.argb32.xfail.png \
+ svg-surface-source.svg12.rgb24.xfail.png \
test-fallback16-surface-source.ps.ref.png \
test-fallback16-surface-source.ref.png \
+ test-fallback16-surface-source.svg12.argb32.xfail.png \
+ test-fallback16-surface-source.svg12.rgb24.xfail.png \
text-antialias-gray.quartz.ref.png \
text-antialias-gray.ref.png \
text-antialias-none.quartz.ref.png \
@@ -846,8 +869,8 @@ REFERENCE_IMAGES = \
text-glyph-range.ps2.ref.png \
text-glyph-range.ps3.ref.png \
text-glyph-range.ref.png \
- text-pattern.pdf.argb32.xfail.png \
- text-pattern.pdf.rgb24.xfail.png \
+ text-pattern.pdf.argb32.ref.png \
+ text-pattern.pdf.rgb24.ref.png \
text-pattern.ps3.argb32.ref.png \
text-pattern.ps3.rgb24.ref.png \
text-pattern.quartz.ref.png \
@@ -924,6 +947,8 @@ REFERENCE_IMAGES = \
xlib-surface-source.ps2.ref.png \
xlib-surface-source.ps3.ref.png \
xlib-surface-source.ref.png \
+ xlib-surface-source.svg12.argb32.xfail.png \
+ xlib-surface-source.svg12.rgb24.xfail.png \
zero-alpha.ref.png
EXTRA_DIST += \
@@ -1218,7 +1243,7 @@ run:
# Check tests under valgrind. Saves log to valgrind-log
check-valgrind:
- $(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) CAIRO_TEST_MODE="$(MODE),foreground" $(top_builddir)/libtool --mode=execute valgrind $(VALGRIND_FLAGS)' 2>&1 | tee valgrind-log
+ $(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) CAIRO_TEST_MODE="$(MODE),foreground CAIRO_TEST_TIMEOUT=0" $(top_builddir)/libtool --mode=execute valgrind $(VALGRIND_FLAGS)' 2>&1 | tee valgrind-log
%.log: %.c cairo-test-suite
-./cairo-test-suite $(<:.c=)
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 4d87a276..573ca848 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -21,6 +21,7 @@ test_sources = \
clip-operator.c \
clip-push-group.c \
clip-twice.c \
+ clip-unbounded.c \
clip-zero.c \
clipped-group.c \
clipped-surface.c \
@@ -64,6 +65,7 @@ test_sources = \
fill-and-stroke-alpha.c \
fill-and-stroke-alpha-add.c \
fill-degenerate-sort-order.c \
+ fill-empty.c \
fill-image.c \
fill-missed-stop.c \
fill-rule.c \
diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index f9b4a951..8fc3f891 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -70,13 +70,12 @@ buffer_diff_core (const unsigned char *_buf_a, int stride_a,
stride_a /= sizeof (uint32_t);
stride_b /= sizeof (uint32_t);
stride_diff /= sizeof (uint32_t);
- for (y = 0; y < height; y++)
- {
+ for (y = 0; y < height; y++) {
const uint32_t *row_a = buf_a + y * stride_a;
const uint32_t *row_b = buf_b + y * stride_b;
uint32_t *row = buf_diff + y * stride_diff;
- for (x = 0; x < width; x++)
- {
+
+ for (x = 0; x < width; x++) {
/* check if the pixels are the same */
if ((row_a[x] & mask) != (row_b[x] & mask)) {
int channel;
@@ -99,6 +98,11 @@ buffer_diff_core (const unsigned char *_buf_a, int stride_a,
}
result.pixels_changed++;
+ if ((diff_pixel & 0x00ffffff) == 0) {
+ /* alpha only difference, convert to luminance */
+ uint8_t alpha = diff_pixel >> 24;
+ diff_pixel = alpha * 0x010101;
+ }
row[x] = diff_pixel;
} else {
row[x] = 0;
diff --git a/test/cairo-test.c b/test/cairo-test.c
index ad74d13f..630036d1 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -566,7 +566,7 @@ cairo_test_file_is_older (const char *filename,
while (num_ref_filenames--) {
struct stat ref;
- char *ref_filename = ref_filenames++;
+ char *ref_filename = *ref_filenames++;
if (ref_filename == NULL)
continue;
@@ -912,6 +912,11 @@ REPEAT:
goto UNWIND_SURFACE;
}
+ cairo_surface_set_user_data (surface,
+ &cairo_boilerplate_output_basename_key,
+ base_path,
+ NULL);
+
cairo_surface_set_device_offset (surface, dev_offset, dev_offset);
cr = cairo_create (surface);
@@ -1080,13 +1085,17 @@ REPEAT:
ctx->test->width,
ctx->test->height);
diff_status = cairo_surface_write_to_png (test_image, out_png_path);
+ cairo_surface_destroy (test_image);
if (diff_status) {
+ if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS)
+ ret = CAIRO_TEST_CRASHED;
+ else
+ ret = CAIRO_TEST_FAILURE;
cairo_test_log (ctx,
"Error: Failed to write output image: %s\n",
cairo_status_to_string (diff_status));
}
have_output = TRUE;
- cairo_surface_destroy (test_image);
ret = CAIRO_TEST_XFAILURE;
goto UNWIND_CAIRO;
@@ -1167,8 +1176,11 @@ REPEAT:
if (cairo_surface_status (test_image)) {
cairo_test_log (ctx, "Error: Failed to extract image: %s\n",
cairo_status_to_string (cairo_surface_status (test_image)));
+ if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS)
+ ret = CAIRO_TEST_CRASHED;
+ else
+ ret = CAIRO_TEST_FAILURE;
cairo_surface_destroy (test_image);
- ret = CAIRO_TEST_FAILURE;
goto UNWIND_CAIRO;
}
diff --git a/test/clip-operator.pdf.argb32.ref.png b/test/clip-operator.pdf.argb32.ref.png
new file mode 100644
index 00000000..4213499b
--- /dev/null
+++ b/test/clip-operator.pdf.argb32.ref.png
Binary files differ
diff --git a/test/clip-operator.pdf.argb32.xfail.png b/test/clip-operator.pdf.argb32.xfail.png
deleted file mode 100644
index c0a4078c..00000000
--- a/test/clip-operator.pdf.argb32.xfail.png
+++ /dev/null
Binary files differ
diff --git a/test/clip-operator.pdf.rgb24.ref.png b/test/clip-operator.pdf.rgb24.ref.png
new file mode 100644
index 00000000..55e7893d
--- /dev/null
+++ b/test/clip-operator.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/clip-operator.pdf.rgb24.xfail.png b/test/clip-operator.pdf.rgb24.xfail.png
deleted file mode 100644
index 01329b55..00000000
--- a/test/clip-operator.pdf.rgb24.xfail.png
+++ /dev/null
Binary files differ
diff --git a/test/clip-operator.svg12.argb32.xfail.png b/test/clip-operator.svg12.argb32.xfail.png
index 1c21d15f..be0696e0 100644
--- a/test/clip-operator.svg12.argb32.xfail.png
+++ b/test/clip-operator.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/clip-operator.svg12.rgb24.xfail.png b/test/clip-operator.svg12.rgb24.xfail.png
index f79de48e..494852da 100644
--- a/test/clip-operator.svg12.rgb24.xfail.png
+++ b/test/clip-operator.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/clip-operator.xlib-fallback.ref.png b/test/clip-operator.xlib-fallback.ref.png
new file mode 100644
index 00000000..be1cac01
--- /dev/null
+++ b/test/clip-operator.xlib-fallback.ref.png
Binary files differ
diff --git a/test/clip-operator.xlib-fallback.rgb24.ref.png b/test/clip-operator.xlib-fallback.rgb24.ref.png
deleted file mode 100644
index 4a05f7ba..00000000
--- a/test/clip-operator.xlib-fallback.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/clip-push-group.pdf.ref.png b/test/clip-push-group.pdf.ref.png
new file mode 100644
index 00000000..37b58c59
--- /dev/null
+++ b/test/clip-push-group.pdf.ref.png
Binary files differ
diff --git a/test/clip-push-group.ref.png b/test/clip-push-group.ref.png
index 327cc90b..86724a23 100644
--- a/test/clip-push-group.ref.png
+++ b/test/clip-push-group.ref.png
Binary files differ
diff --git a/test/clip-push-group.xlib.ref.png b/test/clip-push-group.xlib.ref.png
new file mode 100644
index 00000000..de6ac632
--- /dev/null
+++ b/test/clip-push-group.xlib.ref.png
Binary files differ
diff --git a/test/clip-unbounded.c b/test/clip-unbounded.c
new file mode 100644
index 00000000..cd1c6022
--- /dev/null
+++ b/test/clip-unbounded.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2009 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+#define SIZE 10
+
+static cairo_surface_t *
+create_source (cairo_surface_t *target)
+{
+ cairo_surface_t *similar;
+ cairo_t *cr;
+
+ similar = cairo_surface_create_similar (target,
+ CAIRO_CONTENT_COLOR, SIZE/2, SIZE);
+ cr = cairo_create (similar);
+ cairo_surface_destroy (similar);
+
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ cairo_paint (cr);
+
+ similar = cairo_surface_reference (cairo_get_target (cr));
+ cairo_destroy (cr);
+
+ return similar;
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *source;
+
+ cairo_set_source_rgb (cr, 0, 0, 1);
+ cairo_paint (cr);
+
+ cairo_rectangle (cr, 0, 0, SIZE/2, SIZE);
+ cairo_clip (cr);
+
+ /* Draw a source rectangle outside the image, the effect should be to
+ * clear only within the clip region.
+ */
+ source = create_source (cairo_get_target (cr));
+ cairo_set_source_surface (cr, source, SIZE/2, 0);
+ cairo_surface_destroy (source);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (clip_unbounded,
+ "Test handling of an unbounded fill outside the clip region",
+ "clip", /* keywords */
+ NULL, /* requirements */
+ SIZE, SIZE,
+ NULL, draw)
+
diff --git a/test/clip-unbounded.ref.png b/test/clip-unbounded.ref.png
new file mode 100644
index 00000000..0b659056
--- /dev/null
+++ b/test/clip-unbounded.ref.png
Binary files differ
diff --git a/test/clip-unbounded.rgb24.ref.png b/test/clip-unbounded.rgb24.ref.png
new file mode 100644
index 00000000..2baf9f46
--- /dev/null
+++ b/test/clip-unbounded.rgb24.ref.png
Binary files differ
diff --git a/test/clip-unbounded.svg12.rgb24.xfail.png b/test/clip-unbounded.svg12.rgb24.xfail.png
new file mode 100644
index 00000000..0b659056
--- /dev/null
+++ b/test/clip-unbounded.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/clipped-group.pdf.argb32.ref.png b/test/clipped-group.pdf.argb32.ref.png
deleted file mode 100644
index b9975e12..00000000
--- a/test/clipped-group.pdf.argb32.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/clipped-group.pdf.ref.png b/test/clipped-group.pdf.ref.png
new file mode 100644
index 00000000..64958608
--- /dev/null
+++ b/test/clipped-group.pdf.ref.png
Binary files differ
diff --git a/test/clipped-group.pdf.rgb24.ref.png b/test/clipped-group.pdf.rgb24.ref.png
deleted file mode 100644
index b9975e12..00000000
--- a/test/clipped-group.pdf.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/clipped-group.ref.png b/test/clipped-group.ref.png
index 89a7b184..9855e619 100644
--- a/test/clipped-group.ref.png
+++ b/test/clipped-group.ref.png
Binary files differ
diff --git a/test/composite-integer-translate-source.svg12.argb32.xfail.png b/test/composite-integer-translate-source.svg12.argb32.xfail.png
new file mode 100644
index 00000000..c4f31970
--- /dev/null
+++ b/test/composite-integer-translate-source.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/composite-integer-translate-source.svg12.rgb24.xfail.png b/test/composite-integer-translate-source.svg12.rgb24.xfail.png
new file mode 100644
index 00000000..c4f31970
--- /dev/null
+++ b/test/composite-integer-translate-source.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/device-offset-fractional.pdf.argb32.ref.png b/test/device-offset-fractional.pdf.argb32.ref.png
deleted file mode 100644
index c076932c..00000000
--- a/test/device-offset-fractional.pdf.argb32.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/device-offset-fractional.pdf.ref.png b/test/device-offset-fractional.pdf.ref.png
deleted file mode 100644
index 9ff2b8d5..00000000
--- a/test/device-offset-fractional.pdf.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/device-offset-fractional.pdf.rgb24.ref.png b/test/device-offset-fractional.pdf.rgb24.ref.png
deleted file mode 100644
index c076932c..00000000
--- a/test/device-offset-fractional.pdf.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/device-offset-fractional.pdf.xfail.png b/test/device-offset-fractional.pdf.xfail.png
new file mode 100644
index 00000000..77a49632
--- /dev/null
+++ b/test/device-offset-fractional.pdf.xfail.png
Binary files differ
diff --git a/test/extended-blend-alpha.svg12.argb32.xfail.png b/test/extended-blend-alpha.svg12.argb32.xfail.png
new file mode 100644
index 00000000..d09c168e
--- /dev/null
+++ b/test/extended-blend-alpha.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/extended-blend-alpha.svg12.rgb24.xfail.png b/test/extended-blend-alpha.svg12.rgb24.xfail.png
new file mode 100644
index 00000000..f80569e9
--- /dev/null
+++ b/test/extended-blend-alpha.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/extended-blend.svg12.argb32.xfail.png b/test/extended-blend.svg12.argb32.xfail.png
new file mode 100644
index 00000000..93297a5c
--- /dev/null
+++ b/test/extended-blend.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/extended-blend.svg12.rgb24.xfail.png b/test/extended-blend.svg12.rgb24.xfail.png
new file mode 100644
index 00000000..8db02c55
--- /dev/null
+++ b/test/extended-blend.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/fill-empty.argb32.ref.png b/test/fill-empty.argb32.ref.png
new file mode 100644
index 00000000..8c26f7eb
--- /dev/null
+++ b/test/fill-empty.argb32.ref.png
Binary files differ
diff --git a/test/fill-empty.c b/test/fill-empty.c
new file mode 100644
index 00000000..0594e57a
--- /dev/null
+++ b/test/fill-empty.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2009 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+#define SIZE 10
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_set_source_rgb (cr, 0, 0, 1);
+ cairo_paint (cr);
+
+ cairo_set_source_rgb (cr, 1, 0, 0);
+
+ /* first drawn an ordinary empty path */
+ cairo_save (cr);
+ cairo_rectangle (cr, 0, 0, SIZE, SIZE/2);
+ cairo_clip (cr);
+ cairo_fill (cr);
+ cairo_restore (cr);
+
+ /* and then an unbounded empty path */
+ cairo_save (cr);
+ cairo_rectangle (cr, 0, SIZE/2, SIZE, SIZE/2);
+ cairo_clip (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN);
+ cairo_fill (cr);
+ cairo_restore (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (fill_empty,
+ "Test filling with an empty path",
+ "fill", /* keywords */
+ NULL, /* requirements */
+ SIZE, SIZE,
+ NULL, draw)
+
diff --git a/test/fill-empty.rgb24.ref.png b/test/fill-empty.rgb24.ref.png
new file mode 100644
index 00000000..dc7a8a0e
--- /dev/null
+++ b/test/fill-empty.rgb24.ref.png
Binary files differ
diff --git a/test/fill-empty.svg12.rgb24.xfail.png b/test/fill-empty.svg12.rgb24.xfail.png
new file mode 100644
index 00000000..8c26f7eb
--- /dev/null
+++ b/test/fill-empty.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/filter-nearest-offset.pdf.xfail.png b/test/filter-nearest-offset.pdf.xfail.png
index 4d436aa1..ffe2df12 100644
--- a/test/filter-nearest-offset.pdf.xfail.png
+++ b/test/filter-nearest-offset.pdf.xfail.png
Binary files differ
diff --git a/test/filter-nearest-transformed.pdf.xfail.png b/test/filter-nearest-transformed.pdf.xfail.png
index 5ad98a75..7eb5988b 100644
--- a/test/filter-nearest-transformed.pdf.xfail.png
+++ b/test/filter-nearest-transformed.pdf.xfail.png
Binary files differ
diff --git a/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png b/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png
deleted file mode 100644
index 242c3be5..00000000
--- a/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/ft-text-vertical-layout-type1.pdf.ref.png b/test/ft-text-vertical-layout-type1.pdf.ref.png
index ab6de47a..1f52ff23 100644
--- a/test/ft-text-vertical-layout-type1.pdf.ref.png
+++ b/test/ft-text-vertical-layout-type1.pdf.ref.png
Binary files differ
diff --git a/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png b/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png
deleted file mode 100644
index 242c3be5..00000000
--- a/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png b/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png
deleted file mode 100644
index f232b9a5..00000000
--- a/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/ft-text-vertical-layout-type3.pdf.ref.png b/test/ft-text-vertical-layout-type3.pdf.ref.png
index 04e679b4..a05ec1d7 100644
--- a/test/ft-text-vertical-layout-type3.pdf.ref.png
+++ b/test/ft-text-vertical-layout-type3.pdf.ref.png
Binary files differ
diff --git a/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png b/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png
deleted file mode 100644
index f232b9a5..00000000
--- a/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/ft-text-vertical-layout-type3.ref.png b/test/ft-text-vertical-layout-type3.ref.png
index 6b59c56a..1bda421c 100644
--- a/test/ft-text-vertical-layout-type3.ref.png
+++ b/test/ft-text-vertical-layout-type3.ref.png
Binary files differ
diff --git a/test/group-unaligned.svg.argb32.xfail.png b/test/group-unaligned.svg.argb32.xfail.png
index 38550376..01c34bec 100644
--- a/test/group-unaligned.svg.argb32.xfail.png
+++ b/test/group-unaligned.svg.argb32.xfail.png
Binary files differ
diff --git a/test/group-unaligned.xlib-fallback.ref.png b/test/group-unaligned.xlib-fallback.ref.png
index ed615b22..5ddbc164 100644
--- a/test/group-unaligned.xlib-fallback.ref.png
+++ b/test/group-unaligned.xlib-fallback.ref.png
Binary files differ
diff --git a/test/image-surface-source.svg12.argb32.xfail.png b/test/image-surface-source.svg12.argb32.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/image-surface-source.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/image-surface-source.svg12.rgb24.xfail.png b/test/image-surface-source.svg12.rgb24.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/image-surface-source.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/in-fill-trapezoid.c b/test/in-fill-trapezoid.c
index b05f0002..84b323a0 100644
--- a/test/in-fill-trapezoid.c
+++ b/test/in-fill-trapezoid.c
@@ -27,10 +27,15 @@
#include "cairo-test.h"
static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
+preamble (cairo_test_context_t *ctx)
{
- const cairo_test_context_t *ctx = cairo_test_get_context (cr);
cairo_test_status_t ret = CAIRO_TEST_SUCCESS;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
@@ -80,7 +85,7 @@ draw (cairo_t *cr, int width, int height)
cairo_new_path (cr);
cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI);
if (! cairo_in_fill (cr, 0, 0)) {
- cairo_test_log (ctx, "Error: Failed to find point inside circle\n");
+ cairo_test_log (ctx, "Error: Failed to find point inside circle [even-odd]\n");
ret = CAIRO_TEST_FAILURE;
}
@@ -117,7 +122,7 @@ draw (cairo_t *cr, int width, int height)
cairo_new_path (cr);
cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI);
if (! cairo_in_fill (cr, 0, 0)) {
- cairo_test_log (ctx, "Error: Failed to find point inside circle\n");
+ cairo_test_log (ctx, "Error: Failed to find point inside circle [nonzero]\n");
ret = CAIRO_TEST_FAILURE;
}
@@ -261,12 +266,14 @@ draw (cairo_t *cr, int width, int height)
ret = CAIRO_TEST_FAILURE;
}
+ cairo_destroy (cr);
+
return ret;
}
CAIRO_TEST (in_fill_trapezoid,
- "Test _cairo_trap_contains via cairo_in_fill",
+ "Test cairo_in_fill",
"in, trap", /* keywords */
NULL, /* requirements */
0, 0,
- NULL, draw)
+ preamble, NULL)
diff --git a/test/mask-glyphs.svg.ref.png b/test/mask-glyphs.svg.ref.png
index e99c3ccb..0058afc1 100644
--- a/test/mask-glyphs.svg.ref.png
+++ b/test/mask-glyphs.svg.ref.png
Binary files differ
diff --git a/test/mask.pdf.argb32.ref.png b/test/mask.pdf.argb32.ref.png
new file mode 100644
index 00000000..8c683550
--- /dev/null
+++ b/test/mask.pdf.argb32.ref.png
Binary files differ
diff --git a/test/mask.pdf.argb32.xfail.png b/test/mask.pdf.argb32.xfail.png
deleted file mode 100644
index 227d312a..00000000
--- a/test/mask.pdf.argb32.xfail.png
+++ /dev/null
Binary files differ
diff --git a/test/mask.pdf.rgb24.ref.png b/test/mask.pdf.rgb24.ref.png
new file mode 100644
index 00000000..be5dbfc9
--- /dev/null
+++ b/test/mask.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/mask.pdf.rgb24.xfail.png b/test/mask.pdf.rgb24.xfail.png
deleted file mode 100644
index bb8e99d0..00000000
--- a/test/mask.pdf.rgb24.xfail.png
+++ /dev/null
Binary files differ
diff --git a/test/mask.xlib-fallback.rgb24.ref.png b/test/mask.xlib-fallback.rgb24.ref.png
deleted file mode 100644
index 34400504..00000000
--- a/test/mask.xlib-fallback.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/meta-surface-pattern.pdf.argb32.ref.png b/test/meta-surface-pattern.pdf.argb32.ref.png
index 7e3435b6..786587c3 100644
--- a/test/meta-surface-pattern.pdf.argb32.ref.png
+++ b/test/meta-surface-pattern.pdf.argb32.ref.png
Binary files differ
diff --git a/test/meta-surface-pattern.pdf.rgb24.ref.png b/test/meta-surface-pattern.pdf.rgb24.ref.png
index 9fef6feb..f542dabf 100644
--- a/test/meta-surface-pattern.pdf.rgb24.ref.png
+++ b/test/meta-surface-pattern.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/operator-clear.xlib.argb32.ref.png b/test/operator-clear.xlib.argb32.ref.png
new file mode 100644
index 00000000..2f12e5e8
--- /dev/null
+++ b/test/operator-clear.xlib.argb32.ref.png
Binary files differ
diff --git a/test/operator-clear.xlib.ref.png b/test/operator-clear.xlib.rgb24.ref.png
index d9a59b15..d9a59b15 100644
--- a/test/operator-clear.xlib.ref.png
+++ b/test/operator-clear.xlib.rgb24.ref.png
Binary files differ
diff --git a/test/operator-source.pdf.rgb24.xfail.png b/test/operator-source.pdf.rgb24.ref.png
index 9482ed81..9482ed81 100644
--- a/test/operator-source.pdf.rgb24.xfail.png
+++ b/test/operator-source.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/operator-source.svg12.argb32.xfail.png b/test/operator-source.svg12.argb32.xfail.png
index 722e5ac4..ccf43156 100644
--- a/test/operator-source.svg12.argb32.xfail.png
+++ b/test/operator-source.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/operator-source.svg12.rgb24.xfail.png b/test/operator-source.svg12.rgb24.xfail.png
index 5f445fc5..827521b8 100644
--- a/test/operator-source.svg12.rgb24.xfail.png
+++ b/test/operator-source.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/operator-source.xlib-fallback.ref.png b/test/operator-source.xlib-fallback.ref.png
new file mode 100644
index 00000000..79fb2c52
--- /dev/null
+++ b/test/operator-source.xlib-fallback.ref.png
Binary files differ
diff --git a/test/operator-source.xlib-fallback.rgb24.ref.png b/test/operator-source.xlib-fallback.rgb24.ref.png
deleted file mode 100644
index fe0d3c61..00000000
--- a/test/operator-source.xlib-fallback.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/path-append.xlib-fallback.ref.png b/test/path-append.xlib-fallback.ref.png
index 08a33a26..d34cce12 100644
--- a/test/path-append.xlib-fallback.ref.png
+++ b/test/path-append.xlib-fallback.ref.png
Binary files differ
diff --git a/test/pdf-surface-source.svg12.argb32.xfail.png b/test/pdf-surface-source.svg12.argb32.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/pdf-surface-source.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/pdf-surface-source.svg12.rgb24.xfail.png b/test/pdf-surface-source.svg12.rgb24.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/pdf-surface-source.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/ps-surface-source.svg12.argb32.xfail.png b/test/ps-surface-source.svg12.argb32.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/ps-surface-source.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/ps-surface-source.svg12.rgb24.xfail.png b/test/ps-surface-source.svg12.rgb24.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/ps-surface-source.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/push-group.xlib-fallback.rgb24.ref.png b/test/push-group.xlib-fallback.rgb24.ref.png
deleted file mode 100644
index 3a951827..00000000
--- a/test/push-group.xlib-fallback.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/scale-offset-image.meta.xfail.png b/test/scale-offset-image.meta.xfail.png
new file mode 100644
index 00000000..3e0191a1
--- /dev/null
+++ b/test/scale-offset-image.meta.xfail.png
Binary files differ
diff --git a/test/scale-offset-image.pdf.rgb24.ref.png b/test/scale-offset-image.pdf.rgb24.ref.png
deleted file mode 100644
index 12507d9c..00000000
--- a/test/scale-offset-image.pdf.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/scale-offset-image.pdf.argb32.ref.png b/test/scale-offset-image.pdf.xfail.png
index 4c7fe283..4c7fe283 100644
--- a/test/scale-offset-image.pdf.argb32.ref.png
+++ b/test/scale-offset-image.pdf.xfail.png
Binary files differ
diff --git a/test/scale-offset-image.xlib-fallback.xfail.png b/test/scale-offset-image.xlib-fallback.xfail.png
new file mode 100644
index 00000000..1a286cdb
--- /dev/null
+++ b/test/scale-offset-image.xlib-fallback.xfail.png
Binary files differ
diff --git a/test/scale-offset-similar.meta.xfail.png b/test/scale-offset-similar.meta.xfail.png
new file mode 100644
index 00000000..83d53e65
--- /dev/null
+++ b/test/scale-offset-similar.meta.xfail.png
Binary files differ
diff --git a/test/scale-offset-similar.pdf.argb32.ref.png b/test/scale-offset-similar.pdf.argb32.ref.png
deleted file mode 100644
index 7d0406d5..00000000
--- a/test/scale-offset-similar.pdf.argb32.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/scale-offset-similar.pdf.rgb24.ref.png b/test/scale-offset-similar.pdf.rgb24.ref.png
deleted file mode 100644
index 7d0406d5..00000000
--- a/test/scale-offset-similar.pdf.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/scale-offset-similar.pdf.xfail.png b/test/scale-offset-similar.pdf.xfail.png
new file mode 100644
index 00000000..4b600f4c
--- /dev/null
+++ b/test/scale-offset-similar.pdf.xfail.png
Binary files differ
diff --git a/test/scale-offset-similar.xlib-fallback.xfail.png b/test/scale-offset-similar.xlib-fallback.xfail.png
new file mode 100644
index 00000000..1a286cdb
--- /dev/null
+++ b/test/scale-offset-similar.xlib-fallback.xfail.png
Binary files differ
diff --git a/test/self-intersecting.argb32.xfail.png b/test/self-intersecting.argb32.xfail.png
index bf08d03a..f644ed46 100644
--- a/test/self-intersecting.argb32.xfail.png
+++ b/test/self-intersecting.argb32.xfail.png
Binary files differ
diff --git a/test/self-intersecting.pdf.argb32.xfail.png b/test/self-intersecting.pdf.argb32.xfail.png
index f29b0a69..eb38a893 100644
--- a/test/self-intersecting.pdf.argb32.xfail.png
+++ b/test/self-intersecting.pdf.argb32.xfail.png
Binary files differ
diff --git a/test/self-intersecting.pdf.rgb24.xfail.png b/test/self-intersecting.pdf.rgb24.xfail.png
index c32df82c..a79a2975 100644
--- a/test/self-intersecting.pdf.rgb24.xfail.png
+++ b/test/self-intersecting.pdf.rgb24.xfail.png
Binary files differ
diff --git a/test/self-intersecting.rgb24.xfail.png b/test/self-intersecting.rgb24.xfail.png
index 9529f098..958215c2 100644
--- a/test/self-intersecting.rgb24.xfail.png
+++ b/test/self-intersecting.rgb24.xfail.png
Binary files differ
diff --git a/test/smask-fill.xlib-fallback.ref.png b/test/smask-fill.xlib-fallback.ref.png
deleted file mode 100644
index 28ab7338..00000000
--- a/test/smask-fill.xlib-fallback.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/smask-text.xlib.ref.png b/test/smask-text.xlib.ref.png
new file mode 100644
index 00000000..ee7fc8b6
--- /dev/null
+++ b/test/smask-text.xlib.ref.png
Binary files differ
diff --git a/test/smask.xlib.ref.png b/test/smask.xlib.ref.png
new file mode 100644
index 00000000..bb70abfe
--- /dev/null
+++ b/test/smask.xlib.ref.png
Binary files differ
diff --git a/test/surface-pattern-big-scale-down.ps.xfail.png b/test/surface-pattern-big-scale-down.ps.xfail.png
new file mode 100644
index 00000000..f4c1b481
--- /dev/null
+++ b/test/surface-pattern-big-scale-down.ps.xfail.png
Binary files differ
diff --git a/test/svg-surface-source.svg12.argb32.xfail.png b/test/svg-surface-source.svg12.argb32.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/svg-surface-source.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/svg-surface-source.svg12.rgb24.xfail.png b/test/svg-surface-source.svg12.rgb24.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/svg-surface-source.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/test-fallback16-surface-source.svg12.argb32.xfail.png b/test/test-fallback16-surface-source.svg12.argb32.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/test-fallback16-surface-source.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/test-fallback16-surface-source.svg12.rgb24.xfail.png b/test/test-fallback16-surface-source.svg12.rgb24.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/test-fallback16-surface-source.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/text-pattern.pdf.argb32.ref.png b/test/text-pattern.pdf.argb32.ref.png
new file mode 100644
index 00000000..0c06629a
--- /dev/null
+++ b/test/text-pattern.pdf.argb32.ref.png
Binary files differ
diff --git a/test/text-pattern.pdf.argb32.xfail.png b/test/text-pattern.pdf.argb32.xfail.png
deleted file mode 100644
index 227058ce..00000000
--- a/test/text-pattern.pdf.argb32.xfail.png
+++ /dev/null
Binary files differ
diff --git a/test/text-pattern.pdf.rgb24.ref.png b/test/text-pattern.pdf.rgb24.ref.png
new file mode 100644
index 00000000..b81de88e
--- /dev/null
+++ b/test/text-pattern.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/text-pattern.pdf.rgb24.xfail.png b/test/text-pattern.pdf.rgb24.xfail.png
deleted file mode 100644
index a3a37205..00000000
--- a/test/text-pattern.pdf.rgb24.xfail.png
+++ /dev/null
Binary files differ
diff --git a/test/unbounded-operator.svg12.argb32.xfail.png b/test/unbounded-operator.svg12.argb32.xfail.png
index 45b173fa..15965c8e 100644
--- a/test/unbounded-operator.svg12.argb32.xfail.png
+++ b/test/unbounded-operator.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/unbounded-operator.svg12.rgb24.xfail.png b/test/unbounded-operator.svg12.rgb24.xfail.png
index c369fd26..828a9db9 100644
--- a/test/unbounded-operator.svg12.rgb24.xfail.png
+++ b/test/unbounded-operator.svg12.rgb24.xfail.png
Binary files differ
diff --git a/test/user-font-proxy.svg.ref.png b/test/user-font-proxy.svg.ref.png
index 747750a5..6c458485 100644
--- a/test/user-font-proxy.svg.ref.png
+++ b/test/user-font-proxy.svg.ref.png
Binary files differ
diff --git a/test/xlib-surface-source.svg12.argb32.xfail.png b/test/xlib-surface-source.svg12.argb32.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/xlib-surface-source.svg12.argb32.xfail.png
Binary files differ
diff --git a/test/xlib-surface-source.svg12.rgb24.xfail.png b/test/xlib-surface-source.svg12.rgb24.xfail.png
new file mode 100644
index 00000000..6ebcaf9a
--- /dev/null
+++ b/test/xlib-surface-source.svg12.rgb24.xfail.png
Binary files differ
diff --git a/util/cairo-script/cairo-script-file.c b/util/cairo-script/cairo-script-file.c
index 18b5b862..2a7296d2 100644
--- a/util/cairo-script/cairo-script-file.c
+++ b/util/cairo-script/cairo-script-file.c
@@ -37,6 +37,7 @@
#include <stdio.h>
#include <limits.h> /* INT_MAX */
#include <string.h>
+#include <zlib.h>
#define CHUNK_SIZE 32768
@@ -148,17 +149,43 @@ csi_file_new_from_string (csi_t *ctx,
csi_file_t *file;
file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
- if (file == NULL)
+ if (_csi_unlikely (file == NULL))
return _csi_error (CAIRO_STATUS_NO_MEMORY);
file->base.type = CSI_OBJECT_TYPE_FILE;
file->base.ref = 1;
- file->type = BYTES;
- file->src = src; src->base.ref++;
- file->data = src->string;
- file->bp = file->data;
- file->rem = src->len;
+ if (src->deflate) {
+ uLongf len = src->deflate;
+ csi_object_t tmp_obj;
+ csi_string_t *tmp_str;
+ csi_status_t status;
+
+ status = csi_string_new (ctx, &tmp_obj, NULL, src->deflate);
+ if (_csi_unlikely (status))
+ return status;
+
+ tmp_str = tmp_obj.datum.string;
+ if (uncompress ((Bytef *) tmp_str->string, &len,
+ (Bytef *) src->string, src->len) != Z_OK)
+ {
+ csi_string_free (ctx, tmp_str);
+ _csi_slab_free (ctx, file, sizeof (csi_file_t));
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ file->type = BYTES;
+ file->src = tmp_str;
+ file->data = tmp_str->string;
+ file->bp = file->data;
+ file->rem = tmp_str->len;
+ } else {
+ file->type = BYTES;
+ file->src = src; src->base.ref++;
+ file->data = src->string;
+ file->bp = file->data;
+ file->rem = src->len;
+ }
obj->type = CSI_OBJECT_TYPE_FILE;
obj->datum.file = file;
diff --git a/util/cairo-script/cairo-script-objects.c b/util/cairo-script/cairo-script-objects.c
index 784376b2..9cc59c90 100644
--- a/util/cairo-script/cairo-script-objects.c
+++ b/util/cairo-script/cairo-script-objects.c
@@ -507,6 +507,7 @@ csi_string_new (csi_t *ctx,
string->string[len] = '\0';
}
string->len = len;
+ string->deflate = 0;
string->base.type = CSI_OBJECT_TYPE_STRING;
string->base.ref = 1;
@@ -518,6 +519,26 @@ csi_string_new (csi_t *ctx,
}
csi_status_t
+csi_string_deflate_new (csi_t *ctx,
+ csi_object_t *obj,
+ void *bytes,
+ int in_len,
+ int out_len)
+{
+ csi_status_t status;
+ csi_string_t *string;
+
+ status = csi_string_new (ctx, obj, bytes, in_len);
+ if (_csi_unlikely (status))
+ return status;
+
+ string = obj->datum.string;
+ string->deflate = out_len;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
csi_string_new_from_bytes (csi_t *ctx,
csi_object_t *obj,
char *bytes,
@@ -534,6 +555,7 @@ csi_string_new_from_bytes (csi_t *ctx,
string->string = bytes;
string->len = len;
+ string->deflate = 0;
string->base.type = CSI_OBJECT_TYPE_STRING;
string->base.ref = 1;
diff --git a/util/cairo-script/cairo-script-private.h b/util/cairo-script/cairo-script-private.h
index 996b40d7..54a840f2 100644
--- a/util/cairo-script/cairo-script-private.h
+++ b/util/cairo-script/cairo-script-private.h
@@ -386,6 +386,7 @@ struct _csi_matrix {
struct _csi_string {
csi_compound_object_t base;
csi_integer_t len;
+ csi_integer_t deflate;
char *string;
};
@@ -435,7 +436,6 @@ struct _csi_scanner {
csi_stack_t procedure_stack;
csi_object_t build_procedure;
- int string_p;
unsigned int accumulator;
unsigned int accumulator_count;
@@ -757,6 +757,13 @@ csi_string_new (csi_t *ctx,
int len);
csi_private csi_status_t
+csi_string_deflate_new (csi_t *ctx,
+ csi_object_t *obj,
+ void *bytes,
+ int in_len,
+ int out_len);
+
+csi_private csi_status_t
csi_string_new_from_bytes (csi_t *ctx,
csi_object_t *obj,
char *bytes,
diff --git a/util/cairo-script/cairo-script-scanner.c b/util/cairo-script/cairo-script-scanner.c
index b3217cd7..3cc39575 100644
--- a/util/cairo-script/cairo-script-scanner.c
+++ b/util/cairo-script/cairo-script-scanner.c
@@ -39,6 +39,7 @@
#include <stdio.h> /* EOF */
#include <string.h> /* memset */
#include <assert.h>
+#include <zlib.h>
#define DEBUG_SCAN 0
@@ -488,18 +489,6 @@ token_end (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
}
static void
-string_inc_p (csi_scanner_t *scan)
-{
- scan->string_p++;
-}
-
-static int
-string_dec_p (csi_scanner_t *scan)
-{
- return --scan->string_p == 0;
-}
-
-static void
string_add (csi_t *ctx, csi_scanner_t *scan, int c)
{
buffer_check (ctx, scan, 1);
@@ -616,7 +605,7 @@ base85_add (csi_t *ctx, csi_scanner_t *scan, int c)
}
static void
-base85_end (csi_t *ctx, csi_scanner_t *scan)
+base85_end (csi_t *ctx, csi_scanner_t *scan, cairo_bool_t deflate)
{
csi_object_t obj;
cairo_status_t status;
@@ -647,12 +636,24 @@ base85_end (csi_t *ctx, csi_scanner_t *scan)
break;
}
- status = csi_string_new (ctx,
- &obj,
- scan->buffer.base,
- scan->buffer.ptr - scan->buffer.base);
- if (_csi_unlikely (status))
- longjmp (scan->jmpbuf, status);
+ if (deflate) {
+ uLongf len = *(uint32_t *) scan->buffer.base;
+ Bytef *source = (Bytef *) (scan->buffer.base + sizeof (uint32_t));
+
+ status = csi_string_deflate_new (ctx, &obj,
+ source,
+ (Bytef *) scan->buffer.ptr - source,
+ len);
+ if (_csi_unlikely (status))
+ longjmp (scan->jmpbuf, status);
+ } else {
+ status = csi_string_new (ctx,
+ &obj,
+ scan->buffer.base,
+ scan->buffer.ptr - scan->buffer.base);
+ if (_csi_unlikely (status))
+ longjmp (scan->jmpbuf, status);
+ }
if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
status = csi_array_append (ctx,
@@ -714,6 +715,8 @@ _scan_file (csi_t *ctx, csi_file_t *src)
uint32_t u32;
float f;
} u;
+ int deflate = 0;
+ int string_p;
scan_none:
while ((c = csi_file_getc (src)) != EOF) {
@@ -757,6 +760,8 @@ scan_none:
token_add_unchecked (scan, '<');
token_end (ctx, scan, src);
goto scan_none;
+ case '|':
+ deflate = 1;
case '~':
goto scan_base85;
default:
@@ -1000,7 +1005,7 @@ scan_comment:
scan_string:
buffer_reset (&scan->buffer);
- scan->string_p = 1;
+ string_p = 1;
while ((c = csi_file_getc (src)) != EOF) {
switch (c) {
case '\\': /* escape */
@@ -1086,12 +1091,12 @@ scan_string:
break;
case '(':
- string_inc_p (scan);
+ string_p++;
string_add (ctx, scan, c);
break;
case ')':
- if (string_dec_p (scan)) {
+ if (--string_p == 0) {
string_end (ctx, scan);
goto scan_none;
}
@@ -1166,7 +1171,8 @@ scan_base85:
return;
case '>':
- base85_end (ctx, scan);
+ base85_end (ctx, scan, deflate);
+ deflate = 0;
goto scan_none;
}
csi_file_putc (src, next);
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 3af1fffd..2775d46e 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -1189,15 +1189,6 @@ _write_base85_data_start (struct _data_stream *stream)
stream->base85_pending = 0;
}
-static void
-_write_data_start (struct _data_stream *stream)
-{
- _write_zlib_data_start (stream);
- _write_base85_data_start (stream);
-
- _trace_printf ("<~");
-}
-
static bool
_expand_four_tuple_to_five (unsigned char four_tuple[4],
unsigned char five_tuple[5])
@@ -1271,6 +1262,16 @@ _write_zlib_data (struct _data_stream *stream, bool flush)
}
static void
+_write_data_start (struct _data_stream *stream, uint32_t len)
+{
+ _write_zlib_data_start (stream);
+ _write_base85_data_start (stream);
+
+ _trace_printf ("<|");
+ _write_base85_data (stream, (unsigned char *) &len, len);
+}
+
+static void
_write_data (struct _data_stream *stream,
const void *data,
unsigned int length)
@@ -1328,7 +1329,7 @@ _emit_data (const void *data, unsigned int length)
{
struct _data_stream stream;
- _write_data_start (&stream);
+ _write_data_start (&stream, length);
_write_data (&stream, data, length);
_write_data_end (&stream);
}
@@ -1391,6 +1392,7 @@ _emit_image (cairo_surface_t *image,
...)
{
int stride, row, width, height;
+ uint32_t len;
cairo_format_t format;
uint8_t row_stack[BUFFER_SIZE];
uint8_t *rowdata;
@@ -1400,9 +1402,7 @@ _emit_image (cairo_surface_t *image,
status = DLCALL (cairo_surface_status, image);
if (status) {
- _trace_printf ("dict\n"
- " /status //%s set\n"
- " image",
+ _trace_printf ("<< /status //%s >> image",
_status_to_string (status));
return;
}
@@ -1430,6 +1430,7 @@ _emit_image (cairo_surface_t *image,
if (DLCALL (cairo_version) >= CAIRO_VERSION_ENCODE (1, 9, 0)) {
const char *mime_types[] = {
CAIRO_MIME_TYPE_JPEG,
+ CAIRO_MIME_TYPE_JP2,
CAIRO_MIME_TYPE_PNG,
NULL
}, **mime_type;
@@ -1454,8 +1455,16 @@ _emit_image (cairo_surface_t *image,
}
}
+ switch (format) {
+ case CAIRO_FORMAT_A1: len = (width + 7)/8; break;
+ case CAIRO_FORMAT_A8: len = width; break;
+ case CAIRO_FORMAT_RGB24: len = 3*width; break;
+ default:
+ case CAIRO_FORMAT_ARGB32: len = 4*width; break;
+ }
+
_trace_printf (" /source ");
- _write_data_start (&stream);
+ _write_data_start (&stream, len * height);
#ifdef WORDS_BIGENDIAN
switch (format) {
@@ -1549,8 +1558,7 @@ _emit_image (cairo_surface_t *image,
BAIL:
_write_data_end (&stream);
#endif
- _trace_printf (" /deflate filter set\n"
- " image");
+ _trace_printf (" set\n image");
}
static void
@@ -2658,31 +2666,33 @@ _emit_font_options (const cairo_font_options_t *options)
cairo_hint_style_t hint_style;
cairo_hint_metrics_t hint_metrics;
- _trace_printf ("dict\n");
+ _trace_printf ("<<");
antialias = DLCALL (cairo_font_options_get_antialias, options);
if (antialias != CAIRO_ANTIALIAS_DEFAULT) {
- _trace_printf (" /antialias //%s set\n",
+ _trace_printf (" /antialias //%s",
_antialias_to_string (antialias));
}
subpixel_order = DLCALL (cairo_font_options_get_subpixel_order, options);
if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) {
- _trace_printf (" /subpixel-order //%s set\n",
+ _trace_printf (" /subpixel-order //%s",
_subpixel_order_to_string (subpixel_order));
}
hint_style = DLCALL (cairo_font_options_get_hint_style, options);
if (hint_style != CAIRO_HINT_STYLE_DEFAULT) {
- _trace_printf (" /hint-style //%s set\n",
+ _trace_printf (" /hint-style //%s",
_hint_style_to_string (hint_style));
}
hint_metrics = DLCALL (cairo_font_options_get_hint_metrics, options);
if (hint_style != CAIRO_HINT_METRICS_DEFAULT) {
- _trace_printf (" /hint-metrics //%s set\n",
+ _trace_printf (" /hint-metrics //%s",
_hint_metrics_to_string (hint_metrics));
}
+
+ _trace_printf (" >>");
}
void
@@ -2692,7 +2702,7 @@ cairo_set_font_options (cairo_t *cr, const cairo_font_options_t *options)
if (cr != NULL && options != NULL && _write_lock ()) {
_emit_context (cr);
_emit_font_options (options);
- _trace_printf (" set-font-options\n");
+ _trace_printf (" set-font-options\n");
_write_unlock ();
}
@@ -3621,16 +3631,10 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face, int load_flags)
if (obj->operand != -1)
_object_remove (obj);
- _trace_printf ("dict\n"
- " /type 42 set\n"
- " /source ");
+ _trace_printf ("<< /type 42 /source ");
_emit_data (data->data, data->size);
- _trace_printf (" /deflate filter set\n"
- " /size %lu set\n"
- " /index %lu set\n"
- " /flags %d set\n"
- " font\n",
- data->size, data->index, load_flags);
+ _trace_printf (" /index %lu /flags %d font\n",
+ data->index, load_flags);
_push_operand (FONT_FACE, ret);
_write_unlock ();
}
@@ -4245,17 +4249,12 @@ _cairo_test_fallback_surface_create (cairo_content_t content,
#include <test-paginated-surface.h>
cairo_surface_t *
-_cairo_test_paginated_surface_create_for_data (unsigned char *data,
- cairo_content_t content,
- int width,
- int height,
- int stride)
+_cairo_test_paginated_surface_create (cairo_surface_t *surface)
{
cairo_surface_t *ret;
long surface_id;
- ret = DLCALL (_cairo_test_paginated_surface_create_for_data,
- data, content, width, height, stride);
+ ret = DLCALL (_cairo_test_paginated_surface_create, surface);
surface_id = _create_surface_id (ret);
_emit_line_info ();
@@ -4263,16 +4262,10 @@ _cairo_test_paginated_surface_create_for_data (unsigned char *data,
/* XXX store initial data? */
_trace_printf ("dict\n"
" /type /test-paginated set\n"
- " /content //%s set\n"
- " /width %d set\n"
- " /height %d set\n"
- " /stride %d set\n"
+ " /target s%ld set\n"
" surface dup /s%ld exch def\n",
- _content_to_string (content),
- width, height, stride,
+ _get_surface_id (surface),
surface_id);
- _surface_object_set_size (ret, width, height);
- _get_object (SURFACE, ret)->defined = true;
_push_operand (SURFACE, ret);
_write_unlock ();
}
@@ -4310,27 +4303,35 @@ _cairo_test_null_surface_create (cairo_content_t content)
cairo_surface_t *
cairo_meta_surface_create (cairo_content_t content,
- double width,
- double height)
+ const cairo_rectangle_t *extents)
{
cairo_surface_t *ret;
long surface_id;
- ret = DLCALL (cairo_meta_surface_create, content, width, height);
+ ret = DLCALL (cairo_meta_surface_create, content, extents);
surface_id = _create_surface_id (ret);
_emit_line_info ();
if (_write_lock ()) {
- _trace_printf ("dict\n"
- " /type /meta set\n"
- " /content //%s set\n"
- " /width %f set\n"
- " /height %f set\n"
- " surface dup /s%ld exch def\n",
- _content_to_string (content),
- width, height,
- surface_id);
- _surface_object_set_size (ret, width, height);
+ if (extents) {
+ _trace_printf ("dict\n"
+ " /type /meta set\n"
+ " /content //%s set\n"
+ " /extents [%f %f %f %f] set\n"
+ " surface dup /s%ld exch def\n",
+ _content_to_string (content),
+ extents->x, extents->y,
+ extents->width, extents->height,
+ surface_id);
+ _surface_object_set_size (ret, extents->width, extents->height);
+ } else {
+ _trace_printf ("dict\n"
+ " /type /meta set\n"
+ " /content //%s set\n"
+ " surface dup /s%ld exch def\n",
+ _content_to_string (content),
+ surface_id);
+ }
_get_object (SURFACE, ret)->defined = true;
_push_operand (SURFACE, ret);
_write_unlock ();