summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 ();