summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-07-30 17:28:21 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-09-12 08:29:48 +0100
commitaf9fbd176b145f042408ef5391eef2a51d7531f8 (patch)
tree5f75d1087d4325a013af6f0a4204a666fb4ca4f0
parent0540bf384aed344899417d3b0313bd6704679c1c (diff)
Introduce a new compositor architecture
Having spent the last dev cycle looking at how we could specialize the compositors for various backends, we once again look for the commonalities in order to reduce the duplication. In part this is motivated by the idea that spans is a good interface for both the existent GL backend and pixman, and so they deserve a dedicated compositor. xcb/xlib target an identical rendering system and so they should be using the same compositor, and it should be possible to run that same compositor locally against pixman to generate reference tests. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> P.S. This brings massive upheaval (read breakage) I've tried delaying in order to fix as many things as possible but now this one patch does far, far, far too much. Apologies in advance for breaking your favourite backend, but trust me in that the end result will be much better. :)
-rw-r--r--boilerplate/cairo-boilerplate-test-surfaces.c351
-rw-r--r--boilerplate/cairo-boilerplate-xlib.c3
-rw-r--r--boilerplate/cairo-boilerplate.c14
-rw-r--r--configure.ac4
-rw-r--r--perf/Makefile.sources3
-rw-r--r--perf/cairo-perf-compare-backends.c6
-rw-r--r--perf/cairo-perf-diff-files.c47
-rw-r--r--perf/cairo-perf-micro.c108
-rw-r--r--perf/cairo-perf-report.c7
-rw-r--r--perf/cairo-perf-trace.c136
-rw-r--r--perf/cairo-perf.h16
-rw-r--r--perf/cairo-stats.c66
-rw-r--r--perf/micro/Makefile.sources5
-rw-r--r--perf/micro/a1-curve.c112
-rw-r--r--perf/micro/a1-line.c223
-rw-r--r--perf/micro/box-outline.c119
-rw-r--r--perf/micro/composite-checker.c9
-rw-r--r--perf/micro/curve.c9
-rw-r--r--perf/micro/disjoint.c6
-rw-r--r--perf/micro/dragon.c9
-rw-r--r--perf/micro/fill-clip.c126
-rw-r--r--perf/micro/fill.c9
-rw-r--r--perf/micro/glyphs.c9
-rw-r--r--perf/micro/hash-table.c9
-rw-r--r--perf/micro/hatching.c9
-rw-r--r--perf/micro/intersections.c9
-rw-r--r--perf/micro/line.c9
-rw-r--r--perf/micro/long-dashed-lines.c9
-rw-r--r--perf/micro/long-lines.c9
-rw-r--r--perf/micro/many-curves.c9
-rw-r--r--perf/micro/many-fills.c9
-rw-r--r--perf/micro/many-strokes.c13
-rw-r--r--perf/micro/mask.c6
-rw-r--r--perf/micro/mosaic.c9
-rw-r--r--perf/micro/paint-with-alpha.c9
-rw-r--r--perf/micro/paint.c9
-rw-r--r--perf/micro/pattern_create_radial.c9
-rw-r--r--perf/micro/pixel.c177
-rw-r--r--perf/micro/pythagoras-tree.c9
-rw-r--r--perf/micro/rectangles.c9
-rw-r--r--perf/micro/rounded-rectangles.c9
-rw-r--r--perf/micro/sierpinski.c94
-rw-r--r--perf/micro/spiral.c9
-rw-r--r--perf/micro/stroke.c9
-rw-r--r--perf/micro/subimage_copy.c9
-rw-r--r--perf/micro/tessellate.c9
-rw-r--r--perf/micro/text.c9
-rw-r--r--perf/micro/twin.c9
-rw-r--r--perf/micro/unaligned-clip.c9
-rw-r--r--perf/micro/wave.c9
-rw-r--r--perf/micro/wide-fills.c9
-rw-r--r--perf/micro/wide-strokes.c9
-rw-r--r--perf/micro/world-map.c9
-rw-r--r--perf/micro/zrusin.c8
-rw-r--r--src/Makefile.sources42
-rw-r--r--src/cairo-analysis-surface.c77
-rw-r--r--src/cairo-array-private.h90
-rw-r--r--src/cairo-array.c11
-rw-r--r--src/cairo-atomic-private.h5
-rw-r--r--src/cairo-bentley-ottmann-rectangular.c55
-rw-r--r--src/cairo-bentley-ottmann-rectilinear.c69
-rw-r--r--src/cairo-bentley-ottmann.c154
-rw-r--r--src/cairo-botor-scan-converter.c5
-rw-r--r--src/cairo-box-private.h48
-rw-r--r--src/cairo-boxes-intersect.c47
-rw-r--r--src/cairo-boxes-private.h16
-rw-r--r--src/cairo-boxes.c77
-rw-r--r--src/cairo-cff-subset.c8
-rw-r--r--src/cairo-clip-boxes.c42
-rw-r--r--src/cairo-clip-private.h23
-rw-r--r--src/cairo-clip-region.c8
-rw-r--r--src/cairo-clip-surface.c39
-rw-r--r--src/cairo-clip-tor-scan-converter.c1845
-rw-r--r--src/cairo-clip.c20
-rw-r--r--src/cairo-composite-rectangles-private.h38
-rw-r--r--src/cairo-composite-rectangles.c179
-rw-r--r--src/cairo-compositor-private.h355
-rw-r--r--src/cairo-compositor.c213
-rw-r--r--src/cairo-default-context.c3
-rw-r--r--src/cairo-fallback-compositor.c174
-rw-r--r--src/cairo-freed-pool-private.h6
-rw-r--r--src/cairo-ft-font.c1
-rw-r--r--src/cairo-gl-composite.c1148
-rw-r--r--src/cairo-gl-device.c20
-rw-r--r--src/cairo-gl-glyphs.c382
-rw-r--r--src/cairo-gl-operand.c538
-rw-r--r--src/cairo-gl-private.h106
-rw-r--r--src/cairo-gl-shaders.c69
-rw-r--r--src/cairo-gl-spans-compositor.c502
-rw-r--r--src/cairo-gl-surface.c1021
-rw-r--r--src/cairo-gl-traps-compositor.c550
-rw-r--r--src/cairo-gstate.c341
-rw-r--r--src/cairo-image-compositor.c1545
-rw-r--r--src/cairo-image-mask-compositor.c408
-rw-r--r--src/cairo-image-source.c975
-rw-r--r--src/cairo-image-spans-compositor.c131
-rw-r--r--src/cairo-image-surface-private.h88
-rw-r--r--src/cairo-image-surface.c3981
-rw-r--r--src/cairo-mask-compositor.c1412
-rw-r--r--src/cairo-matrix.c6
-rw-r--r--src/cairo-mesh-pattern-rasterizer.c1
-rw-r--r--src/cairo-mime-surface.c18
-rw-r--r--src/cairo-mono-scan-converter.c607
-rw-r--r--src/cairo-no-compositor.c107
-rw-r--r--src/cairo-output-stream.c2
-rw-r--r--src/cairo-paginated-surface.c29
-rw-r--r--src/cairo-path-bounds.c28
-rw-r--r--src/cairo-path-fill.c69
-rw-r--r--src/cairo-path-fixed-private.h4
-rw-r--r--src/cairo-path-fixed.c57
-rw-r--r--src/cairo-path-stroke-boxes.c90
-rw-r--r--src/cairo-path-stroke-polygon.c71
-rw-r--r--src/cairo-path-stroke-tristrip.c1088
-rw-r--r--src/cairo-path-stroke.c10
-rw-r--r--src/cairo-pattern-private.h58
-rw-r--r--src/cairo-pattern.c1137
-rw-r--r--src/cairo-pdf-operators.c2
-rw-r--r--src/cairo-pdf-shading.c2
-rw-r--r--src/cairo-pdf-surface.c83
-rw-r--r--src/cairo-polygon-intersect.c69
-rw-r--r--src/cairo-polygon.c52
-rw-r--r--src/cairo-ps-surface.c211
-rw-r--r--src/cairo-quartz-image-surface.c160
-rw-r--r--src/cairo-quartz-surface.c802
-rw-r--r--src/cairo-recording-surface-private.h6
-rw-r--r--src/cairo-recording-surface.c131
-rw-r--r--src/cairo-rectangular-scan-converter.c75
-rw-r--r--src/cairo-reference-count-private.h1
-rw-r--r--src/cairo-scaled-font-private.h68
-rw-r--r--src/cairo-scaled-font.c111
-rw-r--r--src/cairo-script-private.h3
-rw-r--r--src/cairo-script-surface.c179
-rw-r--r--src/cairo-slope.c4
-rw-r--r--src/cairo-spans-compositor-private.h96
-rw-r--r--src/cairo-spans-compositor.c1007
-rw-r--r--src/cairo-spans-private.h55
-rw-r--r--src/cairo-spans.c108
-rw-r--r--src/cairo-spline.c53
-rw-r--r--src/cairo-stroke-style.c10
-rw-r--r--src/cairo-surface-backend-private.h196
-rw-r--r--src/cairo-surface-fallback-private.h112
-rw-r--r--src/cairo-surface-fallback.c1563
-rw-r--r--src/cairo-surface-observer-private.h24
-rw-r--r--src/cairo-surface-observer.c227
-rw-r--r--src/cairo-surface-private.h1
-rw-r--r--src/cairo-surface-snapshot-private.h3
-rw-r--r--src/cairo-surface-snapshot.c17
-rw-r--r--src/cairo-surface-subsurface-private.h22
-rw-r--r--src/cairo-surface-subsurface.c21
-rw-r--r--src/cairo-surface-wrapper-private.h1
-rw-r--r--src/cairo-surface-wrapper.c6
-rw-r--r--src/cairo-surface.c1212
-rw-r--r--src/cairo-svg-surface.c26
-rw-r--r--src/cairo-time-private.h19
-rw-r--r--src/cairo-time.c37
-rw-r--r--src/cairo-tor-scan-converter.c265
-rw-r--r--src/cairo-tor22-scan-converter.c1707
-rw-r--r--src/cairo-traps-compositor.c2032
-rw-r--r--src/cairo-traps-private.h126
-rw-r--r--src/cairo-traps.c61
-rw-r--r--src/cairo-tristrip-private.h94
-rw-r--r--src/cairo-tristrip.c185
-rw-r--r--src/cairo-truetype-subset.c2
-rw-r--r--src/cairo-type1-fallback.c2
-rw-r--r--src/cairo-type1-subset.c2
-rw-r--r--src/cairo-type3-glyph-surface.c35
-rw-r--r--src/cairo-types-private.h34
-rw-r--r--src/cairo-wideint-private.h6
-rw-r--r--src/cairo-wideint.c16
-rw-r--r--src/cairo-win32-printing-surface.c19
-rw-r--r--src/cairo-win32-surface.c2
-rw-r--r--src/cairo-xcb-connection.c2
-rw-r--r--src/cairo-xcb-private.h4
-rw-r--r--src/cairo-xcb-surface-core.c1
-rw-r--r--src/cairo-xcb-surface-render.c507
-rw-r--r--src/cairo-xcb-surface.c33
-rw-r--r--src/cairo-xlib-core-compositor.c524
-rw-r--r--src/cairo-xlib-display.c243
-rw-r--r--src/cairo-xlib-fallback-compositor.c (renamed from src/test-null-surface.h)30
-rw-r--r--src/cairo-xlib-private.h254
-rw-r--r--src/cairo-xlib-render-compositor.c1685
-rw-r--r--src/cairo-xlib-screen.c20
-rw-r--r--src/cairo-xlib-source.c938
-rw-r--r--src/cairo-xlib-surface-private.h71
-rw-r--r--src/cairo-xlib-surface.c3224
-rw-r--r--src/cairo.c1
-rw-r--r--src/cairo.h45
-rw-r--r--src/cairoint.h631
-rw-r--r--src/skia/cairo-skia-context.cpp1
-rw-r--r--src/skia/cairo-skia-surface.cpp220
-rw-r--r--src/test-base-compositor-surface.c942
-rw-r--r--src/test-compositor-surface-private.h (renamed from src/test-wrapping-surface.h)22
-rw-r--r--src/test-compositor-surface.c259
-rw-r--r--src/test-compositor-surface.h (renamed from src/test-fallback-surface.h)39
-rw-r--r--src/test-fallback-surface.c244
-rw-r--r--src/test-fallback16-surface.c241
-rw-r--r--src/test-null-compositor-surface.c480
-rw-r--r--src/test-null-compositor-surface.h (renamed from src/test-fallback16-surface.h)28
-rw-r--r--src/test-null-surface.c195
-rw-r--r--src/test-paginated-surface.c24
-rw-r--r--src/test-wrapping-surface.c281
-rw-r--r--test/Makefile.refs9
-rw-r--r--test/Makefile.sources5
-rw-r--r--test/a1-clip-fill-rule.argb32.ref.pngbin0 -> 236 bytes
-rw-r--r--test/a1-clip-fill-rule.rgb24.ref.pngbin0 -> 218 bytes
-rw-r--r--test/a1-rectilinear-grid.ref.pngbin0 -> 207 bytes
-rw-r--r--test/cairo-test-trace.c195
-rw-r--r--test/clear-source.c2
-rw-r--r--test/clip-fill-rule.c13
-rw-r--r--test/map-to-image.c4
-rw-r--r--test/overlapping-boxes.argb32.ref.pngbin0 -> 216 bytes
-rw-r--r--test/overlapping-boxes.c96
-rw-r--r--test/overlapping-boxes.rgb24.ref.pngbin0 -> 204 bytes
-rw-r--r--test/rectilinear-grid.c14
-rw-r--r--test/shape-sierpinski.c85
-rw-r--r--test/shape-sierpinski.ref.pngbin0 -> 54485 bytes
-rw-r--r--test/test-fallback16-surface-source.c43
-rw-r--r--test/test-fallback16-surface-source.ps.ref.pngbin292 -> 0 bytes
-rw-r--r--test/test-fallback16-surface-source.svg12.argb32.xfail.pngbin278 -> 0 bytes
-rw-r--r--test/test-fallback16-surface-source.svg12.rgb24.xfail.pngbin278 -> 0 bytes
-rw-r--r--test/zero-mask.c6
-rw-r--r--util/cairo-script/cairo-script-interpreter.c1
-rw-r--r--util/cairo-script/cairo-script-operators.c12
-rw-r--r--util/cairo-trace/trace.c114
-rw-r--r--util/show-polygon.c31
225 files changed, 27475 insertions, 17885 deletions
diff --git a/boilerplate/cairo-boilerplate-test-surfaces.c b/boilerplate/cairo-boilerplate-test-surfaces.c
index 909475b3..f7a89a72 100644
--- a/boilerplate/cairo-boilerplate-test-surfaces.c
+++ b/boilerplate/cairo-boilerplate-test-surfaces.c
@@ -30,66 +30,133 @@
#include <cairo-types-private.h>
-#include <test-fallback-surface.h>
-#include <test-fallback16-surface.h>
+#include <test-compositor-surface.h>
+#include <test-null-compositor-surface.h>
#if CAIRO_HAS_TEST_PAGINATED_SURFACE
#include <test-paginated-surface.h>
#endif
-#if CAIRO_HAS_TEST_NULL_SURFACE
-#include <test-null-surface.h>
-#endif
-#if CAIRO_HAS_TEST_WRAPPING_SURFACE
-#include <test-wrapping-surface.h>
-#endif
static cairo_surface_t *
-_cairo_boilerplate_test_fallback_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)
+_cairo_boilerplate_test_base_compositor_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)
{
*closure = NULL;
- return _cairo_test_fallback_surface_create (content,
- ceil (width), ceil (height));
+ return _cairo_test_base_compositor_surface_create (content, ceil (width), ceil (height));
}
+
static cairo_surface_t *
-_cairo_boilerplate_test_fallback16_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)
+_cairo_boilerplate_test_fallback_compositor_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)
{
*closure = NULL;
- return _cairo_test_fallback16_surface_create (content,
- ceil (width), ceil (height));
+ return _cairo_test_fallback_compositor_surface_create (content, ceil (width), ceil (height));
}
-#if CAIRO_HAS_TEST_NULL_SURFACE
static cairo_surface_t *
-_cairo_boilerplate_test_null_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)
+_cairo_boilerplate_test_mask_compositor_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)
{
*closure = NULL;
- return _cairo_test_null_surface_create (content);
+ return _cairo_test_mask_compositor_surface_create (content, ceil (width), ceil (height));
+}
+
+
+static cairo_surface_t *
+_cairo_boilerplate_test_traps_compositor_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)
+{
+ *closure = NULL;
+ return _cairo_test_traps_compositor_surface_create (content, ceil (width), ceil (height));
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_test_spans_compositor_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)
+{
+ *closure = NULL;
+ return _cairo_test_spans_compositor_surface_create (content, ceil (width), ceil (height));
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_test_no_fallback_compositor_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)
+{
+ *closure = NULL;
+ return _cairo_test_no_fallback_compositor_surface_create (content, ceil (width), ceil (height));
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_test_no_traps_compositor_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)
+{
+ *closure = NULL;
+ return _cairo_test_no_traps_compositor_surface_create (content, ceil (width), ceil (height));
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_test_no_spans_compositor_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)
+{
+ *closure = NULL;
+ return _cairo_test_no_spans_compositor_surface_create (content, ceil (width), ceil (height));
}
-#endif
#if CAIRO_HAS_TEST_PAGINATED_SURFACE
static const cairo_user_data_key_t test_paginated_closure_key;
@@ -201,40 +268,38 @@ _cairo_boilerplate_test_paginated_cleanup (void *closure)
}
#endif
-#if CAIRO_HAS_TEST_WRAPPING_SURFACE
-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)
-{
- 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;
-}
-#endif
-
static const cairo_boilerplate_target_t targets[] = {
{
+ "test-base", "image", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE,
+ CAIRO_CONTENT_COLOR_ALPHA, 0,
+ "_cairo_test_base_compositor_surface_create",
+ _cairo_boilerplate_test_base_compositor_create_surface,
+ cairo_surface_create_similar,
+ NULL, NULL,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ NULL, NULL, NULL, TRUE, FALSE, FALSE
+ },
+ {
+ "test-base", "image", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE,
+ CAIRO_CONTENT_COLOR, 0,
+ "_cairo_test_base_compositor_surface_create",
+ _cairo_boilerplate_test_base_compositor_create_surface,
+ cairo_surface_create_similar,
+ NULL, NULL,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ NULL, NULL, NULL, FALSE, FALSE, FALSE
+ },
+
+ {
"test-fallback", "image", NULL, NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+ CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR_ALPHA, 0,
- "_cairo_test_fallback_surface_create",
- _cairo_boilerplate_test_fallback_create_surface,
+ "_cairo_test_fallback_compositor_surface_create",
+ _cairo_boilerplate_test_fallback_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@@ -243,40 +308,128 @@ static const cairo_boilerplate_target_t targets[] = {
},
{
"test-fallback", "image", NULL, NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+ CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR, 0,
- "_cairo_test_fallback_surface_create",
- _cairo_boilerplate_test_fallback_create_surface,
+ "_cairo_test_fallback_compositor_surface_create",
+ _cairo_boilerplate_test_fallback_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, FALSE, FALSE, FALSE
},
+
{
- "test-fallback16", "image", NULL, NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+ "test-mask", "mask", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR_ALPHA, 0,
- "_cairo_test_fallback16_surface_create",
- _cairo_boilerplate_test_fallback16_create_surface,
+ "_cairo_test_traps_compositor_surface_create",
+ _cairo_boilerplate_test_mask_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
- NULL, /* _cairo_boilerplate_get_image_surface, */
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ NULL, NULL, NULL, TRUE, FALSE, FALSE
+ },
+ {
+ "test-mask", "mask", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE,
+ CAIRO_CONTENT_COLOR, 0,
+ "_cairo_test_mask_compositor_surface_create",
+ _cairo_boilerplate_test_mask_compositor_create_surface,
+ cairo_surface_create_similar,
+ NULL, NULL,
+ _cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, FALSE, FALSE, FALSE
},
+
{
- "test-fallback16", "image", NULL, NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+ "test-traps", "traps", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE,
+ CAIRO_CONTENT_COLOR_ALPHA, 0,
+ "_cairo_test_traps_compositor_surface_create",
+ _cairo_boilerplate_test_traps_compositor_create_surface,
+ cairo_surface_create_similar,
+ NULL, NULL,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ NULL, NULL, NULL, TRUE, FALSE, FALSE
+ },
+ {
+ "test-traps", "traps", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR, 0,
- "_cairo_test_fallback16_surface_create",
- _cairo_boilerplate_test_fallback16_create_surface,
+ "_cairo_test_traps_compositor_surface_create",
+ _cairo_boilerplate_test_traps_compositor_create_surface,
+ cairo_surface_create_similar,
+ NULL, NULL,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ NULL, NULL, NULL, FALSE, FALSE, FALSE
+ },
+
+ {
+ "test-spans", "spans", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE,
+ CAIRO_CONTENT_COLOR_ALPHA, 0,
+ "_cairo_test_spans_compositor_surface_create",
+ _cairo_boilerplate_test_spans_compositor_create_surface,
+ cairo_surface_create_similar,
+ NULL, NULL,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ NULL, NULL, NULL, TRUE, FALSE, FALSE
+ },
+ {
+ "test-spans", "spans", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE,
+ CAIRO_CONTENT_COLOR, 0,
+ "_cairo_test_spans_compositor_surface_create",
+ _cairo_boilerplate_test_spans_compositor_create_surface,
+ cairo_surface_create_similar,
+ NULL, NULL,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ NULL, NULL, NULL, FALSE, FALSE, FALSE
+ },
+
+ {
+ "no-fallback", "image", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE,
+ CAIRO_CONTENT_COLOR_ALPHA, 0,
+ "_cairo_test_no_fallback_compositor_surface_create",
+ _cairo_boilerplate_test_no_fallback_compositor_create_surface,
cairo_surface_create_similar,
NULL, NULL,
- NULL, /* _cairo_boilerplate_get_image_surface, */
+ _cairo_boilerplate_get_image_surface,
cairo_surface_write_to_png,
NULL, NULL, NULL, FALSE, FALSE, FALSE
},
+ {
+ "no-traps", "traps", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE,
+ CAIRO_CONTENT_COLOR_ALPHA, 0,
+ "_cairo_test_no_traps_compositor_surface_create",
+ _cairo_boilerplate_test_no_traps_compositor_create_surface,
+ cairo_surface_create_similar,
+ NULL, NULL,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ NULL, NULL, NULL, TRUE, FALSE, FALSE
+ },
+ {
+ "no-spans", "spans", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE,
+ CAIRO_CONTENT_COLOR_ALPHA, 0,
+ "_cairo_test_no_spans_compositor_surface_create",
+ _cairo_boilerplate_test_no_spans_compositor_create_surface,
+ cairo_surface_create_similar,
+ NULL, NULL,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ NULL, NULL, NULL, TRUE, FALSE, FALSE
+ },
#if CAIRO_HAS_TEST_PAGINATED_SURFACE
{
"test-paginated", "image", NULL, NULL,
@@ -305,33 +458,5 @@ static const cairo_boilerplate_target_t targets[] = {
NULL, NULL, FALSE, TRUE, FALSE
},
#endif
-#if CAIRO_HAS_TEST_WRAPPING_SURFACE
- {
- "test-wrapping", "image", NULL, NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
- CAIRO_CONTENT_COLOR_ALPHA, 0,
- "_cairo_test_wrapping_surface_create",
- _cairo_boilerplate_test_wrapping_create_surface,
- cairo_surface_create_similar,
- NULL, NULL,
- _cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png,
- NULL, NULL, NULL, FALSE, FALSE, FALSE
- },
-#endif
-#if CAIRO_HAS_TEST_NULL_SURFACE
- {
- "null", "image", NULL, NULL,
- CAIRO_INTERNAL_SURFACE_TYPE_NULL,
- CAIRO_CONTENT_COLOR_ALPHA, 0,
- "_cairo_test_null_surface_create",
- _cairo_boilerplate_test_null_create_surface,
- cairo_surface_create_similar,
- NULL, NULL,
- NULL, NULL, NULL,
- NULL, NULL,
- TRUE, TRUE, FALSE
- },
-#endif
};
CAIRO_BOILERPLATE (test, targets)
diff --git a/boilerplate/cairo-boilerplate-xlib.c b/boilerplate/cairo-boilerplate-xlib.c
index 6818cafd..cad28847 100644
--- a/boilerplate/cairo-boilerplate-xlib.c
+++ b/boilerplate/cairo-boilerplate-xlib.c
@@ -31,7 +31,6 @@
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
#include <cairo-xlib-xrender.h>
#endif
-#include <cairo-xlib-surface-private.h>
#include <X11/Xutil.h> /* for XDestroyImage */
@@ -412,6 +411,7 @@ _cairo_boilerplate_xlib_window_create_surface (const char *name,
cairo_status_t
cairo_boilerplate_xlib_surface_disable_render (cairo_surface_t *abstract_surface)
{
+#if 0
/* The following stunt doesn't work with xlib-xcb because it doesn't use
* cairo_xlib_surface_t for its surfaces. Sadly, there is no sane
* alternative, so we can't disable render with xlib-xcb.
@@ -440,6 +440,7 @@ cairo_boilerplate_xlib_surface_disable_render (cairo_surface_t *abstract_surface
surface->buggy_repeat = TRUE;
#endif
#endif
+#endif
return CAIRO_STATUS_SUCCESS;
}
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 229c4c77..8e252f52 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -683,16 +683,12 @@ cairo_boilerplate_get_image_target (cairo_content_t content)
if (cairo_boilerplate_targets == NULL)
_cairo_boilerplate_register_all ();
- for (list = cairo_boilerplate_targets; list != NULL; list = list->next) {
- const cairo_boilerplate_target_t *target = list->target;
- if (target->expected_type == CAIRO_SURFACE_TYPE_IMAGE &&
- target->content == content)
- {
- return target;
- }
+ switch (content) {
+ default:
+ case CAIRO_CONTENT_ALPHA: return NULL;
+ case CAIRO_CONTENT_COLOR: return &builtin_targets[1];
+ case CAIRO_CONTENT_COLOR_ALPHA: return &builtin_targets[0];
}
-
- return NULL;
}
const cairo_boilerplate_target_t *
diff --git a/configure.ac b/configure.ac
index 4b85c8a7..5879a444 100644
--- a/configure.ac
+++ b/configure.ac
@@ -202,11 +202,11 @@ CAIRO_ENABLE_SURFACE_BACKEND(skia, Skia, no, [
[skia_DIR="`pwd`/../skia"])
AC_ARG_WITH([skia-bulid],
[AS_HELP_STRING([--with-skia-build=(Release|Debug)]
- [build of skia to link with, default is Relese])],
+ [build of skia to link with, default is Release])],
[skia_BUILD="$withval"],
[skia_BUILD="Release"])
skia_NONPKGCONFIG_CFLAGS="-I$skia_DIR/include/config -I$skia_DIR/include/core -I$skia_DIR/include/effects"
- if test "x$(skia_BUILD)" = x"Relese"; then
+ if test "x$skia_BUILD" = x"Release"; then
skia_NONPKGCONFIG_CFLAGS="-DSK_RELEASE -DSK_CAN_USE_FLOAT $skia_NONPKGCONFIG_CFLAGS"
fi
skia_NONPKGCONFIG_LIBS="--start-group $skia_DIR/out/$skia_BUILD/obj.target/gyp/libeffects.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libimages.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libutils.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libopts.a $skia_DIR/out/$skia_BUILD/obj.target/gyp/libcore.a -end-group"
diff --git a/perf/Makefile.sources b/perf/Makefile.sources
index b99234b2..1fcf1480 100644
--- a/perf/Makefile.sources
+++ b/perf/Makefile.sources
@@ -1,5 +1,6 @@
libcairoperf_sources = \
- cairo-perf.c \
+ cairo-perf.c \
+ cairo-perf-report.c \
cairo-stats.c \
$(NULL)
diff --git a/perf/cairo-perf-compare-backends.c b/perf/cairo-perf-compare-backends.c
index 16306377..2cbb24c5 100644
--- a/perf/cairo-perf-compare-backends.c
+++ b/perf/cairo-perf-compare-backends.c
@@ -73,7 +73,7 @@ print_change_bar (double change,
double max_change,
int use_utf)
{
- int units_per_cell = (int) ceil (max_change / CHANGE_BAR_WIDTH);
+ int units_per_cell = ceil (max_change / CHANGE_BAR_WIDTH);
static char const *ascii_boxes[8] = {
"****","***" ,"***", "**",
"**", "*", "*", ""
@@ -369,7 +369,7 @@ main (int argc,
if (args.num_filenames) {
reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t));
for (i = 0; i < args.num_filenames; i++) {
- cairo_perf_report_load (&reports[i], args.filenames[i],
+ cairo_perf_report_load (&reports[i], args.filenames[i], i,
test_report_cmp_name);
printf ("loaded: %s, %d tests\n",
args.filenames[i], reports[i].tests_count);
@@ -377,7 +377,7 @@ main (int argc,
} else {
args.num_filenames = 1;
reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t));
- cairo_perf_report_load (&reports[0], NULL, test_report_cmp_name);
+ cairo_perf_report_load (&reports[0], NULL, 0, test_report_cmp_name);
}
cairo_perf_reports_compare (reports, args.num_filenames, &args.options);
diff --git a/perf/cairo-perf-diff-files.c b/perf/cairo-perf-diff-files.c
index 34311b04..08509271 100644
--- a/perf/cairo-perf-diff-files.c
+++ b/perf/cairo-perf-diff-files.c
@@ -161,16 +161,14 @@ test_diff_print_binary (test_diff_t *diff,
else
printf ("%5s %26s", diff->tests[0]->backend, diff->tests[0]->name);
- if (diff->tests[0]->size) {
- printf (" %6.2f (%.2f %4.2f%%) -> %6.2f (%.2f %4.2f%%): %5.2fx ",
- diff->tests[0]->stats.min_ticks / diff->tests[0]->stats.ticks_per_ms,
- diff->tests[0]->stats.median_ticks / diff->tests[0]->stats.ticks_per_ms,
- diff->tests[0]->stats.std_dev * 100,
- diff->tests[1]->stats.min_ticks / diff->tests[1]->stats.ticks_per_ms,
- diff->tests[1]->stats.median_ticks / diff->tests[1]->stats.ticks_per_ms,
- diff->tests[1]->stats.std_dev * 100,
- fabs (diff->change));
- }
+ printf (" %6.2f (%.2f %4.2f%%) -> %6.2f (%.2f %4.2f%%): %5.2fx ",
+ diff->tests[0]->stats.min_ticks / diff->tests[0]->stats.ticks_per_ms,
+ diff->tests[0]->stats.median_ticks / diff->tests[0]->stats.ticks_per_ms,
+ diff->tests[0]->stats.std_dev * 100,
+ diff->tests[1]->stats.min_ticks / diff->tests[1]->stats.ticks_per_ms,
+ diff->tests[1]->stats.median_ticks / diff->tests[1]->stats.ticks_per_ms,
+ diff->tests[1]->stats.std_dev * 100,
+ fabs (diff->change));
if (diff->change > 1.0)
printf ("speedup\n");
@@ -191,24 +189,32 @@ test_diff_print_multi (test_diff_t *diff,
double test_time;
double change;
- printf ("%s (backend: %s-%s, size: %d)\n",
- diff->tests[0]->name,
- diff->tests[0]->backend,
- diff->tests[0]->content,
- diff->tests[0]->size);
+ if (diff->tests[0]->size) {
+ printf ("%s (backend: %s-%s, size: %d)\n",
+ diff->tests[0]->name,
+ diff->tests[0]->backend,
+ diff->tests[0]->content,
+ diff->tests[0]->size);
+ } else {
+ printf ("%s (backend: %s)\n",
+ diff->tests[0]->name,
+ diff->tests[0]->backend);
+ }
for (i = 0; i < diff->num_tests; i++) {
test_time = diff->tests[i]->stats.min_ticks;
if (! options->use_ticks)
test_time /= diff->tests[i]->stats.ticks_per_ms;
change = diff->max / test_time;
- printf ("%8s %6.2f: %5.2fx ",
- diff->tests[i]->configuration,
+ printf ("[%d] %6.2f: %5.2fx ",
+ diff->tests[i]->fileno,
diff->tests[i]->stats.min_ticks / diff->tests[i]->stats.ticks_per_ms,
change);
if (options->print_change_bars)
print_change_bar (change, max_change, options->use_utf);
+ else
+ printf("\n");
}
printf("\n");
@@ -476,8 +482,11 @@ main (int argc,
reports = xmalloc (args.num_filenames * sizeof (cairo_perf_report_t));
- for (i = 0; i < args.num_filenames; i++ )
- cairo_perf_report_load (&reports[i], args.filenames[i], NULL);
+ for (i = 0; i < args.num_filenames; i++ ) {
+ cairo_perf_report_load (&reports[i], args.filenames[i], i, NULL);
+ printf ("[%d] %s\n", i, args.filenames[i]);
+ }
+ printf ("\n");
cairo_perf_reports_compare (reports, args.num_filenames, &args.options);
diff --git a/perf/cairo-perf-micro.c b/perf/cairo-perf-micro.c
index 096986bc..f3c6f8d9 100644
--- a/perf/cairo-perf-micro.c
+++ b/perf/cairo-perf-micro.c
@@ -50,12 +50,13 @@
#define CAIRO_PERF_ITERATIONS_DEFAULT 100
#define CAIRO_PERF_LOW_STD_DEV 0.03
-#define CAIRO_PERF_STABLE_STD_DEV_COUNT 5
-#define CAIRO_PERF_ITERATION_MS_DEFAULT 2000
+#define CAIRO_PERF_STABLE_STD_DEV_COUNT 5
+#define CAIRO_PERF_ITERATION_MS_DEFAULT 2000
#define CAIRO_PERF_ITERATION_MS_FAST 5
typedef struct _cairo_perf_case {
- CAIRO_PERF_DECL (*run);
+ CAIRO_PERF_RUN_DECL (*run);
+ cairo_bool_t (*enabled) (cairo_perf_t *perf);
unsigned int min_size;
unsigned int max_size;
} cairo_perf_case_t;
@@ -251,7 +252,7 @@ cairo_perf_run (cairo_perf_t *perf,
cairo_boilerplate_content (perf->target->content));
else
cairo_save (perf->cr);
- times[i] = perf_func (perf->cr, perf->size, perf->size, loops) / loops;
+ times[i] = perf_func (perf->cr, perf->size, perf->size, loops) ;
if (similar)
cairo_pattern_destroy (cairo_pop_group (perf->cr));
else
@@ -263,7 +264,7 @@ cairo_perf_run (cairo_perf_t *perf,
_content_to_string (perf->target->content, similar),
name, perf->size,
_cairo_time_to_double (_cairo_time_from_s (1.)) / 1000.);
- printf (" %lld", (long long) times[i]);
+ printf (" %lld", (long long) (times[i] / (double) loops));
} else if (! perf->exact_iterations) {
if (i > 0) {
_cairo_stats_compute (&stats, times, i+1);
@@ -287,18 +288,18 @@ cairo_perf_run (cairo_perf_t *perf,
if (count_func != NULL) {
double count = count_func (perf->cr, perf->size, perf->size);
fprintf (perf->summary,
- "%10lld %#8.3f %#8.3f %#5.2f%% %3d: %.2f\n",
- (long long) stats.min_ticks,
- _cairo_time_to_s (stats.min_ticks) * 1000.0,
- _cairo_time_to_s (stats.median_ticks) * 1000.0,
+ "%10lld/%d %#8.3f %#8.3f %#5.2f%% %3d: %.2f\n",
+ (long long) stats.min_ticks, loops,
+ _cairo_time_to_s (stats.min_ticks) * 1000.0 / loops,
+ _cairo_time_to_s (stats.median_ticks) * 1000.0 / loops,
stats.std_dev * 100.0, stats.iterations,
count / _cairo_time_to_s (stats.min_ticks));
} else {
fprintf (perf->summary,
- "%10lld %#8.3f %#8.3f %#5.2f%% %3d\n",
- (long long) stats.min_ticks,
- _cairo_time_to_s (stats.min_ticks) * 1000.0,
- _cairo_time_to_s (stats.median_ticks) * 1000.0,
+ "%10lld/%d %#8.3f %#8.3f %#5.2f%% %3d\n",
+ (long long) stats.min_ticks, loops,
+ _cairo_time_to_s (stats.min_ticks) * 1000.0 / loops,
+ _cairo_time_to_s (stats.median_ticks) * 1000.0 / loops,
stats.std_dev * 100.0, stats.iterations);
}
fflush (perf->summary);
@@ -491,6 +492,9 @@ main (int argc,
for (j = 0; perf_cases[j].run; j++) {
const cairo_perf_case_t *perf_case = &perf_cases[j];
+ if (! perf_case->enabled (&perf))
+ continue;
+
for (perf.size = perf_case->min_size;
perf.size <= perf_case->max_size;
perf.size *= 2)
@@ -536,42 +540,48 @@ main (int argc,
return 0;
}
+#define FUNC(f) f, f##_enabled
const cairo_perf_case_t perf_cases[] = {
- { paint, 64, 512},
- { paint_with_alpha, 64, 512},
- { fill, 64, 512},
- { stroke, 64, 512},
- { text, 64, 512},
- { glyphs, 64, 512},
- { mask, 64, 512},
- { line, 32, 512},
- { curve, 32, 512},
- { disjoint, 64, 512},
- { hatching, 64, 512},
- { tessellate, 100, 100},
- { subimage_copy, 16, 512},
- { hash_table, 16, 16},
- { pattern_create_radial, 16, 16},
- { zrusin, 415, 415},
- { world_map, 800, 800},
- { box_outline, 100, 100},
- { mosaic, 800, 800 },
- { long_lines, 100, 100},
- { unaligned_clip, 100, 100},
- { rectangles, 512, 512},
- { rounded_rectangles, 512, 512},
- { long_dashed_lines, 512, 512},
- { composite_checker, 16, 512},
- { twin, 800, 800},
- { dragon, 1024, 1024 },
- { pythagoras_tree, 768, 768 },
- { intersections, 512, 512 },
- { many_strokes, 32, 512 },
- { wide_strokes, 32, 512 },
- { many_fills, 32, 512 },
- { wide_fills, 32, 512 },
- { many_curves, 32, 512 },
- { spiral, 512, 512 },
- { wave, 500, 500 },
+ { FUNC(pixel), 1, 1 },
+ { FUNC(paint), 64, 512},
+ { FUNC(paint_with_alpha), 64, 512},
+ { FUNC(fill), 64, 512},
+ { FUNC(stroke), 64, 512},
+ { FUNC(text), 64, 512},
+ { FUNC(glyphs), 64, 512},
+ { FUNC(mask), 64, 512},
+ { FUNC(line), 32, 512},
+ { FUNC(a1_line), 32, 512},
+ { FUNC(curve), 32, 512},
+ { FUNC(a1_curve), 32, 512},
+ { FUNC(disjoint), 64, 512},
+ { FUNC(hatching), 64, 512},
+ { FUNC(tessellate), 100, 100},
+ { FUNC(subimage_copy), 16, 512},
+ { FUNC(hash_table), 16, 16},
+ { FUNC(pattern_create_radial), 16, 16},
+ { FUNC(zrusin), 415, 415},
+ { FUNC(world_map), 800, 800},
+ { FUNC(box_outline), 100, 100},
+ { FUNC(mosaic), 800, 800 },
+ { FUNC(long_lines), 100, 100},
+ { FUNC(unaligned_clip), 100, 100},
+ { FUNC(rectangles), 512, 512},
+ { FUNC(rounded_rectangles), 512, 512},
+ { FUNC(long_dashed_lines), 512, 512},
+ { FUNC(composite_checker), 16, 512},
+ { FUNC(twin), 800, 800},
+ { FUNC(dragon), 1024, 1024 },
+ { FUNC(sierpinski), 32, 1024 },
+ { FUNC(pythagoras_tree), 768, 768 },
+ { FUNC(intersections), 512, 512 },
+ { FUNC(many_strokes), 32, 512 },
+ { FUNC(wide_strokes), 32, 512 },
+ { FUNC(many_fills), 32, 512 },
+ { FUNC(wide_fills), 32, 512 },
+ { FUNC(many_curves), 32, 512 },
+ { FUNC(spiral), 512, 512 },
+ { FUNC(wave), 500, 500 },
+ { FUNC(fill_clip), 16, 512 },
{ NULL }
};
diff --git a/perf/cairo-perf-report.c b/perf/cairo-perf-report.c
index fcce0e03..8df78c64 100644
--- a/perf/cairo-perf-report.c
+++ b/perf/cairo-perf-report.c
@@ -110,6 +110,7 @@ do { \
static test_report_status_t
test_report_parse (test_report_t *report,
+ int fileno,
char *line,
char *configuration)
{
@@ -137,6 +138,7 @@ test_report_parse (test_report_t *report,
skip_space ();
+ report->fileno = fileno;
report->configuration = configuration;
parse_string (report->backend);
end = strrchr (report->backend, '.');
@@ -369,7 +371,7 @@ cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report,
void
cairo_perf_report_load (cairo_perf_report_t *report,
- const char *filename,
+ const char *filename, int id,
int (*cmp) (const void *, const void *))
{
FILE *file;
@@ -401,6 +403,7 @@ cairo_perf_report_load (cairo_perf_report_t *report,
report->tests_size = 16;
report->tests = xmalloc (report->tests_size * sizeof (test_report_t));
report->tests_count = 0;
+ report->fileno = id;
if (filename == NULL) {
file = stdin;
@@ -425,7 +428,7 @@ cairo_perf_report_load (cairo_perf_report_t *report,
break;
status = test_report_parse (&report->tests[report->tests_count],
- line, report->configuration);
+ id, line, report->configuration);
if (status == TEST_REPORT_STATUS_ERROR)
fprintf (stderr, "Ignoring unrecognized line %d of %s:\n%s",
line_number, filename, line);
diff --git a/perf/cairo-perf-trace.c b/perf/cairo-perf-trace.c
index 2cef2b14..8e637a7d 100644
--- a/perf/cairo-perf-trace.c
+++ b/perf/cairo-perf-trace.c
@@ -79,7 +79,7 @@ basename_no_ext (char *path)
name = basename (path);
- dot = strchr (name, '.');
+ dot = strrchr (name, '.');
if (dot)
*dot = '\0';
@@ -108,6 +108,7 @@ struct trace {
void *closure;
cairo_surface_t *surface;
cairo_bool_t observe;
+ int tile_size;
};
cairo_bool_t
@@ -132,7 +133,7 @@ cairo_perf_can_run (cairo_perf_t *perf,
return TRUE;
copy = xstrdup (name);
- dot = strchr (copy, '.');
+ dot = strrchr (copy, '.');
if (dot != NULL)
*dot = '\0';
@@ -435,6 +436,7 @@ parse_options (cairo_perf_t *perf,
perf->raw = FALSE;
perf->observe = FALSE;
perf->list_only = FALSE;
+ perf->tile_size = 0;
perf->names = NULL;
perf->num_names = 0;
perf->summary = stdout;
@@ -443,7 +445,7 @@ parse_options (cairo_perf_t *perf,
perf->num_exclude_names = 0;
while (1) {
- c = _cairo_getopt (argc, argv, "i:x:lsrvc");
+ c = _cairo_getopt (argc, argv, "t:i:x:lsrvc");
if (c == -1)
break;
@@ -457,6 +459,14 @@ parse_options (cairo_perf_t *perf,
exit (1);
}
break;
+ case 't':
+ perf->tile_size = strtoul (optarg, &end, 10);
+ if (*end != '\0') {
+ fprintf (stderr, "Invalid argument for -t (not an integer): %s\n",
+ optarg);
+ exit (1);
+ }
+ break;
case 'l':
perf->list_only = TRUE;
break;
@@ -489,6 +499,11 @@ parse_options (cairo_perf_t *perf,
}
}
+ if (perf->observe && perf->tile_size) {
+ fprintf (stderr, "Can't mix observer and tiling. Sorry.\n");
+ exit (1);
+ }
+
if (verbose && perf->summary == NULL)
perf->summary = stderr;
#if HAVE_UNISTD_H
@@ -536,6 +551,79 @@ have_trace_filenames (cairo_perf_t *perf)
}
static void
+_tiling_surface_finish (cairo_surface_t *observer,
+ cairo_surface_t *target,
+ void *closure)
+{
+ struct trace *args = closure;
+ cairo_surface_t *surface;
+ cairo_content_t content;
+ cairo_rectangle_t r;
+ int width, height;
+ int x, y, w, h;
+
+ cairo_recording_surface_get_extents (target, &r);
+ w = r.width;
+ h = r.height;
+
+ content = cairo_surface_get_content (target);
+
+ for (y = 0; y < h; y += args->tile_size) {
+ height = args->tile_size;
+ if (y + height > h)
+ height = h - y;
+
+ for (x = 0; x < w; x += args->tile_size) {
+ cairo_t *cr;
+
+ width = args->tile_size;
+ if (x + width > w)
+ width = w - x;
+
+ /* XXX to correctly observe the playback we would need
+ * to replay the target onto the observer directly.
+ */
+ surface = args->target->create_similar (args->surface,
+ content, width, height);
+
+ cr = cairo_create (surface);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface (cr, target, -x, -y);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ cairo_surface_destroy (surface);
+ }
+ }
+}
+
+static cairo_surface_t *
+_tiling_surface_create (void *closure,
+ cairo_content_t content,
+ double width,
+ double height,
+ long uid)
+{
+ cairo_rectangle_t r;
+ cairo_surface_t *surface, *observer;
+
+ r.x = r.y = 0;
+ r.width = width;
+ r.height = height;
+
+ surface = cairo_recording_surface_create (content, &r);
+ observer = cairo_surface_create_observer (surface,
+ CAIRO_SURFACE_OBSERVER_NORMAL);
+ cairo_surface_destroy (surface);
+
+ cairo_surface_observer_add_finish_callback (observer,
+ _tiling_surface_finish,
+ closure);
+
+ return observer;
+}
+
+static void
cairo_perf_trace (cairo_perf_t *perf,
const cairo_boilerplate_target_t *target,
const char *trace)
@@ -549,7 +637,7 @@ cairo_perf_trace (cairo_perf_t *perf,
char *trace_cpy, *name;
const cairo_script_interpreter_hooks_t hooks = {
&args,
- _similar_surface_create,
+ perf->tile_size ? _tiling_surface_create : _similar_surface_create,
NULL, /* surface_destroy */
_context_create,
NULL, /* context_destroy */
@@ -557,6 +645,7 @@ cairo_perf_trace (cairo_perf_t *perf,
NULL /* copy_page */
};
+ args.tile_size = perf->tile_size;
args.observe = perf->observe;
trace_cpy = xstrdup (trace);
@@ -648,26 +737,30 @@ cairo_perf_trace (cairo_perf_t *perf,
}
cairo_script_interpreter_run (csi, trace);
+ line_no = cairo_script_interpreter_get_line_number (csi);
+
+ /* Finish before querying timings in case we are using an intermediate
+ * target and so need to destroy all surfaces before rendering
+ * commences.
+ */
+ cairo_script_interpreter_finish (csi);
if (perf->observe) {
cairo_device_t *observer = cairo_surface_get_device (args.surface);
- times[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_elapsed (observer));
- paint[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_paint_elapsed (observer));
- mask[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_mask_elapsed (observer));
- stroke[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_stroke_elapsed (observer));
- fill[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_fill_elapsed (observer));
- glyphs[i] = _cairo_time_from_s (1.e9 * cairo_device_observer_glyphs_elapsed (observer));
+ times[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_elapsed (observer));
+ paint[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_paint_elapsed (observer));
+ mask[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_mask_elapsed (observer));
+ stroke[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_stroke_elapsed (observer));
+ fill[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_fill_elapsed (observer));
+ glyphs[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_glyphs_elapsed (observer));
} else {
clear_surface (args.surface); /* queue a write to the sync'ed surface */
cairo_perf_timer_stop ();
times[i] = cairo_perf_timer_elapsed ();
}
- cairo_script_interpreter_finish (csi);
scache_clear ();
- line_no = cairo_script_interpreter_get_line_number (csi);
-
cairo_surface_destroy (args.surface);
if (target->cleanup)
@@ -766,28 +859,28 @@ cairo_perf_trace (cairo_perf_t *perf,
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
- _cairo_stats_compute (&stats, paint, i+1);
+ _cairo_stats_compute (&stats, paint, i);
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
- _cairo_stats_compute (&stats, mask, i+1);
+ _cairo_stats_compute (&stats, mask, i);
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
- _cairo_stats_compute (&stats, fill, i+1);
+ _cairo_stats_compute (&stats, fill, i);
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
- _cairo_stats_compute (&stats, stroke, i+1);
+ _cairo_stats_compute (&stats, stroke, i);
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
- _cairo_stats_compute (&stats, glyphs, i+1);
+ _cairo_stats_compute (&stats, glyphs, i);
fprintf (perf->summary,
" %#9.3f", _cairo_time_to_s (stats.median_ticks));
fprintf (perf->summary,
- " %5d\n", i+1);
+ " %5d\n", i);
} else {
fprintf (perf->summary,
"%#8.3f %#8.3f %#6.2f%% %4d/%d\n",
@@ -807,11 +900,6 @@ out:
perf->test_number++;
free (trace_cpy);
-
- cairo_debug_reset_static_data ();
-#if HAVE_FCFINI
- FcFini ();
-#endif
}
static void
diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h
index 11c03f75..d6a71ccb 100644
--- a/perf/cairo-perf.h
+++ b/perf/cairo-perf.h
@@ -83,6 +83,8 @@ typedef struct _cairo_perf {
double ms_per_iteration;
cairo_bool_t fast_and_sloppy;
+ unsigned int tile_size;
+
/* Stuff used internally */
cairo_time_t *times;
const cairo_boilerplate_target_t **targets;
@@ -121,6 +123,7 @@ cairo_perf_cover_sources_and_operators (cairo_perf_t *perf,
typedef struct _test_report {
int id;
+ int fileno;
const char *configuration;
char *backend;
char *content;
@@ -149,6 +152,7 @@ typedef struct _test_diff {
typedef struct _cairo_perf_report {
char *configuration;
const char *name;
+ int fileno;
test_report_t *tests;
int tests_size;
int tests_count;
@@ -162,7 +166,7 @@ typedef enum {
void
cairo_perf_report_load (cairo_perf_report_t *report,
- const char *filename,
+ const char *filename, int id,
int (*cmp) (const void *, const void *));
void
@@ -177,7 +181,10 @@ int
test_report_cmp_name (const void *a,
const void *b);
-#define CAIRO_PERF_DECL(func) void (func) (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+#define CAIRO_PERF_ENABLED_DECL(func) cairo_bool_t (func ## _enabled) (cairo_perf_t *perf)
+#define CAIRO_PERF_RUN_DECL(func) void (func) (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+
+#define CAIRO_PERF_DECL(func) CAIRO_PERF_RUN_DECL(func); CAIRO_PERF_ENABLED_DECL(func)
CAIRO_PERF_DECL (fill);
CAIRO_PERF_DECL (paint);
@@ -214,6 +221,11 @@ CAIRO_PERF_DECL (many_fills);
CAIRO_PERF_DECL (wide_fills);
CAIRO_PERF_DECL (many_curves);
CAIRO_PERF_DECL (curve);
+CAIRO_PERF_DECL (a1_curve);
CAIRO_PERF_DECL (line);
+CAIRO_PERF_DECL (a1_line);
+CAIRO_PERF_DECL (pixel);
+CAIRO_PERF_DECL (sierpinski);
+CAIRO_PERF_DECL (fill_clip);
#endif
diff --git a/perf/cairo-stats.c b/perf/cairo-stats.c
index e088e198..c422d6cc 100644
--- a/perf/cairo-stats.c
+++ b/perf/cairo-stats.c
@@ -25,16 +25,25 @@
#include "cairo-stats.h"
+#include <assert.h>
+
void
_cairo_stats_compute (cairo_stats_t *stats,
cairo_time_t *values,
int num_values)
{
- int i;
- cairo_time_t sumtime;
- double sum, mean, delta, q1, q3, iqr;
- double outlier_min, outlier_max;
- int min_valid, num_valid;
+ cairo_time_t sum, mean, delta, q1, q3, iqr;
+ cairo_time_t outlier_min, outlier_max;
+ int i, min_valid, num_valid;
+
+ assert (num_values > 0);
+
+ if (num_values == 1) {
+ stats->min_ticks = stats->median_ticks = values[0];
+ stats->std_dev = 0;
+ stats->iterations = 1;
+ return;
+ }
/* First, identify any outliers, using the definition of "mild
* outliers" from:
@@ -48,44 +57,35 @@ _cairo_stats_compute (cairo_stats_t *stats,
*/
qsort (values, num_values, sizeof (cairo_time_t), _cairo_time_cmp);
- q1 = _cairo_time_to_s (values[(1*num_values)/4]);
- q3 = _cairo_time_to_s (values[(3*num_values)/4]);
+ q1 = values[1*num_values/4];
+ q3 = values[3*num_values/4];
+ /* XXX assumes we have native uint64_t */
iqr = q3 - q1;
+ outlier_min = q1 - 3 * iqr / 2;
+ outlier_max = q3 + 3 * iqr / 2;
- outlier_min = _cairo_time_from_s (q1 - 1.5 * iqr);
- outlier_max = _cairo_time_from_s (q3 + 1.5 * iqr);
-
- min_valid = 0;
- while (min_valid < num_values &&
- _cairo_time_to_s (values[min_valid]) < outlier_min)
- {
- min_valid++;
- }
+ for (i = 0; i < num_values && values[i] < outlier_min; i++)
+ ;
+ min_valid = i;
- i = min_valid;
- num_valid = 0;
- while (i + num_valid < num_values &&
- _cairo_time_to_s (values[i+num_valid]) <= outlier_max)
- {
- num_valid++;
- }
+ for (i = 0; i < num_values && values[i] <= outlier_max; i++)
+ ;
+ num_valid = i - min_valid;
+ assert(num_valid);
stats->iterations = num_valid;
stats->min_ticks = values[min_valid];
-
- sumtime = _cairo_time_from_s (0);
- for (i = min_valid; i < min_valid + num_valid; i++) {
- sumtime = _cairo_time_add (sumtime, values[i]);
- stats->min_ticks = _cairo_time_min (stats->min_ticks, values[i]);
- }
-
- mean = _cairo_time_to_s (sumtime) / num_valid;
stats->median_ticks = values[min_valid + num_valid / 2];
- sum = 0.0;
+ sum = 0;
+ for (i = min_valid; i < min_valid + num_valid; i++)
+ sum = _cairo_time_add (sum, values[i]);
+ mean = sum / num_valid;
+
+ sum = 0;
for (i = min_valid; i < min_valid + num_valid; i++) {
- delta = _cairo_time_to_s (values[i]) - mean;
+ delta = values[i] - mean;
sum += delta * delta;
}
diff --git a/perf/micro/Makefile.sources b/perf/micro/Makefile.sources
index 0c2bca08..e72d44ad 100644
--- a/perf/micro/Makefile.sources
+++ b/perf/micro/Makefile.sources
@@ -7,6 +7,7 @@ libcairo_perf_micro_sources = \
hatching.c \
hash-table.c \
line.c \
+ a1-line.c \
long-lines.c \
mosaic.c \
paint.c \
@@ -35,7 +36,11 @@ libcairo_perf_micro_sources = \
wide-fills.c \
many-curves.c \
curve.c \
+ a1-curve.c \
spiral.c \
+ pixel.c \
+ sierpinski.c \
+ fill-clip.c \
$(NULL)
libcairo_perf_micro_headers = \
diff --git a/perf/micro/a1-curve.c b/perf/micro/a1-curve.c
new file mode 100644
index 00000000..594c46d5
--- /dev/null
+++ b/perf/micro/a1-curve.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-perf.h"
+
+static uint32_t state;
+
+static double
+uniform_random (double minval, double maxval)
+{
+ static uint32_t const poly = 0x9a795537U;
+ uint32_t n = 32;
+ while (n-->0)
+ state = 2*state < state ? (2*state ^ poly) : 2*state;
+ return minval + state * (maxval - minval) / 4294967296.0;
+}
+
+static cairo_time_t
+do_curve_stroke (cairo_t *cr, int width, int height, int loops)
+{
+ state = 0xc0ffee;
+ cairo_set_line_width (cr, 2.);
+ cairo_perf_timer_start ();
+
+ while (loops--) {
+ double x1 = uniform_random (0, width);
+ double x2 = uniform_random (0, width);
+ double x3 = uniform_random (0, width);
+ double y1 = uniform_random (0, height);
+ double y2 = uniform_random (0, height);
+ double y3 = uniform_random (0, height);
+ cairo_move_to (cr, uniform_random (0, width), uniform_random (0, height));
+ cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
+ cairo_stroke(cr);
+ }
+
+ cairo_perf_timer_stop ();
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+do_curve_fill (cairo_t *cr, int width, int height, int loops)
+{
+ state = 0xc0ffee;
+ cairo_perf_timer_start ();
+
+ while (loops--) {
+ double x0 = uniform_random (0, width);
+ double x1 = uniform_random (0, width);
+ double x2 = uniform_random (0, width);
+ double x3 = uniform_random (0, width);
+ double xm = uniform_random (0, width);
+ double xn = uniform_random (0, width);
+ double y0 = uniform_random (0, height);
+ double y1 = uniform_random (0, height);
+ double y2 = uniform_random (0, height);
+ double y3 = uniform_random (0, height);
+ double ym = uniform_random (0, height);
+ double yn = uniform_random (0, height);
+
+ cairo_move_to (cr, xm, ym);
+ cairo_curve_to (cr, x1, y1, x2, y2, xn, yn);
+ cairo_curve_to (cr, x3, y3, x0, y0, xm, ym);
+ cairo_close_path (cr);
+
+ cairo_fill(cr);
+ }
+
+ cairo_perf_timer_stop ();
+
+ return cairo_perf_timer_elapsed ();
+}
+
+cairo_bool_t
+a1_curve_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "a1-curve", NULL);
+}
+
+void
+a1_curve (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+ cairo_set_source_rgb (cr, 1., 1., 1.);
+ cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+
+ cairo_perf_run (perf, "a1-curve-stroked", do_curve_stroke, NULL);
+ cairo_perf_run (perf, "a1-curve-filled", do_curve_fill, NULL);
+}
diff --git a/perf/micro/a1-line.c b/perf/micro/a1-line.c
new file mode 100644
index 00000000..ae866021
--- /dev/null
+++ b/perf/micro/a1-line.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-perf.h"
+
+static cairo_time_t
+horizontal (cairo_t *cr, int width, int height, int loops)
+{
+ double h = height/2 + .5;
+
+ cairo_move_to (cr, 0, h);
+ cairo_line_to (cr, width, h);
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_stroke_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+horizontal_hair (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_line_width (cr, 1.);
+ return horizontal (cr, width, height, loops);
+}
+
+static cairo_time_t
+horizontal_wide (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_line_width (cr, 5.);
+ return horizontal (cr, width, height, loops);
+}
+
+static cairo_time_t
+nearly_horizontal (cairo_t *cr, int width, int height, int loops)
+{
+ double h = height/2;
+
+ cairo_move_to (cr, 0, h);
+ cairo_line_to (cr, width, h+1);
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_stroke_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+nearly_horizontal_hair (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_line_width (cr, 1.);
+ return nearly_horizontal (cr, width, height, loops);
+}
+
+static cairo_time_t
+nearly_horizontal_wide (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_line_width (cr, 5.);
+ return nearly_horizontal (cr, width, height, loops);
+}
+
+
+static cairo_time_t
+vertical (cairo_t *cr, int width, int height, int loops)
+{
+ double w = width/2 + .5;
+
+ cairo_move_to (cr, w, 0);
+ cairo_line_to (cr, w, height);
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_stroke_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+vertical_hair (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_line_width (cr, 1.);
+ return vertical (cr, width, height, loops);
+}
+
+static cairo_time_t
+vertical_wide (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_line_width (cr, 5.);
+ return vertical (cr, width, height, loops);
+}
+
+static cairo_time_t
+nearly_vertical (cairo_t *cr, int width, int height, int loops)
+{
+ double w = width/2;
+
+ cairo_move_to (cr, w, 0);
+ cairo_line_to (cr, w+1, height);
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_stroke_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+nearly_vertical_hair (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_line_width (cr, 1.);
+ return nearly_vertical (cr, width, height, loops);
+}
+
+static cairo_time_t
+nearly_vertical_wide (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_line_width (cr, 5.);
+ return nearly_vertical (cr, width, height, loops);
+}
+
+
+static cairo_time_t
+diagonal (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, width, height);
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_stroke_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+diagonal_hair (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_line_width (cr, 1.);
+ return diagonal (cr, width, height, loops);
+}
+
+static cairo_time_t
+diagonal_wide (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_line_width (cr, 5.);
+ return diagonal (cr, width, height, loops);
+}
+
+cairo_bool_t
+a1_line_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "a1-line", NULL);
+}
+
+void
+a1_line (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+ cairo_set_source_rgb (cr, 1., 1., 1.);
+ cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+
+ cairo_perf_run (perf, "a1-line-hh", horizontal_hair, NULL);
+ cairo_perf_run (perf, "a1-line-hw", horizontal_wide, NULL);
+ cairo_perf_run (perf, "a1-line-nhh", nearly_horizontal_hair, NULL);
+ cairo_perf_run (perf, "a1-line-nhw", nearly_horizontal_wide, NULL);
+
+ cairo_perf_run (perf, "a1-line-vh", vertical_hair, NULL);
+ cairo_perf_run (perf, "a1-line-vw", vertical_wide, NULL);
+ cairo_perf_run (perf, "a1-line-nvh", nearly_vertical_hair, NULL);
+ cairo_perf_run (perf, "a1-line-nvw", nearly_vertical_wide, NULL);
+
+ cairo_perf_run (perf, "a1-line-dh", diagonal_hair, NULL);
+ cairo_perf_run (perf, "a1-line-dw", diagonal_wide, NULL);
+}
diff --git a/perf/micro/box-outline.c b/perf/micro/box-outline.c
index a0c47f77..1e654eb9 100644
--- a/perf/micro/box-outline.c
+++ b/perf/micro/box-outline.c
@@ -65,6 +65,55 @@ box_outline_stroke (cairo_t *cr, int width, int height, int loops)
}
static cairo_time_t
+box_outline_alpha_stroke (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
+ cairo_paint (cr);
+
+ cairo_rectangle (cr,
+ 1.5, 1.5,
+ width - 3, height - 3);
+ cairo_set_line_width (cr, 1.0);
+ cairo_set_source_rgba (cr, 1, 0, 0, .5); /* red */
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_stroke_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+box_outline_aa_stroke (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
+ cairo_paint (cr);
+
+ cairo_translate (cr, .5, .5);
+ cairo_rectangle (cr,
+ 1.5, 1.5,
+ width - 3, height - 3);
+ cairo_set_line_width (cr, 1.0);
+ cairo_set_source_rgb (cr, 1, 0, 0); /* red */
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_stroke_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
box_outline_fill (cairo_t *cr, int width, int height, int loops)
{
cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
@@ -91,12 +140,76 @@ box_outline_fill (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+static cairo_time_t
+box_outline_alpha_fill (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
+ cairo_paint (cr);
+
+ cairo_rectangle (cr,
+ 1.0, 1.0,
+ width - 2, height - 2);
+ cairo_rectangle (cr,
+ 2.0, 2.0,
+ width - 4, height - 4);
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_source_rgba (cr, 0, 1, 0, .5); /* green */
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_fill_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+box_outline_aa_fill (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
+ cairo_paint (cr);
+
+ cairo_translate (cr, .5, .5);
+ cairo_rectangle (cr,
+ 1.0, 1.0,
+ width - 2, height - 2);
+ cairo_rectangle (cr,
+ 2.0, 2.0,
+ width - 4, height - 4);
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_source_rgb (cr, 0, 1, 0); /* green */
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_fill_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+cairo_bool_t
+box_outline_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "box-outline", NULL);
+}
+
void
box_outline (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "box-outline", NULL))
- return;
-
cairo_perf_run (perf, "box-outline-stroke", box_outline_stroke, NULL);
cairo_perf_run (perf, "box-outline-fill", box_outline_fill, NULL);
+
+ cairo_perf_run (perf, "box-outline-alpha-stroke", box_outline_alpha_stroke, NULL);
+ cairo_perf_run (perf, "box-outline-alpha-fill", box_outline_alpha_fill, NULL);
+
+ cairo_perf_run (perf, "box-outline-aa-stroke", box_outline_aa_stroke, NULL);
+ cairo_perf_run (perf, "box-outline-aa-fill", box_outline_aa_fill, NULL);
}
diff --git a/perf/micro/composite-checker.c b/perf/micro/composite-checker.c
index 0d7af0c8..d6d17ab6 100644
--- a/perf/micro/composite-checker.c
+++ b/perf/micro/composite-checker.c
@@ -75,6 +75,12 @@ do_composite_checker (cairo_t *cr,
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+composite_checker_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "composite-checker", NULL);
+}
+
void
composite_checker (cairo_perf_t *perf,
cairo_t *cr,
@@ -83,9 +89,6 @@ composite_checker (cairo_perf_t *perf,
{
cairo_surface_t *image;
- if (! cairo_perf_can_run (perf, "composite-checker", NULL))
- return;
-
/* Create the checker pattern. We don't actually need to draw
* anything on it since that wouldn't affect performance.
*/
diff --git a/perf/micro/curve.c b/perf/micro/curve.c
index 7def326e..3b5a1634 100644
--- a/perf/micro/curve.c
+++ b/perf/micro/curve.c
@@ -95,12 +95,15 @@ do_curve_fill (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+curve_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "curve", NULL);
+}
+
void
curve (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "curve", NULL))
- return;
-
cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_perf_run (perf, "curve-stroked", do_curve_stroke, NULL);
diff --git a/perf/micro/disjoint.c b/perf/micro/disjoint.c
index d7f50260..623eb6f4 100644
--- a/perf/micro/disjoint.c
+++ b/perf/micro/disjoint.c
@@ -85,6 +85,12 @@ draw (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+disjoint_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "disjoint", NULL);
+}
+
void
disjoint (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
diff --git a/perf/micro/dragon.c b/perf/micro/dragon.c
index 5bc8d26f..e215eacc 100644
--- a/perf/micro/dragon.c
+++ b/perf/micro/dragon.c
@@ -265,12 +265,15 @@ do_dragon_solid_circle_clip (cairo_t *cr, int width, int height, int loops)
return do_dragon_solid (cr, width, height, loops);
}
+cairo_bool_t
+dragon_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "dragon", NULL);
+}
+
void
dragon (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "dragon", NULL))
- return;
-
cairo_perf_run (perf, "dragon-solid", do_dragon_solid, NULL);
cairo_perf_run (perf, "dragon-unaligned-solid", do_dragon_solid_unaligned, NULL);
cairo_perf_run (perf, "dragon-solid-aligned-clip", do_dragon_solid_aligned_clip, NULL);
diff --git a/perf/micro/fill-clip.c b/perf/micro/fill-clip.c
new file mode 100644
index 00000000..2d014aca
--- /dev/null
+++ b/perf/micro/fill-clip.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/* Compares the overhead for WebKit's drawRect() */
+
+#include "cairo-perf.h"
+
+#include <pixman.h>
+
+static cairo_time_t
+clip_paint (cairo_t *cr, int width, int height, int loops)
+{
+ int x = width/4, w = width/2;
+ int y = height/4, h = height/2;
+
+ cairo_perf_timer_start ();
+
+ while (loops--) {
+ cairo_reset_clip (cr);
+ cairo_rectangle (cr, x, y, w, h);
+ cairo_clip (cr);
+ cairo_paint (cr);
+ }
+
+ cairo_perf_timer_stop ();
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+rect_fill (cairo_t *cr, int width, int height, int loops)
+{
+ int x = width/4, w = width/2;
+ int y = height/4, h = height/2;
+
+ cairo_perf_timer_start ();
+
+ while (loops--) {
+ cairo_rectangle (cr, x, y, w, h);
+ cairo_fill (cr);
+ }
+
+ cairo_perf_timer_stop ();
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+direct (cairo_t *cr, int width, int height, int loops)
+{
+ int x = width/4, w = width/2;
+ int y = height/4, h = height/2;
+ cairo_surface_t *surface, *image;
+ uint8_t *data;
+ int stride, bpp;
+
+
+ surface = cairo_get_target (cr);
+ image = cairo_surface_map_to_image (surface, NULL);
+ data = cairo_image_surface_get_data (image);
+ stride = cairo_image_surface_get_stride (image);
+
+ switch (cairo_image_surface_get_format (image)) {
+ default:
+ case CAIRO_FORMAT_INVALID:
+ case CAIRO_FORMAT_A1: bpp = 0; break;
+ case CAIRO_FORMAT_A8: bpp = 8; break;
+ case CAIRO_FORMAT_RGB16_565: bpp = 16; break;
+ case CAIRO_FORMAT_RGB24:
+ case CAIRO_FORMAT_RGB30:
+ case CAIRO_FORMAT_ARGB32: bpp = 32; break;
+ }
+
+ cairo_perf_timer_start ();
+
+ while (loops--) {
+ pixman_fill ((uint32_t *)data, stride / sizeof(uint32_t), bpp,
+ x, y, w, h,
+ -1);
+ }
+
+ cairo_perf_timer_stop ();
+
+ cairo_surface_unmap_image (surface, image);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+cairo_bool_t
+fill_clip_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "fillclip", NULL);
+}
+
+void
+fill_clip (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+ cairo_set_source_rgb (cr, 1., 1., 1.);
+
+ cairo_perf_run (perf, "fillclip-clip", clip_paint, NULL);
+ cairo_perf_run (perf, "fillclip-fill", rect_fill, NULL);
+ cairo_perf_run (perf, "fillclip-direct", direct, NULL);
+}
diff --git a/perf/micro/fill.c b/perf/micro/fill.c
index 07952271..d356c26d 100644
--- a/perf/micro/fill.c
+++ b/perf/micro/fill.c
@@ -107,12 +107,15 @@ do_fill_eo_noaa (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+fill_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "fill", NULL);
+}
+
void
fill (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "fill", NULL))
- return;
-
cairo_perf_cover_sources_and_operators (perf, "fill", do_fill, NULL);
cairo_perf_cover_sources_and_operators (perf, "fill-annuli", do_fill_annuli, NULL);
cairo_perf_cover_sources_and_operators (perf, "fill-eo-noaa", do_fill_eo_noaa, NULL);
diff --git a/perf/micro/glyphs.c b/perf/micro/glyphs.c
index 74c67eee..5f088b29 100644
--- a/perf/micro/glyphs.c
+++ b/perf/micro/glyphs.c
@@ -170,12 +170,15 @@ DECL(48ca, 48, CAIRO_ANTIALIAS_SUBPIXEL)
DECL(8mono, 8, CAIRO_ANTIALIAS_NONE)
DECL(48mono, 48, CAIRO_ANTIALIAS_NONE)
+cairo_bool_t
+glyphs_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "glyphs", NULL);
+}
+
void
glyphs (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "glyphs", NULL))
- return;
-
cairo_perf_cover_sources_and_operators (perf, "glyphs8mono", do_glyphs8mono, count_glyphs8mono);
cairo_perf_cover_sources_and_operators (perf, "glyphs8", do_glyphs8, count_glyphs8);
cairo_perf_cover_sources_and_operators (perf, "glyphs8ca", do_glyphs8ca, count_glyphs8ca);
diff --git a/perf/micro/hash-table.c b/perf/micro/hash-table.c
index a0266381..d1629177 100644
--- a/perf/micro/hash-table.c
+++ b/perf/micro/hash-table.c
@@ -101,12 +101,15 @@ do_hash_table (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+hash_table_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "hash-table", NULL);
+}
+
void
hash_table (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "hash-table", NULL))
- return;
-
cairo_perf_cover_sources_and_operators (perf, "hash-table",
do_hash_table, NULL);
}
diff --git a/perf/micro/hatching.c b/perf/micro/hatching.c
index e31d3010..b51acec5 100644
--- a/perf/micro/hatching.c
+++ b/perf/micro/hatching.c
@@ -170,12 +170,15 @@ F(clip_alpha_aligned_mono, clip_alpha, aligned, mono)
F(clip_alpha_misaligned_mono, clip_alpha, misaligned, mono)
F(clip_alpha_rotated_mono, clip_alpha, rotated, mono)
+cairo_bool_t
+hatching_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "hatching", NULL);
+}
+
void
hatching (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "hatching", NULL))
- return;
-
cairo_perf_run (perf, "hatching-aligned-aa", draw_aligned_aa, NULL);
cairo_perf_run (perf, "hatching-misaligned-aa", draw_misaligned_aa, NULL);
cairo_perf_run (perf, "hatching-rotated-aa", draw_rotated_aa, NULL);
diff --git a/perf/micro/intersections.c b/perf/micro/intersections.c
index 9a81eee8..57931faf 100644
--- a/perf/micro/intersections.c
+++ b/perf/micro/intersections.c
@@ -143,12 +143,15 @@ random_curve_nz (cairo_t *cr, int width, int height, int loops)
return draw_random_curve (cr, CAIRO_FILL_RULE_WINDING, width, height, loops);
}
+cairo_bool_t
+intersections_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "intersections", NULL);
+}
+
void
intersections (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "intersections", NULL))
- return;
-
cairo_perf_run (perf, "intersections-nz-fill", random_nz, NULL);
cairo_perf_run (perf, "intersections-eo-fill", random_eo, NULL);
diff --git a/perf/micro/line.c b/perf/micro/line.c
index 7ba9f904..3ed5f8da 100644
--- a/perf/micro/line.c
+++ b/perf/micro/line.c
@@ -196,12 +196,15 @@ diagonal_wide (cairo_t *cr, int width, int height, int loops)
return diagonal (cr, width, height, loops);
}
+cairo_bool_t
+line_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "line", NULL);
+}
+
void
line (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "line", NULL))
- return;
-
cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_perf_run (perf, "line-hh", horizontal_hair, NULL);
diff --git a/perf/micro/long-dashed-lines.c b/perf/micro/long-dashed-lines.c
index fa99b200..ba66a4af 100644
--- a/perf/micro/long-dashed-lines.c
+++ b/perf/micro/long-dashed-lines.c
@@ -61,11 +61,14 @@ do_long_dashed_lines (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+long_dashed_lines_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "long-dashed-lines", NULL);
+}
+
void
long_dashed_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "long-dashed-lines", NULL))
- return;
-
cairo_perf_run (perf, "long-dashed-lines", do_long_dashed_lines, NULL);
}
diff --git a/perf/micro/long-lines.c b/perf/micro/long-lines.c
index b3a94585..a0d134c2 100644
--- a/perf/micro/long-lines.c
+++ b/perf/micro/long-lines.c
@@ -132,12 +132,15 @@ long_lines_cropped_once (cairo_t *cr, int width, int height, int loops)
return do_long_lines (cr, width, height, loops, LONG_LINES_CROPPED | LONG_LINES_ONCE);
}
+cairo_bool_t
+long_lines_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "long-lines", NULL);
+}
+
void
long_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "long-lines", NULL))
- return;
-
cairo_perf_run (perf, "long-lines-uncropped", long_lines_uncropped, NULL);
cairo_perf_run (perf, "long-lines-uncropped-once", long_lines_uncropped_once, NULL);
cairo_perf_run (perf, "long-lines-cropped", long_lines_cropped, NULL);
diff --git a/perf/micro/many-curves.c b/perf/micro/many-curves.c
index dc7cdf9f..f985d349 100644
--- a/perf/micro/many-curves.c
+++ b/perf/micro/many-curves.c
@@ -118,12 +118,15 @@ do_many_curves_filled (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+many_curves_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "many-curves", NULL);
+}
+
void
many_curves (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "many-curves", NULL))
- return;
-
cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_perf_run (perf, "many-curves-hair-stroked", do_many_curves_hair_stroked, NULL);
diff --git a/perf/micro/many-fills.c b/perf/micro/many-fills.c
index eb56e8b9..9d3fd643 100644
--- a/perf/micro/many-fills.c
+++ b/perf/micro/many-fills.c
@@ -170,12 +170,15 @@ do_many_fills (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+many_fills_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "many-fills", NULL);
+}
+
void
many_fills (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "many-fills", NULL))
- return;
-
cairo_perf_run (perf, "many-fills-halign", do_many_fills_ha, NULL);
cairo_perf_run (perf, "many-fills-valign", do_many_fills_va, NULL);
cairo_perf_run (perf, "many-fills-horizontal", do_many_fills_h, NULL);
diff --git a/perf/micro/many-strokes.c b/perf/micro/many-strokes.c
index f0339457..9aeb393d 100644
--- a/perf/micro/many-strokes.c
+++ b/perf/micro/many-strokes.c
@@ -45,7 +45,7 @@ do_many_strokes_ha (cairo_t *cr, int width, int height, int loops)
state = 0xc0ffee;
for (count = 0; count < 1000; count++) {
- double h = floor (uniform_random (0, height));
+ double h = floor (uniform_random (0, height)) + .5;
cairo_move_to (cr, floor (uniform_random (0, width)), h);
cairo_line_to (cr, ceil (uniform_random (0, width)), h);
}
@@ -97,7 +97,7 @@ do_many_strokes_va (cairo_t *cr, int width, int height, int loops)
state = 0xc0ffee;
for (count = 0; count < 1000; count++) {
- double v = floor (uniform_random (0, width));
+ double v = floor (uniform_random (0, width)) + .5;
cairo_move_to (cr, v, floor (uniform_random (0, height)));
cairo_line_to (cr, v, ceil (uniform_random (0, height)));
}
@@ -169,12 +169,15 @@ do_many_strokes (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+many_strokes_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "many-strokes", NULL);
+}
+
void
many_strokes (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "many-strokes", NULL))
- return;
-
cairo_perf_run (perf, "many-strokes-halign", do_many_strokes_ha, NULL);
cairo_perf_run (perf, "many-strokes-valign", do_many_strokes_va, NULL);
cairo_perf_run (perf, "many-strokes-horizontal", do_many_strokes_h, NULL);
diff --git a/perf/micro/mask.c b/perf/micro/mask.c
index 79092e85..11a3ba73 100644
--- a/perf/micro/mask.c
+++ b/perf/micro/mask.c
@@ -272,6 +272,12 @@ do_mask_radial (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+mask_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "mask", NULL);
+}
+
void
mask (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
diff --git a/perf/micro/mosaic.c b/perf/micro/mosaic.c
index d76b8400..ed30ae55 100644
--- a/perf/micro/mosaic.c
+++ b/perf/micro/mosaic.c
@@ -160,12 +160,15 @@ mosaic_tessellate_curves (cairo_t *cr, int width, int height, int loops)
return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_CURVE_TO, width, height, loops);
}
+cairo_bool_t
+mosaic_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "mosaic", NULL);
+}
+
void
mosaic (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "mosaic", NULL))
- return;
-
cairo_perf_run (perf, "mosaic-fill-curves", mosaic_fill_curves, NULL);
cairo_perf_run (perf, "mosaic-fill-lines", mosaic_fill_lines, NULL);
cairo_perf_run (perf, "mosaic-tessellate-curves", mosaic_tessellate_curves, NULL);
diff --git a/perf/micro/paint-with-alpha.c b/perf/micro/paint-with-alpha.c
index 3c1f69ee..047e35c4 100644
--- a/perf/micro/paint-with-alpha.c
+++ b/perf/micro/paint-with-alpha.c
@@ -44,12 +44,15 @@ count_paint_with_alpha (cairo_t *cr, int width, int height)
return width * height / 1e6; /* Mpix/s */
}
+cairo_bool_t
+paint_with_alpha_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "paint-with-alpha", NULL);
+}
+
void
paint_with_alpha (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "paint-with-alpha", NULL))
- return;
-
cairo_perf_cover_sources_and_operators (perf, "paint-with-alpha",
do_paint_with_alpha,
count_paint_with_alpha);
diff --git a/perf/micro/paint.c b/perf/micro/paint.c
index dc7e0a0f..2a59a45e 100644
--- a/perf/micro/paint.c
+++ b/perf/micro/paint.c
@@ -44,11 +44,14 @@ count_paint (cairo_t *cr, int width, int height)
return width * height / 1e6; /* Mpix/s */
}
+cairo_bool_t
+paint_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "paint", NULL);
+}
+
void
paint (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "paint", NULL))
- return;
-
cairo_perf_cover_sources_and_operators (perf, "paint", do_paint, count_paint);
}
diff --git a/perf/micro/pattern_create_radial.c b/perf/micro/pattern_create_radial.c
index 13260bb5..f236ef54 100644
--- a/perf/micro/pattern_create_radial.c
+++ b/perf/micro/pattern_create_radial.c
@@ -79,14 +79,17 @@ do_pattern_create_radial (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+pattern_create_radial_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "pattern-create-radial", NULL);
+}
+
void
pattern_create_radial (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
int i;
- if (! cairo_perf_can_run (perf, "pattern-create-radial", NULL))
- return;
-
srand (time (0));
for (i = 0; i < RADIALS_COUNT; i++)
{
diff --git a/perf/micro/pixel.c b/perf/micro/pixel.c
new file mode 100644
index 00000000..12b8f47b
--- /dev/null
+++ b/perf/micro/pixel.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/* Measure the overhead in setting a single pixel */
+
+#include "cairo-perf.h"
+
+static cairo_time_t
+pixel_paint (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_paint (cr);
+
+ cairo_perf_timer_stop ();
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_mask (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_surface_t *mask;
+ cairo_t *cr2;
+
+ mask = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_ALPHA,
+ 1, 1);
+ cr2 = cairo_create (mask);
+ cairo_set_source_rgb (cr2, 1,1,1);
+ cairo_paint (cr2);
+ cairo_destroy (cr2);
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_mask_surface (cr, mask, 0, 0);
+
+ cairo_perf_timer_stop ();
+
+ cairo_surface_destroy (mask);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_rectangle (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_new_path (cr);
+ cairo_rectangle (cr, 0, 0, 1, 1);
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_fill_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_subrectangle (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_new_path (cr);
+ cairo_rectangle (cr, 0.1, 0.1, .8, .8);
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_fill_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_triangle (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_new_path (cr);
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, 1, 1);
+ cairo_line_to (cr, 0, 1);
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_fill_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_circle (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_new_path (cr);
+ cairo_arc (cr, 0.5, 0.5, 0.5, 0, 2 * M_PI);
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_fill_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_time_t
+pixel_stroke (cairo_t *cr, int width, int height, int loops)
+{
+ cairo_set_line_width (cr, 1.);
+ cairo_new_path (cr);
+ cairo_move_to (cr, 0, 0.5);
+ cairo_line_to (cr, 1, 0.5);
+
+ cairo_perf_timer_start ();
+
+ while (loops--)
+ cairo_stroke_preserve (cr);
+
+ cairo_perf_timer_stop ();
+
+ cairo_new_path (cr);
+ return cairo_perf_timer_elapsed ();
+}
+
+cairo_bool_t
+pixel_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "pixel", NULL);
+}
+
+void
+pixel (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+ cairo_set_source_rgb (cr, 1., 1., 1.);
+
+ cairo_perf_run (perf, "pixel-paint", pixel_paint, NULL);
+ cairo_perf_run (perf, "pixel-mask", pixel_mask, NULL);
+ cairo_perf_run (perf, "pixel-rectangle", pixel_rectangle, NULL);
+ cairo_perf_run (perf, "pixel-subrectangle", pixel_subrectangle, NULL);
+ cairo_perf_run (perf, "pixel-triangle", pixel_triangle, NULL);
+ cairo_perf_run (perf, "pixel-circle", pixel_circle, NULL);
+ cairo_perf_run (perf, "pixel-stroke", pixel_stroke, NULL);
+}
diff --git a/perf/micro/pythagoras-tree.c b/perf/micro/pythagoras-tree.c
index 6e823a8f..9d3ca115 100644
--- a/perf/micro/pythagoras-tree.c
+++ b/perf/micro/pythagoras-tree.c
@@ -82,11 +82,14 @@ do_pythagoras_tree (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+pythagoras_tree_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "pythagoras-tree", NULL);
+}
+
void
pythagoras_tree (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "pythagoras-tree", NULL))
- return;
-
cairo_perf_run (perf, "pythagoras-tree", do_pythagoras_tree, NULL);
}
diff --git a/perf/micro/rectangles.c b/perf/micro/rectangles.c
index 891572b6..9228a4ef 100644
--- a/perf/micro/rectangles.c
+++ b/perf/micro/rectangles.c
@@ -95,14 +95,17 @@ do_rectangle (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+rectangles_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "rectangles", NULL);
+}
+
void
rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
int i;
- if (! cairo_perf_can_run (perf, "rectangles", NULL))
- return;
-
srand (8478232);
for (i = 0; i < RECTANGLE_COUNT; i++)
{
diff --git a/perf/micro/rounded-rectangles.c b/perf/micro/rounded-rectangles.c
index 59852492..1e432dd1 100644
--- a/perf/micro/rounded-rectangles.c
+++ b/perf/micro/rounded-rectangles.c
@@ -119,14 +119,17 @@ do_rectangles_once (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+rounded_rectangles_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "rounded-rectangles", NULL);
+}
+
void
rounded_rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
int i;
- if (! cairo_perf_can_run (perf, "rounded-rectangles", NULL))
- return;
-
srand (8478232);
for (i = 0; i < RECTANGLE_COUNT; i++) {
rects[i].x = rand () % width;
diff --git a/perf/micro/sierpinski.c b/perf/micro/sierpinski.c
new file mode 100644
index 00000000..c6f5fadc
--- /dev/null
+++ b/perf/micro/sierpinski.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-perf.h"
+
+static const double m_1_sqrt_3 = 0.577359269;
+
+static void
+T (cairo_t *cr, int size)
+{
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, size, 0);
+ cairo_line_to (cr, size/2, size*m_1_sqrt_3);
+
+ size /= 2;
+ if (size >= 4) {
+ T (cr, size);
+ cairo_save (cr); {
+ cairo_translate (cr, size, 0);
+ T (cr, size);
+ } cairo_restore (cr);
+ cairo_save (cr); {
+ cairo_translate (cr, size/2, size*m_1_sqrt_3);
+ T (cr, size);
+ } cairo_restore (cr);
+ }
+}
+
+static cairo_time_t
+draw (cairo_t *cr, int width, int height, int loops)
+{
+ int t_height = height/2;
+ int t_width = t_height / m_1_sqrt_3;
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_set_line_width (cr, 1.);
+
+ cairo_perf_timer_start ();
+
+ while (loops--) {
+ cairo_save (cr);
+ T (cr, t_width);
+
+ cairo_translate (cr, 0, height);
+ cairo_scale (cr, 1, -1);
+
+ T (cr, t_width);
+
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
+
+ cairo_perf_timer_stop ();
+
+ return cairo_perf_timer_elapsed ();
+}
+
+cairo_bool_t
+sierpinski_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "sierpinski", NULL);
+}
+
+void
+sierpinski (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+ cairo_perf_run (perf, "sierpinski", draw, NULL);
+}
diff --git a/perf/micro/spiral.c b/perf/micro/spiral.c
index 85d05801..87dbcb52 100644
--- a/perf/micro/spiral.c
+++ b/perf/micro/spiral.c
@@ -326,12 +326,15 @@ draw_spiral_stroke_na (cairo_t *cr, int width, int height, int loops)
width, height, loops);
}
+cairo_bool_t
+spiral_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "spiral", NULL);
+}
+
void
spiral (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "spiral", NULL))
- return;
-
cairo_perf_run (perf, "spiral-box-nonalign-evenodd-fill", draw_spiral_eo_na_box, NULL);
cairo_perf_run (perf, "spiral-box-nonalign-nonzero-fill", draw_spiral_nz_na_box, NULL);
cairo_perf_run (perf, "spiral-box-pixalign-evenodd-fill", draw_spiral_eo_pa_box, NULL);
diff --git a/perf/micro/stroke.c b/perf/micro/stroke.c
index 8d7dc527..4b295477 100644
--- a/perf/micro/stroke.c
+++ b/perf/micro/stroke.c
@@ -86,12 +86,15 @@ do_strokes (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+stroke_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "stroke", NULL);
+}
+
void
stroke (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "stroke", NULL))
- return;
-
cairo_perf_cover_sources_and_operators (perf, "stroke", do_stroke, NULL);
cairo_perf_cover_sources_and_operators (perf, "strokes", do_strokes, NULL);
}
diff --git a/perf/micro/subimage_copy.c b/perf/micro/subimage_copy.c
index eb04154a..e749c062 100644
--- a/perf/micro/subimage_copy.c
+++ b/perf/micro/subimage_copy.c
@@ -52,15 +52,18 @@ do_subimage_copy (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+subimage_copy_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "subimage-copy", NULL);
+}
+
void
subimage_copy (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
cairo_surface_t *image;
cairo_t *cr2;
- if (! cairo_perf_can_run (perf, "subimage-copy", NULL))
- return;
-
cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
cairo_paint (cr);
diff --git a/perf/micro/tessellate.c b/perf/micro/tessellate.c
index 38c8b86f..b6277fe6 100644
--- a/perf/micro/tessellate.c
+++ b/perf/micro/tessellate.c
@@ -141,12 +141,15 @@ tessellate_256 (cairo_t *cr, int width, int height, int loops)
return do_tessellate (cr, 256, loops);
}
+cairo_bool_t
+tessellate_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "tessellate", NULL);
+}
+
void
tessellate (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "tessellate", NULL))
- return;
-
cairo_perf_run (perf, "tessellate-16", tessellate_16, NULL);
cairo_perf_run (perf, "tessellate-64", tessellate_64, NULL);
cairo_perf_run (perf, "tessellate-256", tessellate_256, NULL);
diff --git a/perf/micro/text.c b/perf/micro/text.c
index bd2ca7b4..cdb31993 100644
--- a/perf/micro/text.c
+++ b/perf/micro/text.c
@@ -56,11 +56,14 @@ do_text (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+text_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "text", NULL);
+}
+
void
text (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "text", NULL))
- return;
-
cairo_perf_cover_sources_and_operators (perf, "text", do_text, NULL);
}
diff --git a/perf/micro/twin.c b/perf/micro/twin.c
index cc6f0204..99433bd6 100644
--- a/perf/micro/twin.c
+++ b/perf/micro/twin.c
@@ -43,14 +43,17 @@ do_twin (cairo_t *cr,
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+twin_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "twin", NULL);
+}
+
void
twin (cairo_perf_t *perf,
cairo_t *cr,
int width,
int height)
{
- if (! cairo_perf_can_run (perf, "twin", NULL))
- return;
-
cairo_perf_run (perf, "twin", do_twin, NULL);
}
diff --git a/perf/micro/unaligned-clip.c b/perf/micro/unaligned-clip.c
index d71549cc..41e327f1 100644
--- a/perf/micro/unaligned-clip.c
+++ b/perf/micro/unaligned-clip.c
@@ -60,11 +60,14 @@ do_unaligned_clip (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+unaligned_clip_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "unaligned-clip", NULL);
+}
+
void
unaligned_clip (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "unaligned-clip", NULL))
- return;
-
cairo_perf_run (perf, "unaligned-clip", do_unaligned_clip, NULL);
}
diff --git a/perf/micro/wave.c b/perf/micro/wave.c
index 88029f8c..f6e6f74a 100644
--- a/perf/micro/wave.c
+++ b/perf/micro/wave.c
@@ -102,11 +102,14 @@ do_wave (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+wave_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "wave", NULL);
+}
+
void
wave (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "wave", NULL))
- return;
-
cairo_perf_run (perf, "wave", do_wave, NULL);
}
diff --git a/perf/micro/wide-fills.c b/perf/micro/wide-fills.c
index a9beeeb1..0747e6e6 100644
--- a/perf/micro/wide-fills.c
+++ b/perf/micro/wide-fills.c
@@ -170,12 +170,15 @@ do_wide_fills (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+wide_fills_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "wide-fills", NULL);
+}
+
void
wide_fills (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "wide-fills", NULL))
- return;
-
cairo_perf_run (perf, "wide-fills-halign", do_wide_fills_ha, NULL);
cairo_perf_run (perf, "wide-fills-valign", do_wide_fills_va, NULL);
cairo_perf_run (perf, "wide-fills-horizontal", do_wide_fills_h, NULL);
diff --git a/perf/micro/wide-strokes.c b/perf/micro/wide-strokes.c
index e6c27dab..14130914 100644
--- a/perf/micro/wide-strokes.c
+++ b/perf/micro/wide-strokes.c
@@ -169,12 +169,15 @@ do_wide_strokes (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+wide_strokes_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "wide-strokes", NULL);
+}
+
void
wide_strokes (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "wide-strokes", NULL))
- return;
-
cairo_set_source_rgb (cr, 1., 1., 1.);
cairo_perf_run (perf, "wide-strokes-halign", do_wide_strokes_ha, NULL);
diff --git a/perf/micro/world-map.c b/perf/micro/world-map.c
index cb0aeee6..ff22eebf 100644
--- a/perf/micro/world-map.c
+++ b/perf/micro/world-map.c
@@ -134,12 +134,15 @@ do_world_map_both (cairo_t *cr, int width, int height, int loops)
return do_world_map (cr, width, height, loops, FILL | STROKE);
}
+cairo_bool_t
+world_map_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "world-map", NULL);
+}
+
void
world_map (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "world-map", NULL))
- return;
-
cairo_perf_run (perf, "world-map-stroke", do_world_map_stroke, NULL);
cairo_perf_run (perf, "world-map-fill", do_world_map_fill, NULL);
cairo_perf_run (perf, "world-map", do_world_map_both, NULL);
diff --git a/perf/micro/zrusin.c b/perf/micro/zrusin.c
index c4dccbfa..7d8b004b 100644
--- a/perf/micro/zrusin.c
+++ b/perf/micro/zrusin.c
@@ -84,11 +84,15 @@ zrusin_another_fill (cairo_t *cr, int width, int height, int loops)
return cairo_perf_timer_elapsed ();
}
+cairo_bool_t
+zrusin_enabled (cairo_perf_t *perf)
+{
+ return cairo_perf_can_run (perf, "zrusin", NULL);
+}
+
void
zrusin (cairo_perf_t *perf, cairo_t *cr, int width, int height)
{
- if (! cairo_perf_can_run (perf, "zrusin", NULL))
- return;
cairo_perf_run (perf, "zrusin-another-tessellate", zrusin_another_tessellate, NULL);
cairo_perf_run (perf, "zrusin-another-fill", zrusin_another_fill, NULL);
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 0b820f8f..d23d504f 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -54,6 +54,7 @@ cairo_private = \
cairoint.h \
cairo-analysis-surface-private.h \
cairo-arc-private.h \
+ cairo-array-private.h \
cairo-atomic-private.h \
cairo-backend-private.h \
cairo-box-private.h \
@@ -62,6 +63,7 @@ cairo_private = \
cairo-clip-private.h \
cairo-combsort-private.h \
cairo-compiler-private.h \
+ cairo-compositor-private.h \
cairo-contour-private.h \
cairo-composite-rectangles-private.h \
cairo-default-context-private.h \
@@ -97,10 +99,11 @@ cairo_private = \
cairo-scaled-font-private.h \
cairo-slope-private.h \
cairo-spans-private.h \
+ cairo-spans-compositor-private.h \
cairo-stroke-dash-private.h \
- cairo-surface-fallback-private.h \
cairo-surface-private.h \
cairo-surface-clipper-private.h \
+ cairo-surface-fallback-private.h \
cairo-surface-observer-private.h \
cairo-surface-offset-private.h \
cairo-surface-subsurface-private.h \
@@ -108,6 +111,8 @@ cairo_private = \
cairo-surface-wrapper-private.h \
cairo-time-private.h \
cairo-types-private.h \
+ cairo-traps-private.h \
+ cairo-tristrip-private.h \
cairo-user-font-private.h \
cairo-wideint-private.h \
cairo-wideint-type-private.h \
@@ -134,11 +139,13 @@ cairo_sources = \
cairo-clip-surface.c \
cairo-color.c \
cairo-composite-rectangles.c \
+ cairo-compositor.c \
cairo-contour.c \
cairo-debug.c \
cairo-default-context.c \
cairo-device.c \
cairo-error.c \
+ cairo-fallback-compositor.c \
cairo-fixed.c \
cairo-font-face.c \
cairo-font-face-twin.c \
@@ -149,14 +156,19 @@ cairo_sources = \
cairo-gstate.c \
cairo-hash.c \
cairo-hull.c \
+ cairo-image-compositor.c \
cairo-image-info.c \
+ cairo-image-source.c \
cairo-image-surface.c \
cairo-lzw.c \
cairo-matrix.c \
+ cairo-mask-compositor.c \
cairo-mesh-pattern-rasterizer.c \
cairo-mime-surface.c \
cairo-misc.c \
+ cairo-mono-scan-converter.c \
cairo-mutex.c \
+ cairo-no-compositor.c \
cairo-observer.c \
cairo-output-stream.c \
cairo-paginated-surface.c \
@@ -168,6 +180,7 @@ cairo_sources = \
cairo-path-stroke.c \
cairo-path-stroke-boxes.c \
cairo-path-stroke-polygon.c \
+ cairo-path-stroke-tristrip.c \
cairo-pattern.c \
cairo-pen.c \
cairo-polygon.c \
@@ -181,12 +194,13 @@ cairo_sources = \
cairo-scaled-font.c \
cairo-slope.c \
cairo-spans.c \
+ cairo-spans-compositor.c \
cairo-spline.c \
cairo-stroke-dash.c \
cairo-stroke-style.c \
cairo-surface.c \
- cairo-surface-fallback.c \
cairo-surface-clipper.c \
+ cairo-surface-fallback.c \
cairo-surface-observer.c \
cairo-surface-offset.c \
cairo-surface-snapshot.c \
@@ -195,8 +209,12 @@ cairo_sources = \
cairo-system.c \
cairo-time.c \
cairo-tor-scan-converter.c \
+ cairo-tor22-scan-converter.c \
+ cairo-clip-tor-scan-converter.c \
cairo-toy-font-face.c \
cairo-traps.c \
+ cairo-tristrip.c \
+ cairo-traps-compositor.c \
cairo-unicode.c \
cairo-user-font.c \
cairo-version.c \
@@ -253,18 +271,15 @@ cairo_ft_sources = cairo-ft-font.c
# These are private, even though they look like public headers
cairo_test_surfaces_private = \
- test-fallback-surface.h \
- test-fallback16-surface.h \
- test-null-surface.h \
+ test-compositor-surface.h \
+ test-null-compositor-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-compositor-surface.c \
+ test-null-compositor-surface.c \
+ test-base-compositor-surface.c \
test-paginated-surface.c \
- test-wrapping-surface.c \
$(NULL)
cairo_xlib_headers = cairo-xlib.h
@@ -275,7 +290,11 @@ cairo_xlib_private = \
$(NULL)
cairo_xlib_sources = \
cairo-xlib-display.c \
+ cairo-xlib-core-compositor.c \
+ cairo-xlib-fallback-compositor.c \
+ cairo-xlib-render-compositor.c \
cairo-xlib-screen.c \
+ cairo-xlib-source.c \
cairo-xlib-surface.c \
cairo-xlib-visual.c \
cairo-xlib-xcb-surface.c \
@@ -343,7 +362,10 @@ cairo_gl_sources = cairo-gl-composite.c \
cairo-gl-glyphs.c \
cairo-gl-gradient.c \
cairo-gl-info.c \
+ cairo-gl-operand.c \
cairo-gl-shaders.c \
+ cairo-gl-spans-compositor.c \
+ cairo-gl-traps-compositor.c \
cairo-gl-surface.c
cairo_glesv2_headers = $(cairo_gl_headers)
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index beb9a07b..e1c28b65 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -144,7 +144,7 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
cairo_analysis_surface_t *tmp;
cairo_surface_t *source, *proxy;
cairo_matrix_t p2d;
- cairo_status_t status;
+ cairo_status_t status, analysis_status;
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
surface_pattern = (const cairo_surface_pattern_t *) pattern;
@@ -175,11 +175,16 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
if (_cairo_surface_is_subsurface (source))
source = _cairo_surface_subsurface_get_target (source);
- status = _cairo_recording_surface_replay_and_create_regions (source, &tmp->base);
+ status = _cairo_recording_surface_replay_and_create_regions (source,
+ &tmp->base);
+ analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS;
detach_proxy (proxy);
cairo_surface_destroy (&tmp->base);
- return status;
+ if (unlikely (status))
+ return status;
+
+ return analysis_status;
}
static cairo_int_status_t
@@ -548,8 +553,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs)
+ const cairo_clip_t *clip)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t status, backend_status;
@@ -562,8 +566,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
source,
glyphs, num_glyphs,
scaled_font,
- clip,
- remaining_glyphs);
+ clip);
if (_cairo_int_status_is_error (backend_status))
return backend_status;
}
@@ -652,21 +655,14 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
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,
- clip,
- &remaining_glyphs);
+ clip);
if (_cairo_int_status_is_error (backend_status))
return backend_status;
-
- glyphs += num_glyphs - remaining_glyphs;
- num_glyphs = remaining_glyphs;
- if (remaining_glyphs == 0)
- backend_status = CAIRO_STATUS_SUCCESS;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
@@ -701,35 +697,26 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
NULL, /* create_similar_image */
NULL, /* map_to_image */
NULL, /* unmap */
+
NULL, /* acquire_source_image */
NULL, /* release_source_image */
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ NULL, /* snapshot */
+
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_analysis_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 */
+
_cairo_analysis_surface_paint,
_cairo_analysis_surface_mask,
_cairo_analysis_surface_stroke,
_cairo_analysis_surface_fill,
- _cairo_analysis_surface_show_glyphs,
- NULL, /* snapshot */
- NULL, /* is_similar */
NULL, /* fill_stroke */
- NULL, /* create_solid_pattern_surface */
- NULL, /* can_repaint_solid_pattern_surface */
+ _cairo_analysis_surface_show_glyphs,
_cairo_analysis_surface_has_show_text_glyphs,
_cairo_analysis_surface_show_text_glyphs
};
@@ -891,48 +878,38 @@ typedef cairo_int_status_t
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs);
+ const cairo_clip_t *clip);
static const cairo_surface_backend_t cairo_null_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
NULL, /* finish */
- _cairo_default_context_create, /* XXX */
+ NULL, /* only accessed through the surface functions */
NULL, /* create_similar */
NULL, /* create similar image */
NULL, /* map to image */
NULL, /* unmap image*/
+
NULL, /* acquire_source_image */
NULL, /* release_source_image */
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ NULL, /* snapshot */
+
NULL, /* copy_page */
NULL, /* show_page */
+
NULL, /* get_extents */
- NULL, /* old_show_glyphs */
NULL, /* get_font_options */
+
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
- NULL, /* scaled_font_fini */
- NULL, /* scaled_glyph_fini */
+
(_paint_func) _return_success, /* paint */
(_mask_func) _return_success, /* mask */
(_stroke_func) _return_success, /* stroke */
(_fill_func) _return_success, /* fill */
- (_show_glyphs_func) _return_success, /* show_glyphs */
- NULL, /* snapshot */
- NULL, /* is_similar */
NULL, /* fill_stroke */
- NULL, /* create_solid_pattern_surface */
- NULL, /* can_repaint_solid_pattern_surface */
+ (_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* has_show_text_glyphs */
NULL /* show_text_glyphs */
};
diff --git a/src/cairo-array-private.h b/src/cairo-array-private.h
new file mode 100644
index 00000000..35b29e5f
--- /dev/null
+++ b/src/cairo-array-private.h
@@ -0,0 +1,90 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ */
+
+#ifndef CAIRO_ARRAY_PRIVATE_H
+#define CAIRO_ARRAY_PRIVATE_H
+
+#include "cairo-compiler-private.h"
+#include "cairo-types-private.h"
+
+CAIRO_BEGIN_DECLS
+
+/* cairo-array.c structures and functions */
+
+cairo_private void
+_cairo_array_init (cairo_array_t *array, unsigned int element_size);
+
+cairo_private void
+_cairo_array_fini (cairo_array_t *array);
+
+cairo_private cairo_status_t
+_cairo_array_grow_by (cairo_array_t *array, unsigned int additional);
+
+cairo_private void
+_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements);
+
+cairo_private cairo_status_t
+_cairo_array_append (cairo_array_t *array, const void *element);
+
+cairo_private cairo_status_t
+_cairo_array_append_multiple (cairo_array_t *array,
+ const void *elements,
+ unsigned int num_elements);
+
+cairo_private cairo_status_t
+_cairo_array_allocate (cairo_array_t *array,
+ unsigned int num_elements,
+ void **elements);
+
+cairo_private void *
+_cairo_array_index (cairo_array_t *array, unsigned int index);
+
+cairo_private const void *
+_cairo_array_index_const (const cairo_array_t *array, unsigned int index);
+
+cairo_private void
+_cairo_array_copy_element (const cairo_array_t *array, unsigned int index, void *dst);
+
+cairo_private unsigned int
+_cairo_array_num_elements (const cairo_array_t *array);
+
+cairo_private unsigned int
+_cairo_array_size (const cairo_array_t *array);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_ARRAY_PRIVATE_H */
diff --git a/src/cairo-array.c b/src/cairo-array.c
index 52b283ff..4f3c082f 100644
--- a/src/cairo-array.c
+++ b/src/cairo-array.c
@@ -37,6 +37,7 @@
*/
#include "cairoint.h"
+#include "cairo-array-private.h"
#include "cairo-error-private.h"
/**
@@ -385,11 +386,11 @@ _cairo_user_data_array_fini (cairo_user_data_array_t *array)
cairo_user_data_slot_t *slots;
slots = _cairo_array_index (array, 0);
- do {
- if (slots->user_data != NULL && slots->destroy != NULL)
- slots->destroy (slots->user_data);
- slots++;
- } while (--num_slots);
+ while (num_slots--) {
+ cairo_user_data_slot_t *s = &slots[num_slots];
+ if (s->user_data != NULL && s->destroy != NULL)
+ s->destroy (s->user_data);
+ }
}
_cairo_array_fini (array);
diff --git a/src/cairo-atomic-private.h b/src/cairo-atomic-private.h
index 9f5888ca..327fed1d 100644
--- a/src/cairo-atomic-private.h
+++ b/src/cairo-atomic-private.h
@@ -79,6 +79,7 @@ _cairo_atomic_ptr_get (void **x)
#endif
# define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
+# define _cairo_atomic_int_dec(x) ((void) __sync_fetch_and_add(x, -1))
# define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_bool_compare_and_swap (x, oldv, newv)
# define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
@@ -111,6 +112,7 @@ typedef AO_t cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (AO_load_full (x))
# define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
+# define _cairo_atomic_int_dec(x) ((void) AO_fetch_and_sub1_full(x))
# define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, oldv, newv)
@@ -140,6 +142,7 @@ typedef int32_t cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (OSMemoryBarrier(), *(x))
# define _cairo_atomic_int_inc(x) ((void) OSAtomicIncrement32Barrier (x))
+# define _cairo_atomic_int_dec(x) ((void) OSAtomicDecrement32Barrier (x))
# define _cairo_atomic_int_dec_and_test(x) (OSAtomicDecrement32Barrier (x) == 0)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) OSAtomicCompareAndSwap32Barrier(oldv, newv, x)
@@ -178,6 +181,8 @@ typedef cairo_atomic_intptr_t cairo_atomic_int_t;
cairo_private void
_cairo_atomic_int_inc (cairo_atomic_int_t *x);
+#define _cairo_atomic_int_dec(x) _cairo_atomic_int_dec_and_test(x)
+
cairo_private cairo_bool_t
_cairo_atomic_int_dec_and_test (cairo_atomic_int_t *x);
diff --git a/src/cairo-bentley-ottmann-rectangular.c b/src/cairo-bentley-ottmann-rectangular.c
index 51911786..aec7ae41 100644
--- a/src/cairo-bentley-ottmann-rectangular.c
+++ b/src/cairo-bentley-ottmann-rectangular.c
@@ -42,6 +42,7 @@
#include "cairo-error-private.h"
#include "cairo-combsort-private.h"
#include "cairo-list-private.h"
+#include "cairo-traps-private.h"
#include <setjmp.h>
@@ -740,7 +741,7 @@ _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 3];
rectangle_t *rectangles, **rectangles_ptrs;
rectangle_t *stack_rectangles_chain[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *) ];
- rectangle_t **rectangles_chain;
+ rectangle_t **rectangles_chain = NULL;
const struct _cairo_boxes_chunk *chunk;
cairo_status_t status;
int i, j, y_min, y_max;
@@ -789,13 +790,15 @@ _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
y_max = _cairo_fixed_integer_floor (y_max) + 1;
y_max -= y_min;
- rectangles_chain = stack_rectangles_chain;
- if (y_max > ARRAY_LENGTH (stack_rectangles_chain)) {
- rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *));
- if (unlikely (rectangles_chain == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ if (y_max < in->num_boxes) {
+ rectangles_chain = stack_rectangles_chain;
+ if (y_max > ARRAY_LENGTH (stack_rectangles_chain)) {
+ rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *));
+ if (unlikely (rectangles_chain == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*));
}
- memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*));
rectangles = stack_rectangles;
rectangles_ptrs = stack_rectangles_ptrs;
@@ -839,28 +842,38 @@ _cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
rectangles[j].top = box[i].p1.y;
rectangles[j].bottom = box[i].p2.y;
- h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min;
- rectangles[j].left.next = (edge_t *)rectangles_chain[h];
- rectangles_chain[h] = &rectangles[j];
+ if (rectangles_chain) {
+ h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min;
+ rectangles[j].left.next = (edge_t *)rectangles_chain[h];
+ rectangles_chain[h] = &rectangles[j];
+ } else {
+ rectangles_ptrs[j+2] = &rectangles[j];
+ }
j++;
}
}
- j = 2;
- for (y_min = 0; y_min < y_max; y_min++) {
- rectangle_t *r;
- int start = j;
- for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next)
- rectangles_ptrs[j++] = r;
- if (j > start + 1)
+ if (rectangles_chain) {
+ j = 2;
+ for (y_min = 0; y_min < y_max; y_min++) {
+ rectangle_t *r;
+ int start = j;
+ for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next)
+ rectangles_ptrs[j++] = r;
+ if (j > start + 1)
_rectangle_sort (rectangles_ptrs + start, j - start);
- }
+ }
+
+ if (rectangles_chain != stack_rectangles_chain)
+ free (rectangles_chain);
- if (rectangles_chain != stack_rectangles_chain)
- free (rectangles_chain);
+ j -= 2;
+ } else {
+ _rectangle_sort (rectangles_ptrs + 2, j);
+ }
_cairo_boxes_clear (out);
- status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j-2,
+ status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j,
fill_rule,
FALSE, out);
if (rectangles != stack_rectangles)
diff --git a/src/cairo-bentley-ottmann-rectilinear.c b/src/cairo-bentley-ottmann-rectilinear.c
index a3eb4901..1edeeb52 100644
--- a/src/cairo-bentley-ottmann-rectilinear.c
+++ b/src/cairo-bentley-ottmann-rectilinear.c
@@ -41,6 +41,7 @@
#include "cairo-boxes-private.h"
#include "cairo-combsort-private.h"
#include "cairo-error-private.h"
+#include "cairo-traps-private.h"
typedef struct _cairo_bo_edge cairo_bo_edge_t;
typedef struct _cairo_bo_trap cairo_bo_trap_t;
@@ -437,74 +438,6 @@ _cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events
}
cairo_status_t
-_cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
- const cairo_polygon_t *polygon,
- cairo_fill_rule_t fill_rule)
-{
- cairo_status_t status;
- cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
- cairo_bo_event_t *events;
- cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
- cairo_bo_event_t **event_ptrs;
- cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
- cairo_bo_edge_t *edges;
- int num_events;
- int i, j;
-
- if (unlikely (polygon->num_edges == 0))
- return CAIRO_STATUS_SUCCESS;
-
- num_events = 2 * polygon->num_edges;
-
- events = stack_events;
- event_ptrs = stack_event_ptrs;
- edges = stack_edges;
- if (num_events > ARRAY_LENGTH (stack_events)) {
- events = _cairo_malloc_ab_plus_c (num_events,
- sizeof (cairo_bo_event_t) +
- sizeof (cairo_bo_edge_t) +
- sizeof (cairo_bo_event_t *),
- sizeof (cairo_bo_event_t *));
- if (unlikely (events == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- event_ptrs = (cairo_bo_event_t **) (events + num_events);
- edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1);
- }
-
- for (i = j = 0; i < polygon->num_edges; i++) {
- edges[i].edge = polygon->edges[i];
- edges[i].deferred_trap.right = NULL;
- edges[i].prev = NULL;
- edges[i].next = NULL;
-
- event_ptrs[j] = &events[j];
- events[j].type = CAIRO_BO_EVENT_TYPE_START;
- events[j].point.y = polygon->edges[i].top;
- events[j].point.x = polygon->edges[i].line.p1.x;
- events[j].edge = &edges[i];
- j++;
-
- event_ptrs[j] = &events[j];
- events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
- events[j].point.y = polygon->edges[i].bottom;
- events[j].point.x = polygon->edges[i].line.p1.x;
- events[j].edge = &edges[i];
- j++;
- }
-
- status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
- fill_rule,
- TRUE, traps);
- if (events != stack_events)
- free (events);
-
- traps->is_rectilinear = TRUE;
-
- return status;
-}
-
-cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes)
diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index 70d4482f..634da6f1 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -41,6 +41,7 @@
#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
#include "cairo-combsort-private.h"
+#include "cairo-traps-private.h"
#define DEBUG_PRINT_STATE 0
#define DEBUG_EVENTS 0
@@ -1301,7 +1302,14 @@ event_log (const char *fmt, ...)
static inline cairo_bool_t
edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
{
- if (_line_equal (&a->edge.line, &b->edge.line))
+ unsigned p;
+
+ p = 0;
+ p |= (a->edge.line.p1.x == b->edge.line.p1.x) << 0;
+ p |= (a->edge.line.p1.y == b->edge.line.p1.y) << 1;
+ p |= (a->edge.line.p2.x == b->edge.line.p2.x) << 3;
+ p |= (a->edge.line.p2.y == b->edge.line.p2.y) << 4;
+ if (p == ((1 << 0) | (1 << 1) | (1 << 3) | (1 << 4)))
return TRUE;
if (_slope_compare (a, b))
@@ -1310,8 +1318,9 @@ edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
/* The choice of y is not truly arbitrary since we must guarantee that it
* is greater than the start of either line.
*/
- if (a->edge.line.p1.y == b->edge.line.p1.y) {
- return a->edge.line.p1.x == b->edge.line.p1.x;
+ if (p != 0) {
+ /* colinear if either end-point are coincident */
+ return ((p >> 1) & p) != 0;
} else if (a->edge.line.p1.y < b->edge.line.p1.y) {
return edge_compare_for_y_against_x (b,
a->edge.line.p1.y,
@@ -1377,8 +1386,9 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
if (left->deferred_trap.right == right)
return CAIRO_STATUS_SUCCESS;
+ assert (right);
if (left->deferred_trap.right != NULL) {
- if (right != NULL && edges_colinear (left->deferred_trap.right, right))
+ if (edges_colinear (left->deferred_trap.right, right))
{
/* continuation on right, so just swap edges */
left->deferred_trap.right = right;
@@ -1390,7 +1400,7 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
return status;
}
- if (right != NULL && ! edges_colinear (left, right)) {
+ if (! edges_colinear (left, right)) {
left->deferred_trap.top = top;
left->deferred_trap.right = right;
@@ -1406,112 +1416,50 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
}
static inline cairo_status_t
-_active_edges_to_traps (cairo_bo_edge_t *left,
- int32_t top,
- cairo_fill_rule_t fill_rule,
- cairo_traps_t *traps)
+_active_edges_to_traps (cairo_bo_edge_t *pos,
+ int32_t top,
+ unsigned mask,
+ cairo_traps_t *traps)
{
- cairo_bo_edge_t *right;
+ cairo_bo_edge_t *left;
cairo_status_t status;
+ int in_out;
+
#if DEBUG_PRINT_STATE
printf ("Processing active edges for %x\n", top);
#endif
- if (fill_rule == CAIRO_FILL_RULE_WINDING) {
- while (left != NULL) {
- int in_out;
-
- /* Greedily search for the closing edge, so that we generate the
- * maximal span width with the minimal number of trapezoids.
- */
- in_out = left->edge.dir;
-
- /* Check if there is a co-linear edge with an existing trap */
- right = left->next;
- if (left->deferred_trap.right == NULL) {
- while (right != NULL && right->deferred_trap.right == NULL)
- right = right->next;
-
- if (right != NULL && edges_colinear (left, right)) {
- /* continuation on left */
- left->deferred_trap = right->deferred_trap;
- right->deferred_trap.right = NULL;
- }
- }
-
- /* End all subsumed traps */
- right = left->next;
- while (right != NULL) {
- if (right->deferred_trap.right != NULL) {
- status = _cairo_bo_edge_end_trap (right, top, traps);
- if (unlikely (status))
- return status;
- }
-
- in_out += right->edge.dir;
- if (in_out == 0) {
- cairo_bo_edge_t *next;
- cairo_bool_t skip = FALSE;
-
- /* skip co-linear edges */
- next = right->next;
- if (next != NULL)
- skip = edges_colinear (right, next);
-
- if (! skip)
- break;
- }
-
- right = right->next;
+ in_out = 0;
+ left = pos;
+ while (pos != NULL) {
+ if (pos != left && pos->deferred_trap.right) {
+ if (edges_colinear (left, pos)) {
+ /* continuation on left */
+ assert (left->deferred_trap.right == NULL);
+ left->deferred_trap = pos->deferred_trap;
+ pos->deferred_trap.right = NULL;
+ } else {
+ status = _cairo_bo_edge_end_trap (pos, top, traps);
+ if (unlikely (status))
+ return status;
}
-
- status = _cairo_bo_edge_start_or_continue_trap (left, right,
- top, traps);
- if (unlikely (status))
- return status;
-
- left = right;
- if (left != NULL)
- left = left->next;
}
- } else {
- while (left != NULL) {
- int in_out = 0;
-
- right = left->next;
- while (right != NULL) {
- if (right->deferred_trap.right != NULL) {
- status = _cairo_bo_edge_end_trap (right, top, traps);
- if (unlikely (status))
- return status;
- }
-
- if ((in_out++ & 1) == 0) {
- cairo_bo_edge_t *next;
- cairo_bool_t skip = FALSE;
- /* skip co-linear edges */
- next = right->next;
- if (next != NULL)
- skip = edges_colinear (right, next);
-
- if (! skip)
- break;
- }
+ in_out += pos->edge.dir;
+ if ((in_out & mask) == 0) {
+ /* skip co-linear edges */
+ if (pos->next == NULL || ! edges_colinear (pos, pos->next)) {
+ status = _cairo_bo_edge_start_or_continue_trap (left, pos,
+ top, traps);
+ if (unlikely (status))
+ return status;
- right = right->next;
+ left = pos->next;
}
-
- status = _cairo_bo_edge_start_or_continue_trap (left, right,
- top, traps);
- if (unlikely (status))
- return status;
-
- left = right;
- if (left != NULL)
- left = left->next;
}
+
+ pos = pos->next;
}
return CAIRO_STATUS_SUCCESS;
@@ -1524,7 +1472,7 @@ _active_edges_to_traps (cairo_bo_edge_t *left,
static cairo_status_t
_cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events,
int num_events,
- cairo_fill_rule_t fill_rule,
+ unsigned fill_rule,
cairo_traps_t *traps,
int *num_intersections)
{
@@ -1536,6 +1484,12 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events,
cairo_bo_edge_t *left, *right;
cairo_bo_edge_t *e1, *e2;
+ /* convert the fill_rule into a winding mask */
+ if (fill_rule == CAIRO_FILL_RULE_WINDING)
+ fill_rule = (unsigned) -1;
+ else
+ fill_rule = 1;
+
#if DEBUG_EVENTS
{
int i;
@@ -1781,7 +1735,7 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
for (y = i = 0; y < ymax && i < num_events; y++) {
cairo_bo_start_event_t *e;
int j = i;
- for (e = event_y[y]; e; e = (cairo_bo_start_event_t *)e->edge.next)
+ for (e = event_y[y]; e; e = (cairo_bo_start_event_t *)e->edge.next)
event_ptrs[i++] = (cairo_bo_event_t *) e;
if (i > j + 1)
_cairo_bo_event_queue_sort (event_ptrs+j, i-j);
diff --git a/src/cairo-botor-scan-converter.c b/src/cairo-botor-scan-converter.c
index 0778a5dc..cbb752f0 100644
--- a/src/cairo-botor-scan-converter.c
+++ b/src/cairo-botor-scan-converter.c
@@ -1397,6 +1397,7 @@ render_rows (cairo_botor_scan_converter_t *self,
if (x > prev_x) {
spans[num_spans].x = prev_x;
+ spans[num_spans].inverse = 0;
spans[num_spans].coverage = AREA_TO_ALPHA (cover);
++num_spans;
}
@@ -1413,12 +1414,14 @@ render_rows (cairo_botor_scan_converter_t *self,
if (prev_x <= self->xmax) {
spans[num_spans].x = prev_x;
+ spans[num_spans].inverse = 0;
spans[num_spans].coverage = AREA_TO_ALPHA (cover);
++num_spans;
}
if (cover && prev_x < self->xmax) {
spans[num_spans].x = self->xmax;
+ spans[num_spans].inverse = 1;
spans[num_spans].coverage = 0;
++num_spans;
}
@@ -2179,8 +2182,6 @@ _cairo_botor_scan_converter_init (cairo_botor_scan_converter_t *self,
cairo_fill_rule_t fill_rule)
{
self->base.destroy = _cairo_botor_scan_converter_destroy;
- self->base.add_edge = _cairo_botor_scan_converter_add_edge;
- self->base.add_polygon = _cairo_botor_scan_converter_add_polygon;
self->base.generate = _cairo_botor_scan_converter_generate;
self->extents = *extents;
diff --git a/src/cairo-box-private.h b/src/cairo-box-private.h
index 3bced996..d6b99412 100644
--- a/src/cairo-box-private.h
+++ b/src/cairo-box-private.h
@@ -37,6 +37,7 @@
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
+#include "cairo-fixed-private.h"
static inline void
_cairo_box_set (cairo_box_t *box,
@@ -47,6 +48,15 @@ _cairo_box_set (cairo_box_t *box,
box->p2 = *p2;
}
+static inline void
+_cairo_box_from_integers (cairo_box_t *box, int x, int y, int w, int h)
+{
+ box->p1.x = _cairo_fixed_from_int (x);
+ box->p1.y = _cairo_fixed_from_int (y);
+ box->p2.x = _cairo_fixed_from_int (x + w);
+ box->p2.y = _cairo_fixed_from_int (y + h);
+}
+
/* assumes box->p1 is top-left, p2 bottom-right */
static inline void
_cairo_box_add_point (cairo_box_t *box,
@@ -63,13 +73,49 @@ _cairo_box_add_point (cairo_box_t *box,
box->p2.y = point->y;
}
+static inline void
+_cairo_box_add_box (cairo_box_t *box,
+ const cairo_box_t *add)
+{
+ if (add->p1.x < box->p1.x)
+ box->p1.x = add->p1.x;
+ if (add->p2.x > box->p2.x)
+ box->p2.x = add->p2.x;
+
+ if (add->p1.y < box->p1.y)
+ box->p1.y = add->p1.y;
+ if (add->p2.y > box->p2.y)
+ box->p2.y = add->p2.y;
+}
+
/* assumes box->p1 is top-left, p2 bottom-right */
static inline cairo_bool_t
-_cairo_box_contains_point (cairo_box_t *box,
+_cairo_box_contains_point (const cairo_box_t *box,
const cairo_point_t *point)
{
return box->p1.x <= point->x && point->x <= box->p2.x &&
box->p1.y <= point->y && point->y <= box->p2.y;
}
+static inline cairo_bool_t
+_cairo_box_is_pixel_aligned (const cairo_box_t *box)
+{
+#if CAIRO_FIXED_FRAC_BITS <= 8 && 0
+ return ((box->p1.x & CAIRO_FIXED_FRAC_MASK) << 24 |
+ (box->p1.y & CAIRO_FIXED_FRAC_MASK) << 16 |
+ (box->p2.x & CAIRO_FIXED_FRAC_MASK) << 8 |
+ (box->p2.y & CAIRO_FIXED_FRAC_MASK) << 0) == 0;
+#else /* GCC on i7 prefers this variant (bizarrely according to the profiler) */
+ cairo_fixed_t f;
+
+ f = 0;
+ f |= box->p1.x & CAIRO_FIXED_FRAC_MASK;
+ f |= box->p1.y & CAIRO_FIXED_FRAC_MASK;
+ f |= box->p2.x & CAIRO_FIXED_FRAC_MASK;
+ f |= box->p2.y & CAIRO_FIXED_FRAC_MASK;
+
+ return f == 0;
+#endif
+}
+
#endif /* CAIRO_BOX_H */
diff --git a/src/cairo-boxes-intersect.c b/src/cairo-boxes-intersect.c
index 230c6f01..dd4c2410 100644
--- a/src/cairo-boxes-intersect.c
+++ b/src/cairo-boxes-intersect.c
@@ -535,19 +535,44 @@ _cairo_boxes_intersect_with_box (const cairo_boxes_t *boxes,
const cairo_box_t *box,
cairo_boxes_t *out)
{
- const struct _cairo_boxes_chunk *chunk;
cairo_status_t status;
- int i;
+ int i, j;
+
+ if (out == boxes) { /* inplace update */
+ struct _cairo_boxes_chunk *chunk;
+
+ out->num_boxes = 0;
+ for (chunk = &out->chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = j = 0; i < chunk->count; i++) {
+ cairo_box_t *b = &chunk->base[i];
+
+ b->p1.x = MAX (b->p1.x, box->p1.x);
+ b->p1.y = MAX (b->p1.y, box->p1.y);
+ b->p2.x = MIN (b->p2.x, box->p2.x);
+ b->p2.y = MIN (b->p2.y, box->p2.y);
+ if (b->p1.x < b->p2.x && b->p1.y < b->p2.y) {
+ if (i != j)
+ chunk->base[j] = *b;
+ j++;
+ }
+ }
+ /* XXX unlink empty chains? */
+ chunk->count = j;
+ out->num_boxes += j;
+ }
+ } else {
+ const struct _cairo_boxes_chunk *chunk;
- _cairo_boxes_clear (out);
- _cairo_boxes_limit (out, box, 1);
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- for (i = 0; i < chunk->count; i++) {
- status = _cairo_boxes_add (out,
- CAIRO_ANTIALIAS_DEFAULT,
- &chunk->base[i]);
- if (unlikely (status))
- return status;
+ _cairo_boxes_clear (out);
+ _cairo_boxes_limit (out, box, 1);
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ status = _cairo_boxes_add (out,
+ CAIRO_ANTIALIAS_DEFAULT,
+ &chunk->base[i]);
+ if (unlikely (status))
+ return status;
+ }
}
}
diff --git a/src/cairo-boxes-private.h b/src/cairo-boxes-private.h
index 890d1b2d..57d1228b 100644
--- a/src/cairo-boxes-private.h
+++ b/src/cairo-boxes-private.h
@@ -42,11 +42,14 @@
struct _cairo_boxes_t {
cairo_status_t status;
+
cairo_box_t limit;
const cairo_box_t *limits;
int num_limits;
+
int num_boxes;
- unsigned int is_pixel_aligned : 1;
+
+ unsigned int is_pixel_aligned;
struct _cairo_boxes_chunk {
struct _cairo_boxes_chunk *next;
@@ -70,6 +73,10 @@ _cairo_boxes_init_for_array (cairo_boxes_t *boxes,
int num_boxes);
cairo_private void
+_cairo_boxes_init_from_rectangle (cairo_boxes_t *boxes,
+ int x, int y, int w, int h);
+
+cairo_private void
_cairo_boxes_limit (cairo_boxes_t *boxes,
const cairo_box_t *limits,
int num_limits);
@@ -81,7 +88,7 @@ _cairo_boxes_add (cairo_boxes_t *boxes,
cairo_private void
_cairo_boxes_extents (const cairo_boxes_t *boxes,
- cairo_rectangle_int_t *extents);
+ cairo_box_t *box);
cairo_private cairo_box_t *
_cairo_boxes_to_array (const cairo_boxes_t *boxes,
@@ -104,6 +111,11 @@ _cairo_boxes_intersect (const cairo_boxes_t *a,
cairo_private void
_cairo_boxes_clear (cairo_boxes_t *boxes);
+cairo_private_no_warn cairo_bool_t
+_cairo_boxes_for_each_box (cairo_boxes_t *boxes,
+ cairo_bool_t (*func) (cairo_box_t *box, void *data),
+ void *data);
+
cairo_private void
_cairo_boxes_fini (cairo_boxes_t *boxes);
diff --git a/src/cairo-boxes.c b/src/cairo-boxes.c
index 130a44c7..182601a7 100644
--- a/src/cairo-boxes.c
+++ b/src/cairo-boxes.c
@@ -33,6 +33,7 @@
#include "cairoint.h"
+#include "cairo-box-private.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
@@ -53,6 +54,16 @@ _cairo_boxes_init (cairo_boxes_t *boxes)
}
void
+_cairo_boxes_init_from_rectangle (cairo_boxes_t *boxes,
+ int x, int y, int w, int h)
+{
+ _cairo_boxes_init (boxes);
+
+ _cairo_box_from_integers (&boxes->chunks.base[0], x, y, w, h);
+ boxes->num_boxes = 1;
+}
+
+void
_cairo_boxes_init_with_clip (cairo_boxes_t *boxes,
cairo_clip_t *clip)
{
@@ -154,13 +165,8 @@ _cairo_boxes_add_internal (cairo_boxes_t *boxes,
chunk->base[chunk->count++] = *box;
boxes->num_boxes++;
- if (boxes->is_pixel_aligned) {
- boxes->is_pixel_aligned =
- _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);
- }
+ if (boxes->is_pixel_aligned)
+ boxes->is_pixel_aligned = _cairo_box_is_pixel_aligned (box);
}
cairo_status_t
@@ -261,38 +267,34 @@ _cairo_boxes_add (cairo_boxes_t *boxes,
void
_cairo_boxes_extents (const cairo_boxes_t *boxes,
- cairo_rectangle_int_t *extents)
+ cairo_box_t *box)
{
const struct _cairo_boxes_chunk *chunk;
- cairo_box_t box;
+ cairo_box_t b;
int i;
if (boxes->num_boxes == 0) {
- extents->x = extents->y = extents->width = extents->height = 0;
+ box->p1.x = box->p1.y = box->p2.x = box->p2.y = 0;
return;
}
- box.p1.y = box.p1.x = INT_MAX;
- box.p2.y = box.p2.x = INT_MIN;
-
+ b = boxes->chunks.base[0];
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- const cairo_box_t *b = chunk->base;
for (i = 0; i < chunk->count; i++) {
- if (b[i].p1.x < box.p1.x)
- box.p1.x = b[i].p1.x;
+ if (chunk->base[i].p1.x < b.p1.x)
+ b.p1.x = chunk->base[i].p1.x;
- if (b[i].p1.y < box.p1.y)
- box.p1.y = b[i].p1.y;
+ if (chunk->base[i].p1.y < b.p1.y)
+ b.p1.y = chunk->base[i].p1.y;
- if (b[i].p2.x > box.p2.x)
- box.p2.x = b[i].p2.x;
+ if (chunk->base[i].p2.x > b.p2.x)
+ b.p2.x = chunk->base[i].p2.x;
- if (b[i].p2.y > box.p2.y)
- box.p2.y = b[i].p2.y;
+ if (chunk->base[i].p2.y > b.p2.y)
+ b.p2.y = chunk->base[i].p2.y;
}
}
-
- _cairo_box_round_to_rectangle (&box, extents);
+ *box = b;
}
void
@@ -354,17 +356,38 @@ _cairo_boxes_fini (cairo_boxes_t *boxes)
}
}
+cairo_bool_t
+_cairo_boxes_for_each_box (cairo_boxes_t *boxes,
+ cairo_bool_t (*func) (cairo_box_t *box, void *data),
+ void *data)
+{
+ struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++)
+ if (! func (&chunk->base[i], data))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
void
_cairo_debug_print_boxes (FILE *stream, const cairo_boxes_t *boxes)
{
- cairo_rectangle_int_t extents;
const struct _cairo_boxes_chunk *chunk;
+ cairo_box_t extents;
int i;
_cairo_boxes_extents (boxes, &extents);
- fprintf (stream, "boxes x %d: (%d, %d) x (%d, %d)\n",
+ fprintf (stream, "boxes x %d: (%f, %f) x (%f, %f)\n",
boxes->num_boxes,
- extents.x, extents.y, extents.width, extents.height);
+ _cairo_fixed_to_double (extents.p1.x),
+ _cairo_fixed_to_double (extents.p1.y),
+ _cairo_fixed_to_double (extents.p2.x),
+ _cairo_fixed_to_double (extents.p2.y));
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index 6c717958..3ee3ef39 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -42,6 +42,8 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
+
+#include "cairo-array-private.h"
#include "cairo-error-private.h"
#if CAIRO_HAS_FONT_SUBSET
@@ -2897,7 +2899,7 @@ cairo_bool_t
_cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font)
{
const cairo_scaled_font_backend_t *backend;
- cairo_status_t status;
+ cairo_int_status_t status;
unsigned char *data;
unsigned long data_length;
unsigned char *current_ptr;
@@ -2916,7 +2918,7 @@ _cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font)
/* Try to load an OpenType/CFF font */
if (backend->load_truetype_table &&
(status = backend->load_truetype_table (scaled_font, TT_TAG_CFF,
- 0, NULL, &data_length)) == CAIRO_STATUS_SUCCESS)
+ 0, NULL, &data_length)) == CAIRO_INT_STATUS_SUCCESS)
{
data = malloc (data_length);
if (unlikely (data == NULL)) {
@@ -2933,7 +2935,7 @@ _cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font)
if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
backend->load_type1_data &&
(status = backend->load_type1_data (scaled_font,
- 0, NULL, &data_length)) == CAIRO_STATUS_SUCCESS)
+ 0, NULL, &data_length)) == CAIRO_INT_STATUS_SUCCESS)
{
data = malloc (data_length);
if (unlikely (data == NULL)) {
diff --git a/src/cairo-clip-boxes.c b/src/cairo-clip-boxes.c
index e18c2f8e..3b8265b9 100644
--- a/src/cairo-clip-boxes.c
+++ b/src/cairo-clip-boxes.c
@@ -40,6 +40,8 @@
*/
#include "cairoint.h"
+
+#include "cairo-box-private.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
@@ -62,7 +64,6 @@ pot (int v)
return v;
}
-
static cairo_bool_t
_cairo_clip_contains_rectangle_box (const cairo_clip_t *clip,
const cairo_rectangle_int_t *rect,
@@ -90,7 +91,6 @@ _cairo_clip_contains_rectangle_box (const cairo_clip_t *clip,
}
/* Check for a clip-box that wholly contains the rectangle */
- assert (clip->num_boxes);
for (i = 0; i < clip->num_boxes; i++) {
if (box->p1.x >= clip->boxes[i].p1.x &&
box->p1.y >= clip->boxes[i].p1.y &&
@@ -176,6 +176,8 @@ _cairo_clip_intersect_rectangle_box (cairo_clip_t *clip,
if (! _cairo_rectangle_intersect (&clip->extents, r))
clip = _cairo_clip_set_all_clipped (clip);
}
+ if (clip->path == NULL)
+ clip->is_region = _cairo_box_is_pixel_aligned (box);
return clip;
}
@@ -269,6 +271,7 @@ _cairo_clip_intersect_boxes (cairo_clip_t *clip,
const cairo_boxes_t *boxes)
{
cairo_boxes_t clip_boxes;
+ cairo_box_t limits;
cairo_rectangle_int_t extents;
if (_cairo_clip_is_all_clipped (clip))
@@ -301,10 +304,11 @@ _cairo_clip_intersect_boxes (cairo_clip_t *clip,
} else {
clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes, TRUE);
}
- _cairo_boxes_extents (boxes, &extents);
+ _cairo_boxes_extents (boxes, &limits);
if (boxes == &clip_boxes)
_cairo_boxes_fini (&clip_boxes);
+ _cairo_box_round_to_rectangle (&limits, &extents);
if (clip->path == NULL)
clip->extents = extents;
else if (! _cairo_rectangle_intersect (&clip->extents, &extents))
@@ -557,37 +561,10 @@ _cairo_clip_reduce_for_composite (const cairo_clip_t *clip,
return _cairo_clip_reduce_to_rectangle (clip, r);
}
-cairo_status_t
-_cairo_clip_to_boxes (cairo_clip_t *clip,
- cairo_boxes_t *boxes)
-{
- _cairo_boxes_init_for_array (boxes, clip->boxes, clip->num_boxes);
-
- if (clip->path == NULL) {
- cairo_box_t *src = clip->boxes;
- int i;
-
- clip->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
- if (clip->boxes == NULL) {
- clip->boxes = src;
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- for (i = 0; i < clip->num_boxes; i++) {
- clip->boxes[i].p1.x = _cairo_fixed_floor (src[i].p1.x);
- clip->boxes[i].p1.y = _cairo_fixed_floor (src[i].p1.y);
- clip->boxes[i].p2.x = _cairo_fixed_ceil (src[i].p2.x);
- clip->boxes[i].p2.y = _cairo_fixed_ceil (src[i].p2.y);
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-
-}
-
cairo_clip_t *
_cairo_clip_from_boxes (const cairo_boxes_t *boxes)
{
+ cairo_box_t extents;
cairo_clip_t *clip = _cairo_clip_create ();
if (clip == NULL)
return _cairo_clip_set_all_clipped (clip);
@@ -603,7 +580,8 @@ _cairo_clip_from_boxes (const cairo_boxes_t *boxes)
return _cairo_clip_set_all_clipped (clip);
}
- _cairo_boxes_extents (boxes, &clip->extents);
+ _cairo_boxes_extents (boxes, &extents);
+ _cairo_box_round_to_rectangle (&extents, &clip->extents);
return clip;
}
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 3ebcb0e2..7cbef24a 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -40,6 +40,7 @@
#include "cairo-types-private.h"
#include "cairo-boxes-private.h"
+#include "cairo-error-private.h"
#include "cairo-compiler-private.h"
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
@@ -160,14 +161,30 @@ _cairo_clip_get_extents (const cairo_clip_t *clip);
cairo_private cairo_surface_t *
_cairo_clip_get_surface (const cairo_clip_t *clip, cairo_surface_t *dst, int *tx, int *ty);
+cairo_private cairo_surface_t *
+_cairo_clip_get_image (const cairo_clip_t *clip,
+ cairo_surface_t *target,
+ const cairo_rectangle_int_t *extents);
+
cairo_private cairo_status_t
_cairo_clip_combine_with_surface (const cairo_clip_t *clip,
cairo_surface_t *dst,
int dst_x, int dst_y);
-cairo_private cairo_status_t
-_cairo_clip_to_boxes (cairo_clip_t *clip,
- cairo_boxes_t *boxes);
+static inline void
+_cairo_clip_steal_boxes (cairo_clip_t *clip, cairo_boxes_t *boxes)
+{
+ _cairo_boxes_init_for_array (boxes, clip->boxes, clip->num_boxes);
+ clip->boxes = NULL;
+ clip->num_boxes = 0;
+}
+
+static inline void
+_cairo_clip_unsteal_boxes (cairo_clip_t *clip, cairo_boxes_t *boxes)
+{
+ clip->boxes = boxes->chunks.base;
+ clip->num_boxes = boxes->num_boxes;
+}
cairo_private cairo_clip_t *
_cairo_clip_from_boxes (const cairo_boxes_t *boxes);
diff --git a/src/cairo-clip-region.c b/src/cairo-clip-region.c
index 28a0d4bb..e3f4891e 100644
--- a/src/cairo-clip-region.c
+++ b/src/cairo-clip-region.c
@@ -105,10 +105,16 @@ _cairo_clip_is_region (const cairo_clip_t *clip)
if (clip == NULL)
return TRUE;
+ if (clip->is_region)
+ return TRUE;
+
/* XXX Geometric reduction? */
if (clip->path)
- return FALSE;
+ return FALSE;
+
+ if (clip->num_boxes == 0)
+ return TRUE;
if (clip->region == NULL)
_cairo_clip_extract_region ((cairo_clip_t *) clip);
diff --git a/src/cairo-clip-surface.c b/src/cairo-clip-surface.c
index 79e6a627..e1e93129 100644
--- a/src/cairo-clip-surface.c
+++ b/src/cairo-clip-surface.c
@@ -103,8 +103,7 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
CAIRO_CONTENT_ALPHA,
clip->extents.width,
clip->extents.height,
- CAIRO_COLOR_TRANSPARENT,
- TRUE);
+ CAIRO_COLOR_WHITE);
if (unlikely (surface->status))
return surface;
@@ -114,12 +113,7 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
copy_path = copy->path;
copy->path = NULL;
- assert (copy->num_boxes);
- status = _cairo_surface_paint (surface,
- CAIRO_OPERATOR_ADD,
- &_cairo_pattern_white.base,
- copy);
-
+ status = CAIRO_STATUS_SUCCESS;
clip_path = copy_path;
while (status == CAIRO_STATUS_SUCCESS && clip_path) {
status = _cairo_surface_fill (surface,
@@ -140,3 +134,32 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
*ty = clip->extents.y;
return surface;
}
+
+cairo_surface_t *
+_cairo_clip_get_image (const cairo_clip_t *clip,
+ cairo_surface_t *target,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_surface_t *surface;
+ cairo_status_t status;
+
+ surface = cairo_surface_create_similar_image (target,
+ CAIRO_FORMAT_A8,
+ extents->width,
+ extents->height);
+ if (unlikely (surface->status))
+ return surface;
+
+ status = _cairo_surface_paint (surface, CAIRO_OPERATOR_SOURCE,
+ &_cairo_pattern_white.base, NULL);
+ if (likely (status == CAIRO_STATUS_SUCCESS))
+ status = _cairo_clip_combine_with_surface (clip, surface,
+ extents->x, extents->y);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (surface);
+ surface = _cairo_surface_create_in_error (status);
+ }
+
+ return surface;
+}
diff --git a/src/cairo-clip-tor-scan-converter.c b/src/cairo-clip-tor-scan-converter.c
new file mode 100644
index 00000000..e32a5a9d
--- /dev/null
+++ b/src/cairo-clip-tor-scan-converter.c
@@ -0,0 +1,1845 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* glitter-paths - polygon scan converter
+ *
+ * Copyright (c) 2008 M Joonas Pihlaja
+ * Copyright (c) 2007 David Turner
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+/* This is the Glitter paths scan converter incorporated into cairo.
+ * The source is from commit 734c53237a867a773640bd5b64816249fa1730f8
+ * of
+ *
+ * http://gitweb.freedesktop.org/?p=users/joonas/glitter-paths
+ */
+/* Glitter-paths is a stand alone polygon rasteriser derived from
+ * David Turner's reimplementation of Tor Anderssons's 15x17
+ * supersampling rasteriser from the Apparition graphics library. The
+ * main new feature here is cheaply choosing per-scan line between
+ * doing fully analytical coverage computation for an entire row at a
+ * time vs. using a supersampling approach.
+ *
+ * David Turner's code can be found at
+ *
+ * http://david.freetype.org/rasterizer-shootout/raster-comparison-20070813.tar.bz2
+ *
+ * In particular this file incorporates large parts of ftgrays_tor10.h
+ * from raster-comparison-20070813.tar.bz2
+ */
+/* Overview
+ *
+ * A scan converter's basic purpose to take polygon edges and convert
+ * them into an RLE compressed A8 mask. This one works in two phases:
+ * gathering edges and generating spans.
+ *
+ * 1) As the user feeds the scan converter edges they are vertically
+ * clipped and bucketted into a _polygon_ data structure. The edges
+ * are also snapped from the user's coordinates to the subpixel grid
+ * coordinates used during scan conversion.
+ *
+ * user
+ * |
+ * | edges
+ * V
+ * polygon buckets
+ *
+ * 2) Generating spans works by performing a vertical sweep of pixel
+ * rows from top to bottom and maintaining an _active_list_ of edges
+ * that intersect the row. From the active list the fill rule
+ * determines which edges are the left and right edges of the start of
+ * each span, and their contribution is then accumulated into a pixel
+ * coverage list (_cell_list_) as coverage deltas. Once the coverage
+ * deltas of all edges are known we can form spans of constant pixel
+ * coverage by summing the deltas during a traversal of the cell list.
+ * At the end of a pixel row the cell list is sent to a coverage
+ * blitter for rendering to some target surface.
+ *
+ * The pixel coverages are computed by either supersampling the row
+ * and box filtering a mono rasterisation, or by computing the exact
+ * coverages of edges in the active list. The supersampling method is
+ * used whenever some edge starts or stops within the row or there are
+ * edge intersections in the row.
+ *
+ * polygon bucket for \
+ * current pixel row |
+ * | |
+ * | activate new edges | Repeat GRID_Y times if we
+ * V \ are supersampling this row,
+ * active list / or just once if we're computing
+ * | | analytical coverage.
+ * | coverage deltas |
+ * V |
+ * pixel coverage list /
+ * |
+ * V
+ * coverage blitter
+ */
+#include "cairoint.h"
+#include "cairo-spans-private.h"
+#include "cairo-error-private.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <setjmp.h>
+
+/* The input coordinate scale and the rasterisation grid scales. */
+#define GLITTER_INPUT_BITS CAIRO_FIXED_FRAC_BITS
+#define GRID_X_BITS CAIRO_FIXED_FRAC_BITS
+#define GRID_Y 15
+
+/* Set glitter up to use a cairo span renderer to do the coverage
+ * blitting. */
+struct pool;
+struct cell_list;
+
+/*-------------------------------------------------------------------------
+ * glitter-paths.h
+ */
+
+/* "Input scaled" numbers are fixed precision reals with multiplier
+ * 2**GLITTER_INPUT_BITS. Input coordinates are given to glitter as
+ * pixel scaled numbers. These get converted to the internal grid
+ * scaled numbers as soon as possible. Internal overflow is possible
+ * if GRID_X/Y inside glitter-paths.c is larger than
+ * 1<<GLITTER_INPUT_BITS. */
+#ifndef GLITTER_INPUT_BITS
+# define GLITTER_INPUT_BITS 8
+#endif
+#define GLITTER_INPUT_SCALE (1<<GLITTER_INPUT_BITS)
+typedef int glitter_input_scaled_t;
+
+/* Opaque type for scan converting. */
+typedef struct glitter_scan_converter glitter_scan_converter_t;
+
+/*-------------------------------------------------------------------------
+ * glitter-paths.c: Implementation internal types
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+/* All polygon coordinates are snapped onto a subsample grid. "Grid
+ * scaled" numbers are fixed precision reals with multiplier GRID_X or
+ * GRID_Y. */
+typedef int grid_scaled_t;
+typedef int grid_scaled_x_t;
+typedef int grid_scaled_y_t;
+
+/* Default x/y scale factors.
+ * You can either define GRID_X/Y_BITS to get a power-of-two scale
+ * or define GRID_X/Y separately. */
+#if !defined(GRID_X) && !defined(GRID_X_BITS)
+# define GRID_X_BITS 8
+#endif
+#if !defined(GRID_Y) && !defined(GRID_Y_BITS)
+# define GRID_Y 15
+#endif
+
+/* Use GRID_X/Y_BITS to define GRID_X/Y if they're available. */
+#ifdef GRID_X_BITS
+# define GRID_X (1 << GRID_X_BITS)
+#endif
+#ifdef GRID_Y_BITS
+# define GRID_Y (1 << GRID_Y_BITS)
+#endif
+
+/* The GRID_X_TO_INT_FRAC macro splits a grid scaled coordinate into
+ * integer and fractional parts. The integer part is floored. */
+#if defined(GRID_X_TO_INT_FRAC)
+ /* do nothing */
+#elif defined(GRID_X_BITS)
+# define GRID_X_TO_INT_FRAC(x, i, f) \
+ _GRID_TO_INT_FRAC_shift(x, i, f, GRID_X_BITS)
+#else
+# define GRID_X_TO_INT_FRAC(x, i, f) \
+ _GRID_TO_INT_FRAC_general(x, i, f, GRID_X)
+#endif
+
+#define _GRID_TO_INT_FRAC_general(t, i, f, m) do { \
+ (i) = (t) / (m); \
+ (f) = (t) % (m); \
+ if ((f) < 0) { \
+ --(i); \
+ (f) += (m); \
+ } \
+} while (0)
+
+#define _GRID_TO_INT_FRAC_shift(t, i, f, b) do { \
+ (f) = (t) & ((1 << (b)) - 1); \
+ (i) = (t) >> (b); \
+} while (0)
+
+/* A grid area is a real in [0,1] scaled by 2*GRID_X*GRID_Y. We want
+ * to be able to represent exactly areas of subpixel trapezoids whose
+ * vertices are given in grid scaled coordinates. The scale factor
+ * comes from needing to accurately represent the area 0.5*dx*dy of a
+ * triangle with base dx and height dy in grid scaled numbers. */
+typedef int grid_area_t;
+#define GRID_XY (2*GRID_X*GRID_Y) /* Unit area on the grid. */
+
+/* GRID_AREA_TO_ALPHA(area): map [0,GRID_XY] to [0,255]. */
+#if GRID_XY == 510
+# define GRID_AREA_TO_ALPHA(c) (((c)+1) >> 1)
+#elif GRID_XY == 255
+# define GRID_AREA_TO_ALPHA(c) (c)
+#elif GRID_XY == 64
+# define GRID_AREA_TO_ALPHA(c) (((c) << 2) | -(((c) & 0x40) >> 6))
+#elif GRID_XY == 128
+# define GRID_AREA_TO_ALPHA(c) ((((c) << 1) | -((c) >> 7)) & 255)
+#elif GRID_XY == 256
+# define GRID_AREA_TO_ALPHA(c) (((c) | -((c) >> 8)) & 255)
+#elif GRID_XY == 15
+# define GRID_AREA_TO_ALPHA(c) (((c) << 4) + (c))
+#elif GRID_XY == 2*256*15
+# define GRID_AREA_TO_ALPHA(c) (((c) + ((c)<<4) + 256) >> 9)
+#else
+# define GRID_AREA_TO_ALPHA(c) (((c)*255 + GRID_XY/2) / GRID_XY)
+#endif
+
+#define UNROLL3(x) x x x
+
+struct quorem {
+ int32_t quo;
+ int32_t rem;
+};
+
+/* Header for a chunk of memory in a memory pool. */
+struct _pool_chunk {
+ /* # bytes used in this chunk. */
+ size_t size;
+
+ /* # bytes total in this chunk */
+ size_t capacity;
+
+ /* Pointer to the previous chunk or %NULL if this is the sentinel
+ * chunk in the pool header. */
+ struct _pool_chunk *prev_chunk;
+
+ /* Actual data starts here. Well aligned for pointers. */
+};
+
+/* A memory pool. This is supposed to be embedded on the stack or
+ * within some other structure. It may optionally be followed by an
+ * embedded array from which requests are fulfilled until
+ * malloc needs to be called to allocate a first real chunk. */
+struct pool {
+ /* Chunk we're allocating from. */
+ struct _pool_chunk *current;
+
+ jmp_buf *jmp;
+
+ /* Free list of previously allocated chunks. All have >= default
+ * capacity. */
+ struct _pool_chunk *first_free;
+
+ /* The default capacity of a chunk. */
+ size_t default_capacity;
+
+ /* Header for the sentinel chunk. Directly following the pool
+ * struct should be some space for embedded elements from which
+ * the sentinel chunk allocates from. */
+ struct _pool_chunk sentinel[1];
+};
+
+/* A polygon edge. */
+struct edge {
+ /* Next in y-bucket or active list. */
+ struct edge *next;
+
+ /* Current x coordinate while the edge is on the active
+ * list. Initialised to the x coordinate of the top of the
+ * edge. The quotient is in grid_scaled_x_t units and the
+ * remainder is mod dy in grid_scaled_y_t units.*/
+ struct quorem x;
+
+ /* Advance of the current x when moving down a subsample line. */
+ struct quorem dxdy;
+
+ /* Advance of the current x when moving down a full pixel
+ * row. Only initialised when the height of the edge is large
+ * enough that there's a chance the edge could be stepped by a
+ * full row's worth of subsample rows at a time. */
+ struct quorem dxdy_full;
+
+ /* The clipped y of the top of the edge. */
+ grid_scaled_y_t ytop;
+
+ /* y2-y1 after orienting the edge downwards. */
+ grid_scaled_y_t dy;
+
+ /* Number of subsample rows remaining to scan convert of this
+ * edge. */
+ grid_scaled_y_t height_left;
+
+ /* Original sign of the edge: +1 for downwards, -1 for upwards
+ * edges. */
+ int dir;
+ int vertical;
+ int clip;
+};
+
+/* Number of subsample rows per y-bucket. Must be GRID_Y. */
+#define EDGE_Y_BUCKET_HEIGHT GRID_Y
+
+#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/EDGE_Y_BUCKET_HEIGHT)
+
+/* A collection of sorted and vertically clipped edges of the polygon.
+ * Edges are moved from the polygon to an active list while scan
+ * converting. */
+struct polygon {
+ /* The vertical clip extents. */
+ grid_scaled_y_t ymin, ymax;
+
+ /* Array of edges all starting in the same bucket. An edge is put
+ * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when
+ * it is added to the polygon. */
+ struct edge **y_buckets;
+ struct edge *y_buckets_embedded[64];
+
+ struct {
+ struct pool base[1];
+ struct edge embedded[32];
+ } edge_pool;
+};
+
+/* A cell records the effect on pixel coverage of polygon edges
+ * passing through a pixel. It contains two accumulators of pixel
+ * coverage.
+ *
+ * Consider the effects of a polygon edge on the coverage of a pixel
+ * it intersects and that of the following one. The coverage of the
+ * following pixel is the height of the edge multiplied by the width
+ * of the pixel, and the coverage of the pixel itself is the area of
+ * the trapezoid formed by the edge and the right side of the pixel.
+ *
+ * +-----------------------+-----------------------+
+ * | | |
+ * | | |
+ * |_______________________|_______________________|
+ * | \...................|.......................|\
+ * | \..................|.......................| |
+ * | \.................|.......................| |
+ * | \....covered.....|.......................| |
+ * | \....area.......|.......................| } covered height
+ * | \..............|.......................| |
+ * |uncovered\.............|.......................| |
+ * | area \............|.......................| |
+ * |___________\...........|.......................|/
+ * | | |
+ * | | |
+ * | | |
+ * +-----------------------+-----------------------+
+ *
+ * Since the coverage of the following pixel will always be a multiple
+ * of the width of the pixel, we can store the height of the covered
+ * area instead. The coverage of the pixel itself is the total
+ * coverage minus the area of the uncovered area to the left of the
+ * edge. As it's faster to compute the uncovered area we only store
+ * that and subtract it from the total coverage later when forming
+ * spans to blit.
+ *
+ * The heights and areas are signed, with left edges of the polygon
+ * having positive sign and right edges having negative sign. When
+ * two edges intersect they swap their left/rightness so their
+ * contribution above and below the intersection point must be
+ * computed separately. */
+struct cell {
+ struct cell *next;
+ int x;
+ grid_area_t uncovered_area;
+ grid_scaled_y_t covered_height;
+ grid_scaled_y_t clipped_height;
+};
+
+/* A cell list represents the scan line sparsely as cells ordered by
+ * ascending x. It is geared towards scanning the cells in order
+ * using an internal cursor. */
+struct cell_list {
+ /* Sentinel nodes */
+ struct cell head, tail;
+
+ /* Cursor state for iterating through the cell list. */
+ struct cell *cursor;
+
+ /* Cells in the cell list are owned by the cell list and are
+ * allocated from this pool. */
+ struct {
+ struct pool base[1];
+ struct cell embedded[32];
+ } cell_pool;
+};
+
+struct cell_pair {
+ struct cell *cell1;
+ struct cell *cell2;
+};
+
+/* The active list contains edges in the current scan line ordered by
+ * the x-coordinate of the intercept of the edge and the scan line. */
+struct active_list {
+ /* Leftmost edge on the current scan line. */
+ struct edge *head;
+
+ /* A lower bound on the height of the active edges is used to
+ * estimate how soon some active edge ends. We can't advance the
+ * scan conversion by a full pixel row if an edge ends somewhere
+ * within it. */
+ grid_scaled_y_t min_height;
+};
+
+struct glitter_scan_converter {
+ struct polygon polygon[1];
+ struct active_list active[1];
+ struct cell_list coverages[1];
+
+ /* Clip box. */
+ grid_scaled_y_t ymin, ymax;
+};
+
+/* Compute the floored division a/b. Assumes / and % perform symmetric
+ * division. */
+inline static struct quorem
+floored_divrem(int a, int b)
+{
+ struct quorem qr;
+ qr.quo = a/b;
+ qr.rem = a%b;
+ if ((a^b)<0 && qr.rem) {
+ qr.quo -= 1;
+ qr.rem += b;
+ }
+ return qr;
+}
+
+/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric
+ * division. */
+static struct quorem
+floored_muldivrem(int x, int a, int b)
+{
+ struct quorem qr;
+ long long xa = (long long)x*a;
+ qr.quo = xa/b;
+ qr.rem = xa%b;
+ if ((xa>=0) != (b>=0) && qr.rem) {
+ qr.quo -= 1;
+ qr.rem += b;
+ }
+ return qr;
+}
+
+static struct _pool_chunk *
+_pool_chunk_init(
+ struct _pool_chunk *p,
+ struct _pool_chunk *prev_chunk,
+ size_t capacity)
+{
+ p->prev_chunk = prev_chunk;
+ p->size = 0;
+ p->capacity = capacity;
+ return p;
+}
+
+static struct _pool_chunk *
+_pool_chunk_create(struct pool *pool, size_t size)
+{
+ struct _pool_chunk *p;
+
+ p = malloc(size + sizeof(struct _pool_chunk));
+ if (unlikely (NULL == p))
+ longjmp (*pool->jmp, _cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ return _pool_chunk_init(p, pool->current, size);
+}
+
+static void
+pool_init(struct pool *pool,
+ jmp_buf *jmp,
+ size_t default_capacity,
+ size_t embedded_capacity)
+{
+ pool->jmp = jmp;
+ pool->current = pool->sentinel;
+ pool->first_free = NULL;
+ pool->default_capacity = default_capacity;
+ _pool_chunk_init(pool->sentinel, NULL, embedded_capacity);
+}
+
+static void
+pool_fini(struct pool *pool)
+{
+ struct _pool_chunk *p = pool->current;
+ do {
+ while (NULL != p) {
+ struct _pool_chunk *prev = p->prev_chunk;
+ if (p != pool->sentinel)
+ free(p);
+ p = prev;
+ }
+ p = pool->first_free;
+ pool->first_free = NULL;
+ } while (NULL != p);
+}
+
+/* Satisfy an allocation by first allocating a new large enough chunk
+ * and adding it to the head of the pool's chunk list. This function
+ * is called as a fallback if pool_alloc() couldn't do a quick
+ * allocation from the current chunk in the pool. */
+static void *
+_pool_alloc_from_new_chunk(
+ struct pool *pool,
+ size_t size)
+{
+ struct _pool_chunk *chunk;
+ void *obj;
+ size_t capacity;
+
+ /* If the allocation is smaller than the default chunk size then
+ * try getting a chunk off the free list. Force alloc of a new
+ * chunk for large requests. */
+ capacity = size;
+ chunk = NULL;
+ if (size < pool->default_capacity) {
+ capacity = pool->default_capacity;
+ chunk = pool->first_free;
+ if (chunk) {
+ pool->first_free = chunk->prev_chunk;
+ _pool_chunk_init(chunk, pool->current, chunk->capacity);
+ }
+ }
+
+ if (NULL == chunk)
+ chunk = _pool_chunk_create (pool, capacity);
+ pool->current = chunk;
+
+ obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size);
+ chunk->size += size;
+ return obj;
+}
+
+/* Allocate size bytes from the pool. The first allocated address
+ * returned from a pool is aligned to sizeof(void*). Subsequent
+ * addresses will maintain alignment as long as multiples of void* are
+ * allocated. Returns the address of a new memory area or %NULL on
+ * allocation failures. The pool retains ownership of the returned
+ * memory. */
+inline static void *
+pool_alloc (struct pool *pool, size_t size)
+{
+ struct _pool_chunk *chunk = pool->current;
+
+ if (size <= chunk->capacity - chunk->size) {
+ void *obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size);
+ chunk->size += size;
+ return obj;
+ } else {
+ return _pool_alloc_from_new_chunk(pool, size);
+ }
+}
+
+/* Relinquish all pool_alloced memory back to the pool. */
+static void
+pool_reset (struct pool *pool)
+{
+ /* Transfer all used chunks to the chunk free list. */
+ struct _pool_chunk *chunk = pool->current;
+ if (chunk != pool->sentinel) {
+ while (chunk->prev_chunk != pool->sentinel) {
+ chunk = chunk->prev_chunk;
+ }
+ chunk->prev_chunk = pool->first_free;
+ pool->first_free = pool->current;
+ }
+ /* Reset the sentinel as the current chunk. */
+ pool->current = pool->sentinel;
+ pool->sentinel->size = 0;
+}
+
+/* Rewinds the cell list's cursor to the beginning. After rewinding
+ * we're good to cell_list_find() the cell any x coordinate. */
+inline static void
+cell_list_rewind (struct cell_list *cells)
+{
+ cells->cursor = &cells->head;
+}
+
+/* Rewind the cell list if its cursor has been advanced past x. */
+inline static void
+cell_list_maybe_rewind (struct cell_list *cells, int x)
+{
+ struct cell *tail = cells->cursor;
+ if (tail->x > x)
+ cell_list_rewind (cells);
+}
+
+static void
+cell_list_init(struct cell_list *cells, jmp_buf *jmp)
+{
+ pool_init(cells->cell_pool.base, jmp,
+ 256*sizeof(struct cell),
+ sizeof(cells->cell_pool.embedded));
+ cells->tail.next = NULL;
+ cells->tail.x = INT_MAX;
+ cells->head.x = INT_MIN;
+ cells->head.next = &cells->tail;
+ cell_list_rewind (cells);
+}
+
+static void
+cell_list_fini(struct cell_list *cells)
+{
+ pool_fini (cells->cell_pool.base);
+}
+
+/* Empty the cell list. This is called at the start of every pixel
+ * row. */
+inline static void
+cell_list_reset (struct cell_list *cells)
+{
+ cell_list_rewind (cells);
+ cells->head.next = &cells->tail;
+ pool_reset (cells->cell_pool.base);
+}
+
+static struct cell *
+cell_list_alloc (struct cell_list *cells,
+ struct cell *tail,
+ int x)
+{
+ struct cell *cell;
+
+ cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell));
+ cell->next = tail->next;
+ tail->next = cell;
+ cell->x = x;
+ cell->uncovered_area = 0;
+ cell->covered_height = 0;
+ cell->clipped_height = 0;
+ return cell;
+}
+
+/* Find a cell at the given x-coordinate. Returns %NULL if a new cell
+ * needed to be allocated but couldn't be. Cells must be found with
+ * non-decreasing x-coordinate until the cell list is rewound using
+ * cell_list_rewind(). Ownership of the returned cell is retained by
+ * the cell list. */
+inline static struct cell *
+cell_list_find (struct cell_list *cells, int x)
+{
+ struct cell *tail = cells->cursor;
+
+ while (1) {
+ UNROLL3({
+ if (tail->next->x > x)
+ break;
+ tail = tail->next;
+ });
+ }
+
+ if (tail->x != x)
+ tail = cell_list_alloc (cells, tail, x);
+ return cells->cursor = tail;
+
+}
+
+/* Find two cells at x1 and x2. This is exactly equivalent
+ * to
+ *
+ * pair.cell1 = cell_list_find(cells, x1);
+ * pair.cell2 = cell_list_find(cells, x2);
+ *
+ * except with less function call overhead. */
+inline static struct cell_pair
+cell_list_find_pair(struct cell_list *cells, int x1, int x2)
+{
+ struct cell_pair pair;
+
+ pair.cell1 = cells->cursor;
+ while (1) {
+ UNROLL3({
+ if (pair.cell1->next->x > x1)
+ break;
+ pair.cell1 = pair.cell1->next;
+ });
+ }
+ if (pair.cell1->x != x1) {
+ struct cell *cell = pool_alloc (cells->cell_pool.base,
+ sizeof (struct cell));
+ cell->x = x1;
+ cell->uncovered_area = 0;
+ cell->covered_height = 0;
+ cell->clipped_height = 0;
+ cell->next = pair.cell1->next;
+ pair.cell1->next = cell;
+ pair.cell1 = cell;
+ }
+
+ pair.cell2 = pair.cell1;
+ while (1) {
+ UNROLL3({
+ if (pair.cell2->next->x > x2)
+ break;
+ pair.cell2 = pair.cell2->next;
+ });
+ }
+ if (pair.cell2->x != x2) {
+ struct cell *cell = pool_alloc (cells->cell_pool.base,
+ sizeof (struct cell));
+ cell->uncovered_area = 0;
+ cell->covered_height = 0;
+ cell->clipped_height = 0;
+ cell->x = x2;
+ cell->next = pair.cell2->next;
+ pair.cell2->next = cell;
+ pair.cell2 = cell;
+ }
+
+ cells->cursor = pair.cell2;
+ return pair;
+}
+
+/* Add a subpixel span covering [x1, x2) to the coverage cells. */
+inline static void
+cell_list_add_subspan(struct cell_list *cells,
+ grid_scaled_x_t x1,
+ grid_scaled_x_t x2)
+{
+ int ix1, fx1;
+ int ix2, fx2;
+
+ GRID_X_TO_INT_FRAC(x1, ix1, fx1);
+ GRID_X_TO_INT_FRAC(x2, ix2, fx2);
+
+ if (ix1 != ix2) {
+ struct cell_pair p;
+ p = cell_list_find_pair(cells, ix1, ix2);
+ p.cell1->uncovered_area += 2*fx1;
+ ++p.cell1->covered_height;
+ p.cell2->uncovered_area -= 2*fx2;
+ --p.cell2->covered_height;
+ } else {
+ struct cell *cell = cell_list_find(cells, ix1);
+ cell->uncovered_area += 2*(fx1-fx2);
+ }
+}
+
+/* Adds the analytical coverage of an edge crossing the current pixel
+ * row to the coverage cells and advances the edge's x position to the
+ * following row.
+ *
+ * This function is only called when we know that during this pixel row:
+ *
+ * 1) The relative order of all edges on the active list doesn't
+ * change. In particular, no edges intersect within this row to pixel
+ * precision.
+ *
+ * 2) No new edges start in this row.
+ *
+ * 3) No existing edges end mid-row.
+ *
+ * This function depends on being called with all edges from the
+ * active list in the order they appear on the list (i.e. with
+ * non-decreasing x-coordinate.) */
+static void
+cell_list_render_edge(
+ struct cell_list *cells,
+ struct edge *edge,
+ int sign)
+{
+ grid_scaled_y_t y1, y2, dy;
+ grid_scaled_x_t dx;
+ int ix1, ix2;
+ grid_scaled_x_t fx1, fx2;
+
+ struct quorem x1 = edge->x;
+ struct quorem x2 = x1;
+
+ if (! edge->vertical) {
+ x2.quo += edge->dxdy_full.quo;
+ x2.rem += edge->dxdy_full.rem;
+ if (x2.rem >= 0) {
+ ++x2.quo;
+ x2.rem -= edge->dy;
+ }
+
+ edge->x = x2;
+ }
+
+ GRID_X_TO_INT_FRAC(x1.quo, ix1, fx1);
+ GRID_X_TO_INT_FRAC(x2.quo, ix2, fx2);
+
+ /* Edge is entirely within a column? */
+ if (ix1 == ix2) {
+ /* We always know that ix1 is >= the cell list cursor in this
+ * case due to the no-intersections precondition. */
+ struct cell *cell = cell_list_find(cells, ix1);
+ cell->covered_height += sign*GRID_Y;
+ cell->uncovered_area += sign*(fx1 + fx2)*GRID_Y;
+ return;
+ }
+
+ /* Orient the edge left-to-right. */
+ dx = x2.quo - x1.quo;
+ if (dx >= 0) {
+ y1 = 0;
+ y2 = GRID_Y;
+ } else {
+ int tmp;
+ tmp = ix1; ix1 = ix2; ix2 = tmp;
+ tmp = fx1; fx1 = fx2; fx2 = tmp;
+ dx = -dx;
+ sign = -sign;
+ y1 = GRID_Y;
+ y2 = 0;
+ }
+ dy = y2 - y1;
+
+ /* Add coverage for all pixels [ix1,ix2] on this row crossed
+ * by the edge. */
+ {
+ struct cell_pair pair;
+ struct quorem y = floored_divrem((GRID_X - fx1)*dy, dx);
+
+ /* When rendering a previous edge on the active list we may
+ * advance the cell list cursor past the leftmost pixel of the
+ * current edge even though the two edges don't intersect.
+ * e.g. consider two edges going down and rightwards:
+ *
+ * --\_+---\_+-----+-----+----
+ * \_ \_ | |
+ * | \_ | \_ | |
+ * | \_| \_| |
+ * | \_ \_ |
+ * ----+-----+-\---+-\---+----
+ *
+ * The left edge touches cells past the starting cell of the
+ * right edge. Fortunately such cases are rare.
+ *
+ * The rewinding is never necessary if the current edge stays
+ * within a single column because we've checked before calling
+ * this function that the active list order won't change. */
+ cell_list_maybe_rewind(cells, ix1);
+
+ pair = cell_list_find_pair(cells, ix1, ix1+1);
+ pair.cell1->uncovered_area += sign*y.quo*(GRID_X + fx1);
+ pair.cell1->covered_height += sign*y.quo;
+ y.quo += y1;
+
+ if (ix1+1 < ix2) {
+ struct quorem dydx_full = floored_divrem(GRID_X*dy, dx);
+ struct cell *cell = pair.cell2;
+
+ ++ix1;
+ do {
+ grid_scaled_y_t y_skip = dydx_full.quo;
+ y.rem += dydx_full.rem;
+ if (y.rem >= dx) {
+ ++y_skip;
+ y.rem -= dx;
+ }
+
+ y.quo += y_skip;
+
+ y_skip *= sign;
+ cell->uncovered_area += y_skip*GRID_X;
+ cell->covered_height += y_skip;
+
+ ++ix1;
+ cell = cell_list_find(cells, ix1);
+ } while (ix1 != ix2);
+
+ pair.cell2 = cell;
+ }
+ pair.cell2->uncovered_area += sign*(y2 - y.quo)*fx2;
+ pair.cell2->covered_height += sign*(y2 - y.quo);
+ }
+}
+
+static void
+polygon_init (struct polygon *polygon, jmp_buf *jmp)
+{
+ polygon->ymin = polygon->ymax = 0;
+ polygon->y_buckets = polygon->y_buckets_embedded;
+ pool_init (polygon->edge_pool.base, jmp,
+ 8192 - sizeof (struct _pool_chunk),
+ sizeof (polygon->edge_pool.embedded));
+}
+
+static void
+polygon_fini (struct polygon *polygon)
+{
+ if (polygon->y_buckets != polygon->y_buckets_embedded)
+ free (polygon->y_buckets);
+
+ pool_fini (polygon->edge_pool.base);
+}
+
+/* Empties the polygon of all edges. The polygon is then prepared to
+ * receive new edges and clip them to the vertical range
+ * [ymin,ymax). */
+static cairo_status_t
+polygon_reset (struct polygon *polygon,
+ grid_scaled_y_t ymin,
+ grid_scaled_y_t ymax)
+{
+ unsigned h = ymax - ymin;
+ unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + EDGE_Y_BUCKET_HEIGHT-1,
+ ymin);
+
+ pool_reset(polygon->edge_pool.base);
+
+ if (unlikely (h > 0x7FFFFFFFU - EDGE_Y_BUCKET_HEIGHT))
+ goto bail_no_mem; /* even if you could, you wouldn't want to. */
+
+ if (polygon->y_buckets != polygon->y_buckets_embedded)
+ free (polygon->y_buckets);
+
+ polygon->y_buckets = polygon->y_buckets_embedded;
+ if (num_buckets > ARRAY_LENGTH (polygon->y_buckets_embedded)) {
+ polygon->y_buckets = _cairo_malloc_ab (num_buckets,
+ sizeof (struct edge *));
+ if (unlikely (NULL == polygon->y_buckets))
+ goto bail_no_mem;
+ }
+ memset (polygon->y_buckets, 0, num_buckets * sizeof (struct edge *));
+
+ polygon->ymin = ymin;
+ polygon->ymax = ymax;
+ return CAIRO_STATUS_SUCCESS;
+
+ bail_no_mem:
+ polygon->ymin = 0;
+ polygon->ymax = 0;
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+static void
+_polygon_insert_edge_into_its_y_bucket(
+ struct polygon *polygon,
+ struct edge *e)
+{
+ unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin);
+ struct edge **ptail = &polygon->y_buckets[ix];
+ e->next = *ptail;
+ *ptail = e;
+}
+
+inline static void
+polygon_add_edge (struct polygon *polygon,
+ const cairo_edge_t *edge,
+ int clip)
+{
+ struct edge *e;
+ grid_scaled_x_t dx;
+ grid_scaled_y_t dy;
+ grid_scaled_y_t ytop, ybot;
+ grid_scaled_y_t ymin = polygon->ymin;
+ grid_scaled_y_t ymax = polygon->ymax;
+
+ assert (edge->bottom > edge->top);
+
+ if (unlikely (edge->top >= ymax || edge->bottom <= ymin))
+ return;
+
+ e = pool_alloc (polygon->edge_pool.base, sizeof (struct edge));
+
+ dx = edge->line.p2.x - edge->line.p1.x;
+ dy = edge->line.p2.y - edge->line.p1.y;
+ e->dy = dy;
+ e->dir = edge->dir;
+ e->clip = clip;
+
+ ytop = edge->top >= ymin ? edge->top : ymin;
+ ybot = edge->bottom <= ymax ? edge->bottom : ymax;
+ e->ytop = ytop;
+ e->height_left = ybot - ytop;
+
+ if (dx == 0) {
+ e->vertical = TRUE;
+ e->x.quo = edge->line.p1.x;
+ e->x.rem = 0;
+ e->dxdy.quo = 0;
+ e->dxdy.rem = 0;
+ e->dxdy_full.quo = 0;
+ e->dxdy_full.rem = 0;
+ } else {
+ e->vertical = FALSE;
+ e->dxdy = floored_divrem (dx, dy);
+ if (ytop == edge->line.p1.y) {
+ e->x.quo = edge->line.p1.x;
+ e->x.rem = 0;
+ } else {
+ e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy);
+ e->x.quo += edge->line.p1.x;
+ }
+
+ if (e->height_left >= GRID_Y) {
+ e->dxdy_full = floored_muldivrem (GRID_Y, dx, dy);
+ } else {
+ e->dxdy_full.quo = 0;
+ e->dxdy_full.rem = 0;
+ }
+ }
+
+ _polygon_insert_edge_into_its_y_bucket (polygon, e);
+
+ e->x.rem -= dy; /* Bias the remainder for faster
+ * edge advancement. */
+}
+
+static void
+active_list_reset (struct active_list *active)
+{
+ active->head = NULL;
+ active->min_height = 0;
+}
+
+static void
+active_list_init(struct active_list *active)
+{
+ active_list_reset(active);
+}
+
+/*
+ * Merge two sorted edge lists.
+ * Input:
+ * - head_a: The head of the first list.
+ * - head_b: The head of the second list; head_b cannot be NULL.
+ * Output:
+ * Returns the head of the merged list.
+ *
+ * Implementation notes:
+ * To make it fast (in particular, to reduce to an insertion sort whenever
+ * one of the two input lists only has a single element) we iterate through
+ * a list until its head becomes greater than the head of the other list,
+ * then we switch their roles. As soon as one of the two lists is empty, we
+ * just attach the other one to the current list and exit.
+ * Writes to memory are only needed to "switch" lists (as it also requires
+ * attaching to the output list the list which we will be iterating next) and
+ * to attach the last non-empty list.
+ */
+static struct edge *
+merge_sorted_edges (struct edge *head_a, struct edge *head_b)
+{
+ struct edge *head, **next;
+ int32_t x;
+
+ if (head_a == NULL)
+ return head_b;
+
+ next = &head;
+ if (head_a->x.quo <= head_b->x.quo) {
+ head = head_a;
+ } else {
+ head = head_b;
+ goto start_with_b;
+ }
+
+ do {
+ x = head_b->x.quo;
+ while (head_a != NULL && head_a->x.quo <= x) {
+ next = &head_a->next;
+ head_a = head_a->next;
+ }
+
+ *next = head_b;
+ if (head_a == NULL)
+ return head;
+
+start_with_b:
+ x = head_a->x.quo;
+ while (head_b != NULL && head_b->x.quo <= x) {
+ next = &head_b->next;
+ head_b = head_b->next;
+ }
+
+ *next = head_a;
+ if (head_b == NULL)
+ return head;
+ } while (1);
+}
+
+/*
+ * Sort (part of) a list.
+ * Input:
+ * - list: The list to be sorted; list cannot be NULL.
+ * - limit: Recursion limit.
+ * Output:
+ * - head_out: The head of the sorted list containing the first 2^(level+1) elements of the
+ * input list; if the input list has fewer elements, head_out be a sorted list
+ * containing all the elements of the input list.
+ * Returns the head of the list of unprocessed elements (NULL if the sorted list contains
+ * all the elements of the input list).
+ *
+ * Implementation notes:
+ * Special case single element list, unroll/inline the sorting of the first two elements.
+ * Some tail recursion is used since we iterate on the bottom-up solution of the problem
+ * (we start with a small sorted list and keep merging other lists of the same size to it).
+ */
+static struct edge *
+sort_edges (struct edge *list,
+ unsigned int level,
+ struct edge **head_out)
+{
+ struct edge *head_other, *remaining;
+ unsigned int i;
+
+ head_other = list->next;
+
+ /* Single element list -> return */
+ if (head_other == NULL) {
+ *head_out = list;
+ return NULL;
+ }
+
+ /* Unroll the first iteration of the following loop (halves the number of calls to merge_sorted_edges):
+ * - Initialize remaining to be the list containing the elements after the second in the input list.
+ * - Initialize *head_out to be the sorted list containing the first two element.
+ */
+ remaining = head_other->next;
+ if (list->x.quo <= head_other->x.quo) {
+ *head_out = list;
+ /* list->next = head_other; */ /* The input list is already like this. */
+ head_other->next = NULL;
+ } else {
+ *head_out = head_other;
+ head_other->next = list;
+ list->next = NULL;
+ }
+
+ for (i = 0; i < level && remaining; i++) {
+ /* Extract a sorted list of the same size as *head_out
+ * (2^(i+1) elements) from the list of remaining elements. */
+ remaining = sort_edges (remaining, i, &head_other);
+ *head_out = merge_sorted_edges (*head_out, head_other);
+ }
+
+ /* *head_out now contains (at most) 2^(level+1) elements. */
+
+ return remaining;
+}
+
+/* Test if the edges on the active list can be safely advanced by a
+ * full row without intersections or any edges ending. */
+inline static int
+active_list_can_step_full_row (struct active_list *active)
+{
+ const struct edge *e;
+ int prev_x = INT_MIN;
+
+ /* Recomputes the minimum height of all edges on the active
+ * list if we have been dropping edges. */
+ if (active->min_height <= 0) {
+ int min_height = INT_MAX;
+
+ e = active->head;
+ while (NULL != e) {
+ if (e->height_left < min_height)
+ min_height = e->height_left;
+ e = e->next;
+ }
+
+ active->min_height = min_height;
+ }
+
+ if (active->min_height < GRID_Y)
+ return 0;
+
+ /* Check for intersections as no edges end during the next row. */
+ e = active->head;
+ while (NULL != e) {
+ struct quorem x = e->x;
+
+ if (! e->vertical) {
+ x.quo += e->dxdy_full.quo;
+ x.rem += e->dxdy_full.rem;
+ if (x.rem >= 0)
+ ++x.quo;
+ }
+
+ if (x.quo <= prev_x)
+ return 0;
+
+ prev_x = x.quo;
+ e = e->next;
+ }
+
+ return 1;
+}
+
+/* Merges edges on the given subpixel row from the polygon to the
+ * active_list. */
+inline static void
+active_list_merge_edges_from_polygon(struct active_list *active,
+ struct edge **ptail,
+ grid_scaled_y_t y,
+ struct polygon *polygon)
+{
+ /* Split off the edges on the current subrow and merge them into
+ * the active list. */
+ int min_height = active->min_height;
+ struct edge *subrow_edges = NULL;
+ struct edge *tail = *ptail;
+
+ do {
+ struct edge *next = tail->next;
+
+ if (y == tail->ytop) {
+ tail->next = subrow_edges;
+ subrow_edges = tail;
+
+ if (tail->height_left < min_height)
+ min_height = tail->height_left;
+
+ *ptail = next;
+ } else
+ ptail = &tail->next;
+
+ tail = next;
+ } while (tail);
+
+ if (subrow_edges) {
+ sort_edges (subrow_edges, UINT_MAX, &subrow_edges);
+ active->head = merge_sorted_edges (active->head, subrow_edges);
+ active->min_height = min_height;
+ }
+}
+
+/* Advance the edges on the active list by one subsample row by
+ * updating their x positions. Drop edges from the list that end. */
+inline static void
+active_list_substep_edges(struct active_list *active)
+{
+ struct edge **cursor = &active->head;
+ grid_scaled_x_t prev_x = INT_MIN;
+ struct edge *unsorted = NULL;
+ struct edge *edge = *cursor;
+
+ do {
+ UNROLL3({
+ struct edge *next;
+
+ if (NULL == edge)
+ break;
+
+ next = edge->next;
+ if (--edge->height_left) {
+ edge->x.quo += edge->dxdy.quo;
+ edge->x.rem += edge->dxdy.rem;
+ if (edge->x.rem >= 0) {
+ ++edge->x.quo;
+ edge->x.rem -= edge->dy;
+ }
+
+ if (edge->x.quo < prev_x) {
+ *cursor = next;
+ edge->next = unsorted;
+ unsorted = edge;
+ } else {
+ prev_x = edge->x.quo;
+ cursor = &edge->next;
+ }
+ } else {
+ *cursor = next;
+ }
+ edge = next;
+ })
+ } while (1);
+
+ if (unsorted) {
+ sort_edges (unsorted, UINT_MAX, &unsorted);
+ active->head = merge_sorted_edges (active->head, unsorted);
+ }
+}
+
+inline static void
+apply_nonzero_fill_rule_for_subrow (struct active_list *active,
+ struct cell_list *coverages)
+{
+ struct edge *edge = active->head;
+ int winding = 0;
+ int xstart;
+ int xend;
+
+ cell_list_rewind (coverages);
+
+ while (NULL != edge) {
+ xstart = edge->x.quo;
+ winding = edge->dir;
+ while (1) {
+ edge = edge->next;
+ if (NULL == edge) {
+ ASSERT_NOT_REACHED;
+ return;
+ }
+
+ winding += edge->dir;
+ if (0 == winding) {
+ if (edge->next == NULL || edge->next->x.quo != edge->x.quo)
+ break;
+ }
+ }
+
+ xend = edge->x.quo;
+ cell_list_add_subspan (coverages, xstart, xend);
+
+ edge = edge->next;
+ }
+}
+
+static void
+apply_evenodd_fill_rule_for_subrow (struct active_list *active,
+ struct cell_list *coverages)
+{
+ struct edge *edge = active->head;
+ int xstart;
+ int xend;
+
+ cell_list_rewind (coverages);
+
+ while (NULL != edge) {
+ xstart = edge->x.quo;
+
+ while (1) {
+ edge = edge->next;
+ if (NULL == edge) {
+ ASSERT_NOT_REACHED;
+ return;
+ }
+
+ if (edge->next == NULL || edge->next->x.quo != edge->x.quo)
+ break;
+
+ edge = edge->next;
+ }
+
+ xend = edge->x.quo;
+ cell_list_add_subspan (coverages, xstart, xend);
+
+ edge = edge->next;
+ }
+}
+
+static void
+apply_nonzero_fill_rule_and_step_edges (struct active_list *active,
+ struct cell_list *coverages)
+{
+ struct edge **cursor = &active->head;
+ struct edge *left_edge;
+
+ left_edge = *cursor;
+ while (NULL != left_edge) {
+ struct edge *right_edge;
+ int winding = left_edge->dir;
+
+ left_edge->height_left -= GRID_Y;
+ if (left_edge->height_left)
+ cursor = &left_edge->next;
+ else
+ *cursor = left_edge->next;
+
+ while (1) {
+ right_edge = *cursor;
+ if (NULL == right_edge) {
+ cell_list_render_edge (coverages, left_edge, +1);
+ return;
+ }
+
+ right_edge->height_left -= GRID_Y;
+ if (right_edge->height_left)
+ cursor = &right_edge->next;
+ else
+ *cursor = right_edge->next;
+
+ winding += right_edge->dir;
+ if (0 == winding) {
+ if (right_edge->next == NULL ||
+ right_edge->next->x.quo != right_edge->x.quo)
+ {
+ break;
+ }
+ }
+
+ if (! right_edge->vertical) {
+ right_edge->x.quo += right_edge->dxdy_full.quo;
+ right_edge->x.rem += right_edge->dxdy_full.rem;
+ if (right_edge->x.rem >= 0) {
+ ++right_edge->x.quo;
+ right_edge->x.rem -= right_edge->dy;
+ }
+ }
+ }
+
+ cell_list_render_edge (coverages, left_edge, +1);
+ cell_list_render_edge (coverages, right_edge, -1);
+
+ left_edge = *cursor;
+ }
+}
+
+static void
+apply_evenodd_fill_rule_and_step_edges (struct active_list *active,
+ struct cell_list *coverages)
+{
+ struct edge **cursor = &active->head;
+ struct edge *left_edge;
+
+ left_edge = *cursor;
+ while (NULL != left_edge) {
+ struct edge *right_edge;
+
+ left_edge->height_left -= GRID_Y;
+ if (left_edge->height_left)
+ cursor = &left_edge->next;
+ else
+ *cursor = left_edge->next;
+
+ while (1) {
+ right_edge = *cursor;
+ if (NULL == right_edge) {
+ cell_list_render_edge (coverages, left_edge, +1);
+ return;
+ }
+
+ right_edge->height_left -= GRID_Y;
+ if (right_edge->height_left)
+ cursor = &right_edge->next;
+ else
+ *cursor = right_edge->next;
+
+ if (right_edge->next == NULL ||
+ right_edge->next->x.quo != right_edge->x.quo)
+ {
+ break;
+ }
+
+ if (! right_edge->vertical) {
+ right_edge->x.quo += right_edge->dxdy_full.quo;
+ right_edge->x.rem += right_edge->dxdy_full.rem;
+ if (right_edge->x.rem >= 0) {
+ ++right_edge->x.quo;
+ right_edge->x.rem -= right_edge->dy;
+ }
+ }
+ }
+
+ cell_list_render_edge (coverages, left_edge, +1);
+ cell_list_render_edge (coverages, right_edge, -1);
+
+ left_edge = *cursor;
+ }
+}
+
+static void
+_glitter_scan_converter_init(glitter_scan_converter_t *converter, jmp_buf *jmp)
+{
+ polygon_init(converter->polygon, jmp);
+ active_list_init(converter->active);
+ cell_list_init(converter->coverages, jmp);
+ converter->ymin=0;
+ converter->ymax=0;
+}
+
+static void
+_glitter_scan_converter_fini(glitter_scan_converter_t *converter)
+{
+ polygon_fini(converter->polygon);
+ cell_list_fini(converter->coverages);
+ converter->ymin=0;
+ converter->ymax=0;
+}
+
+static grid_scaled_t
+int_to_grid_scaled(int i, int scale)
+{
+ /* Clamp to max/min representable scaled number. */
+ if (i >= 0) {
+ if (i >= INT_MAX/scale)
+ i = INT_MAX/scale;
+ }
+ else {
+ if (i <= INT_MIN/scale)
+ i = INT_MIN/scale;
+ }
+ return i*scale;
+}
+
+#define int_to_grid_scaled_x(x) int_to_grid_scaled((x), GRID_X)
+#define int_to_grid_scaled_y(x) int_to_grid_scaled((x), GRID_Y)
+
+static cairo_status_t
+glitter_scan_converter_reset(glitter_scan_converter_t *converter,
+ int ymin, int ymax)
+{
+ cairo_status_t status;
+
+ converter->ymin = 0;
+ converter->ymax = 0;
+
+ ymin = int_to_grid_scaled_y(ymin);
+ ymax = int_to_grid_scaled_y(ymax);
+
+ active_list_reset(converter->active);
+ cell_list_reset(converter->coverages);
+ status = polygon_reset(converter->polygon, ymin, ymax);
+ if (status)
+ return status;
+
+ converter->ymin = ymin;
+ converter->ymax = ymax;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* INPUT_TO_GRID_X/Y (in_coord, out_grid_scaled, grid_scale)
+ * These macros convert an input coordinate in the client's
+ * device space to the rasterisation grid.
+ */
+/* Gah.. this bit of ugly defines INPUT_TO_GRID_X/Y so as to use
+ * shifts if possible, and something saneish if not.
+ */
+#if !defined(INPUT_TO_GRID_Y) && defined(GRID_Y_BITS) && GRID_Y_BITS <= GLITTER_INPUT_BITS
+# define INPUT_TO_GRID_Y(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_Y_BITS)
+#else
+# define INPUT_TO_GRID_Y(in, out) INPUT_TO_GRID_general(in, out, GRID_Y)
+#endif
+
+#if !defined(INPUT_TO_GRID_X) && defined(GRID_X_BITS) && GRID_X_BITS <= GLITTER_INPUT_BITS
+# define INPUT_TO_GRID_X(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_X_BITS)
+#else
+# define INPUT_TO_GRID_X(in, out) INPUT_TO_GRID_general(in, out, GRID_X)
+#endif
+
+#define INPUT_TO_GRID_general(in, out, grid_scale) do { \
+ long long tmp__ = (long long)(grid_scale) * (in); \
+ tmp__ >>= GLITTER_INPUT_BITS; \
+ (out) = tmp__; \
+} while (0)
+
+static void
+glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
+ const cairo_edge_t *edge,
+ int clip)
+{
+ cairo_edge_t e;
+
+ INPUT_TO_GRID_Y (edge->top, e.top);
+ INPUT_TO_GRID_Y (edge->bottom, e.bottom);
+ if (e.top >= e.bottom)
+ return;
+
+ /* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */
+ INPUT_TO_GRID_Y (edge->line.p1.y, e.line.p1.y);
+ INPUT_TO_GRID_Y (edge->line.p2.y, e.line.p2.y);
+ if (e.line.p1.y == e.line.p2.y)
+ return;
+
+ INPUT_TO_GRID_X (edge->line.p1.x, e.line.p1.x);
+ INPUT_TO_GRID_X (edge->line.p2.x, e.line.p2.x);
+
+ e.dir = edge->dir;
+
+ polygon_add_edge (converter->polygon, &e, clip);
+}
+
+static cairo_bool_t
+active_list_is_vertical (struct active_list *active)
+{
+ struct edge *e;
+
+ for (e = active->head; e != NULL; e = e->next) {
+ if (! e->vertical)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+step_edges (struct active_list *active, int count)
+{
+ struct edge **cursor = &active->head;
+ struct edge *edge;
+
+ for (edge = *cursor; edge != NULL; edge = *cursor) {
+ edge->height_left -= GRID_Y * count;
+ if (edge->height_left)
+ cursor = &edge->next;
+ else
+ *cursor = edge->next;
+ }
+}
+
+static cairo_status_t
+blit_coverages (struct cell_list *cells,
+ cairo_span_renderer_t *renderer,
+ struct pool *span_pool,
+ int y, int height)
+{
+ struct cell *cell = cells->head.next;
+ int prev_x = -1;
+ int cover = 0, last_cover = 0;
+ int clip = 0;
+ cairo_half_open_span_t *spans;
+ unsigned num_spans;
+
+ assert (cell != &cells->tail);
+
+ /* Count number of cells remaining. */
+ {
+ struct cell *next = cell;
+ num_spans = 2;
+ while (next->next) {
+ next = next->next;
+ ++num_spans;
+ }
+ num_spans = 2*num_spans;
+ }
+
+ /* Allocate enough spans for the row. */
+ pool_reset (span_pool);
+ spans = pool_alloc (span_pool, sizeof(spans[0])*num_spans);
+ num_spans = 0;
+
+ /* Form the spans from the coverages and areas. */
+ for (; cell->next; cell = cell->next) {
+ int x = cell->x;
+ int area;
+
+ if (x > prev_x && cover != last_cover) {
+ spans[num_spans].x = prev_x;
+ spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover);
+ spans[num_spans].inverse = 0;
+ last_cover = cover;
+ ++num_spans;
+ }
+
+ cover += cell->covered_height*GRID_X*2;
+ clip += cell->covered_height*GRID_X*2;
+ area = cover - cell->uncovered_area;
+
+ if (area != last_cover) {
+ spans[num_spans].x = x;
+ spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area);
+ spans[num_spans].inverse = 0;
+ last_cover = area;
+ ++num_spans;
+ }
+
+ prev_x = x+1;
+ }
+
+ /* Dump them into the renderer. */
+ return renderer->render_rows (renderer, y, height, spans, num_spans);
+}
+
+static void
+glitter_scan_converter_render(glitter_scan_converter_t *converter,
+ int nonzero_fill,
+ cairo_span_renderer_t *span_renderer,
+ struct pool *span_pool)
+{
+ int i, j;
+ int ymax_i = converter->ymax / GRID_Y;
+ int ymin_i = converter->ymin / GRID_Y;
+ int h = ymax_i - ymin_i;
+ struct polygon *polygon = converter->polygon;
+ struct cell_list *coverages = converter->coverages;
+ struct active_list *active = converter->active;
+
+ /* Render each pixel row. */
+ for (i = 0; i < h; i = j) {
+ int do_full_step = 0;
+
+ j = i + 1;
+
+ /* Determine if we can ignore this row or use the full pixel
+ * stepper. */
+ if (GRID_Y == EDGE_Y_BUCKET_HEIGHT && ! polygon->y_buckets[i]) {
+ if (! active->head) {
+ for (; j < h && ! polygon->y_buckets[j]; j++)
+ ;
+ continue;
+ }
+
+ do_full_step = active_list_can_step_full_row (active);
+ }
+
+ if (do_full_step) {
+ /* Step by a full pixel row's worth. */
+ if (nonzero_fill)
+ apply_nonzero_fill_rule_and_step_edges (active, coverages);
+ else
+ apply_evenodd_fill_rule_and_step_edges (active, coverages);
+
+ if (active_list_is_vertical (active)) {
+ while (j < h &&
+ polygon->y_buckets[j] == NULL &&
+ active->min_height >= 2*GRID_Y)
+ {
+ active->min_height -= GRID_Y;
+ j++;
+ }
+ if (j != i + 1)
+ step_edges (active, j - (i + 1));
+ }
+ } else {
+ grid_scaled_y_t suby;
+
+ /* Subsample this row. */
+ for (suby = 0; suby < GRID_Y; suby++) {
+ grid_scaled_y_t y = (i+ymin_i)*GRID_Y + suby;
+
+ if (polygon->y_buckets[i]) {
+ active_list_merge_edges_from_polygon (active,
+ &polygon->y_buckets[i], y,
+ polygon);
+ }
+
+ if (nonzero_fill)
+ apply_nonzero_fill_rule_for_subrow (active, coverages);
+ else
+ apply_evenodd_fill_rule_for_subrow (active, coverages);
+
+ active_list_substep_edges(active);
+ }
+ }
+
+ blit_coverages (coverages, span_renderer, span_pool, i+ymin_i, j -i);
+ cell_list_reset (coverages);
+
+ if (! active->head)
+ active->min_height = INT_MAX;
+ else
+ active->min_height -= GRID_Y;
+ }
+}
+
+struct _cairo_clip_tor_scan_converter {
+ cairo_scan_converter_t base;
+
+ glitter_scan_converter_t converter[1];
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+
+ cairo_fill_rule_t clip_fill_rule;
+ cairo_antialias_t clip_antialias;
+
+ jmp_buf jmp;
+
+ struct {
+ struct pool base[1];
+ cairo_half_open_span_t embedded[32];
+ } span_pool;
+};
+
+typedef struct _cairo_clip_tor_scan_converter cairo_clip_tor_scan_converter_t;
+
+static void
+_cairo_clip_tor_scan_converter_destroy (void *converter)
+{
+ cairo_clip_tor_scan_converter_t *self = converter;
+ if (self == NULL) {
+ return;
+ }
+ _glitter_scan_converter_fini (self->converter);
+ pool_fini (self->span_pool.base);
+ free(self);
+}
+
+static cairo_status_t
+_cairo_clip_tor_scan_converter_generate (void *converter,
+ cairo_span_renderer_t *renderer)
+{
+ cairo_clip_tor_scan_converter_t *self = converter;
+ cairo_status_t status;
+
+ if ((status = setjmp (self->jmp)))
+ return _cairo_scan_converter_set_error (self, _cairo_error (status));
+
+ glitter_scan_converter_render (self->converter,
+ self->fill_rule == CAIRO_FILL_RULE_WINDING,
+ renderer,
+ self->span_pool.base);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_scan_converter_t *
+_cairo_clip_tor_scan_converter_create (cairo_clip_t *clip,
+ cairo_polygon_t *polygon,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias)
+{
+ cairo_clip_tor_scan_converter_t *self;
+ cairo_polygon_t clipper;
+ cairo_status_t status;
+ int i;
+
+ self = calloc (1, sizeof(struct _cairo_clip_tor_scan_converter));
+ if (unlikely (self == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto bail_nomem;
+ }
+
+ self->base.destroy = _cairo_clip_tor_scan_converter_destroy;
+ self->base.generate = _cairo_clip_tor_scan_converter_generate;
+
+ pool_init (self->span_pool.base, &self->jmp,
+ 250 * sizeof(self->span_pool.embedded[0]),
+ sizeof(self->span_pool.embedded));
+
+ _glitter_scan_converter_init (self->converter, &self->jmp);
+ status = glitter_scan_converter_reset (self->converter,
+ clip->extents.y,
+ clip->extents.y + clip->extents.height);
+ if (unlikely (status))
+ goto bail;
+
+ self->fill_rule = fill_rule;
+ self->antialias = antialias;
+
+ for (i = 0; i < polygon->num_edges; i++)
+ glitter_scan_converter_add_edge (self->converter,
+ &polygon->edges[i],
+ FALSE);
+
+ status = _cairo_clip_get_polygon (clip,
+ &clipper,
+ &self->clip_fill_rule,
+ &self->clip_antialias);
+ if (unlikely (status))
+ goto bail;
+
+ for (i = 0; i < clipper.num_edges; i++)
+ glitter_scan_converter_add_edge (self->converter,
+ &clipper.edges[i],
+ TRUE);
+ _cairo_polygon_fini (&clipper);
+
+ return &self->base;
+
+ bail:
+ self->base.destroy(&self->base);
+ bail_nomem:
+ return _cairo_scan_converter_create_in_error (status);
+}
+
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 6355a977..44f4e7b2 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -246,16 +246,9 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
if (extents.width == 0 || extents.height == 0)
return _cairo_clip_set_all_clipped (clip);
- if (clip && ! _cairo_rectangle_intersect (&clip->extents, &extents))
- return _cairo_clip_set_all_clipped (clip);
-
- if (clip == NULL) {
- clip = _cairo_clip_create ();
- if (unlikely (clip == NULL))
- return _cairo_clip_set_all_clipped (clip);
-
- clip->extents = extents;
- }
+ clip = _cairo_clip_intersect_rectangle (clip, &extents);
+ if (_cairo_clip_is_all_clipped (clip))
+ return clip;
clip_path = _cairo_clip_path_create (clip);
if (unlikely (clip_path == NULL))
@@ -263,7 +256,7 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
status = _cairo_path_fixed_init_copy (&clip_path->path, path);
if (unlikely (status))
- return _cairo_clip_set_all_clipped (clip);
+ return _cairo_clip_set_all_clipped (clip);
clip_path->fill_rule = fill_rule;
clip_path->tolerance = tolerance;
@@ -532,9 +525,10 @@ _cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip)
}
fprintf (stream, "clip:\n");
- fprintf (stream, " extents: (%d, %d) x (%d, %d)",
+ fprintf (stream, " extents: (%d, %d) x (%d, %d), is-region? %d",
clip->extents.x, clip->extents.y,
- clip->extents.width, clip->extents.height);
+ clip->extents.width, clip->extents.height,
+ clip->is_region);
fprintf (stream, " num_boxes = %d\n", clip->num_boxes);
for (i = 0; i < clip->num_boxes; i++) {
diff --git a/src/cairo-composite-rectangles-private.h b/src/cairo-composite-rectangles-private.h
index f0553ab0..8a06bf9f 100644
--- a/src/cairo-composite-rectangles-private.h
+++ b/src/cairo-composite-rectangles-private.h
@@ -39,6 +39,7 @@
#include "cairo-types-private.h"
#include "cairo-error-private.h"
+#include "cairo-pattern-private.h"
CAIRO_BEGIN_DECLS
@@ -52,6 +53,9 @@ CAIRO_BEGIN_DECLS
*
*/
struct _cairo_composite_rectangles {
+ cairo_surface_t *surface;
+ cairo_operator_t op;
+
cairo_rectangle_int_t source;
cairo_rectangle_int_t mask;
cairo_rectangle_int_t destination;
@@ -60,19 +64,27 @@ struct _cairo_composite_rectangles {
cairo_rectangle_int_t unbounded; /* destination IN clip */
uint32_t is_bounded;
+ cairo_rectangle_int_t source_sample_area;
+ cairo_rectangle_int_t mask_sample_area;
+
+ cairo_pattern_union_t source_pattern;
+ cairo_pattern_union_t mask_pattern;
+ const cairo_pattern_t *original_source_pattern;
+ const cairo_pattern_t *original_mask_pattern;
+
cairo_clip_t *clip; /* clip will be reduced to the minimal container */
};
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
- const cairo_rectangle_int_t *unbounded,
+ cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
- const cairo_rectangle_int_t *unbounded,
+ cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
@@ -80,7 +92,7 @@ _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
- const cairo_rectangle_int_t *unbounded,
+ cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
@@ -90,15 +102,31 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
- const cairo_rectangle_int_t *unbounded,
+ cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
const cairo_clip_t *clip);
cairo_private cairo_int_status_t
+_cairo_composite_rectangles_init_for_boxes (cairo_composite_rectangles_t *extents,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_boxes_t *boxes,
+ const cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_composite_rectangles_init_for_polygon (cairo_composite_rectangles_t *extents,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_polygon_t *polygon,
+ const cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
- const cairo_rectangle_int_t *unbounded,
+ cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font,
diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c
index a25e6d34..a50a3474 100644
--- a/src/cairo-composite-rectangles.c
+++ b/src/cairo-composite-rectangles.c
@@ -46,57 +46,93 @@ void _cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents)
_cairo_clip_destroy (extents->clip);
}
+static void
+_cairo_composite_reduce_pattern (const cairo_pattern_t *src,
+ cairo_pattern_union_t *dst)
+{
+ int tx, ty;
+
+ _cairo_pattern_init_static_copy (&dst->base, src);
+ if (dst->base.type == CAIRO_PATTERN_TYPE_SOLID)
+ return;
+
+ dst->base.filter = _cairo_pattern_analyze_filter (&dst->base, NULL),
+
+ tx = ty = 0;
+ if (_cairo_matrix_is_pixman_translation (&dst->base.matrix,
+ dst->base.filter,
+ &tx, &ty))
+ {
+ dst->base.matrix.x0 = tx;
+ dst->base.matrix.y0 = ty;
+ }
+}
+
static inline cairo_bool_t
_cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
- const cairo_rectangle_int_t *unbounded,
+ cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
{
- extents->clip = NULL;
- extents->destination = *unbounded;
-
if (_cairo_clip_is_all_clipped (clip))
return FALSE;
+ extents->surface = surface;
+ extents->op = op;
+
+ _cairo_surface_get_extents (surface, &extents->destination);
+ extents->clip = NULL;
+
extents->unbounded = extents->destination;
- if (clip != NULL) {
- if (! _cairo_rectangle_intersect (&extents->unbounded,
- _cairo_clip_get_extents (clip)))
- return FALSE;
- }
+ if (clip && ! _cairo_rectangle_intersect (&extents->unbounded,
+ _cairo_clip_get_extents (clip)))
+ return FALSE;
extents->bounded = extents->unbounded;
extents->is_bounded = _cairo_operator_bounded_by_either (op);
- _cairo_pattern_get_extents (source, &extents->source);
+ extents->original_source_pattern = source;
+ _cairo_composite_reduce_pattern (source, &extents->source_pattern);
+
+ _cairo_pattern_get_extents (&extents->source_pattern.base,
+ &extents->source);
if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) {
if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
return FALSE;
}
+ extents->original_mask_pattern = NULL;
+ extents->mask_pattern.base.type = CAIRO_PATTERN_TYPE_SOLID;
+ extents->mask_pattern.solid.color.alpha = 1.; /* XXX full initialisation? */
+
return TRUE;
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
- const cairo_rectangle_int_t *unbounded,
+ cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
{
- if (! _cairo_composite_rectangles_init (extents, unbounded,
- op, source, clip))
+ if (! _cairo_composite_rectangles_init (extents,
+ surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
- extents->mask = *unbounded;
+ extents->mask = extents->destination;
extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
if (_cairo_clip_is_all_clipped (extents->clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
+ _cairo_pattern_sampled_area (&extents->source_pattern.base,
+ &extents->bounded,
+ &extents->source_sample_area);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -117,6 +153,21 @@ _cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents,
if (_cairo_clip_is_all_clipped (extents->clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
+ _cairo_pattern_sampled_area (&extents->source_pattern.base,
+ &extents->bounded,
+ &extents->source_sample_area);
+ if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
+ _cairo_pattern_sampled_area (&extents->mask_pattern.base,
+ &extents->bounded,
+ &extents->mask_sample_area);
+ if (extents->mask_sample_area.width == 0 ||
+ extents->mask_sample_area.height == 0) {
+ _cairo_composite_rectangles_fini (extents);
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+ }
+
return CAIRO_STATUS_SUCCESS;
}
@@ -125,7 +176,6 @@ _cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t
const cairo_box_t *box)
{
cairo_rectangle_int_t mask;
- cairo_int_status_t status;
cairo_clip_t *clip;
_cairo_box_round_to_rectangle (box, &mask);
@@ -139,39 +189,70 @@ _cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t
_cairo_rectangle_intersect (&extents->mask, &mask);
+ mask = extents->bounded;
+ if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask) &&
+ extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+ if (mask.width == extents->bounded.width &&
+ mask.height == extents->bounded.height)
+ return CAIRO_INT_STATUS_SUCCESS;
+
+ if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE))
+ extents->unbounded = extents->bounded;
+
extents->mask = mask;
clip = extents->clip;
- status = _cairo_composite_rectangles_intersect (extents, clip);
+ extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
if (clip != extents->clip)
_cairo_clip_destroy (clip);
- return status;
+ if (_cairo_clip_is_all_clipped (extents->clip))
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+ if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
+ _cairo_pattern_sampled_area (&extents->source_pattern.base,
+ &extents->bounded,
+ &extents->source_sample_area);
+ if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) {
+ _cairo_pattern_sampled_area (&extents->mask_pattern.base,
+ &extents->bounded,
+ &extents->mask_sample_area);
+ if (extents->mask_sample_area.width == 0 ||
+ extents->mask_sample_area.height == 0)
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
+ return CAIRO_INT_STATUS_SUCCESS;
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
- const cairo_rectangle_int_t *unbounded,
+ cairo_surface_t*surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip)
{
- if (! _cairo_composite_rectangles_init (extents, unbounded,
- op, source, clip))
+ if (! _cairo_composite_rectangles_init (extents,
+ surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
- _cairo_pattern_get_extents (mask, &extents->mask);
+
+ extents->original_mask_pattern = mask;
+ _cairo_composite_reduce_pattern (mask, &extents->mask_pattern);
+ _cairo_pattern_get_extents (&extents->mask_pattern.base, &extents->mask);
return _cairo_composite_rectangles_intersect (extents, clip);
}
cairo_int_status_t
_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
- const cairo_rectangle_int_t *unbounded,
+ cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
@@ -179,8 +260,8 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
const cairo_matrix_t *ctm,
const cairo_clip_t *clip)
{
- if (! _cairo_composite_rectangles_init (extents, unbounded,
- op, source, clip))
+ if (! _cairo_composite_rectangles_init (extents,
+ surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
@@ -192,14 +273,14 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
cairo_int_status_t
_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
- const cairo_rectangle_int_t *unbounded,
+ cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
const cairo_clip_t *clip)
{
- if (! _cairo_composite_rectangles_init (extents, unbounded,
- op, source, clip))
+ if (! _cairo_composite_rectangles_init (extents,
+ surface, op, source, clip))
{
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
@@ -210,8 +291,47 @@ _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents
}
cairo_int_status_t
+_cairo_composite_rectangles_init_for_polygon (cairo_composite_rectangles_t *extents,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_polygon_t *polygon,
+ const cairo_clip_t *clip)
+{
+ if (! _cairo_composite_rectangles_init (extents,
+ surface, op, source, clip))
+ {
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
+ _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
+ return _cairo_composite_rectangles_intersect (extents, clip);
+}
+
+cairo_int_status_t
+_cairo_composite_rectangles_init_for_boxes (cairo_composite_rectangles_t *extents,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_boxes_t *boxes,
+ const cairo_clip_t *clip)
+{
+ cairo_box_t box;
+
+ if (! _cairo_composite_rectangles_init (extents,
+ surface, op, source, clip))
+ {
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
+ _cairo_boxes_extents (boxes, &box);
+ _cairo_box_round_to_rectangle (&box, &extents->mask);
+ return _cairo_composite_rectangles_intersect (extents, clip);
+}
+
+cairo_int_status_t
_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
- const cairo_rectangle_int_t *unbounded,
+ cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_scaled_font_t *scaled_font,
@@ -222,8 +342,7 @@ _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *exten
{
cairo_status_t status;
- if (! _cairo_composite_rectangles_init (extents, unbounded,
- op, source, clip))
+ if (! _cairo_composite_rectangles_init (extents, surface, op, source, clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
/* Computing the exact bbox and the overlap is expensive.
diff --git a/src/cairo-compositor-private.h b/src/cairo-compositor-private.h
new file mode 100644
index 00000000..72507b21
--- /dev/null
+++ b/src/cairo-compositor-private.h
@@ -0,0 +1,355 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * 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.uk>
+ */
+
+#ifndef CAIRO_COMPOSITOR_PRIVATE_H
+#define CAIRO_COMPOSITOR_PRIVATE_H
+
+#include "cairo-composite-rectangles-private.h"
+
+CAIRO_BEGIN_DECLS
+
+typedef struct {
+ cairo_scaled_font_t *font;
+ cairo_glyph_t *glyphs;
+ int num_glyphs;
+ cairo_bool_t use_mask;
+ cairo_rectangle_int_t extents;
+} cairo_composite_glyphs_info_t;
+
+struct cairo_compositor {
+ const cairo_compositor_t *delegate;
+
+ cairo_warn cairo_int_status_t
+ (*paint) (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents);
+
+ cairo_warn cairo_int_status_t
+ (*mask) (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents);
+
+ cairo_warn cairo_int_status_t
+ (*stroke) (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias);
+
+ cairo_warn cairo_int_status_t
+ (*fill) (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias);
+
+ cairo_warn cairo_int_status_t
+ (*glyphs) (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_bool_t overlap);
+};
+
+struct cairo_mask_compositor {
+ cairo_compositor_t base;
+
+ cairo_int_status_t (*acquire) (void *surface);
+ cairo_int_status_t (*release) (void *surface);
+
+ cairo_int_status_t (*set_clip_region) (void *surface,
+ cairo_region_t *clip_region);
+
+ cairo_surface_t * (*pattern_to_surface) (cairo_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y);
+
+ cairo_int_status_t (*draw_image_boxes) (void *surface,
+ cairo_image_surface_t *image,
+ cairo_boxes_t *boxes,
+ int dx, int dy);
+
+ cairo_int_status_t (*copy_boxes) (void *surface,
+ cairo_surface_t *src,
+ cairo_boxes_t *boxes,
+ const cairo_rectangle_int_t *extents,
+ int dx, int dy);
+
+ cairo_int_status_t
+ (*fill_rectangles) (void *surface,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_rectangle_int_t *rectangles,
+ int num_rects);
+
+ cairo_int_status_t
+ (*fill_boxes) (void *surface,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes);
+
+ cairo_int_status_t
+ (*composite) (void *dst,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ cairo_surface_t *mask,
+ 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_int_status_t
+ (*composite_boxes) (void *surface,
+ cairo_operator_t op,
+ cairo_surface_t *source,
+ cairo_surface_t *mask,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ cairo_boxes_t *boxes,
+ const cairo_rectangle_int_t *extents);
+
+ cairo_int_status_t
+ (*check_composite_glyphs) (const cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int *num_glyphs);
+ cairo_int_status_t
+ (*composite_glyphs) (void *surface,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info);
+};
+
+struct cairo_traps_compositor {
+ cairo_compositor_t base;
+
+ cairo_int_status_t
+ (*acquire) (void *surface);
+
+ cairo_int_status_t
+ (*release) (void *surface);
+
+ cairo_int_status_t
+ (*set_clip_region) (void *surface,
+ cairo_region_t *clip_region);
+
+ cairo_surface_t *
+ (*pattern_to_surface) (cairo_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y);
+
+ cairo_int_status_t (*draw_image_boxes) (void *surface,
+ cairo_image_surface_t *image,
+ cairo_boxes_t *boxes,
+ int dx, int dy);
+
+ cairo_int_status_t (*copy_boxes) (void *surface,
+ cairo_surface_t *src,
+ cairo_boxes_t *boxes,
+ const cairo_rectangle_int_t *extents,
+ int dx, int dy);
+
+ cairo_int_status_t
+ (*fill_boxes) (void *surface,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes);
+
+ cairo_int_status_t
+ (*composite) (void *dst,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ cairo_surface_t *mask,
+ 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_int_status_t
+ (*lerp) (void *_dst,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ 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_int_status_t
+ (*composite_boxes) (void *surface,
+ cairo_operator_t op,
+ cairo_surface_t *source,
+ cairo_surface_t *mask,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ cairo_boxes_t *boxes,
+ const cairo_rectangle_int_t *extents);
+
+ cairo_int_status_t
+ (*composite_traps) (void *dst,
+ cairo_operator_t op,
+ cairo_surface_t *source,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_antialias_t antialias,
+ cairo_traps_t *traps);
+
+ cairo_int_status_t
+ (*composite_tristrip) (void *dst,
+ cairo_operator_t op,
+ cairo_surface_t *source,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_antialias_t antialias,
+ cairo_tristrip_t *tristrip);
+
+ cairo_int_status_t
+ (*check_composite_glyphs) (const cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int *num_glyphs);
+ cairo_int_status_t
+ (*composite_glyphs) (void *surface,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info);
+};
+
+cairo_private extern const cairo_compositor_t __cairo_no_compositor;
+cairo_private extern const cairo_compositor_t _cairo_fallback_compositor;
+
+cairo_private void
+_cairo_mask_compositor_init (cairo_mask_compositor_t *compositor,
+ const cairo_compositor_t *delegate);
+
+cairo_private void
+_cairo_traps_compositor_init (cairo_traps_compositor_t *compositor,
+ const cairo_compositor_t *delegate);
+
+cairo_private cairo_int_status_t
+_cairo_compositor_paint (const cairo_compositor_t *compositor,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_compositor_mask (const cairo_compositor_t *compositor,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ const cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_compositor_stroke (const cairo_compositor_t *compositor,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_compositor_fill (const cairo_compositor_t *compositor,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_compositor_glyphs (const cairo_compositor_t *compositor,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ const cairo_clip_t *clip);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_COMPOSITOR_PRIVATE_H */
diff --git a/src/cairo-compositor.c b/src/cairo-compositor.c
new file mode 100644
index 00000000..cf943e73
--- /dev/null
+++ b/src/cairo-compositor.c
@@ -0,0 +1,213 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * 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.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-error-private.h"
+
+cairo_int_status_t
+_cairo_compositor_paint (const cairo_compositor_t *compositor,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_int_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_paint (&extents, surface,
+ op, source,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ do {
+ while (compositor->paint == NULL)
+ compositor = compositor->delegate;
+
+ status = compositor->paint (compositor, &extents);
+
+ compositor = compositor->delegate;
+ } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+ _cairo_composite_rectangles_fini (&extents);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_compositor_mask (const cairo_compositor_t *compositor,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ const cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_int_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_mask (&extents, surface,
+ op, source, mask,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ do {
+ while (compositor->mask == NULL)
+ compositor = compositor->delegate;
+
+ status = compositor->mask (compositor, &extents);
+
+ compositor = compositor->delegate;
+ } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+ _cairo_composite_rectangles_fini (&extents);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_compositor_stroke (const cairo_compositor_t *compositor,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_int_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_stroke (&extents, surface,
+ op, source,
+ path, style, ctm,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ do {
+ while (compositor->stroke == NULL)
+ compositor = compositor->delegate;
+
+ status = compositor->stroke (compositor, &extents,
+ path, style, ctm, ctm_inverse,
+ tolerance, antialias);
+
+ compositor = compositor->delegate;
+ } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+ _cairo_composite_rectangles_fini (&extents);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_compositor_fill (const cairo_compositor_t *compositor,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_int_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_fill (&extents, surface,
+ op, source, path,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ do {
+ while (compositor->fill == NULL)
+ compositor = compositor->delegate;
+
+ status = compositor->fill (compositor, &extents,
+ path, fill_rule, tolerance, antialias);
+
+ compositor = compositor->delegate;
+ } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+ _cairo_composite_rectangles_fini (&extents);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_compositor_glyphs (const cairo_compositor_t *compositor,
+ cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ const cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_bool_t overlap;
+ cairo_int_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface,
+ op, source,
+ scaled_font,
+ glyphs, num_glyphs,
+ clip, &overlap);
+ if (unlikely (status))
+ return status;
+
+ do {
+ while (compositor->glyphs == NULL)
+ compositor = compositor->delegate;
+
+ status = compositor->glyphs (compositor, &extents,
+ scaled_font, glyphs, num_glyphs, overlap);
+
+ compositor = compositor->delegate;
+ } while (status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+ _cairo_composite_rectangles_fini (&extents);
+
+ return status;
+}
diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index 017eb7ba..98cc6684 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -158,8 +158,7 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
content,
extents.width,
extents.height,
- CAIRO_COLOR_TRANSPARENT,
- TRUE);
+ CAIRO_COLOR_TRANSPARENT);
status = group_surface->status;
if (unlikely (status))
goto bail;
diff --git a/src/cairo-fallback-compositor.c b/src/cairo-fallback-compositor.c
new file mode 100644
index 00000000..105859d6
--- /dev/null
+++ b/src/cairo-fallback-compositor.c
@@ -0,0 +1,174 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-surface-offset-private.h"
+
+/* high-level compositor interface */
+
+static cairo_int_status_t
+_cairo_fallback_compositor_paint (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *image;
+ cairo_int_status_t status;
+
+ image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
+ status = _cairo_surface_offset_paint (image,
+ -extents->unbounded.x,
+ -extents->unbounded.y,
+ extents->op,
+ &extents->source_pattern.base,
+ extents->clip);
+ cairo_surface_unmap_image (extents->surface, image);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_fallback_compositor_mask (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *image;
+ cairo_int_status_t status;
+
+ image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
+ status = _cairo_surface_offset_mask (image,
+ extents->unbounded.x,
+ extents->unbounded.y,
+ extents->op,
+ &extents->source_pattern.base,
+ &extents->mask_pattern.base,
+ extents->clip);
+ cairo_surface_unmap_image (extents->surface, image);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_fallback_compositor_stroke (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_surface_t *image;
+ cairo_int_status_t status;
+
+ image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
+ status = _cairo_surface_offset_stroke (image,
+ extents->unbounded.x,
+ extents->unbounded.y,
+ extents->op,
+ &extents->source_pattern.base,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ antialias,
+ extents->clip);
+ cairo_surface_unmap_image (extents->surface, image);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_fallback_compositor_fill (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_surface_t *image;
+ cairo_int_status_t status;
+
+ image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
+ status = _cairo_surface_offset_fill (image,
+ extents->unbounded.x,
+ extents->unbounded.y,
+ extents->op,
+ &extents->source_pattern.base,
+ path,
+ fill_rule, tolerance, antialias,
+ extents->clip);
+ cairo_surface_unmap_image (extents->surface, image);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_fallback_compositor_glyphs (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_bool_t overlap)
+{
+ cairo_surface_t *image;
+ cairo_int_status_t status;
+
+ image = cairo_surface_map_to_image (extents->surface, &extents->unbounded);
+ status = _cairo_surface_offset_glyphs (image,
+ extents->unbounded.x,
+ extents->unbounded.y,
+ extents->op,
+ &extents->source_pattern.base,
+ scaled_font, glyphs, num_glyphs,
+ extents->clip);
+ cairo_surface_unmap_image (extents->surface, image);
+
+ return status;
+}
+
+const cairo_compositor_t _cairo_fallback_compositor = {
+ &__cairo_no_compositor,
+
+ _cairo_fallback_compositor_paint,
+ _cairo_fallback_compositor_mask,
+ _cairo_fallback_compositor_stroke,
+ _cairo_fallback_compositor_fill,
+ _cairo_fallback_compositor_glyphs,
+};
diff --git a/src/cairo-freed-pool-private.h b/src/cairo-freed-pool-private.h
index 259c57db..0ec6de3d 100644
--- a/src/cairo-freed-pool-private.h
+++ b/src/cairo-freed-pool-private.h
@@ -42,7 +42,9 @@
CAIRO_BEGIN_DECLS
-#if HAS_ATOMIC_OPS
+#define DISABLE_FREED_POOLS 0
+
+#if HAS_ATOMIC_OPS && ! DISABLE_FREED_POOLS
/* Keep a stash of recently freed clip_paths, since we need to
* reallocate them frequently.
*/
@@ -128,7 +130,7 @@ typedef int freed_pool_t;
#define _freed_pool_get(pool) NULL
#define _freed_pool_put(pool, ptr) free(ptr)
-#define _freed_pool_reset(ptr) assert((ptr) != NULL)
+#define _freed_pool_reset(ptr)
#endif
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 9024463e..e0df535c 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -2586,7 +2586,6 @@ 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 */
_cairo_ft_load_truetype_table,
_cairo_ft_index_to_ucs4,
_cairo_ft_is_synthetic,
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 01fe7259..c59501ec 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -49,326 +49,6 @@
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
-static cairo_int_status_t
-_cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
- const cairo_gradient_pattern_t *pattern,
- cairo_gl_gradient_t **gradient)
-{
- cairo_gl_context_t *ctx;
- cairo_status_t status;
-
- status = _cairo_gl_context_acquire (dst->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient);
-
- return _cairo_gl_context_release (ctx, status);
-}
-
-/*
- * Like cairo_pattern_acquire_surface(), but returns a matrix that transforms
- * from dest to src coords.
- */
-static cairo_status_t
-_cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
- const cairo_pattern_t *src,
- cairo_gl_surface_t *dst,
- int src_x, int src_y,
- int dst_x, int dst_y,
- int width, int height)
-{
- cairo_status_t status;
- cairo_matrix_t m;
- cairo_gl_surface_t *surface;
- cairo_surface_attributes_t *attributes;
- attributes = &operand->texture.attributes;
-
- status = _cairo_pattern_acquire_surface (src, &dst->base,
- src_x, src_y,
- width, height,
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **)
- &surface,
- attributes);
- if (unlikely (status))
- return status;
-
- if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device) &&
- (attributes->extend == CAIRO_EXTEND_REPEAT ||
- attributes->extend == CAIRO_EXTEND_REFLECT))
- {
- _cairo_pattern_release_surface (src,
- &surface->base,
- attributes);
- return UNSUPPORTED ("EXT_texture_rectangle with repeat/reflect");
- }
-
- assert (surface->base.backend == &_cairo_gl_surface_backend);
- assert (_cairo_gl_surface_is_texture (surface));
-
- operand->type = CAIRO_GL_OPERAND_TEXTURE;
- operand->texture.surface = surface;
- operand->texture.tex = surface->tex;
- /* Translate the matrix from
- * (unnormalized src -> unnormalized src) to
- * (unnormalized dst -> unnormalized src)
- */
- cairo_matrix_init_translate (&m,
- src_x - dst_x + attributes->x_offset,
- src_y - dst_y + attributes->y_offset);
- cairo_matrix_multiply (&attributes->matrix,
- &m,
- &attributes->matrix);
-
-
- /* Translate the matrix from
- * (unnormalized dst -> unnormalized src) to
- * (unnormalized dst -> normalized src)
- */
- if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) {
- cairo_matrix_init_scale (&m,
- 1.0,
- 1.0);
- } else {
- cairo_matrix_init_scale (&m,
- 1.0 / surface->width,
- 1.0 / surface->height);
- }
- cairo_matrix_multiply (&attributes->matrix,
- &attributes->matrix,
- &m);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
- const cairo_color_t *color)
-{
- operand->type = CAIRO_GL_OPERAND_CONSTANT;
- operand->constant.color[0] = color->red * color->alpha;
- operand->constant.color[1] = color->green * color->alpha;
- operand->constant.color[2] = color->blue * color->alpha;
- operand->constant.color[3] = color->alpha;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
- const cairo_pattern_t *pattern,
- cairo_gl_surface_t *dst,
- int src_x, int src_y,
- int dst_x, int dst_y)
-{
- const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
- cairo_status_t status;
-
- assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
- gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
-
- if (! _cairo_gl_device_has_glsl (dst->base.device))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_gl_create_gradient_texture (dst,
- gradient,
- &operand->gradient.gradient);
- if (unlikely (status))
- return status;
-
- if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
- cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
- double x0, y0, dx, dy, sf, offset;
-
- dx = linear->pd2.x - linear->pd1.x;
- dy = linear->pd2.y - linear->pd1.y;
- sf = 1.0 / (dx * dx + dy * dy);
- dx *= sf;
- dy *= sf;
-
- x0 = linear->pd1.x;
- y0 = linear->pd1.y;
- offset = dx * x0 + dy * y0;
-
- operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
-
- cairo_matrix_init (&operand->gradient.m, dx, 0, dy, 1, -offset, 0);
- if (! _cairo_matrix_is_identity (&pattern->matrix)) {
- cairo_matrix_multiply (&operand->gradient.m,
- &pattern->matrix,
- &operand->gradient.m);
- }
- } else {
- cairo_matrix_t m;
- cairo_circle_double_t circles[2];
- double x0, y0, r0, dx, dy, dr;
-
- /*
- * Some fragment shader implementations use half-floats to
- * represent numbers, so the maximum number they can represent
- * is about 2^14. Some intermediate computations used in the
- * radial gradient shaders can produce results of up to 2*k^4.
- * Setting k=8 makes the maximum result about 8192 (assuming
- * that the extreme circles are not much smaller than the
- * destination image).
- */
- _cairo_gradient_pattern_fit_to_range (gradient, 8.,
- &operand->gradient.m, circles);
-
- x0 = circles[0].center.x;
- y0 = circles[0].center.y;
- r0 = circles[0].radius;
- dx = circles[1].center.x - x0;
- dy = circles[1].center.y - y0;
- dr = circles[1].radius - r0;
-
- operand->gradient.a = dx * dx + dy * dy - dr * dr;
- operand->gradient.radius_0 = r0;
- operand->gradient.circle_d.center.x = dx;
- operand->gradient.circle_d.center.y = dy;
- operand->gradient.circle_d.radius = dr;
-
- if (operand->gradient.a == 0)
- operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
- else if (pattern->extend == CAIRO_EXTEND_NONE)
- operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE;
- else
- operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT;
-
- cairo_matrix_init_translate (&m, -x0, -y0);
- cairo_matrix_multiply (&operand->gradient.m,
- &operand->gradient.m,
- &m);
- }
-
- cairo_matrix_translate (&operand->gradient.m, src_x - dst_x, src_y - dst_y);
-
- operand->gradient.extend = pattern->extend;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
-{
- switch (operand->type) {
- case CAIRO_GL_OPERAND_CONSTANT:
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- _cairo_gl_gradient_destroy (operand->gradient.gradient);
- break;
- case CAIRO_GL_OPERAND_TEXTURE:
- _cairo_pattern_release_surface (NULL, /* XXX */
- &operand->texture.surface->base,
- &operand->texture.attributes);
- break;
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_SPANS:
- break;
- }
-
- operand->type = CAIRO_GL_OPERAND_NONE;
-}
-
-static cairo_int_status_t
-_cairo_gl_operand_init (cairo_gl_operand_t *operand,
- const cairo_pattern_t *pattern,
- cairo_gl_surface_t *dst,
- int src_x, int src_y,
- int dst_x, int dst_y,
- int width, int height)
-{
- cairo_int_status_t status;
-
- switch (pattern->type) {
- case CAIRO_PATTERN_TYPE_SOLID:
- return _cairo_gl_solid_operand_init (operand,
- &((cairo_solid_pattern_t *) pattern)->color);
- case CAIRO_PATTERN_TYPE_LINEAR:
- case CAIRO_PATTERN_TYPE_RADIAL:
- status = _cairo_gl_gradient_operand_init (operand,
- pattern, dst,
- src_x, src_y,
- dst_x, dst_y);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- /* fall through */
-
- default:
- case CAIRO_PATTERN_TYPE_MESH:
- case CAIRO_PATTERN_TYPE_SURFACE:
- return _cairo_gl_pattern_texture_setup (operand,
- pattern, dst,
- src_x, src_y,
- dst_x, dst_y,
- width, height);
- }
-}
-
-cairo_filter_t
-_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand)
-{
- cairo_filter_t filter;
-
- switch ((int) operand->type) {
- case CAIRO_GL_OPERAND_TEXTURE:
- filter = operand->texture.attributes.filter;
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- filter = CAIRO_FILTER_BILINEAR;
- break;
- default:
- filter = CAIRO_FILTER_DEFAULT;
- break;
- }
-
- return filter;
-}
-
-GLint
-_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand)
-{
- cairo_filter_t filter = _cairo_gl_operand_get_filter (operand);
-
- return filter != CAIRO_FILTER_FAST && filter != CAIRO_FILTER_NEAREST ?
- GL_LINEAR :
- GL_NEAREST;
-}
-
-cairo_extend_t
-_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand)
-{
- cairo_extend_t extend;
-
- switch ((int) operand->type) {
- case CAIRO_GL_OPERAND_TEXTURE:
- extend = operand->texture.attributes.extend;
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- extend = operand->gradient.extend;
- break;
- default:
- extend = CAIRO_EXTEND_NONE;
- break;
- }
-
- return extend;
-}
-
-
cairo_int_status_t
_cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
const cairo_pattern_t *pattern,
@@ -384,6 +64,22 @@ _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
width, height);
}
+void
+_cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
+ const cairo_gl_operand_t *source)
+{
+ _cairo_gl_operand_destroy (&setup->src);
+ setup->src = *source;
+}
+
+void
+_cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
+ const cairo_color_t *color)
+{
+ _cairo_gl_operand_destroy (&setup->src);
+ _cairo_gl_solid_operand_init (&setup->src, color);
+}
+
cairo_int_status_t
_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
const cairo_pattern_t *pattern,
@@ -403,91 +99,25 @@ _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
}
void
-_cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup)
+_cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
+ const cairo_gl_operand_t *mask)
{
_cairo_gl_operand_destroy (&setup->mask);
- setup->mask.type = CAIRO_GL_OPERAND_SPANS;
+ if (mask)
+ setup->mask = *mask;
}
void
-_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
- cairo_region_t *clip_region)
+_cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
{
- setup->clip_region = clip_region;
+ setup->spans = TRUE;
}
-static void
-_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
- cairo_gl_operand_t *operand,
- cairo_gl_tex_t tex_unit)
+void
+_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
+ cairo_region_t *clip_region)
{
- char uniform_name[50];
- char *custom_part;
- static const char *names[] = { "source", "mask" };
-
- strcpy (uniform_name, names[tex_unit]);
- custom_part = uniform_name + strlen (names[tex_unit]);
-
- switch (operand->type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_SPANS:
- break;
- case CAIRO_GL_OPERAND_CONSTANT:
- strcpy (custom_part, "_constant");
- _cairo_gl_shader_bind_vec4 (ctx,
- uniform_name,
- operand->constant.color[0],
- operand->constant.color[1],
- operand->constant.color[2],
- operand->constant.color[3]);
- break;
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- strcpy (custom_part, "_a");
- _cairo_gl_shader_bind_float (ctx,
- uniform_name,
- operand->gradient.a);
- /* fall through */
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- strcpy (custom_part, "_circle_d");
- _cairo_gl_shader_bind_vec3 (ctx,
- uniform_name,
- operand->gradient.circle_d.center.x,
- operand->gradient.circle_d.center.y,
- operand->gradient.circle_d.radius);
- strcpy (custom_part, "_radius_0");
- _cairo_gl_shader_bind_float (ctx,
- uniform_name,
- operand->gradient.radius_0);
- /* fall through */
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_TEXTURE:
- /*
- * For GLES2 we use shaders to implement GL_CLAMP_TO_BORDER (used
- * with CAIRO_EXTEND_NONE). When bilinear filtering is enabled,
- * these shaders need the texture dimensions for their calculations.
- */
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
- _cairo_gl_operand_get_extend (operand) == CAIRO_EXTEND_NONE &&
- _cairo_gl_operand_get_gl_filter (operand) == GL_LINEAR)
- {
- float width, height;
- if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
- width = operand->texture.surface->width;
- height = operand->texture.surface->height;
- }
- else {
- width = operand->gradient.gradient->cache_entry.size,
- height = 1;
- }
- strcpy (custom_part, "_texdims");
- _cairo_gl_shader_bind_vec2 (ctx, uniform_name, width, height);
- }
- break;
- }
+ setup->clip_region = clip_region;
}
static void
@@ -501,6 +131,29 @@ _cairo_gl_composite_bind_to_shader (cairo_gl_context_t *ctx,
}
static void
+_cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
+ GLuint target,
+ cairo_filter_t filter)
+{
+ switch (filter) {
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ break;
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_BILINEAR:
+ glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ break;
+ default:
+ case CAIRO_FILTER_GAUSSIAN:
+ ASSERT_NOT_REACHED;
+ }
+}
+
+static void
_cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
GLuint target,
cairo_extend_t extend)
@@ -534,66 +187,6 @@ _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
}
}
-static void
-_cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
- GLuint target,
- cairo_filter_t filter)
-{
- switch (filter) {
- case CAIRO_FILTER_FAST:
- case CAIRO_FILTER_NEAREST:
- glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- break;
- case CAIRO_FILTER_GOOD:
- case CAIRO_FILTER_BEST:
- case CAIRO_FILTER_BILINEAR:
- glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- break;
- default:
- case CAIRO_FILTER_GAUSSIAN:
- ASSERT_NOT_REACHED;
- }
-}
-
-static cairo_bool_t
-_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
- cairo_gl_operand_t *source,
- unsigned int vertex_offset)
-{
- if (dest->type != source->type)
- return TRUE;
- if (dest->vertex_offset != vertex_offset)
- return TRUE;
-
- switch (source->type) {
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_SPANS:
- return FALSE;
- case CAIRO_GL_OPERAND_CONSTANT:
- return dest->constant.color[0] != source->constant.color[0] ||
- dest->constant.color[1] != source->constant.color[1] ||
- dest->constant.color[2] != source->constant.color[2] ||
- dest->constant.color[3] != source->constant.color[3];
- case CAIRO_GL_OPERAND_TEXTURE:
- return dest->texture.surface != source->texture.surface ||
- dest->texture.attributes.extend != source->texture.attributes.extend ||
- dest->texture.attributes.filter != source->texture.attributes.filter ||
- dest->texture.attributes.has_component_alpha != source->texture.attributes.has_component_alpha;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- /* XXX: improve this */
- return TRUE;
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- break;
- }
- return TRUE;
-}
static void
_cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
@@ -629,11 +222,6 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
break;
- case CAIRO_GL_OPERAND_SPANS:
- dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
- GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
- (void *) (uintptr_t) vertex_offset);
- dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
/* fall through */
case CAIRO_GL_OPERAND_CONSTANT:
break;
@@ -668,6 +256,19 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
}
}
+static void
+_cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
+ unsigned int vertex_size,
+ unsigned int vertex_offset)
+{
+ cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+
+ dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
+ GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
+ (void *) (uintptr_t) vertex_offset);
+ dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
+}
+
void
_cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
cairo_gl_tex_t tex_unit)
@@ -681,8 +282,6 @@ _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
break;
- case CAIRO_GL_OPERAND_SPANS:
- dispatch->DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
/* fall through */
case CAIRO_GL_OPERAND_CONSTANT:
break;
@@ -764,27 +363,6 @@ _cairo_gl_set_operator (cairo_gl_context_t *ctx,
}
}
-static unsigned int
-_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
-{
- switch (type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_CONSTANT:
- return 0;
- case CAIRO_GL_OPERAND_SPANS:
- return 4 * sizeof (GLbyte);
- case CAIRO_GL_OPERAND_TEXTURE:
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- return 2 * sizeof (GLfloat);
- }
-}
-
static cairo_status_t
_cairo_gl_composite_begin_component_alpha (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup)
@@ -872,6 +450,7 @@ _cairo_gl_composite_begin_component_alpha (cairo_gl_context_t *ctx,
status = _cairo_gl_get_shader_by_type (ctx,
&setup->src,
&setup->mask,
+ setup->spans,
CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
&pre_shader);
if (unlikely (status))
@@ -919,10 +498,12 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
}
status = _cairo_gl_get_shader_by_type (ctx,
- &setup->src,
- &setup->mask,
- component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE
- : CAIRO_GL_SHADER_IN_NORMAL,
+ &setup->src,
+ &setup->mask,
+ setup->spans,
+ component_alpha ?
+ CAIRO_GL_SHADER_IN_CA_SOURCE :
+ CAIRO_GL_SHADER_IN_NORMAL,
&shader);
if (unlikely (status)) {
ctx->pre_shader = NULL;
@@ -954,10 +535,12 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
_cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size);
_cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size);
+ if (setup->spans)
+ _cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size);
+ else
+ ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
- _cairo_gl_set_operator (ctx,
- setup->op,
- component_alpha);
+ _cairo_gl_set_operator (ctx, setup->op, component_alpha);
ctx->vertex_size = vertex_size;
@@ -1065,62 +648,6 @@ _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
}
static inline void
-_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
- GLfloat ** vb,
- GLfloat x,
- GLfloat y,
- uint8_t alpha)
-{
- switch (operand->type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_CONSTANT:
- break;
- case CAIRO_GL_OPERAND_SPANS:
- {
- union fi {
- float f;
- GLbyte bytes[4];
- } fi;
-
- fi.bytes[0] = 0;
- fi.bytes[1] = 0;
- fi.bytes[2] = 0;
- fi.bytes[3] = alpha;
- *(*vb)++ = fi.f;
- }
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- {
- double s = x;
- double t = y;
-
- cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
-
- *(*vb)++ = s;
- *(*vb)++ = t;
- }
- break;
- case CAIRO_GL_OPERAND_TEXTURE:
- {
- cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
- double s = x;
- double t = y;
-
- cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
- *(*vb)++ = s;
- *(*vb)++ = t;
- }
- break;
- }
-}
-
-static inline void
_cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
GLfloat x,
GLfloat y,
@@ -1134,6 +661,19 @@ _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
_cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y, alpha);
_cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y, alpha);
+ if (ctx->spans) {
+ union fi {
+ float f;
+ GLbyte bytes[4];
+ } fi;
+
+ fi.bytes[0] = 0;
+ fi.bytes[1] = 0;
+ fi.bytes[2] = 0;
+ fi.bytes[3] = alpha;
+ *vb++ = fi.f;
+ }
+
ctx->vb_offset += ctx->vertex_size;
}
@@ -1229,517 +769,3 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
return CAIRO_STATUS_SUCCESS;
}
-
-static cairo_bool_t
-cairo_boxes_for_each_box (cairo_boxes_t *boxes,
- cairo_bool_t (*func) (cairo_box_t *box,
- void *data),
- void *data)
-{
- struct _cairo_boxes_chunk *chunk;
- int i;
-
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- for (i = 0; i < chunk->count; i++)
- if (! func (&chunk->base[i], data))
- return FALSE;
- }
-
- return TRUE;
-}
-
-struct image_contains_box {
- int width, height;
- int tx, ty;
-};
-
-static cairo_bool_t image_contains_box (cairo_box_t *box, void *closure)
-{
- struct image_contains_box *data = closure;
-
- return
- _cairo_fixed_integer_part (box->p1.x) + data->tx >= 0 &&
- _cairo_fixed_integer_part (box->p1.y) + data->ty >= 0 &&
- _cairo_fixed_integer_part (box->p2.x) + data->tx <= data->width &&
- _cairo_fixed_integer_part (box->p2.y) + data->ty <= data->height;
-}
-
-struct image_upload_box {
- cairo_gl_surface_t *surface;
- cairo_image_surface_t *image;
- int tx, ty;
-};
-
-static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure)
-{
- const struct image_upload_box *iub = closure;
- int x = _cairo_fixed_integer_part (box->p1.x);
- int y = _cairo_fixed_integer_part (box->p1.y);
- int w = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
- int h = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
-
- return _cairo_gl_surface_draw_image (iub->surface,
- iub->image,
- x + iub->tx, y + iub->ty,
- w, h,
- x, y) == CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_upload_image_inplace (cairo_gl_surface_t *surface,
- const cairo_pattern_t *source,
- cairo_boxes_t *boxes)
-{
- const cairo_surface_pattern_t *pattern;
- struct image_contains_box icb;
- struct image_upload_box iub;
- cairo_image_surface_t *image;
- int tx, ty;
-
- if (! boxes->is_pixel_aligned)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- pattern = (const cairo_surface_pattern_t *) source;
- if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- image = (cairo_image_surface_t *) pattern->surface;
- if (image->format == CAIRO_FORMAT_INVALID)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* Check that the data is entirely within the image */
- icb.width = image->width;
- icb.height = image->height;
- icb.tx = tx;
- icb.ty = ty;
- if (! cairo_boxes_for_each_box (boxes, image_contains_box, &icb))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- iub.surface = surface;
- iub.image = image;
- iub.tx = tx;
- iub.ty = ty;
- cairo_boxes_for_each_box (boxes, image_upload_box, &iub);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_bool_t composite_box (cairo_box_t *box, void *closure)
-{
- _cairo_gl_composite_emit_rect (closure,
- _cairo_fixed_integer_part (box->p1.x),
- _cairo_fixed_integer_part (box->p1.y),
- _cairo_fixed_integer_part (box->p2.x),
- _cairo_fixed_integer_part (box->p2.y),
- 0);
- return TRUE;
-}
-
-static cairo_status_t
-_composite_boxes (cairo_gl_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_boxes_t *boxes,
- const cairo_composite_rectangles_t *extents)
-{
- cairo_bool_t need_clip_mask = FALSE;
- cairo_gl_composite_t setup;
- cairo_gl_context_t *ctx;
- cairo_surface_pattern_t mask;
- cairo_status_t status;
-
- /* If the boxes are not pixel-aligned, we will need to compute a real mask */
- if (! boxes->is_pixel_aligned)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (extents->clip->path &&
- (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
- {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- if (! extents->is_bounded)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_gl_composite_init (&setup, op, dst, FALSE,
- &extents->bounded);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_gl_composite_set_source (&setup, src,
- extents->bounded.x,
- extents->bounded.y,
- extents->bounded.x,
- extents->bounded.y,
- extents->bounded.width,
- extents->bounded.height);
- if (unlikely (status))
- goto CLEANUP;
-
- need_clip_mask = extents->clip->path != NULL;
- if (need_clip_mask) {
- cairo_surface_t *clip_surface;
- int clip_x, clip_y;
-
- clip_surface = _cairo_clip_get_surface (extents->clip,
- &dst->base,
- &clip_x, &clip_y);
- if (unlikely (clip_surface->status)) {
- status = clip_surface->status;
- need_clip_mask = FALSE;
- goto CLEANUP;
- }
-
- _cairo_pattern_init_for_surface (&mask, clip_surface);
- mask.base.filter = CAIRO_FILTER_NEAREST;
- cairo_matrix_init_translate (&mask.base.matrix,
- -clip_x,
- -clip_y);
- cairo_surface_destroy (clip_surface);
-
- if (op == CAIRO_OPERATOR_CLEAR) {
- src = NULL;
- op = CAIRO_OPERATOR_DEST_OUT;
- }
-
- status = _cairo_gl_composite_set_mask (&setup, &mask.base,
- extents->bounded.x,
- extents->bounded.y,
- extents->bounded.x,
- extents->bounded.y,
- extents->bounded.width,
- extents->bounded.height);
- if (unlikely (status))
- goto CLEANUP;
- }
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto CLEANUP;
-
- cairo_boxes_for_each_box (boxes, composite_box, ctx);
-
- status = _cairo_gl_context_release (ctx, status);
-
- CLEANUP:
- if (need_clip_mask)
- _cairo_pattern_fini (&mask.base);
-
- _cairo_gl_composite_fini (&setup);
- return status;
-}
-
-static cairo_bool_t converter_add_box (cairo_box_t *box, void *closure)
-{
- return _cairo_rectangular_scan_converter_add_box (closure, box, 1) == CAIRO_STATUS_SUCCESS;
-}
-
-typedef struct _cairo_gl_surface_span_renderer {
- cairo_span_renderer_t base;
-
- cairo_gl_composite_t setup;
-
- int xmin, xmax;
- int ymin, ymax;
-
- cairo_gl_context_t *ctx;
-} cairo_gl_surface_span_renderer_t;
-
-static cairo_status_t
-_cairo_gl_render_bounded_spans (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- if (num_spans == 0)
- return CAIRO_STATUS_SUCCESS;
-
- do {
- if (spans[0].coverage) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- spans[0].coverage);
- }
-
- spans++;
- } while (--num_spans > 1);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_render_unbounded_spans (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- if (y > renderer->ymin) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, renderer->ymin,
- renderer->xmax, y,
- 0);
- }
-
- if (num_spans == 0) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, y,
- renderer->xmax, y + height,
- 0);
- } else {
- if (spans[0].x != renderer->xmin) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, y,
- spans[0].x, y + height,
- 0);
- }
-
- do {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- spans[0].coverage);
- spans++;
- } while (--num_spans > 1);
-
- if (spans[0].x != renderer->xmax) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- spans[0].x, y,
- renderer->xmax, y + height,
- 0);
- }
- }
-
- renderer->ymin = y + height;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- if (renderer->ymax > renderer->ymin) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, renderer->ymin,
- renderer->xmax, renderer->ymax,
- 0);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_finish_bounded_spans (void *abstract_renderer)
-{
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_composite_unaligned_boxes (cairo_gl_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_boxes_t *boxes,
- const cairo_composite_rectangles_t *composite)
-{
- cairo_rectangular_scan_converter_t converter;
- cairo_gl_surface_span_renderer_t renderer;
- const cairo_rectangle_int_t *extents;
- cairo_status_t status;
-
- if (composite->clip->path)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* XXX for ADD or if we know the boxes are disjoint we can do a simpler
- * pass, but for now... */
-
- _cairo_rectangular_scan_converter_init (&converter, &composite->bounded);
- cairo_boxes_for_each_box (boxes, converter_add_box, &converter);
-
- if (composite->is_bounded) {
- renderer.base.render_rows = _cairo_gl_render_bounded_spans;
- renderer.base.finish = _cairo_gl_finish_bounded_spans;
- extents = &composite->bounded;
- } else {
- renderer.base.render_rows = _cairo_gl_render_unbounded_spans;
- renderer.base.finish = _cairo_gl_finish_unbounded_spans;
- extents = &composite->unbounded;
- }
- renderer.xmin = extents->x;
- renderer.xmax = extents->x + extents->width;
- renderer.ymin = extents->y;
- renderer.ymax = extents->y + extents->height;
-
- status = _cairo_gl_composite_init (&renderer.setup,
- op, dst,
- FALSE, extents);
- if (unlikely (status))
- goto FAIL;
-
- status = _cairo_gl_composite_set_source (&renderer.setup, pattern,
- extents->x, extents->y,
- extents->x, extents->y,
- extents->width, extents->height);
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_mask_spans (&renderer.setup);
- if (! composite->is_bounded)
- _cairo_gl_composite_set_clip_region (&renderer.setup,
- _cairo_clip_get_region (composite->clip));
-
- status = _cairo_gl_composite_begin (&renderer.setup, &renderer.ctx);
- if (unlikely (status))
- goto FAIL;
-
- status = converter.base.generate (&converter.base, &renderer.base);
-
- converter.base.destroy (&converter.base);
- renderer.base.finish (&renderer.base);
-
- status = _cairo_gl_context_release (renderer.ctx, status);
-FAIL:
- _cairo_gl_composite_fini (&renderer.setup);
- return status;
-}
-
-/* XXX _cairo_gl_clip_and_composite_polygon() */
-cairo_int_status_t
-_cairo_gl_surface_polygon (cairo_gl_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_polygon_t *polygon,
- cairo_fill_rule_t fill_rule,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *extents)
-{
- cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
-
- if (! _cairo_clip_is_region (extents->clip))
- return UNSUPPORTED ("a clip surface would be required");
-
- if (! _cairo_surface_check_span_renderer (op, src, &dst->base, antialias))
- return UNSUPPORTED ("no span renderer");
-
- if (op == CAIRO_OPERATOR_SOURCE)
- return UNSUPPORTED ("SOURCE compositing doesn't work in GL");
- if (op == CAIRO_OPERATOR_CLEAR) {
- op = CAIRO_OPERATOR_DEST_OUT;
- src = &_cairo_pattern_white.base;
- }
-
- return _cairo_surface_composite_polygon (&dst->base,
- op,
- src,
- fill_rule,
- antialias,
- extents,
- polygon,
- clip_region);
-}
-
-cairo_int_status_t
-_cairo_gl_clip_and_composite_boxes (cairo_gl_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_boxes_t *boxes,
- cairo_composite_rectangles_t *extents)
-{
- cairo_int_status_t status;
-
- if (boxes->num_boxes == 0 && extents->is_bounded)
- return CAIRO_STATUS_SUCCESS;
-
- if (! _cairo_gl_operator_is_supported (op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (boxes->is_pixel_aligned && _cairo_clip_is_region (extents->clip) &&
- (op == CAIRO_OPERATOR_SOURCE ||
- (dst->base.is_clear && (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))))
- {
- if (boxes->num_boxes == 1 &&
- extents->bounded.width == dst->width &&
- extents->bounded.height == dst->height)
- {
- op = CAIRO_OPERATOR_SOURCE;
-#if 0
- dst->deferred_clear = FALSE;
-#endif
- }
-
- status = _upload_image_inplace (dst, src, boxes);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
- /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
- if (extents->clip->path != NULL && extents->is_bounded) {
- cairo_polygon_t polygon;
- cairo_fill_rule_t fill_rule;
- cairo_antialias_t antialias;
- cairo_clip_t *clip;
-
- clip = _cairo_clip_copy (extents->clip);
- clip = _cairo_clip_intersect_boxes (clip, boxes);
- status = _cairo_clip_get_polygon (clip, &polygon,
- &fill_rule, &antialias);
- _cairo_clip_path_destroy (clip->path);
- clip->path = NULL;
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- cairo_clip_t *saved_clip = extents->clip;
- extents->clip = clip;
- status = _cairo_gl_surface_polygon (dst, op, src,
- &polygon,
- fill_rule,
- antialias,
- extents);
- if (extents->clip != clip)
- clip = NULL;
- extents->clip = saved_clip;
- _cairo_polygon_fini (&polygon);
- }
- if (clip)
- _cairo_clip_destroy (clip);
-
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
-#if 0
- if (dst->deferred_clear) {
- status = _cairo_gl_surface_clear (dst);
- if (unlikely (status))
- return status;
- }
-#endif
-
- if (boxes->is_pixel_aligned &&
- _cairo_clip_is_region (extents->clip) &&
- op == CAIRO_OPERATOR_SOURCE) {
- status = _upload_image_inplace (dst, src, boxes);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
- /* Use a fast path if the boxes are pixel aligned */
- status = _composite_boxes (dst, op, src, boxes, extents);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- status = _composite_unaligned_boxes (dst, op, src, boxes, extents);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- /* Otherwise XXX */
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 170cf962..f20850e7 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -113,18 +113,20 @@ static void
_gl_destroy (void *device)
{
cairo_gl_context_t *ctx = device;
- cairo_scaled_font_t *scaled_font, *next_scaled_font;
int n;
ctx->acquire (ctx);
- cairo_list_foreach_entry_safe (scaled_font,
- next_scaled_font,
- cairo_scaled_font_t,
- &ctx->fonts,
- link)
- {
- _cairo_scaled_font_revoke_ownership (scaled_font);
+ while (! cairo_list_is_empty (&ctx->fonts)) {
+ cairo_gl_font_t *font;
+
+ font = cairo_list_first_entry (&ctx->fonts,
+ cairo_gl_font_t,
+ link);
+
+ cairo_list_del (&font->base.link);
+ cairo_list_del (&font->link);
+ free (font);
}
for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
@@ -161,6 +163,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
_cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
+ ctx->compositor = _cairo_gl_span_compositor_get ();
+
memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
cairo_list_init (&ctx->fonts);
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 0772d2a0..ee5c543c 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -40,6 +40,7 @@
#include "cairo-gl-private.h"
+#include "cairo-compositor-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
@@ -50,11 +51,26 @@
#define GLYPH_CACHE_MIN_SIZE 4
#define GLYPH_CACHE_MAX_SIZE 128
-typedef struct _cairo_gl_glyph_private {
+typedef struct _cairo_gl_glyph {
cairo_rtree_node_t node;
+ cairo_scaled_glyph_private_t base;
cairo_gl_glyph_cache_t *cache;
struct { float x, y; } p1, p2;
-} cairo_gl_glyph_private_t;
+} cairo_gl_glyph_t;
+
+static void
+_cairo_gl_glyph_fini (cairo_scaled_glyph_private_t *_priv,
+ cairo_scaled_glyph_t *scaled_glyph,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_gl_glyph_t *priv = cairo_container_of (_priv, cairo_gl_glyph_t, base);
+
+ priv->node.owner = NULL;
+ if (! priv->node.pinned) {
+ /* XXX thread-safety? Probably ok due to the frozen scaled-font. */
+ _cairo_rtree_node_remove (&priv->cache->rtree, &priv->node);
+ }
+}
static cairo_int_status_t
_cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
@@ -63,7 +79,7 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
{
cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
cairo_gl_surface_t *cache_surface;
- cairo_gl_glyph_private_t *glyph_private;
+ cairo_gl_glyph_t *glyph_private;
cairo_rtree_node_t *node = NULL;
cairo_int_status_t status;
int width, height;
@@ -101,11 +117,15 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
if (unlikely (status))
return status;
- scaled_glyph->surface_private = node;
- node->owner = &scaled_glyph->surface_private;
-
- glyph_private = (cairo_gl_glyph_private_t *) node;
+ glyph_private = (cairo_gl_glyph_t *) node;
glyph_private->cache = cache;
+ _cairo_scaled_glyph_attach_private (scaled_glyph,
+ &glyph_private->base,
+ cache,
+ _cairo_gl_glyph_fini);
+
+ scaled_glyph->dev_private = glyph_private;
+ scaled_glyph->dev_private_key = cache;
/* compute tex coords */
glyph_private->p1.x = node->x;
@@ -122,11 +142,11 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_gl_glyph_private_t *
+static cairo_gl_glyph_t *
_cairo_gl_glyph_cache_lock (cairo_gl_glyph_cache_t *cache,
cairo_scaled_glyph_t *scaled_glyph)
{
- return _cairo_rtree_pin (&cache->rtree, scaled_glyph->surface_private);
+ return _cairo_rtree_pin (&cache->rtree, scaled_glyph->dev_private);
}
static cairo_status_t
@@ -183,63 +203,29 @@ _cairo_gl_glyph_cache_unlock (cairo_gl_glyph_cache_t *cache)
_cairo_rtree_unpin (&cache->rtree);
}
-static cairo_bool_t
-_cairo_gl_surface_owns_font (cairo_gl_surface_t *surface,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_device_t *font_private;
-
- font_private = scaled_font->surface_private;
- if ((scaled_font->surface_backend != NULL &&
- scaled_font->surface_backend != &_cairo_gl_surface_backend) ||
- (font_private != NULL && font_private != surface->base.device))
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-void
-_cairo_gl_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+static void
+_cairo_gl_font_fini (cairo_scaled_font_private_t *_priv,
+ cairo_scaled_font_t *scaled_font)
{
- cairo_list_del (&scaled_font->link);
-}
+ cairo_gl_font_t *priv = (cairo_gl_font_t *)_priv;
-void
-_cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_gl_glyph_private_t *glyph_private;
-
- glyph_private = scaled_glyph->surface_private;
- if (glyph_private != NULL) {
- glyph_private->node.owner = NULL;
- if (! glyph_private->node.pinned) {
- /* XXX thread-safety? Probably ok due to the frozen scaled-font. */
- _cairo_rtree_node_remove (&glyph_private->cache->rtree,
- &glyph_private->node);
- }
- }
+ cairo_list_del (&priv->link);
+ free (priv);
}
static cairo_status_t
-_render_glyphs (cairo_gl_surface_t *dst,
- int dst_x, int dst_y,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const cairo_composite_rectangles_t *extents,
- cairo_bool_t *has_component_alpha,
- int *remaining_glyphs)
+render_glyphs (cairo_gl_surface_t *dst,
+ int dst_x, int dst_y,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_composite_glyphs_info_t *info,
+ cairo_bool_t *has_component_alpha)
{
cairo_format_t last_format = CAIRO_FORMAT_INVALID;
cairo_gl_glyph_cache_t *cache = NULL;
cairo_gl_context_t *ctx;
cairo_gl_composite_t setup;
- cairo_status_t status;
+ cairo_int_status_t status;
int i = 0;
*has_component_alpha = FALSE;
@@ -248,45 +234,30 @@ _render_glyphs (cairo_gl_surface_t *dst,
if (unlikely (status))
return status;
- _cairo_scaled_font_freeze_cache (scaled_font);
-
- status = _cairo_gl_composite_init (&setup, op, dst,
- TRUE, &extents->bounded);
-
+ status = _cairo_gl_composite_init (&setup, op, dst, TRUE, &info->extents);
if (unlikely (status))
goto FINISH;
- if (! _cairo_gl_surface_owns_font (dst, scaled_font)) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto FINISH;
- }
-
status = _cairo_gl_composite_set_source (&setup, source,
- extents->bounded.x,
- extents->bounded.y,
+ info->extents.x,
+ info->extents.y,
dst_x, dst_y,
- extents->bounded.width,
- extents->bounded.height);
+ info->extents.width,
+ info->extents.height);
if (unlikely (status))
goto FINISH;
- if (scaled_font->surface_private == NULL) {
- scaled_font->surface_private = ctx;
- scaled_font->surface_backend = &_cairo_gl_surface_backend;
- cairo_list_add (&scaled_font->link, &ctx->fonts);
- }
- _cairo_gl_composite_set_clip_region (&setup,
- _cairo_clip_get_region (extents->clip));
+ //_cairo_gl_composite_set_clip_region (&setup, _cairo_clip_get_region (extents->clip));
- for (i = 0; i < num_glyphs; i++) {
+ for (i = 0; i < info->num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
- cairo_gl_glyph_private_t *glyph;
+ cairo_gl_glyph_t *glyph;
double x_offset, y_offset;
double x1, x2, y1, y2;
- status = _cairo_scaled_glyph_lookup (scaled_font,
- glyphs[i].index,
+ status = _cairo_scaled_glyph_lookup (info->font,
+ info->glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (unlikely (status))
@@ -297,13 +268,6 @@ _render_glyphs (cairo_gl_surface_t *dst,
{
continue;
}
- if (scaled_glyph->surface->width > GLYPH_CACHE_MAX_SIZE ||
- scaled_glyph->surface->height > GLYPH_CACHE_MAX_SIZE)
- {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto FINISH;
- }
-
if (scaled_glyph->surface->format != last_format) {
status = cairo_gl_context_get_glyph_cache (ctx,
scaled_glyph->surface->format,
@@ -331,25 +295,35 @@ _render_glyphs (cairo_gl_surface_t *dst,
goto FINISH;
}
- if (scaled_glyph->surface_private == NULL) {
- status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
+ if (scaled_glyph->dev_private_key != cache) {
+ cairo_scaled_glyph_private_t *priv;
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- /* Cache is full, so flush existing prims and try again. */
- _cairo_gl_composite_flush (ctx);
- _cairo_gl_glyph_cache_unlock (cache);
+ priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache);
+ if (priv) {
+ scaled_glyph->dev_private_key = cache;
+ scaled_glyph->dev_private = cairo_container_of (priv,
+ cairo_gl_glyph_t,
+ base);;
+ } else {
status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
- }
- if (unlikely (_cairo_status_is_error (status)))
- goto FINISH;
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ /* Cache is full, so flush existing prims and try again. */
+ _cairo_gl_composite_flush (ctx);
+ _cairo_gl_glyph_cache_unlock (cache);
+ status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
+ }
+
+ if (unlikely (_cairo_int_status_is_error (status)))
+ goto FINISH;
+ }
}
x_offset = scaled_glyph->surface->base.device_transform.x0;
y_offset = scaled_glyph->surface->base.device_transform.y0;
- x1 = _cairo_lround (glyphs[i].x - x_offset);
- y1 = _cairo_lround (glyphs[i].y - y_offset);
+ x1 = _cairo_lround (info->glyphs[i].x - x_offset);
+ y1 = _cairo_lround (info->glyphs[i].y - y_offset);
x2 = x1 + scaled_glyph->surface->width;
y2 = y1 + scaled_glyph->surface->height;
@@ -362,75 +336,59 @@ _render_glyphs (cairo_gl_surface_t *dst,
status = CAIRO_STATUS_SUCCESS;
FINISH:
- _cairo_scaled_font_thaw_cache (scaled_font);
-
status = _cairo_gl_context_release (ctx, status);
_cairo_gl_composite_fini (&setup);
-
- *remaining_glyphs = num_glyphs - i;
return status;
}
static cairo_int_status_t
-_cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- cairo_composite_rectangles_t *extents,
- int *remaining_glyphs)
+render_glyphs_via_mask (cairo_gl_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_surface_t *source,
+ cairo_composite_glyphs_info_t *info)
{
cairo_surface_t *mask;
cairo_status_t status;
cairo_bool_t has_component_alpha;
- cairo_clip_t *saved_clip;
int i;
/* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
mask = cairo_gl_surface_create (dst->base.device,
CAIRO_CONTENT_COLOR_ALPHA,
- extents->bounded.width,
- extents->bounded.height);
+ info->extents.width,
+ info->extents.height);
if (unlikely (mask->status))
return mask->status;
- for (i = 0; i < num_glyphs; i++) {
- glyphs[i].x -= extents->bounded.x;
- glyphs[i].y -= extents->bounded.y;
+ for (i = 0; i < info->num_glyphs; i++) {
+ info->glyphs[i].x -= info->extents.x;
+ info->glyphs[i].y -= info->extents.y;
}
-
- saved_clip = extents->clip;
- extents->clip = NULL;
- status = _render_glyphs ((cairo_gl_surface_t *) mask, 0, 0,
- CAIRO_OPERATOR_ADD,
- &_cairo_pattern_white.base,
- glyphs, num_glyphs, scaled_font,
- extents,
- &has_component_alpha,
- remaining_glyphs);
- extents->clip = saved_clip;
-
+ status = render_glyphs ((cairo_gl_surface_t *) mask, 0, 0,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
+ info, &has_component_alpha);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ /* XXX composite */
+#if 0
cairo_surface_pattern_t mask_pattern;
-
mask->is_clear = FALSE;
_cairo_pattern_init_for_surface (&mask_pattern, mask);
mask_pattern.base.has_component_alpha = has_component_alpha;
cairo_matrix_init_translate (&mask_pattern.base.matrix,
- -extents->bounded.x, -extents->bounded.y);
+ -info->extents.x, -info->extents.y);
status = _cairo_surface_mask (&dst->base, op,
source, &mask_pattern.base,
- extents->clip);
+ NULL);
_cairo_pattern_fini (&mask_pattern.base);
+#endif
} else {
- for (i = 0; i < num_glyphs; i++) {
- glyphs[i].x += extents->bounded.x;
- glyphs[i].y += extents->bounded.y;
+ for (i = 0; i < info->num_glyphs; i++) {
+ info->glyphs[i].x += info->extents.x;
+ info->glyphs[i].y += info->extents.y;
}
- *remaining_glyphs = num_glyphs;
}
cairo_surface_destroy (mask);
@@ -438,143 +396,62 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst,
return status;
}
+cairo_int_status_t
+_cairo_gl_check_composite_glyphs (const cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int *num_glyphs)
+{
+ if (! _cairo_gl_operator_is_supported (extents->op))
+ return UNSUPPORTED ("unsupported operator");
+
+ /* XXX use individual masks for large glyphs? */
+ if (ceil (scaled_font->max_scale) >= GLYPH_CACHE_MAX_SIZE)
+ return UNSUPPORTED ("glyphs too large");
-cairo_private cairo_bool_t
-_cairo_gl_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *rectangle);
+ return CAIRO_STATUS_SUCCESS;
+}
cairo_int_status_t
-_cairo_gl_surface_show_glyphs (void *abstract_dst,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs)
+_cairo_gl_composite_glyphs (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info)
{
- cairo_gl_surface_t *dst = abstract_dst;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
- cairo_bool_t overlap, use_mask = FALSE;
+ cairo_gl_surface_t *dst = _dst;
cairo_bool_t has_component_alpha;
- cairo_status_t status;
int i;
- if (! _cairo_gl_operator_is_supported (op))
- return UNSUPPORTED ("unsupported operator");
-
- if (! _cairo_operator_bounded_by_mask (op))
- use_mask |= TRUE;
-
/* If any of the glyphs are component alpha, we have to go through a mask,
* since only _cairo_gl_surface_composite() currently supports component
* alpha.
*/
- if (!use_mask && op != CAIRO_OPERATOR_OVER) {
- for (i = 0; i < num_glyphs; i++) {
+ if (!dst->base.is_clear && ! info->use_mask && op != CAIRO_OPERATOR_OVER) {
+ for (i = 0; i < info->num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
- status = _cairo_scaled_glyph_lookup (scaled_font,
- glyphs[i].index,
- CAIRO_SCALED_GLYPH_INFO_SURFACE,
- &scaled_glyph);
- if (!_cairo_status_is_error (status) &&
+ if (_cairo_scaled_glyph_lookup (info->font, info->glyphs[i].index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph) == CAIRO_INT_STATUS_SUCCESS &&
scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32)
{
- use_mask = TRUE;
+ info->use_mask = TRUE;
break;
}
}
}
- /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
- * http://lists.cairographics.org/archives/cairo/2005-August/004992.html)
- * is:
- * mask IN clip ? src OP dest : dest
- * or more simply:
- * mask IN CLIP ? 0 : dest
- *
- * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
- *
- * The model we use in _cairo_gl_set_operator() is Render's:
- * src IN mask IN clip OP dest
- * which would boil down to:
- * 0 (bounded by the extents of the drawing).
- *
- * However, we can do a Render operation using an opaque source
- * and DEST_OUT to produce:
- * 1 IN mask IN clip DEST_OUT dest
- * which is
- * mask IN clip ? 0 : dest
- */
- if (op == CAIRO_OPERATOR_CLEAR) {
- source = &_cairo_pattern_white.base;
- op = CAIRO_OPERATOR_DEST_OUT;
- }
-
- /* For SOURCE, cairo's rendering equation is:
- * (mask IN clip) ? src OP dest : dest
- * or more simply:
- * (mask IN clip) ? src : dest.
- *
- * If we just used the Render equation, we would get:
- * (src IN mask IN clip) OP dest
- * or:
- * (src IN mask IN clip) bounded by extents of the drawing.
- *
- * The trick is that for GL blending, we only get our 4 source values
- * into the blender, and since we need all 4 components of source, we
- * can't also get the mask IN clip into the blender. But if we did
- * two passes we could make it work:
- * dest = (mask IN clip) DEST_OUT dest
- * dest = src IN mask IN clip ADD dest
- *
- * But for now, composite via an intermediate mask.
- */
- if (op == CAIRO_OPERATOR_SOURCE)
- use_mask |= TRUE;
-
- /* XXX we don't need ownership of the font as we use a global
- * glyph cache -- but we do need scaled_glyph eviction notification. :-(
- */
- if (! _cairo_gl_surface_owns_font (dst, scaled_font))
- return UNSUPPORTED ("do not control font");
-
- _cairo_gl_surface_get_extents (dst, &unbounded);
- status = _cairo_composite_rectangles_init_for_glyphs (&extents,
- &unbounded,
- op, source,
- scaled_font,
- glyphs, num_glyphs,
- clip, &overlap);
- if (unlikely (status))
- return status;
-
- /* If the glyphs overlap, we need to build an intermediate mask rather
- * then perform the compositing directly.
- */
- use_mask |= overlap;
- use_mask |= ! _cairo_clip_is_region (extents.clip);
-
- if (use_mask) {
- status = _cairo_gl_surface_show_glyphs_via_mask (dst, op,
- source,
- glyphs, num_glyphs,
- scaled_font,
- &extents,
- remaining_glyphs);
+ if (info->use_mask) {
+ return render_glyphs_via_mask (dst, op, _src, info);
} else {
- status = _render_glyphs (dst, extents.bounded.x, extents.bounded.y,
- op, source,
- glyphs, num_glyphs, scaled_font,
- &extents,
- &has_component_alpha,
- remaining_glyphs);
+ return render_glyphs (dst, dst_x, dst_y,
+ op, _src, info,
+ &has_component_alpha);
}
-
- _cairo_composite_rectangles_fini (&extents);
- return status;
}
void
@@ -584,7 +461,7 @@ _cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache)
GLYPH_CACHE_WIDTH,
GLYPH_CACHE_HEIGHT,
GLYPH_CACHE_MIN_SIZE,
- sizeof (cairo_gl_glyph_private_t));
+ sizeof (cairo_gl_glyph_t));
}
void
@@ -598,4 +475,3 @@ _cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx,
cache->pattern.surface = NULL;
}
}
-
diff --git a/src/cairo-gl-operand.c b/src/cairo-gl-operand.c
new file mode 100644
index 00000000..8b345bbd
--- /dev/null
+++ b/src/cairo-gl-operand.c
@@ -0,0 +1,538 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005,2010 Red Hat, Inc
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Benjamin Otte <otte@gnome.org>
+ * Carl Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ * Eric Anholt <eric@anholt.net>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-gl-private.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-surface-backend-private.h"
+
+static cairo_int_status_t
+_cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
+ const cairo_gradient_pattern_t *pattern,
+ cairo_gl_gradient_t **gradient)
+{
+ cairo_gl_context_t *ctx;
+ cairo_status_t status;
+
+ status = _cairo_gl_context_acquire (dst->base.device, &ctx);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient);
+
+ return _cairo_gl_context_release (ctx, status);
+}
+
+/*
+ * Like cairo_pattern_acquire_surface(), but returns a matrix that transforms
+ * from dest to src coords.
+ */
+static cairo_status_t
+_cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
+ const cairo_pattern_t *src,
+ cairo_gl_surface_t *dst,
+ int src_x, int src_y,
+ int dst_x, int dst_y,
+ int width, int height)
+{
+ cairo_status_t status;
+ cairo_matrix_t m;
+ cairo_gl_surface_t *surface;
+ cairo_surface_attributes_t *attributes;
+
+ attributes = &operand->texture.attributes;
+
+#if 0
+ status = _cairo_pattern_acquire_surface (src, &dst->base,
+ src_x, src_y,
+ width, height,
+ CAIRO_PATTERN_ACQUIRE_NONE,
+ (cairo_surface_t **)
+ &surface,
+ attributes);
+ if (unlikely (status))
+ return status;
+#endif
+
+ if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device) &&
+ (attributes->extend == CAIRO_EXTEND_REPEAT ||
+ attributes->extend == CAIRO_EXTEND_REFLECT))
+ {
+ return UNSUPPORTED ("EXT_texture_rectangle with repeat/reflect");
+ }
+
+ assert (_cairo_gl_surface_is_texture (surface));
+
+ operand->type = CAIRO_GL_OPERAND_TEXTURE;
+ operand->texture.surface = surface;
+ operand->texture.tex = surface->tex;
+ /* Translate the matrix from
+ * (unnormalized src -> unnormalized src) to
+ * (unnormalized dst -> unnormalized src)
+ */
+ cairo_matrix_init_translate (&m,
+ src_x - dst_x + attributes->x_offset,
+ src_y - dst_y + attributes->y_offset);
+ cairo_matrix_multiply (&attributes->matrix,
+ &m,
+ &attributes->matrix);
+
+
+ /* Translate the matrix from
+ * (unnormalized dst -> unnormalized src) to
+ * (unnormalized dst -> normalized src)
+ */
+ if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) {
+ cairo_matrix_init_scale (&m,
+ 1.0,
+ 1.0);
+ } else {
+ cairo_matrix_init_scale (&m,
+ 1.0 / surface->width,
+ 1.0 / surface->height);
+ }
+ cairo_matrix_multiply (&attributes->matrix,
+ &attributes->matrix,
+ &m);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
+ const cairo_color_t *color)
+{
+ operand->type = CAIRO_GL_OPERAND_CONSTANT;
+ operand->constant.color[0] = color->red * color->alpha;
+ operand->constant.color[1] = color->green * color->alpha;
+ operand->constant.color[2] = color->blue * color->alpha;
+ operand->constant.color[3] = color->alpha;
+}
+
+static cairo_status_t
+_cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
+ const cairo_pattern_t *pattern,
+ cairo_gl_surface_t *dst,
+ int src_x, int src_y,
+ int dst_x, int dst_y)
+{
+ const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
+ cairo_status_t status;
+
+ assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
+ gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
+
+ if (! _cairo_gl_device_has_glsl (dst->base.device))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_gl_create_gradient_texture (dst,
+ gradient,
+ &operand->gradient.gradient);
+ if (unlikely (status))
+ return status;
+
+ if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
+ cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
+ double x0, y0, dx, dy, sf, offset;
+
+ dx = linear->pd2.x - linear->pd1.x;
+ dy = linear->pd2.y - linear->pd1.y;
+ sf = 1.0 / (dx * dx + dy * dy);
+ dx *= sf;
+ dy *= sf;
+
+ x0 = linear->pd1.x;
+ y0 = linear->pd1.y;
+ offset = dx * x0 + dy * y0;
+
+ operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
+
+ cairo_matrix_init (&operand->gradient.m, dx, 0, dy, 1, -offset, 0);
+ if (! _cairo_matrix_is_identity (&pattern->matrix)) {
+ cairo_matrix_multiply (&operand->gradient.m,
+ &pattern->matrix,
+ &operand->gradient.m);
+ }
+ } else {
+ cairo_matrix_t m;
+ cairo_circle_double_t circles[2];
+ double x0, y0, r0, dx, dy, dr;
+
+ /*
+ * Some fragment shader implementations use half-floats to
+ * represent numbers, so the maximum number they can represent
+ * is about 2^14. Some intermediate computations used in the
+ * radial gradient shaders can produce results of up to 2*k^4.
+ * Setting k=8 makes the maximum result about 8192 (assuming
+ * that the extreme circles are not much smaller than the
+ * destination image).
+ */
+ _cairo_gradient_pattern_fit_to_range (gradient, 8.,
+ &operand->gradient.m, circles);
+
+ x0 = circles[0].center.x;
+ y0 = circles[0].center.y;
+ r0 = circles[0].radius;
+ dx = circles[1].center.x - x0;
+ dy = circles[1].center.y - y0;
+ dr = circles[1].radius - r0;
+
+ operand->gradient.a = dx * dx + dy * dy - dr * dr;
+ operand->gradient.radius_0 = r0;
+ operand->gradient.circle_d.center.x = dx;
+ operand->gradient.circle_d.center.y = dy;
+ operand->gradient.circle_d.radius = dr;
+
+ if (operand->gradient.a == 0)
+ operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
+ else if (pattern->extend == CAIRO_EXTEND_NONE)
+ operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE;
+ else
+ operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT;
+
+ cairo_matrix_init_translate (&m, -x0, -y0);
+ cairo_matrix_multiply (&operand->gradient.m,
+ &operand->gradient.m,
+ &m);
+ }
+
+ cairo_matrix_translate (&operand->gradient.m, src_x - dst_x, src_y - dst_y);
+
+ operand->gradient.extend = pattern->extend;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
+{
+ switch (operand->type) {
+ case CAIRO_GL_OPERAND_CONSTANT:
+ break;
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ _cairo_gl_gradient_destroy (operand->gradient.gradient);
+ break;
+ case CAIRO_GL_OPERAND_TEXTURE:
+ break;
+ default:
+ case CAIRO_GL_OPERAND_COUNT:
+ ASSERT_NOT_REACHED;
+ case CAIRO_GL_OPERAND_NONE:
+ break;
+ }
+
+ operand->type = CAIRO_GL_OPERAND_NONE;
+}
+
+cairo_int_status_t
+_cairo_gl_operand_init (cairo_gl_operand_t *operand,
+ const cairo_pattern_t *pattern,
+ cairo_gl_surface_t *dst,
+ int src_x, int src_y,
+ int dst_x, int dst_y,
+ int width, int height)
+{
+ cairo_int_status_t status;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ _cairo_gl_solid_operand_init (operand,
+ &((cairo_solid_pattern_t *) pattern)->color);
+ return CAIRO_STATUS_SUCCESS;
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ status = _cairo_gl_gradient_operand_init (operand,
+ pattern, dst,
+ src_x, src_y,
+ dst_x, dst_y);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ /* fall through */
+
+ default:
+ case CAIRO_PATTERN_TYPE_MESH:
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return _cairo_gl_pattern_texture_setup (operand,
+ pattern, dst,
+ src_x, src_y,
+ dst_x, dst_y,
+ width, height);
+ }
+}
+
+cairo_filter_t
+_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand)
+{
+ cairo_filter_t filter;
+
+ switch ((int) operand->type) {
+ case CAIRO_GL_OPERAND_TEXTURE:
+ filter = operand->texture.attributes.filter;
+ break;
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ filter = CAIRO_FILTER_BILINEAR;
+ break;
+ default:
+ filter = CAIRO_FILTER_DEFAULT;
+ break;
+ }
+
+ return filter;
+}
+
+GLint
+_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand)
+{
+ cairo_filter_t filter = _cairo_gl_operand_get_filter (operand);
+
+ return filter != CAIRO_FILTER_FAST && filter != CAIRO_FILTER_NEAREST ?
+ GL_LINEAR :
+ GL_NEAREST;
+}
+
+cairo_extend_t
+_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand)
+{
+ cairo_extend_t extend;
+
+ switch ((int) operand->type) {
+ case CAIRO_GL_OPERAND_TEXTURE:
+ extend = operand->texture.attributes.extend;
+ break;
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ extend = operand->gradient.extend;
+ break;
+ default:
+ extend = CAIRO_EXTEND_NONE;
+ break;
+ }
+
+ return extend;
+}
+
+
+void
+_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
+ cairo_gl_operand_t *operand,
+ cairo_gl_tex_t tex_unit)
+{
+ char uniform_name[50];
+ char *custom_part;
+ static const char *names[] = { "source", "mask" };
+
+ strcpy (uniform_name, names[tex_unit]);
+ custom_part = uniform_name + strlen (names[tex_unit]);
+
+ switch (operand->type) {
+ default:
+ case CAIRO_GL_OPERAND_COUNT:
+ ASSERT_NOT_REACHED;
+ case CAIRO_GL_OPERAND_NONE:
+ break;
+ case CAIRO_GL_OPERAND_CONSTANT:
+ strcpy (custom_part, "_constant");
+ _cairo_gl_shader_bind_vec4 (ctx,
+ uniform_name,
+ operand->constant.color[0],
+ operand->constant.color[1],
+ operand->constant.color[2],
+ operand->constant.color[3]);
+ break;
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ strcpy (custom_part, "_a");
+ _cairo_gl_shader_bind_float (ctx,
+ uniform_name,
+ operand->gradient.a);
+ /* fall through */
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ strcpy (custom_part, "_circle_d");
+ _cairo_gl_shader_bind_vec3 (ctx,
+ uniform_name,
+ operand->gradient.circle_d.center.x,
+ operand->gradient.circle_d.center.y,
+ operand->gradient.circle_d.radius);
+ strcpy (custom_part, "_radius_0");
+ _cairo_gl_shader_bind_float (ctx,
+ uniform_name,
+ operand->gradient.radius_0);
+ /* fall through */
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_TEXTURE:
+ /*
+ * For GLES2 we use shaders to implement GL_CLAMP_TO_BORDER (used
+ * with CAIRO_EXTEND_NONE). When bilinear filtering is enabled,
+ * these shaders need the texture dimensions for their calculations.
+ */
+ if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
+ _cairo_gl_operand_get_extend (operand) == CAIRO_EXTEND_NONE &&
+ _cairo_gl_operand_get_gl_filter (operand) == GL_LINEAR)
+ {
+ float width, height;
+ if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
+ width = operand->texture.surface->width;
+ height = operand->texture.surface->height;
+ }
+ else {
+ width = operand->gradient.gradient->cache_entry.size,
+ height = 1;
+ }
+ strcpy (custom_part, "_texdims");
+ _cairo_gl_shader_bind_vec2 (ctx, uniform_name, width, height);
+ }
+ break;
+ }
+}
+
+
+cairo_bool_t
+_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
+ cairo_gl_operand_t *source,
+ unsigned int vertex_offset)
+{
+ if (dest->type != source->type)
+ return TRUE;
+ if (dest->vertex_offset != vertex_offset)
+ return TRUE;
+
+ switch (source->type) {
+ case CAIRO_GL_OPERAND_NONE:
+ return FALSE;
+ case CAIRO_GL_OPERAND_CONSTANT:
+ return dest->constant.color[0] != source->constant.color[0] ||
+ dest->constant.color[1] != source->constant.color[1] ||
+ dest->constant.color[2] != source->constant.color[2] ||
+ dest->constant.color[3] != source->constant.color[3];
+ case CAIRO_GL_OPERAND_TEXTURE:
+ return dest->texture.surface != source->texture.surface ||
+ dest->texture.attributes.extend != source->texture.attributes.extend ||
+ dest->texture.attributes.filter != source->texture.attributes.filter ||
+ dest->texture.attributes.has_component_alpha != source->texture.attributes.has_component_alpha;
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ /* XXX: improve this */
+ return TRUE;
+ default:
+ case CAIRO_GL_OPERAND_COUNT:
+ ASSERT_NOT_REACHED;
+ break;
+ }
+ return TRUE;
+}
+
+unsigned int
+_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
+{
+ switch (type) {
+ default:
+ case CAIRO_GL_OPERAND_COUNT:
+ ASSERT_NOT_REACHED;
+ case CAIRO_GL_OPERAND_NONE:
+ case CAIRO_GL_OPERAND_CONSTANT:
+ return 0;
+ case CAIRO_GL_OPERAND_TEXTURE:
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ return 2 * sizeof (GLfloat);
+ }
+}
+
+void
+_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
+ GLfloat ** vb,
+ GLfloat x,
+ GLfloat y,
+ uint8_t alpha)
+{
+ switch (operand->type) {
+ default:
+ case CAIRO_GL_OPERAND_COUNT:
+ ASSERT_NOT_REACHED;
+ case CAIRO_GL_OPERAND_NONE:
+ case CAIRO_GL_OPERAND_CONSTANT:
+ break;
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ {
+ double s = x;
+ double t = y;
+
+ cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
+
+ *(*vb)++ = s;
+ *(*vb)++ = t;
+ }
+ break;
+ case CAIRO_GL_OPERAND_TEXTURE:
+ {
+ cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
+ double s = x;
+ double t = y;
+
+ cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
+ *(*vb)++ = s;
+ *(*vb)++ = t;
+ }
+ break;
+ }
+}
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index ee79b23a..e1005ba8 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -48,16 +48,17 @@
#include "cairoint.h"
+#include "cairo-gl.h"
#include "cairo-gl-gradient-private.h"
#include "cairo-device-private.h"
#include "cairo-error-private.h"
#include "cairo-rtree-private.h"
+#include "cairo-scaled-font-private.h"
+#include "cairo-spans-compositor-private.h"
#include <assert.h>
-#include "cairo-gl.h"
-
#if CAIRO_HAS_GL_SURFACE
#include <GL/gl.h>
#include <GL/glext.h>
@@ -138,7 +139,6 @@ typedef enum cairo_gl_operand_type {
CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0,
CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE,
CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT,
- CAIRO_GL_OPERAND_SPANS,
CAIRO_GL_OPERAND_COUNT
} cairo_gl_operand_type_t;
@@ -161,11 +161,10 @@ typedef enum cairo_gl_shader_in {
typedef enum cairo_gl_var_type {
CAIRO_GL_VAR_NONE,
CAIRO_GL_VAR_TEXCOORDS,
- CAIRO_GL_VAR_COVERAGE
} cairo_gl_var_type_t;
-#define cairo_gl_var_type_hash(src,mask,dest) ((mask) << 2 | (src << 1) | (dest))
-#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_COVERAGE << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS)
+#define cairo_gl_var_type_hash(src,mask,spans,dest) ((spans) << 3) | ((mask) << 2 | (src << 1) | (dest))
+#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_TEXCOORDS << 3) | (CAIRO_GL_VAR_TEXCOORDS << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS)
/* This union structure describes a potential source or mask operand to the
* compositing equation.
@@ -259,6 +258,8 @@ typedef struct _cairo_gl_dispatch {
struct _cairo_gl_context {
cairo_device_t base;
+ const cairo_compositor_t *compositor;
+
GLuint texture_load_pbo;
GLuint vbo;
GLint max_framebuffer_size;
@@ -283,6 +284,7 @@ struct _cairo_gl_context {
cairo_gl_shader_t *current_shader;
cairo_gl_operand_t operands[2];
+ cairo_bool_t spans;
char *vb;
char *vb_mem;
@@ -311,8 +313,15 @@ typedef struct _cairo_gl_composite {
cairo_gl_operand_t src;
cairo_gl_operand_t mask;
+ cairo_bool_t spans;
} cairo_gl_composite_t;
+typedef struct _cairo_gl_font {
+ cairo_scaled_font_private_t base;
+ cairo_device_t *device;
+ cairo_list_t link;
+} cairo_gl_font_t;
+
cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
static cairo_always_inline GLenum
@@ -432,6 +441,13 @@ _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
int src_x, int src_y,
int dst_x, int dst_y,
int width, int height);
+cairo_private void
+_cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
+ const cairo_color_t *color);
+
+cairo_private void
+_cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
+ const cairo_gl_operand_t *source);
cairo_private cairo_int_status_t
_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
@@ -441,7 +457,11 @@ _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
int width, int height);
cairo_private void
-_cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup);
+_cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
+ const cairo_gl_operand_t *mask);
+
+cairo_private void
+_cairo_gl_composite_set_spans (cairo_gl_composite_t *setup);
cairo_private cairo_status_t
_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
@@ -481,13 +501,6 @@ _cairo_gl_get_image_format_and_type (cairo_gl_flavor_t flavor,
cairo_bool_t *needs_swap);
cairo_private void
-_cairo_gl_surface_scaled_font_fini ( cairo_scaled_font_t *scaled_font);
-
-cairo_private void
-_cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font);
-
-cairo_private void
_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache);
cairo_private void
@@ -529,6 +542,7 @@ cairo_private cairo_status_t
_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
cairo_gl_operand_t *source,
cairo_gl_operand_t *mask,
+ cairo_bool_t use_coverage,
cairo_gl_shader_in_t in,
cairo_gl_shader_t **shader);
@@ -585,6 +599,17 @@ cairo_private cairo_status_t
_cairo_gl_dispatch_init(cairo_gl_dispatch_t *dispatch,
cairo_gl_get_proc_addr_func_t get_proc_addr);
+cairo_private cairo_int_status_t
+_cairo_gl_operand_init (cairo_gl_operand_t *operand,
+ const cairo_pattern_t *pattern,
+ cairo_gl_surface_t *dst,
+ int src_x, int src_y,
+ int dst_x, int dst_y,
+ int width, int height);
+cairo_private void
+_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
+ const cairo_color_t *color);
+
cairo_private cairo_filter_t
_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand);
@@ -594,25 +619,50 @@ _cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand);
cairo_private cairo_extend_t
_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand);
+cairo_private unsigned int
+_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type);
+
cairo_private cairo_bool_t
-_cairo_gl_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *rectangle);
+_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
+ cairo_gl_operand_t *source,
+ unsigned int vertex_offset);
+
+cairo_private void
+_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
+ cairo_gl_operand_t *operand,
+ cairo_gl_tex_t tex_unit);
+
+cairo_private void
+_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
+ GLfloat ** vb,
+ GLfloat x,
+ GLfloat y,
+ uint8_t alpha);
+
+cairo_private void
+_cairo_gl_operand_destroy (cairo_gl_operand_t *operand);
+
+cairo_private const cairo_compositor_t *
+_cairo_gl_span_compositor_get (void);
+
+cairo_private const cairo_compositor_t *
+_cairo_gl_traps_compositor_get (void);
cairo_private cairo_int_status_t
-_cairo_gl_surface_polygon (cairo_gl_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_polygon_t *polygon,
- cairo_fill_rule_t fill_rule,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *extents);
+_cairo_gl_check_composite_glyphs (const cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int *num_glyphs);
cairo_private cairo_int_status_t
-_cairo_gl_clip_and_composite_boxes (cairo_gl_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_boxes_t *boxes,
- cairo_composite_rectangles_t *extents);
+_cairo_gl_composite_glyphs (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info);
slim_hidden_proto (cairo_gl_surface_create);
slim_hidden_proto (cairo_gl_surface_create_for_texture);
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 7d60c0f3..69609dfb 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -108,6 +108,7 @@ _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
cairo_gl_shader_t *shader,
cairo_gl_var_type_t src,
cairo_gl_var_type_t mask,
+ cairo_bool_t use_coverage,
const char *fragment_text);
/* OpenGL Core 2.0 API. */
@@ -426,6 +427,7 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
&ctx->fill_rectangles_shader,
CAIRO_GL_VAR_NONE,
CAIRO_GL_VAR_NONE,
+ FALSE,
fill_fs_source);
if (unlikely (status))
return status;
@@ -475,8 +477,6 @@ cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
case CAIRO_GL_OPERAND_TEXTURE:
return CAIRO_GL_VAR_TEXCOORDS;
- case CAIRO_GL_OPERAND_SPANS:
- return CAIRO_GL_VAR_COVERAGE;
}
}
@@ -491,13 +491,8 @@ cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
case CAIRO_GL_VAR_NONE:
break;
case CAIRO_GL_VAR_TEXCOORDS:
- _cairo_output_stream_printf (stream,
- "varying vec2 %s_texcoords;\n",
- operand_names[name]);
- break;
- case CAIRO_GL_VAR_COVERAGE:
- _cairo_output_stream_printf (stream,
- "varying float %s_coverage;\n",
+ _cairo_output_stream_printf (stream,
+ "varying vec2 %s_texcoords;\n",
operand_names[name]);
break;
}
@@ -514,21 +509,29 @@ cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
case CAIRO_GL_VAR_NONE:
break;
case CAIRO_GL_VAR_TEXCOORDS:
- _cairo_output_stream_printf (stream,
+ _cairo_output_stream_printf (stream,
" %s_texcoords = MultiTexCoord%d.xy;\n",
operand_names[name], name);
break;
- case CAIRO_GL_VAR_COVERAGE:
- _cairo_output_stream_printf (stream,
- " %s_coverage = Color.a;\n",
- operand_names[name]);
- break;
}
}
+static void
+cairo_gl_shader_dcl_coverage (cairo_output_stream_t *stream)
+{
+ _cairo_output_stream_printf (stream, "varying float coverage;\n");
+}
+
+static void
+cairo_gl_shader_def_coverage (cairo_output_stream_t *stream)
+{
+ _cairo_output_stream_printf (stream, " coverage = Color.a;\n");
+}
+
static cairo_status_t
cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
cairo_gl_var_type_t mask,
+ cairo_bool_t use_coverage,
cairo_gl_var_type_t dest,
char **out)
{
@@ -539,6 +542,8 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_TEX_SOURCE);
cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_TEX_MASK);
+ if (use_coverage)
+ cairo_gl_shader_dcl_coverage (stream);
_cairo_output_stream_printf (stream,
"attribute vec4 Vertex;\n"
@@ -552,6 +557,8 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_TEX_SOURCE);
cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_TEX_MASK);
+ if (use_coverage)
+ cairo_gl_shader_def_coverage (stream);
_cairo_output_stream_write (stream,
"}\n\0", 3);
@@ -774,15 +781,6 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
namestr, namestr, namestr, namestr, namestr,
namestr, namestr, namestr, rectstr, namestr);
break;
- case CAIRO_GL_OPERAND_SPANS:
- _cairo_output_stream_printf (stream,
- "varying float %s_coverage;\n"
- "vec4 get_%s()\n"
- "{\n"
- " return vec4(0, 0, 0, %s_coverage);\n"
- "}\n",
- namestr, namestr, namestr);
- break;
}
}
@@ -842,6 +840,7 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
cairo_gl_shader_in_t in,
cairo_gl_operand_t *src,
cairo_gl_operand_t *mask,
+ cairo_bool_t use_coverage,
cairo_gl_operand_type_t dest_type,
char **out)
{
@@ -849,6 +848,7 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
unsigned char *source;
unsigned long length;
cairo_status_t status;
+ const char *coverage_str;
_cairo_output_stream_printf (stream,
"#ifdef GL_ES\n"
@@ -865,6 +865,10 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
cairo_gl_shader_emit_color (stream, ctx, src, CAIRO_GL_TEX_SOURCE);
cairo_gl_shader_emit_color (stream, ctx, mask, CAIRO_GL_TEX_MASK);
+ coverage_str = "";
+ if (use_coverage)
+ coverage_str = " * coverage.a";
+
_cairo_output_stream_printf (stream,
"void main()\n"
"{\n");
@@ -874,15 +878,18 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
ASSERT_NOT_REACHED;
case CAIRO_GL_SHADER_IN_NORMAL:
_cairo_output_stream_printf (stream,
- " gl_FragColor = get_source() * get_mask().a;\n");
+ " gl_FragColor = get_source() * get_mask().a%s;\n",
+ coverage_str);
break;
case CAIRO_GL_SHADER_IN_CA_SOURCE:
_cairo_output_stream_printf (stream,
- " gl_FragColor = get_source() * get_mask();\n");
+ " gl_FragColor = get_source() * get_mask()%s;\n",
+ coverage_str);
break;
case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA:
_cairo_output_stream_printf (stream,
- " gl_FragColor = get_source().a * get_mask();\n");
+ " gl_FragColor = get_source().a * get_mask()%s;\n",
+ coverage_str);
break;
}
@@ -902,6 +909,7 @@ _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
cairo_gl_shader_t *shader,
cairo_gl_var_type_t src,
cairo_gl_var_type_t mask,
+ cairo_bool_t use_coverage,
const char *fragment_text)
{
unsigned int vertex_shader;
@@ -909,12 +917,14 @@ _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
assert (shader->program == 0);
- vertex_shader = cairo_gl_var_type_hash (src, mask, CAIRO_GL_VAR_NONE);
+ vertex_shader = cairo_gl_var_type_hash (src, mask, use_coverage,
+ CAIRO_GL_VAR_NONE);
if (ctx->vertex_shaders[vertex_shader] == 0) {
char *source;
status = cairo_gl_shader_get_vertex_source (src,
mask,
+ use_coverage,
CAIRO_GL_VAR_NONE,
&source);
if (unlikely (status))
@@ -1042,6 +1052,7 @@ cairo_status_t
_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
cairo_gl_operand_t *source,
cairo_gl_operand_t *mask,
+ cairo_bool_t use_coverage,
cairo_gl_shader_in_t in,
cairo_gl_shader_t **shader)
{
@@ -1071,6 +1082,7 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
in,
source,
mask,
+ use_coverage,
CAIRO_GL_OPERAND_NONE,
&fs_source);
if (unlikely (status))
@@ -1090,6 +1102,7 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
&entry->shader,
cairo_gl_operand_get_var_type (source->type),
cairo_gl_operand_get_var_type (mask->type),
+ use_coverage,
fs_source);
free (fs_source);
diff --git a/src/cairo-gl-spans-compositor.c b/src/cairo-gl-spans-compositor.c
new file mode 100644
index 00000000..57cccc9f
--- /dev/null
+++ b/src/cairo-gl-spans-compositor.c
@@ -0,0 +1,502 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005,2010 Red Hat, Inc
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Benjamin Otte <otte@gnome.org>
+ * Carl Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ * Eric Anholt <eric@anholt.net>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-gl-private.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-spans-compositor-private.h"
+#include "cairo-surface-backend-private.h"
+
+typedef struct _cairo_gl_span_renderer {
+ cairo_span_renderer_t base;
+
+ cairo_gl_composite_t setup;
+ double opacity;
+
+ int xmin, xmax;
+ int ymin, ymax;
+
+ cairo_gl_context_t *ctx;
+} cairo_gl_span_renderer_t;
+
+static cairo_status_t
+_cairo_gl_bounded_opaque_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_gl_span_renderer_t *r = abstract_renderer;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ do {
+ if (spans[0].coverage) {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ spans[0].coverage);
+ }
+
+ spans++;
+ } while (--num_spans > 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_bounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_gl_span_renderer_t *r = abstract_renderer;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ do {
+ if (spans[0].coverage) {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ r->opacity * spans[0].coverage);
+ }
+
+ spans++;
+ } while (--num_spans > 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_unbounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_gl_span_renderer_t *r = abstract_renderer;
+
+ if (y > r->ymin) {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ r->xmin, r->ymin,
+ r->xmax, y,
+ 0);
+ }
+
+ if (num_spans == 0) {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ r->xmin, y,
+ r->xmax, y + height,
+ 0);
+ } else {
+ if (spans[0].x != r->xmin) {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ r->xmin, y,
+ spans[0].x, y + height,
+ 0);
+ }
+
+ do {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ r->opacity * spans[0].coverage);
+ spans++;
+ } while (--num_spans > 1);
+
+ if (spans[0].x != r->xmax) {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ spans[0].x, y,
+ r->xmax, y + height,
+ 0);
+ }
+ }
+
+ r->ymin = y + height;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* XXX */
+static cairo_status_t
+_cairo_gl_clipped_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_gl_span_renderer_t *r = abstract_renderer;
+
+ if (y > r->ymin) {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ r->xmin, r->ymin,
+ r->xmax, y,
+ 0);
+ }
+
+ if (num_spans == 0) {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ r->xmin, y,
+ r->xmax, y + height,
+ 0);
+ } else {
+ if (spans[0].x != r->xmin) {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ r->xmin, y,
+ spans[0].x, y + height,
+ 0);
+ }
+
+ do {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ r->opacity * spans[0].coverage);
+ spans++;
+ } while (--num_spans > 1);
+
+ if (spans[0].x != r->xmax) {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ spans[0].x, y,
+ r->xmax, y + height,
+ 0);
+ }
+ }
+
+ r->ymin = y + height;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
+{
+ cairo_gl_span_renderer_t *r = abstract_renderer;
+
+ if (r->ymax > r->ymin) {
+ _cairo_gl_composite_emit_rect (r->ctx,
+ r->xmin, r->ymin,
+ r->xmax, r->ymax,
+ 0);
+ }
+
+ return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
+}
+
+static cairo_status_t
+_cairo_gl_finish_bounded_spans (void *abstract_renderer)
+{
+ cairo_gl_span_renderer_t *r = abstract_renderer;
+
+ return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
+}
+
+static void
+emit_aligned_boxes (cairo_gl_context_t *ctx,
+ const cairo_boxes_t *boxes)
+{
+ const struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+ _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 0);
+ }
+ }
+}
+
+static cairo_int_status_t
+fill_boxes (void *_dst,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ cairo_gl_composite_t setup;
+ cairo_gl_context_t *ctx;
+ cairo_int_status_t status;
+
+ status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
+ if (unlikely (status))
+ goto FAIL;
+
+ _cairo_gl_composite_set_solid_source (&setup, color);
+
+ status = _cairo_gl_composite_begin (&setup, &ctx);
+ if (unlikely (status))
+ goto FAIL;
+
+ emit_aligned_boxes (ctx, boxes);
+ status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+ _cairo_gl_composite_fini (&setup);
+ return status;
+}
+
+typedef struct cairo_gl_source {
+ cairo_surface_t base;
+
+ cairo_gl_operand_t operand;
+} cairo_gl_source_t;
+
+static cairo_status_t
+_cairo_gl_source_finish (void *abstract_surface)
+{
+ cairo_gl_source_t *source = abstract_surface;
+
+ _cairo_gl_operand_destroy (&source->operand);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_gl_source_backend = {
+ CAIRO_SURFACE_TYPE_GL,
+ _cairo_gl_source_finish,
+ NULL, /* read-only wrapper */
+};
+
+static cairo_surface_t *
+pattern_to_surface (cairo_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y)
+{
+ cairo_gl_source_t *source;
+ cairo_int_status_t status;
+
+ source = malloc (sizeof (*source));
+ if (unlikely (source == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&source->base,
+ &cairo_gl_source_backend,
+ NULL, /* device */
+ CAIRO_CONTENT_COLOR_ALPHA);
+
+ *src_x = *src_y = 0;
+ status = _cairo_gl_operand_init (&source->operand, pattern, (cairo_gl_surface_t *)dst,
+ extents->x, extents->y,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&source->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ return &source->base;
+}
+
+static inline cairo_gl_operand_t *
+source_to_operand (cairo_surface_t *surface)
+{
+ cairo_gl_source_t *source = (cairo_gl_source_t *)surface;
+ return &source->operand;
+}
+
+static cairo_int_status_t
+composite_boxes (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ cairo_boxes_t *boxes,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_gl_composite_t setup;
+ cairo_gl_context_t *ctx;
+ cairo_int_status_t status;
+
+ status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, extents);
+ if (unlikely (status))
+ goto FAIL;
+
+ _cairo_gl_composite_set_source_operand (&setup,
+ source_to_operand (abstract_src));
+
+ _cairo_gl_composite_set_mask_operand (&setup,
+ source_to_operand (abstract_mask));
+
+ status = _cairo_gl_composite_begin (&setup, &ctx);
+ if (unlikely (status))
+ goto FAIL;
+
+ emit_aligned_boxes (ctx, boxes);
+ status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+ _cairo_gl_composite_fini (&setup);
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t *_r,
+ const cairo_composite_rectangles_t *composite,
+ cairo_bool_t needs_clip)
+{
+ cairo_gl_span_renderer_t *r = (cairo_gl_span_renderer_t *)_r;
+ const cairo_pattern_t *source = &composite->source_pattern.base;
+ cairo_operator_t op = composite->op;
+ cairo_int_status_t status;
+
+ /* XXX earlier! */
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ source = &_cairo_pattern_white.base;
+ op = CAIRO_OPERATOR_DEST_OUT;
+ } else if (composite->surface->is_clear &&
+ (op == CAIRO_OPERATOR_SOURCE ||
+ op == CAIRO_OPERATOR_OVER ||
+ op == CAIRO_OPERATOR_ADD)) {
+ op = CAIRO_OPERATOR_SOURCE;
+ } else if (op == CAIRO_OPERATOR_SOURCE) {
+ /* no lerp equivalent without some major PITA */
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ } else if (! _cairo_gl_operator_is_supported (op))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_gl_composite_init (&r->setup,
+ op, (cairo_gl_surface_t *)composite->surface,
+ FALSE, &composite->unbounded);
+ if (unlikely (status))
+ goto FAIL;
+
+ status = _cairo_gl_composite_set_source (&r->setup, source,
+ composite->unbounded.x,
+ composite->unbounded.y,
+ composite->unbounded.x,
+ composite->unbounded.y,
+ composite->unbounded.width,
+ composite->unbounded.height);
+ if (unlikely (status))
+ goto FAIL;
+
+ r->opacity = 1.0;
+ if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
+ r->opacity = composite->mask_pattern.solid.color.alpha;
+ } else {
+ status = _cairo_gl_composite_set_mask (&r->setup,
+ &composite->mask_pattern.base,
+ composite->unbounded.x,
+ composite->unbounded.y,
+ composite->unbounded.x,
+ composite->unbounded.y,
+ composite->unbounded.width,
+ composite->unbounded.height);
+ if (unlikely (status))
+ goto FAIL;
+ }
+
+ _cairo_gl_composite_set_spans (&r->setup);
+
+ status = _cairo_gl_composite_begin (&r->setup, &r->ctx);
+ if (unlikely (status))
+ goto FAIL;
+
+ if (composite->is_bounded) {
+ if (r->opacity == 1.)
+ r->base.render_rows = _cairo_gl_bounded_opaque_spans;
+ else
+ r->base.render_rows = _cairo_gl_bounded_spans;
+ r->base.finish = _cairo_gl_finish_bounded_spans;
+ } else {
+ if (needs_clip)
+ r->base.render_rows = _cairo_gl_clipped_spans;
+ else
+ r->base.render_rows = _cairo_gl_unbounded_spans;
+ r->base.finish = _cairo_gl_finish_unbounded_spans;
+ r->xmin = composite->unbounded.x;
+ r->xmax = composite->unbounded.x + composite->unbounded.width;
+ r->ymin = composite->unbounded.y;
+ r->ymax = composite->unbounded.y + composite->unbounded.height;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+
+FAIL:
+ return status;
+}
+
+static void
+_cairo_gl_span_renderer_fini (cairo_abstract_span_renderer_t *_r,
+ cairo_int_status_t status)
+{
+ cairo_gl_span_renderer_t *r = (cairo_gl_span_renderer_t *) _r;
+
+ if (status == CAIRO_INT_STATUS_SUCCESS)
+ r->base.finish (r);
+
+ _cairo_gl_composite_fini (&r->setup);
+}
+
+const cairo_compositor_t *
+_cairo_gl_span_compositor_get (void)
+{
+ static cairo_spans_compositor_t compositor;
+
+ if (compositor.base.delegate == NULL) {
+ /* The fallback to traps here is essentially just for glyphs... */
+ _cairo_spans_compositor_init (&compositor,
+ _cairo_gl_traps_compositor_get());
+
+ compositor.fill_boxes = fill_boxes;
+ //compositor.check_composite_boxes = check_composite_boxes;
+ compositor.pattern_to_surface = pattern_to_surface;
+ compositor.composite_boxes = composite_boxes;
+ //compositor.check_span_renderer = check_span_renderer;
+ compositor.renderer_init = _cairo_gl_span_renderer_init;
+ compositor.renderer_fini = _cairo_gl_span_renderer_fini;
+ }
+
+ return &compositor.base;
+}
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index ec708204..dec4b82a 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -43,31 +43,11 @@
#include "cairo-gl-private.h"
#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
-
-static cairo_int_status_t
-_cairo_gl_surface_fill_rectangles (void *abstract_dst,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects);
-
-static cairo_int_status_t
-_cairo_gl_surface_composite (cairo_operator_t op,
- const cairo_pattern_t *src,
- const cairo_pattern_t *mask,
- 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,
- cairo_region_t *clip_region);
+#include "cairo-surface-backend-private.h"
static cairo_status_t
_cairo_gl_surface_flush (void *abstract_surface);
@@ -306,6 +286,9 @@ _cairo_gl_get_image_format_and_type_gl (pixman_format_code_t pixman_format,
case PIXMAN_yv12:
case PIXMAN_x2r10g10b10:
case PIXMAN_a2r10g10b10:
+ case PIXMAN_r8g8b8x8:
+ case PIXMAN_r8g8b8a8:
+ case PIXMAN_x14r6g6b6:
default:
return FALSE;
}
@@ -509,10 +492,8 @@ cairo_gl_surface_create (cairo_device_t *abstract_device,
if (! CAIRO_CONTENT_VALID (content))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
- if (abstract_device == NULL) {
- return cairo_image_surface_create (_cairo_format_from_content (content),
- width, height);
- }
+ if (abstract_device == NULL)
+ return _cairo_image_surface_create_with_content (content, width, height);
if (abstract_device->status)
return _cairo_surface_create_in_error (abstract_device->status);
@@ -545,7 +526,6 @@ cairo_gl_surface_create (cairo_device_t *abstract_device,
}
slim_hidden_def (cairo_gl_surface_create);
-
/**
* cairo_gl_surface_create_for_texture:
* @content: type of content in the surface
@@ -592,7 +572,7 @@ cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device,
return _cairo_surface_create_in_error (abstract_device->status);
if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH));
status = _cairo_gl_context_acquire (abstract_device, &ctx);
if (unlikely (status))
@@ -614,20 +594,19 @@ cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
int height)
{
cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
- cairo_status_t status;
if (unlikely (abstract_surface->status))
return;
if (unlikely (abstract_surface->finished)) {
- status = _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ _cairo_surface_set_error (abstract_surface,
+ _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
if (! _cairo_surface_is_gl (abstract_surface) ||
_cairo_gl_surface_is_texture (surface)) {
- status = _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+ _cairo_surface_set_error (abstract_surface,
+ _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
return;
}
@@ -664,19 +643,18 @@ void
cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
{
cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
- cairo_status_t status;
if (unlikely (abstract_surface->status))
return;
if (unlikely (abstract_surface->finished)) {
- status = _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ _cairo_surface_set_error (abstract_surface,
+ _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
if (! _cairo_surface_is_gl (abstract_surface)) {
- status = _cairo_surface_set_error (abstract_surface,
- CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ _cairo_surface_set_error (abstract_surface,
+ CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return;
}
@@ -694,10 +672,20 @@ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
status = _cairo_gl_context_release (ctx, status);
if (status)
- status = _cairo_surface_set_error (abstract_surface, status);
+ status = _cairo_surface_set_error (abstract_surface, status);
}
}
+static cairo_bool_t
+_cairo_gl_surface_size_valid (cairo_gl_surface_t *surface,
+ int width, int height)
+{
+ cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
+ return width > 0 && height > 0 &&
+ width <= ctx->max_framebuffer_size &&
+ height <= ctx->max_framebuffer_size;
+}
+
static cairo_surface_t *
_cairo_gl_surface_create_similar (void *abstract_surface,
cairo_content_t content,
@@ -708,24 +696,15 @@ _cairo_gl_surface_create_similar (void *abstract_surface,
cairo_gl_context_t *ctx;
cairo_status_t status;
- if (width < 1 || height < 1)
- return cairo_image_surface_create (_cairo_format_from_content (content),
- width, height);
+ if (! _cairo_gl_surface_size_valid (abstract_surface, width, height))
+ return _cairo_image_surface_create_with_content (content, width, height);
status = _cairo_gl_context_acquire (surface->device, &ctx);
if (unlikely (status))
return _cairo_surface_create_in_error (status);
- if (width > ctx->max_framebuffer_size ||
- height > ctx->max_framebuffer_size)
- {
- surface = NULL;
- goto RELEASE;
- }
-
surface = _cairo_gl_surface_create_scratch (ctx, content, width, height);
-RELEASE:
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status)) {
cairo_surface_destroy (surface);
@@ -735,6 +714,43 @@ RELEASE:
return surface;
}
+static cairo_int_status_t
+_cairo_gl_surface_fill_alpha_channel (void *abstract_dst,
+ int x, int y,
+ int width, int height)
+{
+ cairo_gl_surface_t *dst = abstract_dst;
+ cairo_gl_composite_t setup;
+ cairo_gl_context_t *ctx;
+ cairo_status_t status;
+
+ _cairo_gl_composite_flush (ctx);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
+
+ status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_SOURCE, dst,
+ FALSE, NULL);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_BLACK);
+
+ status = _cairo_gl_composite_begin (&setup, &ctx);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ _cairo_gl_composite_emit_rect (ctx, x, y, x + width, y + height, 0);
+
+ status = _cairo_gl_context_release (ctx, status);
+
+ CLEANUP:
+ _cairo_gl_composite_fini (&setup);
+
+ _cairo_gl_composite_flush (ctx);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ return status;
+}
+
cairo_status_t
_cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
cairo_image_surface_t *src,
@@ -797,8 +813,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
* image data ourselves in some cases. In particular, we must extract
* the pixels if:
* a. we don't want full-length lines or
- * b. the row stride cannot be handled by GL itself using a 4 byte alignment
- * constraint
+ * b. the row stride cannot be handled by GL itself using a 4 byte
+ * alignment constraint
*/
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
(src->width * cpp < src->stride - 3 ||
@@ -826,7 +842,6 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
data_start_gles2 != NULL ? data_start_gles2 :
data_start);
-
free (data_start_gles2);
/* If we just treated some rgb-only data as rgba, then we have to
@@ -834,21 +849,9 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
* texture data.
*/
if (!has_alpha) {
- cairo_rectangle_int_t rect;
-
- rect.x = dst_x;
- rect.y = dst_y;
- rect.width = width;
- rect.height = height;
-
- _cairo_gl_composite_flush (ctx);
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
- _cairo_gl_surface_fill_rectangles (dst,
- CAIRO_OPERATOR_SOURCE,
- CAIRO_COLOR_BLACK,
- &rect, 1);
- _cairo_gl_composite_flush (ctx);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ _cairo_gl_surface_fill_alpha_channel (dst,
+ dst_x, dst_y,
+ width, height);
}
} else {
cairo_surface_t *tmp;
@@ -869,15 +872,10 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
cairo_surface_pattern_t tmp_pattern;
_cairo_pattern_init_for_surface (&tmp_pattern, tmp);
- _cairo_gl_surface_composite (CAIRO_OPERATOR_SOURCE,
- &tmp_pattern.base,
- NULL,
- dst,
- 0, 0,
- 0, 0,
- dst_x, dst_y,
- width, height,
- NULL);
+ status = _cairo_surface_paint (&dst->base,
+ CAIRO_OPERATOR_SOURCE,
+ &tmp_pattern.base,
+ NULL);
_cairo_pattern_fini (&tmp_pattern.base);
}
@@ -896,17 +894,53 @@ FAIL:
return status;
}
+static int _cairo_gl_surface_flavor (cairo_gl_surface_t *surface)
+{
+ cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
+ return ctx->gl_flavor;
+}
+
static cairo_status_t
-_cairo_gl_surface_get_image (cairo_gl_surface_t *surface,
- cairo_rectangle_int_t *interest,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *rect_out)
+_cairo_gl_surface_finish (void *abstract_surface)
{
+ cairo_gl_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+ cairo_gl_context_t *ctx;
+
+ status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+ if (unlikely (status))
+ return status;
+
+ if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
+ ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface)
+ _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
+ if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
+ ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface)
+ _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
+ if (ctx->current_target == surface)
+ ctx->current_target = NULL;
+
+ if (surface->depth)
+ ctx->dispatch.DeleteFramebuffers (1, &surface->depth);
+ if (surface->fb)
+ ctx->dispatch.DeleteFramebuffers (1, &surface->fb);
+ if (surface->owns_tex)
+ glDeleteTextures (1, &surface->tex);
+
+ return _cairo_gl_context_release (ctx, status);
+}
+
+static cairo_surface_t *
+_cairo_gl_surface_map_to_image (void *abstract_surface,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_gl_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
cairo_gl_context_t *ctx;
GLenum format, type;
pixman_format_code_t pixman_format;
unsigned int cpp;
+ cairo_bool_t invert;
cairo_status_t status;
/* Want to use a switch statement here but the compiler gets whiny. */
@@ -927,22 +961,18 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t *surface,
cpp = 1;
} else {
ASSERT_NOT_REACHED;
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return NULL;
}
- status = _cairo_gl_context_acquire (surface->base.device, &ctx);
- if (unlikely (status))
- return status;
-
/*
* GLES2 supports only RGBA, UNSIGNED_BYTE so use that.
* We are also using this format for ALPHA as GLES2 does not
* support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
* pixman image that is created has row_stride = row_width * bpp.
*/
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
+ if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES) {
format = GL_RGBA;
- if (!_cairo_is_little_endian ()) {
+ if (! _cairo_is_little_endian ()) {
if (surface->base.content == CAIRO_CONTENT_COLOR)
pixman_format = PIXMAN_r8g8b8x8;
else
@@ -960,11 +990,20 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t *surface,
image = (cairo_image_surface_t*)
_cairo_image_surface_create_with_pixman_format (NULL,
pixman_format,
- interest->width,
- interest->height,
+ extents->width,
+ extents->height,
-1);
if (unlikely (image->base.status))
- return _cairo_gl_context_release (ctx, image->base.status);
+ return &image->base;
+
+ if (surface->base.serial == 0)
+ return &image->base;
+
+ status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
+ return _cairo_surface_create_in_error (status);
+ }
/* This is inefficient, as we'd rather just read the thing without making
* it the destination. But then, this is the fallback path, so let's not
@@ -973,60 +1012,28 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t *surface,
_cairo_gl_composite_flush (ctx);
_cairo_gl_context_set_destination (ctx, surface);
+ invert = ! _cairo_gl_surface_is_texture (surface) &&
+ ctx->has_mesa_pack_invert;
+
glPixelStorei (GL_PACK_ALIGNMENT, 4);
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
- if (! _cairo_gl_surface_is_texture (surface) &&
- ctx->has_mesa_pack_invert)
+ if (invert)
glPixelStorei (GL_PACK_INVERT_MESA, 1);
- glReadPixels (interest->x, interest->y,
- interest->width, interest->height,
+ glReadPixels (extents->x, extents->y,
+ extents->width, extents->height,
format, type, image->data);
- if (! _cairo_gl_surface_is_texture (surface) &&
- ctx->has_mesa_pack_invert)
+ if (invert)
glPixelStorei (GL_PACK_INVERT_MESA, 0);
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status)) {
cairo_surface_destroy (&image->base);
- return status;
+ image = (cairo_image_surface_t *)
+ _cairo_surface_create_in_error (status);
}
- *image_out = image;
- if (rect_out != NULL)
- *rect_out = *interest;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_surface_finish (void *abstract_surface)
-{
- cairo_gl_surface_t *surface = abstract_surface;
- cairo_status_t status;
- cairo_gl_context_t *ctx;
-
- status = _cairo_gl_context_acquire (surface->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
- ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface)
- _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
- if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
- ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface)
- _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
- if (ctx->current_target == surface)
- ctx->current_target = NULL;
-
- if (surface->depth)
- ctx->dispatch.DeleteFramebuffers (1, &surface->depth);
- if (surface->fb)
- ctx->dispatch.DeleteFramebuffers (1, &surface->fb);
- if (surface->owns_tex)
- glDeleteTextures (1, &surface->tex);
-
- return _cairo_gl_context_release (ctx, status);
+ return &image->base;
}
static cairo_status_t
@@ -1042,7 +1049,10 @@ _cairo_gl_surface_acquire_source_image (void *abstract_surface,
extents.x = extents.y = 0;
extents.width = surface->width;
extents.height = surface->height;
- return _cairo_gl_surface_get_image (surface, &extents, image_out, NULL);
+
+ *image_out = (cairo_image_surface_t *)
+ _cairo_gl_surface_map_to_image (surface, &extents);
+ return (*image_out)->base.status;
}
static void
@@ -1053,536 +1063,18 @@ _cairo_gl_surface_release_source_image (void *abstract_surface,
cairo_surface_destroy (&image->base);
}
-static cairo_status_t
-_cairo_gl_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect_out,
- void **image_extra)
-{
- cairo_gl_surface_t *surface = abstract_surface;
-
- *image_extra = NULL;
- return _cairo_gl_surface_get_image (surface, interest_rect, image_out,
- image_rect_out);
-}
-
-static void
-_cairo_gl_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
-{
- cairo_status_t status;
-
- status = _cairo_gl_surface_draw_image (abstract_surface, image,
- 0, 0,
- image->width, image->height,
- image_rect->x, image_rect->y);
- /* as we created the image, its format should be directly applicable */
- assert (status == CAIRO_STATUS_SUCCESS);
-
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_gl_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
-{
- cairo_gl_surface_t *surface = abstract_surface;
-
- /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */
- if (src->device == surface->base.device &&
- _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) {
- *clone_offset_x = 0;
- *clone_offset_y = 0;
- *clone_out = cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- } else if (_cairo_surface_is_image (src)) {
- cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
- cairo_gl_surface_t *clone;
- cairo_status_t status;
-
- clone = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_similar (&surface->base,
- src->content,
- width, height);
- if (clone == NULL)
- return UNSUPPORTED ("create_similar failed");
- if (clone->base.status)
- return clone->base.status;
-
- status = _cairo_gl_surface_draw_image (clone, image_src,
- src_x, src_y,
- width, height,
- 0, 0);
- if (status) {
- cairo_surface_destroy (&clone->base);
- return status;
- }
-
- *clone_out = &clone->base;
- *clone_offset_x = src_x;
- *clone_offset_y = src_y;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return UNSUPPORTED ("unknown src surface type in clone_similar");
-}
-
-/** Creates a cairo-gl pattern surface for the given trapezoids */
-static cairo_status_t
-_cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
- int dst_x, int dst_y,
- int width, int height,
- cairo_trapezoid_t *traps,
- int num_traps,
- cairo_antialias_t antialias,
- cairo_surface_pattern_t *pattern)
-{
- pixman_format_code_t pixman_format;
- pixman_image_t *image;
- cairo_surface_t *surface;
- int i;
-
- pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
- image = pixman_image_create_bits (pixman_format, width, height, NULL, 0);
- if (unlikely (image == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- for (i = 0; i < num_traps; i++) {
- pixman_trapezoid_t trap;
-
- trap.top = _cairo_fixed_to_16_16 (traps[i].top);
- trap.bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
-
- trap.left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
- trap.left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
- trap.left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
- trap.left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
-
- trap.right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
- trap.right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
- trap.right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
- trap.right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
-
- pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
- }
-
- surface = _cairo_image_surface_create_for_pixman_image (image,
- pixman_format);
- if (unlikely (surface->status)) {
- pixman_image_unref (image);
- return surface->status;
- }
-
- _cairo_pattern_init_for_surface (pattern, surface);
- cairo_surface_destroy (surface);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_int_status_t
-_cairo_gl_surface_composite (cairo_operator_t op,
- const cairo_pattern_t *src,
- const cairo_pattern_t *mask,
- 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,
- cairo_region_t *clip_region)
+_cairo_gl_surface_unmap_image (void *abstract_surface,
+ cairo_image_surface_t *image)
{
- cairo_gl_surface_t *dst = abstract_dst;
- cairo_gl_context_t *ctx;
- cairo_int_status_t status;
- cairo_gl_composite_t setup;
- cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
- int dx, dy;
-
- if (op == CAIRO_OPERATOR_SOURCE &&
- mask == NULL &&
- src->type == CAIRO_PATTERN_TYPE_SURFACE &&
- _cairo_surface_is_image (((cairo_surface_pattern_t *) src)->surface) &&
- _cairo_matrix_is_integer_translation (&src->matrix, &dx, &dy)) {
- cairo_image_surface_t *image = (cairo_image_surface_t *)
- ((cairo_surface_pattern_t *) src)->surface;
- dx += src_x;
- dy += src_y;
- if (dx >= 0 &&
- dy >= 0 &&
- dx + width <= (unsigned int) image->width &&
- dy + height <= (unsigned int) image->height) {
- status = _cairo_gl_surface_draw_image (dst, image,
- dx, dy,
- width, height,
- dst_x, dst_y);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
- }
-
- status = _cairo_gl_composite_init (&setup, op, dst,
- mask && mask->has_component_alpha,
- &rect);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_gl_composite_set_source (&setup, src,
- src_x, src_y,
- dst_x, dst_y,
- width, height);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_gl_composite_set_mask (&setup, mask,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto CLEANUP;
-
- if (clip_region != NULL) {
- int i, num_rectangles;
-
- num_rectangles = cairo_region_num_rectangles (clip_region);
-
- for (i = 0; i < num_rectangles; i++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (clip_region, i, &rect);
- _cairo_gl_composite_emit_rect (ctx,
- rect.x, rect.y,
- rect.x + rect.width, rect.y + rect.height,
- 0);
- }
- } else {
- _cairo_gl_composite_emit_rect (ctx,
- dst_x, dst_y,
- dst_x + width, dst_y + height,
- 0);
- }
-
- status = _cairo_gl_context_release (ctx, status);
-
- CLEANUP:
- _cairo_gl_composite_fini (&setup);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *abstract_dst,
- cairo_antialias_t antialias,
- int src_x, int src_y,
- int dst_x, int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps,
- cairo_region_t *clip_region)
-{
- cairo_gl_surface_t *dst = abstract_dst;
- cairo_surface_pattern_t traps_pattern;
- cairo_int_status_t status;
-
- if (! _cairo_gl_operator_is_supported (op))
- return UNSUPPORTED ("unsupported operator");
-
- status = _cairo_gl_get_traps_pattern (dst,
- dst_x, dst_y, width, height,
- traps, num_traps, antialias,
- &traps_pattern);
- if (unlikely (status))
- return status;
-
- status = _cairo_gl_surface_composite (op,
- pattern, &traps_pattern.base, dst,
- src_x, src_y,
- 0, 0,
- dst_x, dst_y,
- width, height,
- clip_region);
-
- _cairo_pattern_fini (&traps_pattern.base);
-
- assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
- return status;
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_fill_rectangles (void *abstract_dst,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects)
-{
- cairo_gl_surface_t *dst = abstract_dst;
- cairo_solid_pattern_t solid;
- cairo_gl_context_t *ctx;
- cairo_status_t status;
- cairo_gl_composite_t setup;
- int i;
-
- status = _cairo_gl_composite_init (&setup, op, dst,
- FALSE,
- /* XXX */ NULL);
- if (unlikely (status))
- goto CLEANUP;
-
- _cairo_pattern_init_solid (&solid, color);
- status = _cairo_gl_composite_set_source (&setup, &solid.base,
- 0, 0,
- 0, 0,
- 0, 0);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_gl_composite_set_mask (&setup, NULL,
- 0, 0,
- 0, 0,
- 0, 0);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto CLEANUP;
-
- for (i = 0; i < num_rects; i++) {
- _cairo_gl_composite_emit_rect (ctx,
- rects[i].x,
- rects[i].y,
- rects[i].x + rects[i].width,
- rects[i].y + rects[i].height,
- 0);
- }
-
- status = _cairo_gl_context_release (ctx, status);
-
- CLEANUP:
- _cairo_gl_composite_fini (&setup);
-
- return status;
-}
-
-typedef struct _cairo_gl_surface_span_renderer {
- cairo_span_renderer_t base;
-
- cairo_gl_composite_t setup;
-
- int xmin, xmax;
- int ymin, ymax;
-
- cairo_gl_context_t *ctx;
-} cairo_gl_surface_span_renderer_t;
-
-static cairo_status_t
-_cairo_gl_render_bounded_spans (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- if (num_spans == 0)
- return CAIRO_STATUS_SUCCESS;
-
- do {
- if (spans[0].coverage) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- spans[0].coverage);
- }
-
- spans++;
- } while (--num_spans > 1);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_render_unbounded_spans (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- if (y > renderer->ymin) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, renderer->ymin,
- renderer->xmax, y,
- 0);
- }
-
- if (num_spans == 0) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, y,
- renderer->xmax, y + height,
- 0);
- } else {
- if (spans[0].x != renderer->xmin) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, y,
- spans[0].x, y + height,
- 0);
- }
-
- do {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- spans[0].coverage);
- spans++;
- } while (--num_spans > 1);
-
- if (spans[0].x != renderer->xmax) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- spans[0].x, y,
- renderer->xmax, y + height,
- 0);
- }
- }
-
- renderer->ymin = y + height;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- if (renderer->ymax > renderer->ymin) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, renderer->ymin,
- renderer->xmax, renderer->ymax,
- 0);
- }
-
- return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
-}
-
-static cairo_status_t
-_cairo_gl_finish_bounded_spans (void *abstract_renderer)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
-}
-
-static void
-_cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- if (!renderer)
- return;
-
- _cairo_gl_composite_fini (&renderer->setup);
-
- free (renderer);
+ return _cairo_gl_surface_draw_image (abstract_surface, image,
+ 0, 0,
+ image->width, image->height,
+ image->base.device_transform_inverse.x0,
+ image->base.device_transform_inverse.y0);
}
static cairo_bool_t
-_cairo_gl_surface_check_span_renderer (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *abstract_dst,
- cairo_antialias_t antialias)
-{
- if (! _cairo_gl_operator_is_supported (op))
- return FALSE;
-
- return TRUE;
-
- (void) pattern;
- (void) abstract_dst;
- (void) antialias;
-}
-
-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,
- cairo_region_t *clip_region)
-{
- cairo_gl_surface_t *dst = abstract_dst;
- cairo_gl_surface_span_renderer_t *renderer;
- cairo_status_t status;
- const cairo_rectangle_int_t *extents;
-
- 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;
- if (rects->is_bounded) {
- renderer->base.render_rows = _cairo_gl_render_bounded_spans;
- renderer->base.finish = _cairo_gl_finish_bounded_spans;
- extents = &rects->bounded;
- } else {
- renderer->base.render_rows = _cairo_gl_render_unbounded_spans;
- renderer->base.finish = _cairo_gl_finish_unbounded_spans;
- extents = &rects->unbounded;
- }
- renderer->xmin = extents->x;
- renderer->xmax = extents->x + extents->width;
- renderer->ymin = extents->y;
- renderer->ymax = extents->y + extents->height;
-
- status = _cairo_gl_composite_init (&renderer->setup,
- op, dst,
- FALSE, extents);
- if (unlikely (status))
- goto FAIL;
-
- status = _cairo_gl_composite_set_source (&renderer->setup, src,
- extents->x, extents->y,
- extents->x, extents->y,
- extents->width, extents->height);
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_mask_spans (&renderer->setup);
- _cairo_gl_composite_set_clip_region (&renderer->setup, clip_region);
-
- status = _cairo_gl_composite_begin (&renderer->setup, &renderer->ctx);
- if (unlikely (status))
- goto FAIL;
-
- return &renderer->base;
-
-FAIL:
- _cairo_gl_composite_fini (&renderer->setup);
- free (renderer);
- return _cairo_span_renderer_create_in_error (status);
-}
-
-cairo_bool_t
_cairo_gl_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -1596,16 +1088,6 @@ _cairo_gl_surface_get_extents (void *abstract_surface,
return TRUE;
}
-static void
-_cairo_gl_surface_get_font_options (void *abstract_surface,
- cairo_font_options_t *options)
-{
- _cairo_font_options_init_default (options);
-
- cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
- _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
-}
-
static cairo_status_t
_cairo_gl_surface_flush (void *abstract_surface)
{
@@ -1627,18 +1109,20 @@ _cairo_gl_surface_flush (void *abstract_surface)
return _cairo_gl_context_release (ctx, status);
}
+static const cairo_compositor_t *
+get_compositor (cairo_gl_surface_t *surface)
+{
+ cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
+ return ctx->compositor;
+}
+
static cairo_int_status_t
-_cairo_gl_surface_paint (void *abstract_surface,
+_cairo_gl_surface_paint (void *surface,
cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_clip_t *clip)
+ const cairo_pattern_t *source,
+ const cairo_clip_t *clip)
{
- cairo_gl_surface_t *surface = abstract_surface;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
- cairo_boxes_t boxes;
- cairo_status_t status;
-
+#if 0
/* simplify the common case of clearing the surface */
if (clip == NULL) {
if (op == CAIRO_OPERATOR_CLEAR)
@@ -1650,93 +1134,43 @@ _cairo_gl_surface_paint (void *abstract_surface,
&((cairo_solid_pattern_t *) source)->color);
}
}
+#endif
- _cairo_gl_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
- op, source,
- clip);
- if (unlikely (status))
- return status;
-
- status = _cairo_clip_to_boxes(extents.clip, &boxes);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _cairo_gl_clip_and_composite_boxes (surface, op, source,
- &boxes, &extents);
- }
-
- _cairo_composite_rectangles_fini (&extents);
+ return _cairo_compositor_paint (get_compositor (surface), surface,
+ op, source, clip);
+}
- return status;
+static cairo_int_status_t
+_cairo_gl_surface_mask (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ const cairo_clip_t *clip)
+{
+ return _cairo_compositor_mask (get_compositor (surface), surface,
+ op, source, mask, clip);
}
static cairo_int_status_t
-_cairo_gl_surface_stroke (void *abstract_surface,
+_cairo_gl_surface_stroke (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
+ const cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- const cairo_clip_t *clip)
+ const cairo_clip_t *clip)
{
- cairo_gl_surface_t *surface = abstract_surface;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
- cairo_int_status_t status;
-
- _cairo_gl_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_stroke (&extents,
- &unbounded,
- op, source,
- path, style, ctm,
- clip);
- if (unlikely (status))
- return status;
-
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
- cairo_boxes_t boxes;
-
- _cairo_boxes_init_with_clip (&boxes, extents.clip);
- status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
- style,
- ctm,
- antialias,
- &boxes);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- status = _cairo_gl_clip_and_composite_boxes (surface, op, source,
- &boxes, &extents);
- }
- _cairo_boxes_fini (&boxes);
- }
-
-
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- cairo_polygon_t polygon;
-
- _cairo_polygon_init_with_clip (&polygon, extents.clip);
- status = _cairo_path_fixed_stroke_to_polygon (path,
- style,
- ctm, ctm_inverse,
- tolerance,
- &polygon);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
- CAIRO_FILL_RULE_WINDING, antialias,
- &extents);
- }
- _cairo_polygon_fini (&polygon);
- }
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
+ return _cairo_compositor_stroke (get_compositor (surface), surface,
+ op, source, path, style,
+ ctm, ctm_inverse, tolerance, antialias,
+ clip);
}
static cairo_int_status_t
-_cairo_gl_surface_fill (void *abstract_surface,
+_cairo_gl_surface_fill (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t*path,
@@ -1745,51 +1179,24 @@ _cairo_gl_surface_fill (void *abstract_surface,
cairo_antialias_t antialias,
const cairo_clip_t *clip)
{
- cairo_gl_surface_t *surface = abstract_surface;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
- cairo_int_status_t status;
-
- _cairo_gl_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_fill (&extents,
- &unbounded,
- op, source, path,
- clip);
- if (unlikely (status))
- return status;
-
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (_cairo_path_fixed_fill_is_rectilinear (path)) {
- cairo_boxes_t boxes;
-
- _cairo_boxes_init_with_clip (&boxes, extents.clip);
- status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
- fill_rule,
- antialias,
- &boxes);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- status = _cairo_gl_clip_and_composite_boxes (surface, op, source,
- &boxes, &extents);
- }
- _cairo_boxes_fini (&boxes);
- }
-
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- cairo_polygon_t polygon;
-
- _cairo_polygon_init_with_clip (&polygon, extents.clip);
- status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
- fill_rule, antialias,
- &extents);
- }
- _cairo_polygon_fini (&polygon);
- }
-
- _cairo_composite_rectangles_fini (&extents);
+ return _cairo_compositor_fill (get_compositor (surface), surface,
+ op, source, path,
+ fill_rule, tolerance, antialias,
+ clip);
+}
- return status;
+static cairo_int_status_t
+_cairo_gl_surface_glyphs (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *font,
+ const cairo_clip_t *clip)
+{
+ return _cairo_compositor_glyphs (get_compositor (surface), surface,
+ op, source, glyphs, num_glyphs, font,
+ clip);
}
const cairo_surface_backend_t _cairo_gl_surface_backend = {
@@ -1799,34 +1206,26 @@ const cairo_surface_backend_t _cairo_gl_surface_backend = {
_cairo_gl_surface_create_similar,
NULL, /* similar image */
- NULL, /* map to image */
- NULL, /* unmap image */
+ _cairo_gl_surface_map_to_image,
+ _cairo_gl_surface_unmap_image,
_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, /* snapshot */
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_gl_surface_get_extents,
- NULL, /* old_show_glyphs */
- _cairo_gl_surface_get_font_options,
+ _cairo_image_surface_get_font_options,
+
_cairo_gl_surface_flush,
NULL, /* mark_dirty_rectangle */
- _cairo_gl_surface_scaled_font_fini,
- _cairo_gl_surface_scaled_glyph_fini,
+
_cairo_gl_surface_paint,
- NULL, /* mask */
+ _cairo_gl_surface_mask,
_cairo_gl_surface_stroke,
_cairo_gl_surface_fill,
- _cairo_gl_surface_show_glyphs, /* show_glyphs */
- NULL /* snapshot */
+ NULL, /* fill/stroke */
+ _cairo_gl_surface_glyphs,
};
diff --git a/src/cairo-gl-traps-compositor.c b/src/cairo-gl-traps-compositor.c
new file mode 100644
index 00000000..afc74d0e
--- /dev/null
+++ b/src/cairo-gl-traps-compositor.c
@@ -0,0 +1,550 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005,2010 Red Hat, Inc
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Benjamin Otte <otte@gnome.org>
+ * Carl Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ * Eric Anholt <eric@anholt.net>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-gl-private.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-spans-compositor-private.h"
+#include "cairo-surface-backend-private.h"
+
+static cairo_int_status_t
+acquire (void *abstract_dst)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+release (void *abstract_dst)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+set_clip_region (void *_surface,
+ cairo_region_t *region)
+{
+ cairo_gl_surface_t *surface = _surface;
+
+ //surface->clip_region = region;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+draw_image_boxes (void *_dst,
+ cairo_image_surface_t *image,
+ cairo_boxes_t *boxes,
+ int dx, int dy)
+{
+ cairo_gl_surface_t *dst = _dst;
+ struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ cairo_box_t *b = &chunk->base[i];
+ int x = _cairo_fixed_integer_part (b->p1.x);
+ int y = _cairo_fixed_integer_part (b->p1.y);
+ int w = _cairo_fixed_integer_part (b->p2.x) - x;
+ int h = _cairo_fixed_integer_part (b->p2.y) - y;
+ cairo_status_t status;
+
+ status = _cairo_gl_surface_draw_image (dst, image,
+ x + dx, y + dy,
+ w, h,
+ x, y);
+ if (unlikely (status))
+ return status;
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+emit_aligned_boxes (cairo_gl_context_t *ctx,
+ const cairo_boxes_t *boxes)
+{
+ const struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+ _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 0);
+ }
+ }
+}
+
+static cairo_int_status_t
+fill_boxes (void *_dst,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ cairo_gl_composite_t setup;
+ cairo_gl_context_t *ctx;
+ cairo_int_status_t status;
+
+ status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
+ if (unlikely (status))
+ goto FAIL;
+
+ _cairo_gl_composite_set_solid_source (&setup, color);
+
+ status = _cairo_gl_composite_begin (&setup, &ctx);
+ if (unlikely (status))
+ goto FAIL;
+
+ emit_aligned_boxes (ctx, boxes);
+ status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+ _cairo_gl_composite_fini (&setup);
+ return status;
+}
+
+typedef struct cairo_gl_source {
+ cairo_surface_t base;
+
+ cairo_gl_operand_t operand;
+} cairo_gl_source_t;
+
+static cairo_status_t
+_cairo_gl_source_finish (void *abstract_surface)
+{
+ cairo_gl_source_t *source = abstract_surface;
+
+ _cairo_gl_operand_destroy (&source->operand);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_gl_source_backend = {
+ CAIRO_SURFACE_TYPE_GL,
+ _cairo_gl_source_finish,
+ NULL, /* read-only wrapper */
+};
+
+static cairo_surface_t *
+pattern_to_surface (cairo_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y)
+{
+ cairo_gl_source_t *source;
+ cairo_int_status_t status;
+
+ source = malloc (sizeof (*source));
+ if (unlikely (source == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&source->base,
+ &cairo_gl_source_backend,
+ NULL, /* device */
+ CAIRO_CONTENT_COLOR_ALPHA);
+
+ *src_x = *src_y = 0;
+ status = _cairo_gl_operand_init (&source->operand, pattern, (cairo_gl_surface_t *)dst,
+ extents->x, extents->y,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&source->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ return &source->base;
+}
+
+static inline cairo_gl_operand_t *
+source_to_operand (cairo_surface_t *surface)
+{
+ cairo_gl_source_t *source = (cairo_gl_source_t *)surface;
+ return &source->operand;
+}
+
+static cairo_int_status_t
+composite_boxes (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ cairo_boxes_t *boxes,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_gl_composite_t setup;
+ cairo_gl_context_t *ctx;
+ cairo_int_status_t status;
+
+ status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, extents);
+ if (unlikely (status))
+ goto FAIL;
+
+ _cairo_gl_composite_set_source_operand (&setup,
+ source_to_operand (abstract_src));
+
+ _cairo_gl_composite_set_mask_operand (&setup,
+ source_to_operand (abstract_mask));
+
+ status = _cairo_gl_composite_begin (&setup, &ctx);
+ if (unlikely (status))
+ goto FAIL;
+
+ emit_aligned_boxes (ctx, boxes);
+ status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+ _cairo_gl_composite_fini (&setup);
+ return status;
+}
+
+static cairo_int_status_t
+composite (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ 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_gl_composite_t setup;
+ cairo_gl_context_t *ctx;
+ cairo_int_status_t status;
+
+ status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
+ if (unlikely (status))
+ goto FAIL;
+
+ _cairo_gl_composite_set_source_operand (&setup,
+ source_to_operand (abstract_src));
+
+ _cairo_gl_composite_set_mask_operand (&setup,
+ source_to_operand (abstract_mask));
+
+ status = _cairo_gl_composite_begin (&setup, &ctx);
+ if (unlikely (status))
+ goto FAIL;
+
+ /* XXX clip */
+ _cairo_gl_composite_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height, 0);
+ status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+ _cairo_gl_composite_fini (&setup);
+ return status;
+}
+
+static cairo_int_status_t
+lerp (void *dst,
+ cairo_surface_t *src,
+ cairo_surface_t *mask,
+ 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_int_status_t status;
+
+ /* we could avoid some repetition... */
+ status = composite (dst, CAIRO_OPERATOR_DEST_OUT, src, mask,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+ if (unlikely (status))
+ return status;
+
+ status = composite (dst, CAIRO_OPERATOR_ADD, src, mask,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+ if (unlikely (status))
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_gl_surface_t *
+traps_to_surface (void *_dst,
+ const cairo_rectangle_int_t *extents,
+ cairo_antialias_t antialias,
+ cairo_traps_t *traps)
+{
+ pixman_format_code_t pixman_format;
+ pixman_image_t *pixman_image;
+ cairo_surface_t *image, *mask;
+ cairo_status_t status;
+
+ pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
+ pixman_image = pixman_image_create_bits (pixman_format,
+ extents->width,
+ extents->height,
+ NULL, 0);
+ if (unlikely (pixman_image == NULL))
+ return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps);
+ image = _cairo_image_surface_create_for_pixman_image (pixman_image,
+ pixman_format);
+ if (unlikely (image->status)) {
+ pixman_image_unref (pixman_image);
+ return (cairo_gl_surface_t *)image;
+ }
+
+ mask = _cairo_surface_create_similar_scratch (_dst, CAIRO_CONTENT_ALPHA,
+ extents->width,
+ extents->height);
+ if (unlikely (mask->status)) {
+ cairo_surface_destroy (image);
+ return (cairo_gl_surface_t *)mask;
+ }
+
+ status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
+ (cairo_image_surface_t *)image,
+ 0, 0,
+ extents->width, extents->height,
+ 0, 0);
+ cairo_surface_destroy (image);
+ if (unlikely (status)) {
+ cairo_surface_destroy (mask);
+ return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status);
+ }
+
+ return (cairo_gl_surface_t*)mask;
+}
+
+static cairo_int_status_t
+composite_traps (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_antialias_t antialias,
+ cairo_traps_t *traps)
+{
+ cairo_gl_composite_t setup;
+ cairo_gl_context_t *ctx;
+ cairo_gl_surface_t *mask;
+ cairo_int_status_t status;
+
+ mask = traps_to_surface (_dst, extents, antialias, traps);
+ if (unlikely (mask->base.status))
+ return mask->base.status;
+
+ status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
+ if (unlikely (status))
+ goto FAIL;
+
+ _cairo_gl_composite_set_source_operand (&setup,
+ source_to_operand (abstract_src));
+
+ //_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
+
+ status = _cairo_gl_composite_begin (&setup, &ctx);
+ if (unlikely (status))
+ goto FAIL;
+
+ /* XXX clip */
+ _cairo_gl_composite_emit_rect (ctx,
+ dst_x, dst_y,
+ dst_x+extents->width,
+ dst_y+extents->height, 0);
+ status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+ _cairo_gl_composite_fini (&setup);
+ cairo_surface_destroy (&mask->base);
+ return status;
+}
+
+static cairo_gl_surface_t *
+tristrip_to_surface (void *_dst,
+ const cairo_rectangle_int_t *extents,
+ cairo_antialias_t antialias,
+ cairo_tristrip_t *strip)
+{
+ pixman_format_code_t pixman_format;
+ pixman_image_t *pixman_image;
+ cairo_surface_t *image, *mask;
+ cairo_status_t status;
+
+ pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
+ pixman_image = pixman_image_create_bits (pixman_format,
+ extents->width,
+ extents->height,
+ NULL, 0);
+ if (unlikely (pixman_image == NULL))
+ return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _pixman_image_add_tristrip (pixman_image, extents->x, extents->y, strip);
+ image = _cairo_image_surface_create_for_pixman_image (pixman_image,
+ pixman_format);
+ if (unlikely (image->status)) {
+ pixman_image_unref (pixman_image);
+ return (cairo_gl_surface_t *)image;
+ }
+
+ mask = _cairo_surface_create_similar_scratch (_dst, CAIRO_CONTENT_ALPHA,
+ extents->width,
+ extents->height);
+ if (unlikely (mask->status)) {
+ cairo_surface_destroy (image);
+ return (cairo_gl_surface_t *)mask;
+ }
+
+ status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
+ (cairo_image_surface_t *)image,
+ 0, 0,
+ extents->width, extents->height,
+ 0, 0);
+ cairo_surface_destroy (image);
+ if (unlikely (status)) {
+ cairo_surface_destroy (mask);
+ return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status);
+ }
+
+ return (cairo_gl_surface_t*)mask;
+}
+
+static cairo_int_status_t
+composite_tristrip (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_antialias_t antialias,
+ cairo_tristrip_t *strip)
+{
+ cairo_gl_composite_t setup;
+ cairo_gl_context_t *ctx;
+ cairo_gl_surface_t *mask;
+ cairo_int_status_t status;
+
+ mask = tristrip_to_surface (_dst, extents, antialias, strip);
+ if (unlikely (mask->base.status))
+ return mask->base.status;
+
+ status = _cairo_gl_composite_init (&setup, op, _dst, FALSE, NULL);
+ if (unlikely (status))
+ goto FAIL;
+
+ _cairo_gl_composite_set_source_operand (&setup,
+ source_to_operand (abstract_src));
+
+ //_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
+
+ status = _cairo_gl_composite_begin (&setup, &ctx);
+ if (unlikely (status))
+ goto FAIL;
+
+ /* XXX clip */
+ _cairo_gl_composite_emit_rect (ctx,
+ dst_x, dst_y,
+ dst_x+extents->width,
+ dst_y+extents->height, 0);
+ status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
+
+FAIL:
+ _cairo_gl_composite_fini (&setup);
+ cairo_surface_destroy (&mask->base);
+ return status;
+}
+
+const cairo_compositor_t *
+_cairo_gl_traps_compositor_get (void)
+{
+ static cairo_traps_compositor_t compositor;
+
+ if (compositor.base.delegate == NULL) {
+ _cairo_traps_compositor_init (&compositor, &_cairo_fallback_compositor);
+ compositor.acquire = acquire;
+ compositor.release = release;
+ compositor.set_clip_region = set_clip_region;
+ compositor.pattern_to_surface = pattern_to_surface;
+ compositor.draw_image_boxes = draw_image_boxes;
+ //compositor.copy_boxes = copy_boxes;
+ compositor.fill_boxes = fill_boxes;
+ //compositor.check_composite = check_composite;
+ compositor.composite = composite;
+ compositor.lerp = lerp;
+ //compositor.check_composite_boxes = check_composite_boxes;
+ compositor.composite_boxes = composite_boxes;
+ //compositor.check_composite_traps = check_composite_traps;
+ compositor.composite_traps = composite_traps;
+ //compositor.check_composite_tristrip = check_composite_traps;
+ compositor.composite_tristrip = composite_tristrip;
+ compositor.check_composite_glyphs = _cairo_gl_check_composite_glyphs;
+ compositor.composite_glyphs = _cairo_gl_composite_glyphs;
+ }
+
+ return &compositor.base;
+}
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 1b0658d8..c37fd8b4 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -41,6 +41,7 @@
#include "cairo-error-private.h"
#include "cairo-gstate-private.h"
#include "cairo-pattern-private.h"
+#include "cairo-traps-private.h"
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
#define ISFINITE(x) isfinite (x)
@@ -60,7 +61,7 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate);
static void
_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
-static cairo_status_t
+static void
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
@@ -800,11 +801,21 @@ _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
{
cairo_matrix_t matrix_inverse;
- cairo_matrix_multiply (&matrix_inverse,
- &gstate->target->device_transform_inverse,
- &gstate->ctm_inverse);
- _cairo_matrix_transform_bounding_box (&matrix_inverse,
- x1, y1, x2, y2, is_tight);
+ if (! _cairo_matrix_is_identity (&gstate->target->device_transform_inverse) ||
+ ! _cairo_matrix_is_identity (&gstate->ctm_inverse))
+ {
+ cairo_matrix_multiply (&matrix_inverse,
+ &gstate->target->device_transform_inverse,
+ &gstate->ctm_inverse);
+ _cairo_matrix_transform_bounding_box (&matrix_inverse,
+ x1, y1, x2, y2, is_tight);
+ }
+
+ else
+ {
+ if (is_tight)
+ *is_tight = TRUE;
+ }
}
/* XXX: NYI
@@ -1346,45 +1357,29 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate)
}
static void
-_cairo_gstate_traps_extents_to_user_rectangle (cairo_gstate_t *gstate,
- cairo_traps_t *traps,
- double *x1, double *y1,
- double *x2, double *y2)
+_cairo_gstate_extents_to_user_rectangle (cairo_gstate_t *gstate,
+ const cairo_box_t *extents,
+ double *x1, double *y1,
+ double *x2, double *y2)
{
- cairo_box_t extents;
-
- if (traps->num_traps == 0) {
- /* no traps, so we actually won't draw anything */
- if (x1)
- *x1 = 0.0;
- if (y1)
- *y1 = 0.0;
- if (x2)
- *x2 = 0.0;
- if (y2)
- *y2 = 0.0;
- } else {
- double px1, py1, px2, py2;
-
- _cairo_traps_extents (traps, &extents);
+ double px1, py1, px2, py2;
- px1 = _cairo_fixed_to_double (extents.p1.x);
- py1 = _cairo_fixed_to_double (extents.p1.y);
- px2 = _cairo_fixed_to_double (extents.p2.x);
- py2 = _cairo_fixed_to_double (extents.p2.y);
+ px1 = _cairo_fixed_to_double (extents->p1.x);
+ py1 = _cairo_fixed_to_double (extents->p1.y);
+ px2 = _cairo_fixed_to_double (extents->p2.x);
+ py2 = _cairo_fixed_to_double (extents->p2.y);
- _cairo_gstate_backend_to_user_rectangle (gstate,
- &px1, &py1, &px2, &py2,
- NULL);
- if (x1)
- *x1 = px1;
- if (y1)
- *y1 = py1;
- if (x2)
- *x2 = px2;
- if (y2)
- *y2 = py2;
- }
+ _cairo_gstate_backend_to_user_rectangle (gstate,
+ &px1, &py1, &px2, &py2,
+ NULL);
+ if (x1)
+ *x1 = px1;
+ if (y1)
+ *y1 = py1;
+ if (x2)
+ *x2 = px2;
+ if (y2)
+ *y2 = py2;
}
cairo_status_t
@@ -1393,35 +1388,57 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
double *x1, double *y1,
double *x2, double *y2)
{
- cairo_status_t status;
- cairo_traps_t traps;
+ cairo_int_status_t status;
+ cairo_box_t extents;
+ cairo_bool_t empty;
- if (gstate->stroke_style.line_width <= 0.0) {
- if (x1)
- *x1 = 0.0;
- if (y1)
- *y1 = 0.0;
- if (x2)
- *x2 = 0.0;
- if (y2)
- *y2 = 0.0;
- return CAIRO_STATUS_SUCCESS;
- }
+ if (x1)
+ *x1 = 0.0;
+ if (y1)
+ *y1 = 0.0;
+ if (x2)
+ *x2 = 0.0;
+ if (y2)
+ *y2 = 0.0;
- _cairo_traps_init (&traps);
+ if (gstate->stroke_style.line_width <= 0.0)
+ return CAIRO_STATUS_SUCCESS;
- status = _cairo_path_fixed_stroke_to_traps (path,
- &gstate->stroke_style,
- &gstate->ctm,
- &gstate->ctm_inverse,
- gstate->tolerance,
- &traps);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- _cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
- x1, y1, x2, y2);
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+ &gstate->stroke_style,
+ &gstate->ctm,
+ gstate->antialias,
+ &boxes);
+ empty = boxes.num_boxes == 0;
+ if (! empty)
+ _cairo_boxes_extents (&boxes, &extents);
+ _cairo_boxes_fini (&boxes);
}
- _cairo_traps_fini (&traps);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ cairo_traps_t traps;
+
+ _cairo_traps_init (&traps);
+ status = _cairo_path_fixed_stroke_to_traps (path,
+ &gstate->stroke_style,
+ &gstate->ctm,
+ &gstate->ctm_inverse,
+ gstate->tolerance,
+ &traps);
+ empty = traps.num_traps == 0;
+ if (! empty)
+ _cairo_traps_extents (&traps, &extents);
+ _cairo_traps_fini (&traps);
+ }
+ if (! empty) {
+ _cairo_gstate_extents_to_user_rectangle (gstate, &extents,
+ x1, y1, x2, y2);
+ }
return status;
}
@@ -1433,32 +1450,54 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
double *x2, double *y2)
{
cairo_status_t status;
- cairo_traps_t traps;
+ cairo_box_t extents;
+ cairo_bool_t empty;
- if (_cairo_path_fixed_fill_is_empty (path)) {
- if (x1)
- *x1 = 0.0;
- if (y1)
- *y1 = 0.0;
- if (x2)
- *x2 = 0.0;
- if (y2)
- *y2 = 0.0;
+ if (x1)
+ *x1 = 0.0;
+ if (y1)
+ *y1 = 0.0;
+ if (x2)
+ *x2 = 0.0;
+ if (y2)
+ *y2 = 0.0;
+
+ if (_cairo_path_fixed_fill_is_empty (path))
return CAIRO_STATUS_SUCCESS;
- }
- _cairo_traps_init (&traps);
+ if (_cairo_path_fixed_fill_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+ gstate->fill_rule,
+ gstate->antialias,
+ &boxes);
+ empty = boxes.num_boxes == 0;
+ if (! empty)
+ _cairo_boxes_extents (&boxes, &extents);
+
+ _cairo_boxes_fini (&boxes);
+ } else {
+ cairo_traps_t traps;
- status = _cairo_path_fixed_fill_to_traps (path,
- gstate->fill_rule,
- gstate->tolerance,
- &traps);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- _cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
- x1, y1, x2, y2);
+ _cairo_traps_init (&traps);
+
+ status = _cairo_path_fixed_fill_to_traps (path,
+ gstate->fill_rule,
+ gstate->tolerance,
+ &traps);
+ empty = traps.num_traps == 0;
+ if (! empty)
+ _cairo_traps_extents (&traps, &extents);
+
+ _cairo_traps_fini (&traps);
}
- _cairo_traps_fini (&traps);
+ if (! empty) {
+ _cairo_gstate_extents_to_user_rectangle (gstate, &extents,
+ x1, y1, x2, y2);
+ }
return status;
}
@@ -1834,12 +1873,12 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
int num_glyphs,
cairo_glyph_text_info_t *info)
{
- cairo_pattern_union_t source_pattern;
- const cairo_pattern_t *pattern;
cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
- cairo_glyph_t *transformed_glyphs;
cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
- cairo_text_cluster_t *transformed_clusters = NULL;
+ cairo_pattern_union_t source_pattern;
+ cairo_glyph_t *transformed_glyphs;
+ const cairo_pattern_t *pattern;
+ cairo_text_cluster_t *transformed_clusters;
cairo_operator_t op;
cairo_status_t status;
@@ -1858,16 +1897,15 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
return status;
transformed_glyphs = stack_transformed_glyphs;
+ transformed_clusters = stack_transformed_clusters;
+
if (num_glyphs > ARRAY_LENGTH (stack_transformed_glyphs)) {
transformed_glyphs = cairo_glyph_allocate (num_glyphs);
- if (unlikely (transformed_glyphs == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto CLEANUP_GLYPHS;
- }
+ if (unlikely (transformed_glyphs == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
if (info != NULL) {
- transformed_clusters = stack_transformed_clusters;
if (info->num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) {
transformed_clusters = cairo_text_cluster_allocate (info->num_clusters);
if (unlikely (transformed_clusters == NULL)) {
@@ -1876,24 +1914,24 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
}
}
- status = _cairo_gstate_transform_glyphs_to_backend (gstate,
- glyphs, num_glyphs,
- info->clusters,
- info->num_clusters,
- info->cluster_flags,
- transformed_glyphs,
- &num_glyphs,
- transformed_clusters);
+ _cairo_gstate_transform_glyphs_to_backend (gstate,
+ glyphs, num_glyphs,
+ info->clusters,
+ info->num_clusters,
+ info->cluster_flags,
+ transformed_glyphs,
+ &num_glyphs,
+ transformed_clusters);
} else {
- status = _cairo_gstate_transform_glyphs_to_backend (gstate,
- glyphs, num_glyphs,
- NULL, 0, 0,
- transformed_glyphs,
- &num_glyphs,
- NULL);
+ _cairo_gstate_transform_glyphs_to_backend (gstate,
+ glyphs, num_glyphs,
+ NULL, 0, 0,
+ transformed_glyphs,
+ &num_glyphs,
+ NULL);
}
- if (status || num_glyphs == 0)
+ if (num_glyphs == 0)
goto CLEANUP_GLYPHS;
op = _reduce_op (gstate);
@@ -1971,35 +2009,32 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
int num_glyphs,
cairo_path_fixed_t *path)
{
- cairo_status_t status;
- cairo_glyph_t *transformed_glyphs;
cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
+ cairo_glyph_t *transformed_glyphs;
+ cairo_status_t status;
status = _cairo_gstate_ensure_scaled_font (gstate);
if (unlikely (status))
return status;
if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) {
- transformed_glyphs = stack_transformed_glyphs;
+ transformed_glyphs = stack_transformed_glyphs;
} else {
transformed_glyphs = cairo_glyph_allocate (num_glyphs);
if (unlikely (transformed_glyphs == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- status = _cairo_gstate_transform_glyphs_to_backend (gstate,
- glyphs, num_glyphs,
- NULL, 0, 0,
- transformed_glyphs,
- &num_glyphs, NULL);
- if (unlikely (status))
- goto CLEANUP_GLYPHS;
+ _cairo_gstate_transform_glyphs_to_backend (gstate,
+ glyphs, num_glyphs,
+ NULL, 0, 0,
+ transformed_glyphs,
+ &num_glyphs, NULL);
status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
transformed_glyphs, num_glyphs,
path);
- CLEANUP_GLYPHS:
if (transformed_glyphs != stack_transformed_glyphs)
cairo_glyph_free (transformed_glyphs);
@@ -2039,7 +2074,7 @@ _cairo_gstate_get_antialias (cairo_gstate_t *gstate)
* This also uses information from the scaled font and the surface to
* cull/drop glyphs that will not be visible.
**/
-static cairo_status_t
+static void
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
@@ -2050,44 +2085,40 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
int *num_transformed_glyphs,
cairo_text_cluster_t *transformed_clusters)
{
- int i, j, k;
+ cairo_rectangle_int_t surface_extents;
cairo_matrix_t *ctm = &gstate->ctm;
cairo_matrix_t *font_matrix = &gstate->font_matrix;
cairo_matrix_t *device_transform = &gstate->target->device_transform;
cairo_bool_t drop = FALSE;
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
+ int i, j, k;
- if (num_transformed_glyphs != NULL) {
- cairo_rectangle_int_t surface_extents;
-
- drop = TRUE;
- 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);
- if (surface_extents.width == 0 || surface_extents.height == 0) {
- /* No visible area. Don't draw anything */
- *num_transformed_glyphs = 0;
- return CAIRO_STATUS_SUCCESS;
- }
- /* XXX We currently drop any glyphs that has its position outside
- * of the surface boundaries by a safety margin depending on the
- * font scale. This however can fail in extreme cases where the
- * font has really long swashes for example... We can correctly
- * handle that by looking the glyph up and using its device bbox
- * to device if it's going to be visible, but I'm not inclined to
- * do that now.
- */
- x1 = surface_extents.x - scale10;
- y1 = surface_extents.y - scale10;
- x2 = surface_extents.x + (int) surface_extents.width + scale10;
- y2 = surface_extents.y + (int) surface_extents.height + scale10;
+ drop = TRUE;
+ 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);
+ if (surface_extents.width == 0 || surface_extents.height == 0) {
+ /* No visible area. Don't draw anything */
+ *num_transformed_glyphs = 0;
+ return;
}
+ /* XXX We currently drop any glyphs that has its position outside
+ * of the surface boundaries by a safety margin depending on the
+ * font scale. This however can fail in extreme cases where the
+ * font has really long swashes for example... We can correctly
+ * handle that by looking the glyph up and using its device bbox
+ * to device if it's going to be visible, but I'm not inclined to
+ * do that now.
+ */
+ x1 = surface_extents.x - scale10;
+ y1 = surface_extents.y - scale10;
+ x2 = surface_extents.x + (int) surface_extents.width + scale10;
+ y2 = surface_extents.y + (int) surface_extents.height + scale10;
+ }
- if (!drop)
- *num_transformed_glyphs = num_glyphs;
- } else
- num_transformed_glyphs = &j;
+ if (!drop)
+ *num_transformed_glyphs = num_glyphs;
#define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
@@ -2156,6 +2187,8 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
j++;
}
+ memcpy (transformed_clusters, clusters,
+ num_clusters * sizeof (cairo_text_cluster_t));
} else {
const cairo_glyph_t *cur_glyph;
@@ -2209,6 +2242,8 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
if (! drop || KEEP_GLYPH (transformed_glyphs[j]))
j++;
}
+ memcpy (transformed_clusters, clusters,
+ num_clusters * sizeof (cairo_text_cluster_t));
} else {
const cairo_glyph_t *cur_glyph;
@@ -2252,6 +2287,4 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
transformed_glyphs[j] = tmp;
}
}
-
- return CAIRO_STATUS_SUCCESS;
}
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
new file mode 100644
index 00000000..35472de3
--- /dev/null
+++ b/src/cairo-image-compositor.c
@@ -0,0 +1,1545 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2003 University of Southern California
+ * Copyright © 2009,2010,2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/* The primarily reason for keeping a traps-compositor around is
+ * for validating cairo-xlib (which currently also uses traps).
+ */
+
+#include "cairoint.h"
+
+#include "cairo-image-surface-private.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-spans-compositor-private.h"
+
+#include "cairo-region-private.h"
+#include "cairo-traps-private.h"
+#include "cairo-tristrip-private.h"
+
+static pixman_image_t *
+to_pixman_image (cairo_surface_t *s)
+{
+ return ((cairo_image_surface_t *)s)->pixman_image;
+}
+
+static cairo_int_status_t
+acquire (void *abstract_dst)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+release (void *abstract_dst)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+set_clip_region (void *_surface,
+ cairo_region_t *region)
+{
+ cairo_image_surface_t *surface = _surface;
+ pixman_region32_t *rgn = region ? &region->rgn : NULL;
+
+ if (! pixman_image_set_clip_region32 (surface->pixman_image, rgn))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+draw_image_boxes (void *_dst,
+ cairo_image_surface_t *image,
+ cairo_boxes_t *boxes,
+ int dx, int dy)
+{
+ cairo_image_surface_t *dst = _dst;
+ struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ cairo_box_t *b = &chunk->base[i];
+ int x = _cairo_fixed_integer_part (b->p1.x);
+ int y = _cairo_fixed_integer_part (b->p1.y);
+ int w = _cairo_fixed_integer_part (b->p2.x) - x;
+ int h = _cairo_fixed_integer_part (b->p2.y) - y;
+ if (dst->pixman_format != image->pixman_format ||
+ ! pixman_blt ((uint32_t *)image->data, (uint32_t *)dst->data,
+ image->stride / sizeof (uint32_t),
+ dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (image->pixman_format),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ x + dx, y + dy,
+ x, y,
+ w, h))
+ {
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image, NULL, dst->pixman_image,
+ x + dx, y + dy,
+ 0, 0,
+ x, y,
+ w, h);
+ }
+ }
+ }
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static inline uint32_t
+color_to_uint32 (const cairo_color_t *color)
+{
+ return
+ (color->alpha_short >> 8 << 24) |
+ (color->red_short >> 8 << 16) |
+ (color->green_short & 0xff00) |
+ (color->blue_short >> 8);
+}
+
+static inline cairo_bool_t
+color_to_pixel (const cairo_color_t *color,
+ pixman_format_code_t format,
+ uint32_t *pixel)
+{
+ uint32_t c;
+
+ if (!(format == PIXMAN_a8r8g8b8 ||
+ format == PIXMAN_x8r8g8b8 ||
+ format == PIXMAN_a8b8g8r8 ||
+ format == PIXMAN_x8b8g8r8 ||
+ format == PIXMAN_b8g8r8a8 ||
+ format == PIXMAN_b8g8r8x8 ||
+ format == PIXMAN_r5g6b5 ||
+ format == PIXMAN_b5g6r5 ||
+ format == PIXMAN_a8))
+ {
+ return FALSE;
+ }
+
+ c = color_to_uint32 (color);
+
+ if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
+ c = ((c & 0xff000000) >> 0) |
+ ((c & 0x00ff0000) >> 16) |
+ ((c & 0x0000ff00) >> 0) |
+ ((c & 0x000000ff) << 16);
+ }
+
+ if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
+ c = ((c & 0xff000000) >> 24) |
+ ((c & 0x00ff0000) >> 8) |
+ ((c & 0x0000ff00) << 8) |
+ ((c & 0x000000ff) << 24);
+ }
+
+ if (format == PIXMAN_a8) {
+ c = c >> 24;
+ } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
+ c = ((((c) >> 3) & 0x001f) |
+ (((c) >> 5) & 0x07e0) |
+ (((c) >> 8) & 0xf800));
+ }
+
+ *pixel = c;
+ return TRUE;
+}
+
+static pixman_op_t
+_pixman_operator (cairo_operator_t op)
+{
+ switch ((int) op) {
+ case CAIRO_OPERATOR_CLEAR:
+ return PIXMAN_OP_CLEAR;
+
+ case CAIRO_OPERATOR_SOURCE:
+ return PIXMAN_OP_SRC;
+ case CAIRO_OPERATOR_OVER:
+ return PIXMAN_OP_OVER;
+ case CAIRO_OPERATOR_IN:
+ return PIXMAN_OP_IN;
+ case CAIRO_OPERATOR_OUT:
+ return PIXMAN_OP_OUT;
+ case CAIRO_OPERATOR_ATOP:
+ return PIXMAN_OP_ATOP;
+
+ case CAIRO_OPERATOR_DEST:
+ return PIXMAN_OP_DST;
+ case CAIRO_OPERATOR_DEST_OVER:
+ return PIXMAN_OP_OVER_REVERSE;
+ case CAIRO_OPERATOR_DEST_IN:
+ return PIXMAN_OP_IN_REVERSE;
+ case CAIRO_OPERATOR_DEST_OUT:
+ return PIXMAN_OP_OUT_REVERSE;
+ case CAIRO_OPERATOR_DEST_ATOP:
+ return PIXMAN_OP_ATOP_REVERSE;
+
+ case CAIRO_OPERATOR_XOR:
+ return PIXMAN_OP_XOR;
+ case CAIRO_OPERATOR_ADD:
+ return PIXMAN_OP_ADD;
+ case CAIRO_OPERATOR_SATURATE:
+ return PIXMAN_OP_SATURATE;
+
+ case CAIRO_OPERATOR_MULTIPLY:
+ return PIXMAN_OP_MULTIPLY;
+ case CAIRO_OPERATOR_SCREEN:
+ return PIXMAN_OP_SCREEN;
+ case CAIRO_OPERATOR_OVERLAY:
+ return PIXMAN_OP_OVERLAY;
+ case CAIRO_OPERATOR_DARKEN:
+ return PIXMAN_OP_DARKEN;
+ case CAIRO_OPERATOR_LIGHTEN:
+ return PIXMAN_OP_LIGHTEN;
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ return PIXMAN_OP_COLOR_DODGE;
+ case CAIRO_OPERATOR_COLOR_BURN:
+ return PIXMAN_OP_COLOR_BURN;
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ return PIXMAN_OP_HARD_LIGHT;
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ return PIXMAN_OP_SOFT_LIGHT;
+ case CAIRO_OPERATOR_DIFFERENCE:
+ return PIXMAN_OP_DIFFERENCE;
+ case CAIRO_OPERATOR_EXCLUSION:
+ return PIXMAN_OP_EXCLUSION;
+ case CAIRO_OPERATOR_HSL_HUE:
+ return PIXMAN_OP_HSL_HUE;
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ return PIXMAN_OP_HSL_SATURATION;
+ case CAIRO_OPERATOR_HSL_COLOR:
+ return PIXMAN_OP_HSL_COLOR;
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
+ return PIXMAN_OP_HSL_LUMINOSITY;
+
+ default:
+ ASSERT_NOT_REACHED;
+ return PIXMAN_OP_OVER;
+ }
+}
+
+static cairo_bool_t
+fill_reduces_to_source (cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_image_surface_t *dst)
+{
+ if (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR)
+ return TRUE;
+ if (op == CAIRO_OPERATOR_OVER && CAIRO_COLOR_IS_OPAQUE (color))
+ return TRUE;
+ if (dst->base.is_clear)
+ return op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD;
+
+ return FALSE;
+}
+
+static cairo_int_status_t
+fill_rectangles (void *_dst,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_rectangle_int_t *rects,
+ int num_rects)
+{
+ cairo_image_surface_t *dst = _dst;
+ uint32_t pixel;
+ int i;
+
+ if (fill_reduces_to_source (op, color, dst) &&
+ color_to_pixel (color, dst->pixman_format, &pixel))
+ {
+ for (i = 0; i < num_rects; i++) {
+ pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ rects[i].x, rects[i].y,
+ rects[i].width, rects[i].height,
+ pixel);
+ }
+ }
+ else
+ {
+ pixman_image_t *src = _pixman_image_for_color (color);
+
+ op = _pixman_operator (op);
+ for (i = 0; i < num_rects; i++) {
+ pixman_image_composite32 (op,
+ src, NULL, dst->pixman_image,
+ 0, 0,
+ 0, 0,
+ rects[i].x, rects[i].y,
+ rects[i].width, rects[i].height);
+ }
+
+ pixman_image_unref (src);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+fill_boxes (void *_dst,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ cairo_image_surface_t *dst = _dst;
+ struct _cairo_boxes_chunk *chunk;
+ uint32_t pixel;
+ int i;
+
+ if (fill_reduces_to_source (op, color, dst) &&
+ color_to_pixel (color, dst->pixman_format, &pixel))
+ {
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int w = _cairo_fixed_integer_part (chunk->base[i].p2.x) - x;
+ int h = _cairo_fixed_integer_part (chunk->base[i].p2.y) - y;
+ pixman_fill ((uint32_t *) dst->data,
+ dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ x, y, w, h, pixel);
+ }
+ }
+ }
+ else
+ {
+ pixman_image_t *src = _pixman_image_for_color (color);
+
+ op = _pixman_operator (op);
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+ pixman_image_composite32 (op,
+ src, NULL, dst->pixman_image,
+ 0, 0,
+ 0, 0,
+ x1, y1,
+ x2-x1, y2-y1);
+ }
+ }
+
+ pixman_image_unref (src);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ 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_image_source_t *src = (cairo_image_source_t *)abstract_src;
+ cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask;
+ if (mask) {
+ pixman_image_composite32 (_pixman_operator (op),
+ src->pixman_image, mask->pixman_image, to_pixman_image (_dst),
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+ } else {
+ pixman_image_composite32 (_pixman_operator (op),
+ src->pixman_image, NULL, to_pixman_image (_dst),
+ src_x, src_y,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+lerp (void *_dst,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ 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_image_surface_t *dst = _dst;
+ cairo_image_source_t *src = (cairo_image_source_t *)abstract_src;
+ cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask;
+
+#if PIXMAN_HAS_OP_LERP
+ pixman_image_composite32 (PIXMAN_OP_LERP,
+ src->pixman_image, mask->pixman_image, dst->pixman_image,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+#else
+ /* Punch the clip out of the destination */
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+ mask->pixman_image, NULL, dst->pixman_image,
+ mask_x, mask_y,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+
+ /* Now add the two results together */
+ pixman_image_composite32 (PIXMAN_OP_ADD,
+ src->pixman_image, mask->pixman_image, dst->pixman_image,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+#endif
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_boxes (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ cairo_boxes_t *boxes,
+ const cairo_rectangle_int_t *extents)
+{
+ pixman_image_t *dst = to_pixman_image (_dst);
+ pixman_image_t *src = ((cairo_image_source_t *)abstract_src)->pixman_image;
+ pixman_image_t *mask = abstract_mask ? ((cairo_image_source_t *)abstract_mask)->pixman_image : NULL;
+ struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ /* XXX consider using a region? saves multiple prepare-composite */
+
+ op = _pixman_operator (op);
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+ pixman_image_composite32 (op, src, mask, dst,
+ x1 + src_x, y1 + src_y,
+ x1 + mask_x, y1 + mask_y,
+ x1 + dst_x, y1 + dst_y,
+ x2 - x1, y2 - y1);
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
+#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
+
+static cairo_bool_t
+line_exceeds_16_16 (const cairo_line_t *line)
+{
+ return
+ line->p1.x <= CAIRO_FIXED_16_16_MIN ||
+ line->p1.x >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p2.x <= CAIRO_FIXED_16_16_MIN ||
+ line->p2.x >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p1.y <= CAIRO_FIXED_16_16_MIN ||
+ line->p1.y >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p2.y <= CAIRO_FIXED_16_16_MIN ||
+ line->p2.y >= CAIRO_FIXED_16_16_MAX;
+}
+
+static void
+project_line_x_onto_16_16 (const cairo_line_t *line,
+ cairo_fixed_t top,
+ cairo_fixed_t bottom,
+ pixman_line_fixed_t *out)
+{
+ /* XXX use fixed-point arithmetic? */
+ cairo_point_double_t p1, p2;
+ double m;
+
+ p1.x = _cairo_fixed_to_double (line->p1.x);
+ p1.y = _cairo_fixed_to_double (line->p1.y);
+
+ p2.x = _cairo_fixed_to_double (line->p2.x);
+ p2.y = _cairo_fixed_to_double (line->p2.y);
+
+ m = (p2.x - p1.x) / (p2.y - p1.y);
+ out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
+ out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
+}
+
+void
+_pixman_image_add_traps (pixman_image_t *image,
+ int dst_x, int dst_y,
+ cairo_traps_t *traps)
+{
+ cairo_trapezoid_t *t = traps->traps;
+ int num_traps = traps->num_traps;
+ while (num_traps--) {
+ pixman_trapezoid_t trap;
+
+ /* top/bottom will be clamped to surface bounds */
+ trap.top = _cairo_fixed_to_16_16 (t->top);
+ trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
+
+ /* However, all the other coordinates will have been left untouched so
+ * as not to introduce numerical error. Recompute them if they
+ * exceed the 16.16 limits.
+ */
+ if (unlikely (line_exceeds_16_16 (&t->left))) {
+ project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
+ trap.left.p1.y = trap.top;
+ trap.left.p2.y = trap.bottom;
+ } else {
+ trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
+ trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
+ trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
+ trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
+ }
+
+ if (unlikely (line_exceeds_16_16 (&t->right))) {
+ project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
+ trap.right.p1.y = trap.top;
+ trap.right.p2.y = trap.bottom;
+ } else {
+ trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
+ trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
+ trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
+ trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
+ }
+
+ pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
+ t++;
+ }
+}
+
+static cairo_int_status_t
+composite_traps (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_antialias_t antialias,
+ cairo_traps_t *traps)
+{
+ cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst;
+ cairo_image_source_t *src = (cairo_image_source_t *) abstract_src;
+ pixman_image_t *mask;
+ pixman_format_code_t format;
+
+ /* Special case adding trapezoids onto a mask surface; we want to avoid
+ * creating an intermediate temporary mask unnecessarily.
+ *
+ * We make the assumption here that the portion of the trapezoids
+ * contained within the surface is bounded by [dst_x,dst_y,width,height];
+ * the Cairo core code passes bounds based on the trapezoid extents.
+ */
+ format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
+ if (dst->pixman_format == format &&
+ (abstract_src == NULL ||
+ (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid)))
+ {
+ _pixman_image_add_traps (dst->pixman_image, dst_x, dst_y, traps);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ mask = pixman_image_create_bits (format,
+ extents->width, extents->height,
+ NULL, 0);
+ if (unlikely (mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ _pixman_image_add_traps (mask, extents->x, extents->y, traps);
+ pixman_image_composite32 (_pixman_operator (op),
+ src->pixman_image, mask, dst->pixman_image,
+ extents->x + src_x, extents->y + src_y,
+ 0, 0,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+
+ pixman_image_unref (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+set_point (pixman_point_fixed_t *p, cairo_point_t *c)
+{
+ p->x = _cairo_fixed_to_16_16 (c->x);
+ p->y = _cairo_fixed_to_16_16 (c->y);
+}
+
+void
+_pixman_image_add_tristrip (pixman_image_t *image,
+ int dst_x, int dst_y,
+ cairo_tristrip_t *strip)
+{
+ pixman_triangle_t tri;
+ pixman_point_fixed_t *p[3] = {&tri.p1, &tri.p2, &tri.p3 };
+ int n;
+
+ set_point (p[0], &strip->points[0]);
+ set_point (p[1], &strip->points[1]);
+ set_point (p[2], &strip->points[2]);
+ pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri);
+ for (n = 3; n < strip->num_points; n++) {
+ set_point (p[n%3], &strip->points[n]);
+ pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri);
+ }
+}
+
+static cairo_int_status_t
+composite_tristrip (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_antialias_t antialias,
+ cairo_tristrip_t *strip)
+{
+ cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst;
+ cairo_image_source_t *src = (cairo_image_source_t *) abstract_src;
+ pixman_image_t *mask;
+ pixman_format_code_t format;
+
+ if (strip->num_points < 3)
+ return CAIRO_STATUS_SUCCESS;
+
+ format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
+ if (dst->pixman_format == format &&
+ (abstract_src == NULL ||
+ (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid)))
+ {
+ _pixman_image_add_tristrip (dst->pixman_image, dst_x, dst_y, strip);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ mask = pixman_image_create_bits (format,
+ extents->width, extents->height,
+ NULL, 0);
+ if (unlikely (mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ _pixman_image_add_tristrip (mask, extents->x, extents->y, strip);
+ pixman_image_composite32 (_pixman_operator (op),
+ src->pixman_image, mask, dst->pixman_image,
+ extents->x + src_x, extents->y + src_y,
+ 0, 0,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+
+ pixman_image_unref (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+check_composite_glyphs (const cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int *num_glyphs)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_one_glyph (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info)
+{
+ cairo_image_surface_t *glyph_surface;
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_status_t status;
+ int x, y;
+
+ status = _cairo_scaled_glyph_lookup (info->font,
+ info->glyphs[0].index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+
+ if (unlikely (status))
+ return status;
+
+ glyph_surface = scaled_glyph->surface;
+ if (glyph_surface->width == 0 || glyph_surface->height == 0)
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+ /* round glyph locations to the nearest pixel */
+ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+ x = _cairo_lround (info->glyphs[0].x -
+ glyph_surface->base.device_transform.x0);
+ y = _cairo_lround (info->glyphs[0].y -
+ glyph_surface->base.device_transform.y0);
+
+ pixman_image_composite32 (_pixman_operator (op),
+ ((cairo_image_source_t *)_src)->pixman_image,
+ glyph_surface->pixman_image,
+ to_pixman_image (_dst),
+ x + src_x, y + src_y,
+ 0, 0,
+ x - dst_x, y - dst_y,
+ glyph_surface->width,
+ glyph_surface->height);
+
+ return CAIRO_INT_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_glyphs_via_mask (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info)
+{
+ cairo_scaled_glyph_t *glyph_cache[64];
+ cairo_bool_t component_alpha = FALSE;
+ uint8_t buf[2048];
+ pixman_image_t *mask;
+ cairo_status_t status;
+ int i;
+
+ /* XXX convert the glyphs to common formats a8/a8r8g8b8 to hit
+ * optimised paths through pixman. Should we increase the bit
+ * depth of the target surface, we should reconsider the appropriate
+ * mask formats.
+ */
+ i = (info->extents.width + 3) & ~3;
+ if (i * info->extents.height > (int) sizeof (buf)) {
+ mask = pixman_image_create_bits (PIXMAN_a8,
+ info->extents.width,
+ info->extents.height,
+ NULL, 0);
+ } else {
+ memset (buf, 0, i * info->extents.height);
+ mask = pixman_image_create_bits (PIXMAN_a8,
+ info->extents.width,
+ info->extents.height,
+ (uint32_t *)buf, i);
+ }
+ if (unlikely (mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ memset (glyph_cache, 0, sizeof (glyph_cache));
+ status = CAIRO_STATUS_SUCCESS;
+
+ for (i = 0; i < info->num_glyphs; i++) {
+ cairo_image_surface_t *glyph_surface;
+ cairo_scaled_glyph_t *scaled_glyph;
+ unsigned long glyph_index = info->glyphs[i].index;
+ int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
+ int x, y;
+
+ scaled_glyph = glyph_cache[cache_index];
+ if (scaled_glyph == NULL ||
+ _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
+ {
+ status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+
+ if (unlikely (status)) {
+ pixman_image_unref (mask);
+ return status;
+ }
+
+ glyph_cache[cache_index] = scaled_glyph;
+ }
+
+ glyph_surface = scaled_glyph->surface;
+ if (glyph_surface->width && glyph_surface->height) {
+ if (glyph_surface->base.content & CAIRO_CONTENT_COLOR &&
+ ! component_alpha) {
+ pixman_image_t *ca_mask;
+
+ ca_mask = pixman_image_create_bits (PIXMAN_a8r8g8b8,
+ info->extents.width,
+ info->extents.height,
+ NULL, 0);
+ if (unlikely (ca_mask == NULL)) {
+ pixman_image_unref (mask);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ mask, 0, ca_mask,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ info->extents.width,
+ info->extents.height);
+ pixman_image_unref (mask);
+ mask = ca_mask;
+ component_alpha = TRUE;
+ }
+
+ /* round glyph locations to the nearest pixel */
+ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+ x = _cairo_lround (info->glyphs[i].x -
+ glyph_surface->base.device_transform.x0);
+ y = _cairo_lround (info->glyphs[i].y -
+ glyph_surface->base.device_transform.y0);
+
+ pixman_image_composite32 (PIXMAN_OP_ADD,
+ glyph_surface->pixman_image, NULL, mask,
+ 0, 0,
+ 0, 0,
+ x - info->extents.x, y - info->extents.y,
+ glyph_surface->width,
+ glyph_surface->height);
+ }
+ }
+
+ if (component_alpha)
+ pixman_image_set_component_alpha (mask, TRUE);
+
+ pixman_image_composite32 (_pixman_operator (op),
+ ((cairo_image_source_t *)_src)->pixman_image,
+ mask,
+ to_pixman_image (_dst),
+ info->extents.x + src_x, info->extents.y + src_y,
+ 0, 0,
+ info->extents.x - dst_x, info->extents.y - dst_y,
+ info->extents.width, info->extents.height);
+ pixman_image_unref (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_glyphs (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info)
+{
+ cairo_scaled_glyph_t *glyph_cache[64];
+ pixman_image_t *dst, *src;
+ cairo_status_t status;
+ int i;
+
+ if (info->num_glyphs == 1)
+ return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+
+ if (info->use_mask)
+ return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+
+ op = _pixman_operator (op);
+ dst = to_pixman_image (_dst);
+ src = ((cairo_image_source_t *)_src)->pixman_image;
+
+ memset (glyph_cache, 0, sizeof (glyph_cache));
+ status = CAIRO_STATUS_SUCCESS;
+
+ for (i = 0; i < info->num_glyphs; i++) {
+ int x, y;
+ cairo_image_surface_t *glyph_surface;
+ cairo_scaled_glyph_t *scaled_glyph;
+ unsigned long glyph_index = info->glyphs[i].index;
+ int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
+
+ scaled_glyph = glyph_cache[cache_index];
+ if (scaled_glyph == NULL ||
+ _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
+ {
+ status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+
+ if (unlikely (status))
+ break;
+
+ glyph_cache[cache_index] = scaled_glyph;
+ }
+
+ glyph_surface = scaled_glyph->surface;
+ if (glyph_surface->width && glyph_surface->height) {
+ /* round glyph locations to the nearest pixel */
+ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+ x = _cairo_lround (info->glyphs[i].x -
+ glyph_surface->base.device_transform.x0);
+ y = _cairo_lround (info->glyphs[i].y -
+ glyph_surface->base.device_transform.y0);
+
+ pixman_image_composite32 (op, src, glyph_surface->pixman_image, dst,
+ x + src_x, y + src_y,
+ 0, 0,
+ x - dst_x, y - dst_y,
+ glyph_surface->width,
+ glyph_surface->height);
+ }
+ }
+
+ return status;
+}
+
+const cairo_compositor_t *
+_cairo_image_traps_compositor_get (void)
+{
+ static cairo_traps_compositor_t compositor;
+
+ if (compositor.base.delegate == NULL) {
+ _cairo_traps_compositor_init (&compositor,
+ &__cairo_no_compositor);
+ compositor.acquire = acquire;
+ compositor.release = release;
+ compositor.set_clip_region = set_clip_region;
+ compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
+ compositor.draw_image_boxes = draw_image_boxes;
+ //compositor.copy_boxes = copy_boxes;
+ compositor.fill_boxes = fill_boxes;
+ //compositor.check_composite = check_composite;
+ compositor.composite = composite;
+ compositor.lerp = lerp;
+ //compositor.check_composite_boxes = check_composite_boxes;
+ compositor.composite_boxes = composite_boxes;
+ //compositor.check_composite_traps = check_composite_traps;
+ compositor.composite_traps = composite_traps;
+ //compositor.check_composite_tristrip = check_composite_traps;
+ compositor.composite_tristrip = composite_tristrip;
+ compositor.check_composite_glyphs = check_composite_glyphs;
+ compositor.composite_glyphs = composite_glyphs;
+ }
+
+ return &compositor.base;
+}
+
+const cairo_compositor_t *
+_cairo_image_mask_compositor_get (void)
+{
+ static cairo_mask_compositor_t compositor;
+
+ if (compositor.base.delegate == NULL) {
+ _cairo_mask_compositor_init (&compositor,
+ _cairo_image_traps_compositor_get ());
+ compositor.acquire = acquire;
+ compositor.release = release;
+ compositor.set_clip_region = set_clip_region;
+ compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
+ compositor.draw_image_boxes = draw_image_boxes;
+ compositor.fill_rectangles = fill_rectangles;
+ compositor.fill_boxes = fill_boxes;
+ //compositor.check_composite = check_composite;
+ compositor.composite = composite;
+ //compositor.lerp = lerp;
+ //compositor.check_composite_boxes = check_composite_boxes;
+ compositor.composite_boxes = composite_boxes;
+ compositor.check_composite_glyphs = check_composite_glyphs;
+ compositor.composite_glyphs = composite_glyphs;
+ }
+
+ return &compositor.base;
+}
+
+#if PIXMAN_HAS_COMPOSITOR
+typedef struct _cairo_image_span_renderer {
+ cairo_span_renderer_t base;
+
+ pixman_image_compositor_t *compositor;
+ pixman_image_t *src, *mask;
+ float opacity;
+ cairo_rectangle_int_t extents;
+} cairo_image_span_renderer_t;
+COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
+
+static cairo_status_t
+_cairo_image_bounded_opaque_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ do {
+ if (spans[0].coverage)
+ pixman_image_compositor_blt (r->compositor,
+ spans[0].x, y,
+ spans[1].x - spans[0].x, height,
+ spans[0].coverage);
+ spans++;
+ } while (--num_spans > 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_bounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ do {
+ if (spans[0].coverage) {
+ pixman_image_compositor_blt (r->compositor,
+ spans[0].x, y,
+ spans[1].x - spans[0].x, height,
+ r->opacity * spans[0].coverage);
+ }
+ spans++;
+ } while (--num_spans > 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_unbounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+
+ assert (y + height <= r->extents.height);
+ if (y > r->extents.y) {
+ pixman_image_compositor_blt (r->compositor,
+ r->extents.x, r->extents.y,
+ r->extents.width, y - r->extents.y,
+ 0);
+ }
+
+ if (num_spans == 0) {
+ pixman_image_compositor_blt (r->compositor,
+ r->extents.x, y,
+ r->extents.width, height,
+ 0);
+ } else {
+ if (spans[0].x != r->extents.x) {
+ pixman_image_compositor_blt (r->compositor,
+ r->extents.x, y,
+ spans[0].x - r->extents.x,
+ height,
+ 0);
+ }
+
+ do {
+ assert (spans[0].x < r->extents.x + r->extents.width);
+ pixman_image_compositor_blt (r->compositor,
+ spans[0].x, y,
+ spans[1].x - spans[0].x, height,
+ r->opacity * spans[0].coverage);
+ spans++;
+ } while (--num_spans > 1);
+
+ if (spans[0].x != r->extents.x + r->extents.width) {
+ assert (spans[0].x < r->extents.x + r->extents.width);
+ pixman_image_compositor_blt (r->compositor,
+ spans[0].x, y,
+ r->extents.x + r->extents.width - spans[0].x, height,
+ 0);
+ }
+ }
+
+ r->extents.y = y + height;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_clipped_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+
+ assert (num_spans);
+
+ do {
+ if (! spans[0].inverse)
+ pixman_image_compositor_blt (r->compositor,
+ spans[0].x, y,
+ spans[1].x - spans[0].x, height,
+ r->opacity * spans[0].coverage);
+ spans++;
+ } while (--num_spans > 1);
+
+ r->extents.y = y + height;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_finish_unbounded_spans (void *abstract_renderer)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+
+ if (r->extents.y < r->extents.height) {
+ pixman_image_compositor_blt (r->compositor,
+ r->extents.x, r->extents.y,
+ r->extents.width,
+ r->extents.height - r->extents.y,
+ 0);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+span_renderer_init (cairo_abstract_span_renderer_t *_r,
+ const cairo_composite_rectangles_t *composite,
+ cairo_bool_t needs_clip)
+{
+ cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
+ cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
+ const cairo_pattern_t *source = &composite->source_pattern.base;
+ cairo_operator_t op = composite->op;
+ int src_x, src_y;
+ int mask_x, mask_y;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ source = &_cairo_pattern_white.base;
+ op = PIXMAN_OP_OUT_REVERSE;
+ } else if (dst->base.is_clear &&
+ (op == CAIRO_OPERATOR_SOURCE ||
+ op == CAIRO_OPERATOR_OVER ||
+ op == CAIRO_OPERATOR_ADD)) {
+ op = PIXMAN_OP_SRC;
+ } else if (op == CAIRO_OPERATOR_SOURCE) {
+ op = PIXMAN_OP_LERP;
+ } else {
+ op = _pixman_operator (op);
+ }
+
+ r->compositor = NULL;
+ r->mask = NULL;
+ r->src = _pixman_image_for_pattern (dst, source, FALSE,
+ &composite->unbounded,
+ &composite->source_sample_area,
+ &src_x, &src_y);
+ if (unlikely (r->src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ r->opacity = 1.0;
+ if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
+ r->opacity = composite->mask_pattern.solid.color.alpha;
+ } else {
+ r->mask = _pixman_image_for_pattern (dst,
+ &composite->mask_pattern.base,
+ TRUE,
+ &composite->unbounded,
+ &composite->mask_sample_area,
+ &mask_x, &mask_y);
+ if (unlikely (r->mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ /* XXX Component-alpha? */
+ if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
+ _cairo_pattern_is_opaque (source, &composite->source_sample_area))
+ {
+ pixman_image_unref (r->src);
+ r->src = r->mask;
+ src_x = mask_x;
+ src_y = mask_y;
+ r->mask = NULL;
+ }
+ }
+
+ if (composite->is_bounded) {
+ if (r->opacity == 1.)
+ r->base.render_rows = _cairo_image_bounded_opaque_spans;
+ else
+ r->base.render_rows = _cairo_image_bounded_spans;
+ r->base.finish = NULL;
+ } else {
+ if (needs_clip)
+ r->base.render_rows = _cairo_image_clipped_spans;
+ else
+ r->base.render_rows = _cairo_image_unbounded_spans;
+ r->base.finish = _cairo_image_finish_unbounded_spans;
+ r->extents = composite->unbounded;
+ r->extents.height += r->extents.y;
+ }
+
+ r->compositor =
+ pixman_image_create_compositor (op, r->src, r->mask, dst->pixman_image,
+ composite->unbounded.x + src_x,
+ composite->unbounded.y + src_y,
+ composite->unbounded.x + mask_x,
+ composite->unbounded.y + mask_y,
+ composite->unbounded.x,
+ composite->unbounded.y,
+ composite->unbounded.width,
+ composite->unbounded.height);
+ if (unlikely (r->compositor == NULL))
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+span_renderer_fini (cairo_abstract_span_renderer_t *_r,
+ cairo_int_status_t status)
+{
+ cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
+
+ if (status == CAIRO_INT_STATUS_SUCCESS && r->base.finish)
+ r->base.finish (r);
+
+ if (r->compositor)
+ pixman_image_compositor_destroy (r->compositor);
+
+ if (r->src)
+ pixman_image_unref (r->src);
+ if (r->mask)
+ pixman_image_unref (r->mask);
+}
+#else
+typedef struct _cairo_image_span_renderer {
+ cairo_span_renderer_t base;
+
+ cairo_rectangle_int_t extents;
+
+ float opacity;
+ int stride;
+ uint8_t *data;
+
+ const cairo_composite_rectangles_t *composite;
+ pixman_image_t *src, *mask;
+ int src_x, src_y;
+
+ uint8_t op;
+
+ uint8_t buf[sizeof(cairo_abstract_span_renderer_t)-128];
+} cairo_image_span_renderer_t;
+COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
+
+static cairo_status_t
+_cairo_image_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+ uint8_t *mask, *row;
+ int len;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ mask = r->data + (y - r->extents.y) * r->stride;
+ mask += spans[0].x - r->extents.x;
+ row = mask;
+
+ do {
+ len = spans[1].x - spans[0].x;
+ if (spans[0].coverage) {
+ *row++ = r->opacity * spans[0].coverage;
+ if (--len)
+ memset (row, row[-1], len);
+ }
+ row += len;
+ spans++;
+ } while (--num_spans > 1);
+
+ len = row - mask;
+ row = mask;
+ while (--height) {
+ mask += r->stride;
+ memcpy (mask, row, len);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_spans_and_zero (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+ uint8_t *mask;
+ int len;
+
+ mask = r->data;
+ if (y > r->extents.y) {
+ len = (y - r->extents.y) * r->stride;
+ memset (mask, 0, len);
+ mask += len;
+ }
+
+ r->extents.y = y + height;
+ r->data = mask + height * r->stride;
+ if (num_spans == 0) {
+ memset (mask, 0, height * r->stride);
+ } else {
+ uint8_t *row = mask;
+
+ if (spans[0].x != r->extents.x) {
+ len = spans[0].x - r->extents.x;
+ memset (row, 0, len);
+ row += len;
+ }
+
+ do {
+ len = spans[1].x - spans[0].x;
+ *row++ = r->opacity * spans[0].coverage;
+ if (len > 1) {
+ memset (row, row[-1], --len);
+ row += len;
+ }
+ spans++;
+ } while (--num_spans > 1);
+
+ if (spans[0].x != r->extents.x + r->extents.width) {
+ len = r->extents.x + r->extents.width - spans[0].x;
+ memset (row, 0, len);
+ }
+
+ row = mask;
+ while (--height) {
+ mask += r->stride;
+ memcpy (mask, row, r->extents.width);
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_finish_spans_and_zero (void *abstract_renderer)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+
+ if (r->extents.y < r->extents.height)
+ memset (r->data, 0, (r->extents.height - r->extents.y) * r->stride);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+span_renderer_init (cairo_abstract_span_renderer_t *_r,
+ const cairo_composite_rectangles_t *composite,
+ cairo_bool_t needs_clip)
+{
+ cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
+ cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
+ const cairo_pattern_t *source = &composite->source_pattern.base;
+ cairo_operator_t op = composite->op;
+
+ r->composite = composite;
+ r->mask = NULL;
+ r->src = NULL;
+
+ if (needs_clip)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ source = &_cairo_pattern_white.base;
+ op = PIXMAN_OP_OUT_REVERSE;
+ } else if (dst->base.is_clear &&
+ (op == CAIRO_OPERATOR_SOURCE ||
+ op == CAIRO_OPERATOR_OVER ||
+ op == CAIRO_OPERATOR_ADD)) {
+ op = PIXMAN_OP_SRC;
+ } else if (op == CAIRO_OPERATOR_SOURCE) {
+#if PIXMAN_HAS_OP_LERP
+ op = PIXMAN_OP_LERP;
+#else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+#endif
+ } else {
+ op = _pixman_operator (op);
+ }
+ r->op = op;
+
+ r->src = _pixman_image_for_pattern (dst, source, FALSE,
+ &composite->unbounded,
+ &composite->source_sample_area,
+ &r->src_x, &r->src_y);
+ if (unlikely (r->src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ r->opacity = 1.0;
+ if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
+ r->opacity = composite->mask_pattern.solid.color.alpha;
+ } else {
+ pixman_image_t *mask;
+ int mask_x, mask_y;
+
+ mask = _pixman_image_for_pattern (dst,
+ &composite->mask_pattern.base,
+ TRUE,
+ &composite->unbounded,
+ &composite->mask_sample_area,
+ &mask_x, &mask_y);
+ if (unlikely (mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ /* XXX Component-alpha? */
+ if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 &&
+ _cairo_pattern_is_opaque (source, &composite->source_sample_area))
+ {
+ pixman_image_unref (r->src);
+ r->src = mask;
+ r->src_x = mask_x;
+ r->src_y = mask_y;
+ mask = NULL;
+ }
+
+ if (mask) {
+ pixman_image_unref (mask);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ }
+
+ r->extents = composite->unbounded;
+ r->stride = (r->extents.width + 3) & ~3;
+ if (r->extents.height * r->stride > (int)sizeof (r->buf)) {
+ r->mask = pixman_image_create_bits (PIXMAN_a8,
+ r->extents.width,
+ r->extents.height,
+ NULL, 0);
+
+ r->base.render_rows = _cairo_image_spans;
+ r->base.finish = NULL;
+ } else {
+ r->mask = pixman_image_create_bits (PIXMAN_a8,
+ r->extents.width,
+ r->extents.height,
+ (uint32_t *)r->buf, r->stride);
+
+ r->base.render_rows = _cairo_image_spans_and_zero;
+ r->base.finish = _cairo_image_finish_spans_and_zero;
+ }
+ if (unlikely (r->mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ r->data = (uint8_t *) pixman_image_get_data (r->mask);
+ r->stride = pixman_image_get_stride (r->mask);
+
+ r->extents.height += r->extents.y;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+span_renderer_fini (cairo_abstract_span_renderer_t *_r,
+ cairo_int_status_t status)
+{
+ cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r;
+
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ const cairo_composite_rectangles_t *composite = r->composite;
+
+ if (r->base.finish)
+ r->base.finish (r);
+
+ pixman_image_composite32 (r->op, r->src, r->mask,
+ to_pixman_image (composite->surface),
+ composite->unbounded.x + r->src_x,
+ composite->unbounded.y + r->src_y,
+ 0, 0,
+ composite->unbounded.x,
+ composite->unbounded.y,
+ composite->unbounded.width,
+ composite->unbounded.height);
+ }
+
+ if (r->src)
+ pixman_image_unref (r->src);
+ if (r->mask)
+ pixman_image_unref (r->mask);
+}
+#endif
+
+const cairo_compositor_t *
+_cairo_image_spans_compositor_get (void)
+{
+ static cairo_spans_compositor_t compositor;
+
+ if (compositor.base.delegate == NULL) {
+ _cairo_spans_compositor_init (&compositor,
+ _cairo_image_traps_compositor_get());
+
+ //compositor.acquire = acquire;
+ //compositor.release = release;
+ compositor.fill_boxes = fill_boxes;
+ compositor.pattern_to_surface = _cairo_image_source_create_for_pattern;
+ //compositor.check_composite_boxes = check_composite_boxes;
+ compositor.composite_boxes = composite_boxes;
+ //compositor.check_span_renderer = check_span_renderer;
+ compositor.renderer_init = span_renderer_init;
+ compositor.renderer_fini = span_renderer_fini;
+ }
+
+ return &compositor.base;
+}
diff --git a/src/cairo-image-mask-compositor.c b/src/cairo-image-mask-compositor.c
new file mode 100644
index 00000000..33fd6dd8
--- /dev/null
+++ b/src/cairo-image-mask-compositor.c
@@ -0,0 +1,408 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2003 University of Southern California
+ * Copyright © 2009,2010,2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/* This compositor is slightly pointless. Just exists for testing
+ * and as skeleton code.
+ */
+
+#include "cairoint.h"
+
+#include "cairo-image-surface-private.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-region-private.h"
+
+static cairo_int_status_t
+acquire (void *abstract_dst)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+release (void *abstract_dst)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+set_clip_region (void *_surface,
+ cairo_region_t *region)
+{
+ cairo_image_surface_t *surface = _surface;
+ pixman_region32_t *rgn = region ? &region->rgn : NULL;
+
+ if (! pixman_image_set_clip_region32 (surface->pixman_image, rgn))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+has_snapshot (void *_dst,
+ const cairo_pattern_t *pattern)
+{
+ return FALSE;
+}
+
+static cairo_int_status_t
+draw_image (void *_dst,
+ cairo_image_surface_t *image,
+ int src_x, int src_y,
+ int width, int height,
+ int dst_x, int dst_y)
+{
+ cairo_image_surface_t *dst = (cairo_image_surface_t *)_dst;
+
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image, NULL, dst->pixman_image,
+ src_x, src_y,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static inline uint32_t
+color_to_uint32 (const cairo_color_t *color)
+{
+ return
+ (color->alpha_short >> 8 << 24) |
+ (color->red_short >> 8 << 16) |
+ (color->green_short & 0xff00) |
+ (color->blue_short >> 8);
+}
+
+static inline cairo_bool_t
+color_to_pixel (const cairo_color_t *color,
+ double opacity,
+ pixman_format_code_t format,
+ uint32_t *pixel)
+{
+ cairo_color_t opacity_color;
+ uint32_t c;
+
+ if (!(format == PIXMAN_a8r8g8b8 ||
+ format == PIXMAN_x8r8g8b8 ||
+ format == PIXMAN_a8b8g8r8 ||
+ format == PIXMAN_x8b8g8r8 ||
+ format == PIXMAN_b8g8r8a8 ||
+ format == PIXMAN_b8g8r8x8 ||
+ format == PIXMAN_r5g6b5 ||
+ format == PIXMAN_b5g6r5 ||
+ format == PIXMAN_a8))
+ {
+ return FALSE;
+ }
+
+ if (opacity != 1.0) {
+ _cairo_color_init_rgba (&opacity_color,
+ color->red,
+ color->green,
+ color->blue,
+ color->alpha * opacity);
+ color = &opacity_color;
+ }
+ c = color_to_uint32 (color);
+
+ if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
+ c = ((c & 0xff000000) >> 0) |
+ ((c & 0x00ff0000) >> 16) |
+ ((c & 0x0000ff00) >> 0) |
+ ((c & 0x000000ff) << 16);
+ }
+
+ if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
+ c = ((c & 0xff000000) >> 24) |
+ ((c & 0x00ff0000) >> 8) |
+ ((c & 0x0000ff00) << 8) |
+ ((c & 0x000000ff) << 24);
+ }
+
+ if (format == PIXMAN_a8) {
+ c = c >> 24;
+ } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
+ c = ((((c) >> 3) & 0x001f) |
+ (((c) >> 5) & 0x07e0) |
+ (((c) >> 8) & 0xf800));
+ }
+
+ *pixel = c;
+ return TRUE;
+}
+
+static cairo_int_status_t
+fill_rectangles (void *_dst,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_rectangle_int_t *rects,
+ int num_rects)
+{
+ cairo_image_surface_t *dst = _dst;
+ uint32_t pixel;
+ int i;
+
+ if (! color_to_pixel (color, 1.0, dst->pixman_format, &pixel))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ for (i = 0; i < num_rects; i++) {
+ pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ rects[i].x, rects[i].y,
+ rects[i].width, rects[i].height,
+ pixel);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+fill_boxes (void *_dst,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ cairo_image_surface_t *dst = _dst;
+ struct _cairo_boxes_chunk *chunk;
+ uint32_t pixel;
+ int i;
+
+ assert (boxes->is_pixel_aligned);
+
+ if (! color_to_pixel (color, 1.0, dst->pixman_format, &pixel))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+ pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ x1, y1, x2 - x1, y2 - y1,
+ pixel);
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static pixman_op_t
+_pixman_operator (cairo_operator_t op)
+{
+ switch ((int) op) {
+ case CAIRO_OPERATOR_CLEAR:
+ return PIXMAN_OP_CLEAR;
+
+ case CAIRO_OPERATOR_SOURCE:
+ return PIXMAN_OP_SRC;
+ case CAIRO_OPERATOR_OVER:
+ return PIXMAN_OP_OVER;
+ case CAIRO_OPERATOR_IN:
+ return PIXMAN_OP_IN;
+ case CAIRO_OPERATOR_OUT:
+ return PIXMAN_OP_OUT;
+ case CAIRO_OPERATOR_ATOP:
+ return PIXMAN_OP_ATOP;
+
+ case CAIRO_OPERATOR_DEST:
+ return PIXMAN_OP_DST;
+ case CAIRO_OPERATOR_DEST_OVER:
+ return PIXMAN_OP_OVER_REVERSE;
+ case CAIRO_OPERATOR_DEST_IN:
+ return PIXMAN_OP_IN_REVERSE;
+ case CAIRO_OPERATOR_DEST_OUT:
+ return PIXMAN_OP_OUT_REVERSE;
+ case CAIRO_OPERATOR_DEST_ATOP:
+ return PIXMAN_OP_ATOP_REVERSE;
+
+ case CAIRO_OPERATOR_XOR:
+ return PIXMAN_OP_XOR;
+ case CAIRO_OPERATOR_ADD:
+ return PIXMAN_OP_ADD;
+ case CAIRO_OPERATOR_SATURATE:
+ return PIXMAN_OP_SATURATE;
+
+ case CAIRO_OPERATOR_MULTIPLY:
+ return PIXMAN_OP_MULTIPLY;
+ case CAIRO_OPERATOR_SCREEN:
+ return PIXMAN_OP_SCREEN;
+ case CAIRO_OPERATOR_OVERLAY:
+ return PIXMAN_OP_OVERLAY;
+ case CAIRO_OPERATOR_DARKEN:
+ return PIXMAN_OP_DARKEN;
+ case CAIRO_OPERATOR_LIGHTEN:
+ return PIXMAN_OP_LIGHTEN;
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ return PIXMAN_OP_COLOR_DODGE;
+ case CAIRO_OPERATOR_COLOR_BURN:
+ return PIXMAN_OP_COLOR_BURN;
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ return PIXMAN_OP_HARD_LIGHT;
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ return PIXMAN_OP_SOFT_LIGHT;
+ case CAIRO_OPERATOR_DIFFERENCE:
+ return PIXMAN_OP_DIFFERENCE;
+ case CAIRO_OPERATOR_EXCLUSION:
+ return PIXMAN_OP_EXCLUSION;
+ case CAIRO_OPERATOR_HSL_HUE:
+ return PIXMAN_OP_HSL_HUE;
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ return PIXMAN_OP_HSL_SATURATION;
+ case CAIRO_OPERATOR_HSL_COLOR:
+ return PIXMAN_OP_HSL_COLOR;
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
+ return PIXMAN_OP_HSL_LUMINOSITY;
+
+ default:
+ ASSERT_NOT_REACHED;
+ return PIXMAN_OP_OVER;
+ }
+}
+
+static cairo_int_status_t
+composite (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ 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_image_surface_t *dst = _dst;
+ cairo_pixman_source_t *src = (cairo_pixman_source_t *)abstract_src;
+ cairo_pixman_source_t *mask = (cairo_pixman_source_t *)abstract_mask;
+ if (mask) {
+ pixman_image_composite32 (_pixman_operator (op),
+ src->pixman_image, mask->pixman_image, dst->pixman_image,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+ } else {
+ pixman_image_composite32 (_pixman_operator (op),
+ src->pixman_image, NULL, dst->pixman_image,
+ src_x, src_y,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_boxes (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ cairo_boxes_t *boxes)
+{
+ cairo_image_surface_t *dst = _dst;
+ cairo_pixman_source_t *src = (cairo_pixman_source_t *)abstract_src;
+ cairo_pixman_source_t *mask = (cairo_pixman_source_t *)abstract_mask;
+ struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ assert (boxes->is_pixel_aligned);
+
+ op = _pixman_operator (op);
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+ if (mask) {
+ pixman_image_composite32 (op,
+ src->pixman_image, mask->pixman_image, dst->pixman_image,
+ x1 + src_x, y1 + src_y,
+ x1 + mask_x, y1 + mask_y,
+ x1 + dst_x, y1 + dst_y,
+ x2 - x1, y2 - y1);
+ } else {
+ pixman_image_composite32 (op,
+ src->pixman_image, NULL, dst->pixman_image,
+ x1 + src_x, y1 + src_y,
+ 0, 0,
+ x1 + dst_x, y1 + dst_y,
+ x2 - x1, y2 - y1);
+ }
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+const cairo_compositor_t *
+_cairo_image_mask_compositor_get (void)
+{
+ static cairo_mask_compositor_t compositor;
+
+ if (compositor.base.delegate == NULL) {
+ _cairo_mask_compositor_init (&compositor,
+ _cairo_image_traps_compositor_get ());
+ compositor.acquire = acquire;
+ compositor.release = release;
+ compositor.set_clip_region = set_clip_region;
+ compositor.pattern_to_surface = _cairo_pixman_source_create_for_pattern;
+ compositor.has_snapshot = has_snapshot;
+ compositor.draw_image = draw_image;
+ compositor.fill_rectangles = fill_rectangles;
+ compositor.fill_boxes = fill_boxes;
+ //compositor.check_composite = check_composite;
+ compositor.composite = composite;
+ //compositor.check_composite_boxes = check_composite_boxes;
+ compositor.composite_boxes = composite_boxes;
+ }
+
+ return &compositor.base;
+}
diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
new file mode 100644
index 00000000..7c1eb826
--- /dev/null
+++ b/src/cairo-image-source.c
@@ -0,0 +1,975 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2003 University of Southern California
+ * Copyright © 2009,2010,2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/* The purpose of this file/surface is to simply translate a pattern
+ * to a pixman_image_t and thence to feed it back to the general
+ * compositor interface.
+ */
+
+#include "cairoint.h"
+
+#include "cairo-image-surface-private.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-error-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-paginated-private.h"
+#include "cairo-recording-surface-private.h"
+#include "cairo-surface-observer-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-subsurface-private.h"
+
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+
+#if CAIRO_NO_MUTEX
+#define PIXMAN_HAS_ATOMIC_OPS 1
+#endif
+
+#if PIXMAN_HAS_ATOMIC_OPS
+static pixman_image_t *__pixman_transparent_image;
+static pixman_image_t *__pixman_black_image;
+static pixman_image_t *__pixman_white_image;
+
+static pixman_image_t *
+_pixman_transparent_image (void)
+{
+ pixman_image_t *image;
+
+ image = __pixman_transparent_image;
+ if (unlikely (image == NULL)) {
+ pixman_color_t color;
+
+ color.red = 0x00;
+ color.green = 0x00;
+ color.blue = 0x00;
+ color.alpha = 0x00;
+
+ image = pixman_image_create_solid_fill (&color);
+ if (unlikely (image == NULL))
+ return NULL;
+
+ if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
+ NULL, image))
+ {
+ pixman_image_ref (image);
+ }
+ } else {
+ pixman_image_ref (image);
+ }
+
+ return image;
+}
+
+static pixman_image_t *
+_pixman_black_image (void)
+{
+ pixman_image_t *image;
+
+ image = __pixman_black_image;
+ if (unlikely (image == NULL)) {
+ pixman_color_t color;
+
+ color.red = 0x00;
+ color.green = 0x00;
+ color.blue = 0x00;
+ color.alpha = 0xffff;
+
+ image = pixman_image_create_solid_fill (&color);
+ if (unlikely (image == NULL))
+ return NULL;
+
+ if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
+ NULL, image))
+ {
+ pixman_image_ref (image);
+ }
+ } else {
+ pixman_image_ref (image);
+ }
+
+ return image;
+}
+
+static pixman_image_t *
+_pixman_white_image (void)
+{
+ pixman_image_t *image;
+
+ image = __pixman_white_image;
+ if (unlikely (image == NULL)) {
+ pixman_color_t color;
+
+ color.red = 0xffff;
+ color.green = 0xffff;
+ color.blue = 0xffff;
+ color.alpha = 0xffff;
+
+ image = pixman_image_create_solid_fill (&color);
+ if (unlikely (image == NULL))
+ return NULL;
+
+ if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
+ NULL, image))
+ {
+ pixman_image_ref (image);
+ }
+ } else {
+ pixman_image_ref (image);
+ }
+
+ return image;
+}
+
+static uint32_t
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+ static uint32_t x;
+ return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static struct {
+ cairo_color_t color;
+ pixman_image_t *image;
+} cache[16];
+static int n_cached;
+
+#else /* !PIXMAN_HAS_ATOMIC_OPS */
+static pixman_image_t *
+_pixman_transparent_image (void)
+{
+ return _pixman_image_for_color (CAIRO_COLOR_TRANSPARENT);
+}
+
+static pixman_image_t *
+_pixman_black_image (void)
+{
+ return _pixman_image_for_color (CAIRO_COLOR_BLACK);
+}
+
+static pixman_image_t *
+_pixman_white_image (void)
+{
+ return _pixman_image_for_color (CAIRO_COLOR_WHITE);
+}
+#endif /* !PIXMAN_HAS_ATOMIC_OPS */
+
+
+pixman_image_t *
+_pixman_image_for_color (const cairo_color_t *cairo_color)
+{
+ pixman_color_t color;
+ pixman_image_t *image;
+
+#if PIXMAN_HAS_ATOMIC_OPS
+ int i;
+
+ if (CAIRO_COLOR_IS_CLEAR (cairo_color))
+ return _pixman_transparent_image ();
+
+ if (CAIRO_COLOR_IS_OPAQUE (cairo_color)) {
+ if (cairo_color->red_short <= 0x00ff &&
+ cairo_color->green_short <= 0x00ff &&
+ cairo_color->blue_short <= 0x00ff)
+ {
+ return _pixman_black_image ();
+ }
+
+ if (cairo_color->red_short >= 0xff00 &&
+ cairo_color->green_short >= 0xff00 &&
+ cairo_color->blue_short >= 0xff00)
+ {
+ return _pixman_white_image ();
+ }
+ }
+
+ CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
+ for (i = 0; i < n_cached; i++) {
+ if (_cairo_color_equal (&cache[i].color, cairo_color)) {
+ image = pixman_image_ref (cache[i].image);
+ goto UNLOCK;
+ }
+ }
+#endif
+
+ color.red = cairo_color->red_short;
+ color.green = cairo_color->green_short;
+ color.blue = cairo_color->blue_short;
+ color.alpha = cairo_color->alpha_short;
+
+ image = pixman_image_create_solid_fill (&color);
+#if PIXMAN_HAS_ATOMIC_OPS
+ if (image == NULL)
+ goto UNLOCK;
+
+ if (n_cached < ARRAY_LENGTH (cache)) {
+ i = n_cached++;
+ } else {
+ i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
+ pixman_image_unref (cache[i].image);
+ }
+ cache[i].image = pixman_image_ref (image);
+ cache[i].color = *cairo_color;
+
+UNLOCK:
+ CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
+#endif
+ return image;
+}
+
+
+void
+_cairo_image_reset_static_data (void)
+{
+#if PIXMAN_HAS_ATOMIC_OPS
+ while (n_cached)
+ pixman_image_unref (cache[--n_cached].image);
+
+ if (__pixman_transparent_image) {
+ pixman_image_unref (__pixman_transparent_image);
+ __pixman_transparent_image = NULL;
+ }
+
+ if (__pixman_black_image) {
+ pixman_image_unref (__pixman_black_image);
+ __pixman_black_image = NULL;
+ }
+
+ if (__pixman_white_image) {
+ pixman_image_unref (__pixman_white_image);
+ __pixman_white_image = NULL;
+ }
+#endif
+}
+
+static pixman_image_t *
+_pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ int *ix, int *iy)
+{
+ pixman_image_t *pixman_image;
+ pixman_gradient_stop_t pixman_stops_static[2];
+ pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
+ pixman_transform_t pixman_transform;
+ cairo_matrix_t matrix;
+ cairo_circle_double_t extremes[2];
+ pixman_point_fixed_t p1, p2;
+ unsigned int i;
+ cairo_int_status_t status;
+
+ if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
+ pixman_stops = _cairo_malloc_ab (pattern->n_stops,
+ sizeof(pixman_gradient_stop_t));
+ if (unlikely (pixman_stops == NULL))
+ return NULL;
+ }
+
+ for (i = 0; i < pattern->n_stops; i++) {
+ pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
+ pixman_stops[i].color.red = pattern->stops[i].color.red_short;
+ pixman_stops[i].color.green = pattern->stops[i].color.green_short;
+ pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
+ pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
+ }
+
+ _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
+
+ p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
+ p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
+ p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
+ p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
+
+ if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
+ pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
+ pixman_stops,
+ pattern->n_stops);
+ } else {
+ pixman_fixed_t r1, r2;
+
+ r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
+ r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
+
+ pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
+ pixman_stops,
+ pattern->n_stops);
+ }
+
+ if (pixman_stops != pixman_stops_static)
+ free (pixman_stops);
+
+ if (unlikely (pixman_image == NULL))
+ return NULL;
+
+ *ix = *iy = 0;
+ status = _cairo_matrix_to_pixman_matrix_offset (&matrix, pattern->base.filter,
+ extents->x + extents->width/2.,
+ extents->y + extents->height/2.,
+ &pixman_transform, ix, iy);
+ if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
+ if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) ||
+ ! pixman_image_set_transform (pixman_image, &pixman_transform))
+ {
+ pixman_image_unref (pixman_image);
+ return NULL;
+ }
+ }
+
+ {
+ pixman_repeat_t pixman_repeat;
+
+ switch (pattern->base.extend) {
+ default:
+ case CAIRO_EXTEND_NONE:
+ pixman_repeat = PIXMAN_REPEAT_NONE;
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ pixman_repeat = PIXMAN_REPEAT_NORMAL;
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ pixman_repeat = PIXMAN_REPEAT_REFLECT;
+ break;
+ case CAIRO_EXTEND_PAD:
+ pixman_repeat = PIXMAN_REPEAT_PAD;
+ break;
+ }
+
+ pixman_image_set_repeat (pixman_image, pixman_repeat);
+ }
+
+ return pixman_image;
+}
+
+static pixman_image_t *
+_pixman_image_for_mesh (const cairo_mesh_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ int *tx, int *ty)
+{
+ pixman_image_t *image;
+ int width, height;
+
+ *tx = -extents->x;
+ *ty = -extents->y;
+ width = extents->width;
+ height = extents->height;
+
+ image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, height, NULL, 0);
+ if (unlikely (image == NULL))
+ return NULL;
+
+ _cairo_mesh_pattern_rasterize (pattern,
+ pixman_image_get_data (image),
+ width, height,
+ pixman_image_get_stride (image),
+ *tx, *ty);
+ return image;
+}
+
+struct acquire_source_cleanup {
+ cairo_surface_t *surface;
+ cairo_image_surface_t *image;
+ void *image_extra;
+};
+
+static void
+_acquire_source_cleanup (pixman_image_t *pixman_image,
+ void *closure)
+{
+ struct acquire_source_cleanup *data = closure;
+
+ _cairo_surface_release_source_image (data->surface,
+ data->image,
+ data->image_extra);
+ free (data);
+}
+
+static uint16_t
+expand_channel (uint16_t v, uint32_t bits)
+{
+ int offset = 16 - bits;
+ while (offset > 0) {
+ v |= v >> bits;
+ offset -= bits;
+ bits += bits;
+ }
+ return v;
+}
+
+static pixman_image_t *
+_pixel_to_solid (cairo_image_surface_t *image, int x, int y)
+{
+ uint32_t pixel;
+ pixman_color_t color;
+
+ switch (image->format) {
+ default:
+ case CAIRO_FORMAT_INVALID:
+ ASSERT_NOT_REACHED;
+ return NULL;
+
+ case CAIRO_FORMAT_A1:
+ pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
+ return pixel & (1 << (x&7)) ? _pixman_black_image () : _pixman_transparent_image ();
+
+ case CAIRO_FORMAT_A8:
+ color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
+ color.alpha |= color.alpha << 8;
+ if (color.alpha == 0)
+ return _pixman_transparent_image ();
+ if (color.alpha == 0xffff)
+ return _pixman_black_image ();
+
+ color.red = color.green = color.blue = 0;
+ return pixman_image_create_solid_fill (&color);
+
+ case CAIRO_FORMAT_RGB16_565:
+ pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
+ if (pixel == 0)
+ return _pixman_black_image ();
+ if (pixel == 0xffff)
+ return _pixman_white_image ();
+
+ color.alpha = 0xffff;
+ color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
+ color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
+ color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
+ return pixman_image_create_solid_fill (&color);
+
+ case CAIRO_FORMAT_RGB30:
+ pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
+ pixel &= 0x3fffffff; /* ignore alpha bits */
+ if (pixel == 0)
+ return _pixman_black_image ();
+ if (pixel == 0x3fffffff)
+ return _pixman_white_image ();
+
+ /* convert 10bpc to 16bpc */
+ color.alpha = 0xffff;
+ color.red = expand_channel((pixel >> 20) & 0x3fff, 10);
+ color.green = expand_channel((pixel >> 10) & 0x3fff, 10);
+ color.blue = expand_channel(pixel & 0x3fff, 10);
+ return pixman_image_create_solid_fill (&color);
+
+ case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB24:
+ pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
+ color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
+ if (color.alpha == 0)
+ return _pixman_transparent_image ();
+ if (pixel == 0xffffffff)
+ return _pixman_white_image ();
+ if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
+ return _pixman_black_image ();
+
+ color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
+ color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
+ color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
+ return pixman_image_create_solid_fill (&color);
+ }
+}
+
+static cairo_bool_t
+_pixman_image_set_properties (pixman_image_t *pixman_image,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ int *ix,int *iy)
+{
+ pixman_transform_t pixman_transform;
+ cairo_int_status_t status;
+
+ status = _cairo_matrix_to_pixman_matrix_offset (&pattern->matrix,
+ pattern->filter,
+ extents->x + extents->width/2.,
+ extents->y + extents->height/2.,
+ &pixman_transform, ix, iy);
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ {
+ /* If the transform is an identity, we don't need to set it
+ * and we can use any filtering, so choose the fastest one. */
+ pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
+ }
+ else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS ||
+ ! pixman_image_set_transform (pixman_image,
+ &pixman_transform)))
+ {
+ return FALSE;
+ }
+ else
+ {
+ pixman_filter_t pixman_filter;
+
+ switch (pattern->filter) {
+ case CAIRO_FILTER_FAST:
+ pixman_filter = PIXMAN_FILTER_FAST;
+ break;
+ case CAIRO_FILTER_GOOD:
+ pixman_filter = PIXMAN_FILTER_GOOD;
+ break;
+ case CAIRO_FILTER_BEST:
+ pixman_filter = PIXMAN_FILTER_BEST;
+ break;
+ case CAIRO_FILTER_NEAREST:
+ pixman_filter = PIXMAN_FILTER_NEAREST;
+ break;
+ case CAIRO_FILTER_BILINEAR:
+ pixman_filter = PIXMAN_FILTER_BILINEAR;
+ break;
+ case CAIRO_FILTER_GAUSSIAN:
+ /* XXX: The GAUSSIAN value has no implementation in cairo
+ * whatsoever, so it was really a mistake to have it in the
+ * API. We could fix this by officially deprecating it, or
+ * else inventing semantics and providing an actual
+ * implementation for it. */
+ default:
+ pixman_filter = PIXMAN_FILTER_BEST;
+ }
+
+ pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
+ }
+
+ {
+ pixman_repeat_t pixman_repeat;
+
+ switch (pattern->extend) {
+ default:
+ case CAIRO_EXTEND_NONE:
+ pixman_repeat = PIXMAN_REPEAT_NONE;
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ pixman_repeat = PIXMAN_REPEAT_NORMAL;
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ pixman_repeat = PIXMAN_REPEAT_REFLECT;
+ break;
+ case CAIRO_EXTEND_PAD:
+ pixman_repeat = PIXMAN_REPEAT_PAD;
+ break;
+ }
+
+ pixman_image_set_repeat (pixman_image, pixman_repeat);
+ }
+
+ if (pattern->has_component_alpha)
+ pixman_image_set_component_alpha (pixman_image, TRUE);
+
+ return TRUE;
+}
+
+static pixman_image_t *
+_pixman_image_for_recording (cairo_image_surface_t *dst,
+ const cairo_surface_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *ix, int *iy)
+{
+ cairo_surface_t *source, *clone;
+ cairo_rectangle_int_t limit;
+ pixman_image_t *pixman_image;
+ cairo_status_t status;
+ cairo_extend_t extend;
+ cairo_matrix_t *m, matrix;
+ int tx = 0, ty = 0;
+
+ *ix = *iy = 0;
+
+ source = pattern->surface;
+ if (_cairo_surface_is_subsurface (source))
+ source = _cairo_surface_subsurface_get_target_with_offset (source, &tx, &ty);
+ if (_cairo_surface_is_snapshot (source))
+ source = _cairo_surface_snapshot_get_target (source);
+ if (_cairo_surface_is_observer (source))
+ source = _cairo_surface_observer_get_target (source);
+ if (_cairo_surface_is_paginated (source))
+ source = _cairo_paginated_surface_get_target (source);
+
+ extend = pattern->base.extend;
+ if (_cairo_surface_get_extents (source, &limit)) {
+ if (sample->x >= limit.x &&
+ sample->y >= limit.y &&
+ sample->x + sample->width <= limit.x + limit.width &&
+ sample->y + sample->height <= limit.y + limit.height)
+ {
+ extend = CAIRO_EXTEND_NONE;
+ }
+ else if (extend == CAIRO_EXTEND_NONE &&
+ (sample->x + sample->width <= limit.x ||
+ sample->x >= limit.x + limit.width ||
+ sample->y + sample->height <= limit.y ||
+ sample->y >= limit.y + limit.height))
+ {
+ return _pixman_transparent_image ();
+ }
+ } else
+ extend = CAIRO_EXTEND_NONE;
+
+ if (extents == CAIRO_EXTEND_NONE)
+ limit = *extents;
+
+ clone = cairo_image_surface_create (dst->format, limit.width, limit.height);
+ cairo_surface_set_device_offset (clone, limit.x, limit.y);
+
+ m = NULL;
+ if (extend == CAIRO_EXTEND_NONE) {
+ m = &matrix;
+ cairo_matrix_multiply (m,
+ &dst->base.device_transform,
+ &pattern->base.matrix);
+ if (tx | ty)
+ cairo_matrix_translate (m, tx, ty);
+ } else {
+ /* XXX extract scale factor for repeating patterns */
+ }
+
+ status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (clone);
+ return NULL;
+ }
+
+ pixman_image = pixman_image_ref (((cairo_image_surface_t *)clone)->pixman_image);
+ cairo_surface_destroy (clone);
+
+ if (extend != CAIRO_EXTEND_NONE) {
+ if (! _pixman_image_set_properties (pixman_image,
+ &pattern->base, extents,
+ ix, iy)) {
+ pixman_image_unref (pixman_image);
+ pixman_image= NULL;
+ }
+ }
+
+
+ return pixman_image;
+}
+
+static pixman_image_t *
+_pixman_image_for_surface (cairo_image_surface_t *dst,
+ const cairo_surface_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *ix, int *iy)
+{
+ cairo_extend_t extend = pattern->base.extend;
+ pixman_image_t *pixman_image;
+
+ *ix = *iy = 0;
+ pixman_image = NULL;
+ if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
+ return _pixman_image_for_recording(dst, pattern,
+ is_mask, extents, sample,
+ ix, iy);
+
+ if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
+ (! is_mask || ! pattern->base.has_component_alpha ||
+ (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
+ {
+ cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
+ cairo_surface_type_t type;
+
+ if (_cairo_surface_is_snapshot (&source->base))
+ source = (cairo_image_surface_t *) _cairo_surface_snapshot_get_target (&source->base);
+
+ type = source->base.backend->type;
+ if (type == CAIRO_SURFACE_TYPE_IMAGE) {
+ if (extend != CAIRO_EXTEND_NONE &&
+ sample->x >= 0 &&
+ sample->y >= 0 &&
+ sample->x + sample->width <= source->width &&
+ sample->y + sample->height <= source->height)
+ {
+ extend = CAIRO_EXTEND_NONE;
+ }
+
+ if (sample->width == 1 && sample->height == 1) {
+ if (sample->x < 0 ||
+ sample->y < 0 ||
+ sample->x >= source->width ||
+ sample->y >= source->height)
+ {
+ if (extend == CAIRO_EXTEND_NONE)
+ return _pixman_transparent_image ();
+ }
+ else
+ {
+ pixman_image = _pixel_to_solid (source,
+ sample->x, sample->y);
+ if (pixman_image)
+ return pixman_image;
+ }
+ }
+
+#if PIXMAN_HAS_ATOMIC_OPS
+ /* avoid allocating a 'pattern' image if we can reuse the original */
+ *ix = *iy = 0;
+ if (extend == CAIRO_EXTEND_NONE &&
+ _cairo_matrix_is_pixman_translation (&pattern->base.matrix,
+ pattern->base.filter,
+ ix, iy))
+ {
+ return pixman_image_ref (source->pixman_image);
+ }
+#endif
+
+ pixman_image = pixman_image_create_bits (source->pixman_format,
+ source->width,
+ source->height,
+ (uint32_t *) source->data,
+ source->stride);
+ if (unlikely (pixman_image == NULL))
+ return NULL;
+ } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
+ cairo_surface_subsurface_t *sub;
+ cairo_bool_t is_contained = FALSE;
+
+ sub = (cairo_surface_subsurface_t *) source;
+ source = (cairo_image_surface_t *) sub->target;
+
+ if (sample->x >= 0 &&
+ sample->y >= 0 &&
+ sample->x + sample->width <= sub->extents.width &&
+ sample->y + sample->height <= sub->extents.height)
+ {
+ is_contained = TRUE;
+ }
+
+ if (sample->width == 1 && sample->height == 1) {
+ if (is_contained) {
+ pixman_image = _pixel_to_solid (source,
+ sub->extents.x + sample->x,
+ sub->extents.y + sample->y);
+ if (pixman_image)
+ return pixman_image;
+ } else {
+ if (extend == CAIRO_EXTEND_NONE)
+ return _pixman_transparent_image ();
+ }
+ }
+
+#if PIXMAN_HAS_ATOMIC_OPS
+ *ix = sub->extents.x;
+ *iy = sub->extents.y;
+ if (is_contained &&
+ _cairo_matrix_is_pixman_translation (&pattern->base.matrix,
+ pattern->base.filter,
+ ix, iy))
+ {
+ return pixman_image_ref (source->pixman_image);
+ }
+#endif
+
+ /* Avoid sub-byte offsets, force a copy in that case. */
+ if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
+ void *data = source->data
+ + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8
+ + sub->extents.y * source->stride;
+ pixman_image = pixman_image_create_bits (source->pixman_format,
+ sub->extents.width,
+ sub->extents.height,
+ data,
+ source->stride);
+ if (unlikely (pixman_image == NULL))
+ return NULL;
+ }
+ }
+ }
+
+#if PIXMAN_HAS_ATOMIC_OPS
+ *ix = *iy = 0;
+#endif
+ if (pixman_image == NULL) {
+ struct acquire_source_cleanup *cleanup;
+ cairo_image_surface_t *image;
+ void *extra;
+ cairo_status_t status;
+
+ status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
+ if (unlikely (status))
+ return NULL;
+
+ if (sample->x >= 0 && sample->y >= 0 &&
+ sample->x + sample->width <= image->width &&
+ sample->y + sample->height <= image->height)
+ {
+ extend = CAIRO_EXTEND_NONE;
+ }
+
+ if (sample->width == 1 && sample->height == 1) {
+ if (sample->x < 0 ||
+ sample->y < 0 ||
+ sample->x >= image->width ||
+ sample->y >= image->height)
+ {
+ if (extend == CAIRO_EXTEND_NONE) {
+ pixman_image = _pixman_transparent_image ();
+ _cairo_surface_release_source_image (pattern->surface, image, extra);
+ return pixman_image;
+ }
+ }
+ else
+ {
+ pixman_image = _pixel_to_solid (image, sample->x, sample->y);
+ if (pixman_image) {
+ _cairo_surface_release_source_image (pattern->surface, image, extra);
+ return pixman_image;
+ }
+ }
+ }
+
+ pixman_image = pixman_image_create_bits (image->pixman_format,
+ image->width,
+ image->height,
+ (uint32_t *) image->data,
+ image->stride);
+ if (unlikely (pixman_image == NULL)) {
+ _cairo_surface_release_source_image (pattern->surface, image, extra);
+ return NULL;
+ }
+
+ cleanup = malloc (sizeof (*cleanup));
+ if (unlikely (cleanup == NULL)) {
+ _cairo_surface_release_source_image (pattern->surface, image, extra);
+ pixman_image_unref (pixman_image);
+ return NULL;
+ }
+
+ cleanup->surface = pattern->surface;
+ cleanup->image = image;
+ cleanup->image_extra = extra;
+ pixman_image_set_destroy_function (pixman_image,
+ _acquire_source_cleanup, cleanup);
+ }
+
+ if (! _pixman_image_set_properties (pixman_image,
+ &pattern->base, extents,
+ ix, iy)) {
+ pixman_image_unref (pixman_image);
+ pixman_image= NULL;
+ }
+
+ return pixman_image;
+}
+
+pixman_image_t *
+_pixman_image_for_pattern (cairo_image_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *tx, int *ty)
+{
+ *tx = *ty = 0;
+
+ if (pattern == NULL)
+ return _pixman_white_image ();
+
+ switch (pattern->type) {
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return _pixman_image_for_color (&((const cairo_solid_pattern_t *) pattern)->color);
+
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
+ extents, tx, ty);
+
+ case CAIRO_PATTERN_TYPE_MESH:
+ return _pixman_image_for_mesh ((const cairo_mesh_pattern_t *) pattern,
+ extents, tx, ty);
+
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return _pixman_image_for_surface (dst,
+ (const cairo_surface_pattern_t *) pattern,
+ is_mask, extents, sample,
+ tx, ty);
+
+ }
+}
+
+static cairo_status_t
+_cairo_image_source_finish (void *abstract_surface)
+{
+ cairo_image_source_t *source = abstract_surface;
+
+ pixman_image_unref (source->pixman_image);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_image_source_backend = {
+ CAIRO_SURFACE_TYPE_IMAGE,
+ _cairo_image_source_finish,
+ NULL, /* read-only wrapper */
+};
+
+cairo_surface_t *
+_cairo_image_source_create_for_pattern (cairo_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y)
+{
+ cairo_image_source_t *source;
+
+ source = malloc (sizeof (cairo_image_source_t));
+ if (unlikely (source == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ source->pixman_image =
+ _pixman_image_for_pattern ((cairo_image_surface_t *)dst,
+ pattern, is_mask,
+ extents, sample,
+ src_x, src_y);
+ if (unlikely (source->pixman_image == NULL)) {
+ free (source);
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ _cairo_surface_init (&source->base,
+ &cairo_image_source_backend,
+ NULL, /* device */
+ CAIRO_CONTENT_COLOR_ALPHA);
+
+ source->is_opaque_solid =
+ pattern == NULL || _cairo_pattern_is_opaque_solid (pattern);
+
+ return &source->base;
+}
diff --git a/src/cairo-image-spans-compositor.c b/src/cairo-image-spans-compositor.c
new file mode 100644
index 00000000..5718b555
--- /dev/null
+++ b/src/cairo-image-spans-compositor.c
@@ -0,0 +1,131 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2003 University of Southern California
+ * Copyright © 2009,2010,2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-spans-compositor-private.h"
+
+typedef struct _cairo_image_span_renderer {
+ cairo_span_renderer_t base;
+
+ pixman_image_compositor_t *compositor;
+ pixman_image_t *src;
+ float opacity;
+ cairo_rectangle_int_t extents;
+} cairo_image_span_renderer_t;
+
+static cairo_status_t
+_cairo_image_span_renderer_init (cairo_abstract_span_renderer_t *_r,
+ cairo_surface_t *dst,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x, int src_y;
+ float opacity,
+ const cairo_composite_rectangles_t *composite,
+ cairo_bool_t needs_clip)
+{
+ cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r;
+ cairo_pixman_source_t *src = (cairo_pixman_source_t *)_src;
+ int src_x, src_y;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ op = CAIRO_OPERATOR_DEST_OUT;
+ pattern = NULL;
+ }
+
+ r->src = ((cairo_pixman_source_t *) src)->pixman_image;
+ r->opacity = opacity;
+
+ if (composite->is_bounded) {
+ if (opacity == 1.)
+ r->base.render_rows = _cairo_image_bounded_opaque_spans;
+ else
+ r->base.render_rows = _cairo_image_bounded_spans;
+ r->base.finish = NULL;
+ } else {
+ if (needs_clip)
+ r->base.render_rows = _cairo_image_clipped_spans;
+ else
+ r->base.render_rows = _cairo_image_unbounded_spans;
+ r->base.finish = _cairo_image_finish_unbounded_spans;
+ r->extents = composite->unbounded;
+ r->extents.height += r->extents.y;
+
+ }
+ r->compositor =
+ pixman_image_create_compositor (_pixman_operator (op),
+ r->src, NULL, dst->pixman_image,
+ composite->bounded.x + src_x,
+ composite->bounded.y + src_y,
+ 0, 0,
+ composite->bounded.x,
+ composite->bounded.y,
+ composite->bounded.width,
+ composite->bounded.height);
+ if (unlikely (r->compositor == NULL))
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_image_span_renderer_fini (cairo_abstract_span_renderer_t *_r)
+{
+ cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) r;
+ pixman_image_compositor_destroy (r->compositor);
+}
+
+const cairo_compositor_t *
+_cairo_image_spans_compositor_get (void)
+{
+ static cairo_spans_compositor_t compositor;
+
+ if (compositor.base.delegate == NULL) {
+ /* Can't fallback to the mask compositor as that will simply
+ * call the spans-compositor again to render the mask!
+ */
+ _cairo_spans_compositor_init (&compositor,
+ _cairo_image_traps_compositor_get());
+
+ }
+
+ return &compositor.base;
+}
diff --git a/src/cairo-image-surface-private.h b/src/cairo-image-surface-private.h
index 56a1dc40..227a447c 100644
--- a/src/cairo-image-surface-private.h
+++ b/src/cairo-image-surface-private.h
@@ -44,9 +44,13 @@
CAIRO_BEGIN_DECLS
+/* The canonical image backend */
struct _cairo_image_surface {
cairo_surface_t base;
+ pixman_image_t *pixman_image;
+ const cairo_compositor_t *compositor;
+
pixman_format_code_t pixman_format;
cairo_format_t format;
unsigned char *data;
@@ -56,20 +60,55 @@ struct _cairo_image_surface {
int stride;
int depth;
- pixman_image_t *pixman_image;
-
unsigned owns_data : 1;
unsigned transparency : 2;
unsigned color : 2;
};
-extern const cairo_private cairo_surface_backend_t _cairo_image_surface_backend;
+/* A wrapper for holding pixman images returned by create_for_pattern */
+typedef struct _cairo_image_source {
+ cairo_surface_t base;
+
+ pixman_image_t *pixman_image;
+ unsigned is_opaque_solid : 1;
+} cairo_image_source_t;
+
+cairo_private extern const cairo_surface_backend_t _cairo_image_surface_backend;
+
+cairo_private const cairo_compositor_t *
+_cairo_image_mask_compositor_get (void);
+
+cairo_private const cairo_compositor_t *
+_cairo_image_traps_compositor_get (void);
+
+cairo_private const cairo_compositor_t *
+_cairo_image_spans_compositor_get (void);
cairo_private void
_cairo_image_surface_init (cairo_image_surface_t *surface,
pixman_image_t *pixman_image,
pixman_format_code_t pixman_format);
+cairo_private cairo_surface_t *
+_cairo_image_surface_map_to_image (void *abstract_other,
+ const cairo_rectangle_int_t *extents);
+
+cairo_private cairo_int_status_t
+_cairo_image_surface_unmap_image (void *abstract_surface,
+ cairo_image_surface_t *image);
+cairo_private cairo_status_t
+_cairo_image_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra);
+
+cairo_private void
+_cairo_image_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra);
+
+cairo_private cairo_surface_t *
+_cairo_image_surface_snapshot (void *abstract_surface);
+
cairo_private_no_warn cairo_bool_t
_cairo_image_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle);
@@ -78,9 +117,52 @@ cairo_private void
_cairo_image_surface_get_font_options (void *abstract_surface,
cairo_font_options_t *options);
+cairo_private cairo_surface_t *
+_cairo_image_source_create_for_pattern (cairo_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y);
+
cairo_private cairo_status_t
_cairo_image_surface_finish (void *abstract_surface);
+cairo_private pixman_image_t *
+_pixman_image_for_color (const cairo_color_t *cairo_color);
+
+cairo_private pixman_image_t *
+_pixman_image_for_pattern (cairo_image_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *tx, int *ty);
+
+cairo_private void
+_pixman_image_add_traps (pixman_image_t *image,
+ int dst_x, int dst_y,
+ cairo_traps_t *traps);
+
+cairo_private void
+_pixman_image_add_tristrip (pixman_image_t *image,
+ int dst_x, int dst_y,
+ cairo_tristrip_t *strip);
+
+/**
+ * _cairo_surface_is_image:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is an #cairo_image_surface_t
+ *
+ * Return value: %TRUE if the surface is an image surface
+ **/
+static inline cairo_bool_t
+_cairo_surface_is_image (const cairo_surface_t *surface)
+{
+ return surface->backend == &_cairo_image_surface_backend;
+}
+
CAIRO_END_DECLS
#endif /* CAIRO_IMAGE_SURFACE_PRIVATE_H */
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index bda05eb9..6adbdd61 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -2,7 +2,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
- * Copyright © 2009,2010 Intel Corporation
+ * Copyright © 2009,2010,2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -42,6 +42,7 @@
#include "cairo-boxes-private.h"
#include "cairo-clip-private.h"
#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
@@ -57,7 +58,6 @@
* mainly determined by coordinates of things sent to pixman at the
* moment being in 16.16 format. */
#define MAX_IMAGE_SIZE 32767
-#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
/**
* SECTION:cairo-image
@@ -80,9 +80,6 @@
* @Since: 1.8
*/
-static pixman_image_t *
-_pixman_image_for_solid (const cairo_solid_pattern_t *pattern);
-
static cairo_bool_t
_cairo_image_surface_is_size_valid (int width, int height)
{
@@ -165,6 +162,8 @@ _cairo_image_surface_init (cairo_image_surface_t *surface,
surface->depth = pixman_image_get_depth (pixman_image);
surface->base.is_clear = surface->width == 0 || surface->height == 0;
+
+ surface->compositor = _cairo_image_spans_compositor_get ();
}
cairo_surface_t *
@@ -391,7 +390,7 @@ cairo_image_surface_create (cairo_format_t format,
}
slim_hidden_def (cairo_image_surface_create);
-cairo_surface_t *
+ cairo_surface_t *
_cairo_image_surface_create_with_content (cairo_content_t content,
int width,
int height)
@@ -427,7 +426,7 @@ _cairo_image_surface_create_with_content (cairo_content_t content,
*
* Since: 1.6
**/
-int
+ int
cairo_format_stride_for_width (cairo_format_t format,
int width)
{
@@ -489,7 +488,7 @@ slim_hidden_def (cairo_format_stride_for_width);
* See cairo_surface_set_user_data() for a means of attaching a
* destroy-notification fallback to the surface if necessary.
**/
-cairo_surface_t *
+ cairo_surface_t *
cairo_image_surface_create_for_data (unsigned char *data,
cairo_format_t format,
int width,
@@ -545,7 +544,7 @@ slim_hidden_def (cairo_image_surface_create_for_data);
*
* Since: 1.2
**/
-unsigned char *
+ unsigned char *
cairo_image_surface_get_data (cairo_surface_t *surface)
{
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
@@ -569,7 +568,7 @@ slim_hidden_def (cairo_image_surface_get_data);
*
* Since: 1.2
**/
-cairo_format_t
+ cairo_format_t
cairo_image_surface_get_format (cairo_surface_t *surface)
{
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
@@ -591,7 +590,7 @@ slim_hidden_def (cairo_image_surface_get_format);
*
* Return value: the width of the surface in pixels.
**/
-int
+ int
cairo_image_surface_get_width (cairo_surface_t *surface)
{
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
@@ -613,7 +612,7 @@ slim_hidden_def (cairo_image_surface_get_width);
*
* Return value: the height of the surface in pixels.
**/
-int
+ int
cairo_image_surface_get_height (cairo_surface_t *surface)
{
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
@@ -640,7 +639,7 @@ slim_hidden_def (cairo_image_surface_get_height);
*
* Since: 1.2
**/
-int
+ int
cairo_image_surface_get_stride (cairo_surface_t *surface)
{
@@ -655,7 +654,7 @@ cairo_image_surface_get_stride (cairo_surface_t *surface)
}
slim_hidden_def (cairo_image_surface_get_stride);
-cairo_format_t
+ cairo_format_t
_cairo_format_from_content (cairo_content_t content)
{
switch (content) {
@@ -671,7 +670,7 @@ _cairo_format_from_content (cairo_content_t content)
return CAIRO_FORMAT_INVALID;
}
-cairo_content_t
+ cairo_content_t
_cairo_content_from_format (cairo_format_t format)
{
switch (format) {
@@ -694,7 +693,7 @@ _cairo_content_from_format (cairo_format_t format)
return CAIRO_CONTENT_COLOR_ALPHA;
}
-int
+ int
_cairo_format_bits_per_pixel (cairo_format_t format)
{
switch (format) {
@@ -715,7 +714,7 @@ _cairo_format_bits_per_pixel (cairo_format_t format)
}
}
-static cairo_surface_t *
+ static cairo_surface_t *
_cairo_image_surface_create_similar (void *abstract_other,
cairo_content_t content,
int width,
@@ -737,7 +736,7 @@ _cairo_image_surface_create_similar (void *abstract_other,
width, height);
}
-static cairo_surface_t *
+cairo_surface_t *
_cairo_image_surface_snapshot (void *abstract_surface)
{
cairo_image_surface_t *image = abstract_surface;
@@ -766,8 +765,7 @@ _cairo_image_surface_snapshot (void *abstract_surface)
return &clone->base;
}
-
-static cairo_surface_t *
+cairo_surface_t *
_cairo_image_surface_map_to_image (void *abstract_other,
const cairo_rectangle_int_t *extents)
{
@@ -790,7 +788,7 @@ _cairo_image_surface_map_to_image (void *abstract_other,
return surface;
}
-static cairo_int_status_t
+cairo_int_status_t
_cairo_image_surface_unmap_image (void *abstract_surface,
cairo_image_surface_t *image)
{
@@ -821,7 +819,7 @@ _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
surface->owns_data = TRUE;
}
-static cairo_status_t
+cairo_status_t
_cairo_image_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
@@ -832,2601 +830,13 @@ _cairo_image_surface_acquire_source_image (void *abstract_sur
return CAIRO_STATUS_SUCCESS;
}
-static void
+void
_cairo_image_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra)
{
}
-/* XXX: I think we should fix pixman to match the names/order of the
- * cairo operators, but that will likely be better done at the same
- * time the X server is ported to pixman, (which will change a lot of
- * things in pixman I think).
- */
-static pixman_op_t
-_pixman_operator (cairo_operator_t op)
-{
- switch (op) {
- case CAIRO_OPERATOR_CLEAR:
- return PIXMAN_OP_CLEAR;
-
- case CAIRO_OPERATOR_SOURCE:
- return PIXMAN_OP_SRC;
- case CAIRO_OPERATOR_OVER:
- return PIXMAN_OP_OVER;
- case CAIRO_OPERATOR_IN:
- return PIXMAN_OP_IN;
- case CAIRO_OPERATOR_OUT:
- return PIXMAN_OP_OUT;
- case CAIRO_OPERATOR_ATOP:
- return PIXMAN_OP_ATOP;
-
- case CAIRO_OPERATOR_DEST:
- return PIXMAN_OP_DST;
- case CAIRO_OPERATOR_DEST_OVER:
- return PIXMAN_OP_OVER_REVERSE;
- case CAIRO_OPERATOR_DEST_IN:
- return PIXMAN_OP_IN_REVERSE;
- case CAIRO_OPERATOR_DEST_OUT:
- return PIXMAN_OP_OUT_REVERSE;
- case CAIRO_OPERATOR_DEST_ATOP:
- return PIXMAN_OP_ATOP_REVERSE;
-
- case CAIRO_OPERATOR_XOR:
- return PIXMAN_OP_XOR;
- case CAIRO_OPERATOR_ADD:
- return PIXMAN_OP_ADD;
- case CAIRO_OPERATOR_SATURATE:
- return PIXMAN_OP_SATURATE;
-
- case CAIRO_OPERATOR_MULTIPLY:
- return PIXMAN_OP_MULTIPLY;
- case CAIRO_OPERATOR_SCREEN:
- return PIXMAN_OP_SCREEN;
- case CAIRO_OPERATOR_OVERLAY:
- return PIXMAN_OP_OVERLAY;
- case CAIRO_OPERATOR_DARKEN:
- return PIXMAN_OP_DARKEN;
- case CAIRO_OPERATOR_LIGHTEN:
- return PIXMAN_OP_LIGHTEN;
- case CAIRO_OPERATOR_COLOR_DODGE:
- return PIXMAN_OP_COLOR_DODGE;
- case CAIRO_OPERATOR_COLOR_BURN:
- return PIXMAN_OP_COLOR_BURN;
- case CAIRO_OPERATOR_HARD_LIGHT:
- return PIXMAN_OP_HARD_LIGHT;
- case CAIRO_OPERATOR_SOFT_LIGHT:
- return PIXMAN_OP_SOFT_LIGHT;
- case CAIRO_OPERATOR_DIFFERENCE:
- return PIXMAN_OP_DIFFERENCE;
- case CAIRO_OPERATOR_EXCLUSION:
- return PIXMAN_OP_EXCLUSION;
- case CAIRO_OPERATOR_HSL_HUE:
- return PIXMAN_OP_HSL_HUE;
- case CAIRO_OPERATOR_HSL_SATURATION:
- return PIXMAN_OP_HSL_SATURATION;
- case CAIRO_OPERATOR_HSL_COLOR:
- return PIXMAN_OP_HSL_COLOR;
- case CAIRO_OPERATOR_HSL_LUMINOSITY:
- return PIXMAN_OP_HSL_LUMINOSITY;
-
- default:
- ASSERT_NOT_REACHED;
- return PIXMAN_OP_OVER;
- }
-}
-
-static cairo_status_t
-_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
- cairo_region_t *region)
-{
- if (! pixman_image_set_clip_region32 (surface->pixman_image, &region->rgn))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_image_surface_unset_clip_region (cairo_image_surface_t *surface)
-{
- pixman_image_set_clip_region32 (surface->pixman_image, NULL);
-}
-
-#if PIXMAN_HAS_ATOMIC_OPS
-static pixman_image_t *__pixman_transparent_image;
-static pixman_image_t *__pixman_black_image;
-static pixman_image_t *__pixman_white_image;
-
-static pixman_image_t *
-_pixman_transparent_image (void)
-{
- pixman_image_t *image;
-
- image = __pixman_transparent_image;
- if (unlikely (image == NULL)) {
- pixman_color_t color;
-
- color.red = 0x00;
- color.green = 0x00;
- color.blue = 0x00;
- color.alpha = 0x00;
-
- image = pixman_image_create_solid_fill (&color);
- if (unlikely (image == NULL))
- return NULL;
-
- if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
- NULL, image))
- {
- pixman_image_ref (image);
- }
- } else {
- pixman_image_ref (image);
- }
-
- return image;
-}
-
-static pixman_image_t *
-_pixman_black_image (void)
-{
- pixman_image_t *image;
-
- image = __pixman_black_image;
- if (unlikely (image == NULL)) {
- pixman_color_t color;
-
- color.red = 0x00;
- color.green = 0x00;
- color.blue = 0x00;
- color.alpha = 0xffff;
-
- image = pixman_image_create_solid_fill (&color);
- if (unlikely (image == NULL))
- return NULL;
-
- if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
- NULL, image))
- {
- pixman_image_ref (image);
- }
- } else {
- pixman_image_ref (image);
- }
-
- return image;
-}
-
-static pixman_image_t *
-_pixman_white_image (void)
-{
- pixman_image_t *image;
-
- image = __pixman_white_image;
- if (unlikely (image == NULL)) {
- pixman_color_t color;
-
- color.red = 0xffff;
- color.green = 0xffff;
- color.blue = 0xffff;
- color.alpha = 0xffff;
-
- image = pixman_image_create_solid_fill (&color);
- if (unlikely (image == NULL))
- return NULL;
-
- if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
- NULL, image))
- {
- pixman_image_ref (image);
- }
- } else {
- pixman_image_ref (image);
- }
-
- return image;
-}
-
-static uint32_t
-hars_petruska_f54_1_random (void)
-{
-#define rol(x,k) ((x << k) | (x >> (32-k)))
- static uint32_t x;
- return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
-#undef rol
-}
-
-static struct {
- cairo_color_t color;
- pixman_image_t *image;
-} cache[16];
-static int n_cached;
-
-#else /* !PIXMAN_HAS_ATOMIC_OPS */
-static pixman_image_t *
-_pixman_transparent_image (void)
-{
- return _pixman_image_for_solid (&_cairo_pattern_clear);
-}
-
-static pixman_image_t *
-_pixman_black_image (void)
-{
- return _pixman_image_for_solid (&_cairo_pattern_black);
-}
-
-static pixman_image_t *
-_pixman_white_image (void)
-{
- return _pixman_image_for_solid (&_cairo_pattern_white);
-}
-#endif /* !PIXMAN_HAS_ATOMIC_OPS */
-
-void
-_cairo_image_reset_static_data (void)
-{
-#if PIXMAN_HAS_ATOMIC_OPS
- while (n_cached)
- pixman_image_unref (cache[--n_cached].image);
-
- if (__pixman_transparent_image) {
- pixman_image_unref (__pixman_transparent_image);
- __pixman_transparent_image = NULL;
- }
-
- if (__pixman_black_image) {
- pixman_image_unref (__pixman_black_image);
- __pixman_black_image = NULL;
- }
-
- if (__pixman_white_image) {
- pixman_image_unref (__pixman_white_image);
- __pixman_white_image = NULL;
- }
-#endif
-}
-
-static pixman_image_t *
-_pixman_image_for_solid (const cairo_solid_pattern_t *pattern)
-{
- pixman_color_t color;
- pixman_image_t *image;
-
-#if PIXMAN_HAS_ATOMIC_OPS
- int i;
-
- if (pattern->color.alpha_short <= 0x00ff)
- return _pixman_transparent_image ();
-
- if (pattern->color.alpha_short >= 0xff00) {
- if (pattern->color.red_short <= 0x00ff &&
- pattern->color.green_short <= 0x00ff &&
- pattern->color.blue_short <= 0x00ff)
- {
- return _pixman_black_image ();
- }
-
- if (pattern->color.red_short >= 0xff00 &&
- pattern->color.green_short >= 0xff00 &&
- pattern->color.blue_short >= 0xff00)
- {
- return _pixman_white_image ();
- }
- }
-
- CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
- for (i = 0; i < n_cached; i++) {
- if (_cairo_color_equal (&cache[i].color, &pattern->color)) {
- image = pixman_image_ref (cache[i].image);
- goto UNLOCK;
- }
- }
-#endif
-
- color.red = pattern->color.red_short;
- color.green = pattern->color.green_short;
- color.blue = pattern->color.blue_short;
- color.alpha = pattern->color.alpha_short;
-
- image = pixman_image_create_solid_fill (&color);
-#if PIXMAN_HAS_ATOMIC_OPS
- if (image == NULL)
- goto UNLOCK;
-
- if (n_cached < ARRAY_LENGTH (cache)) {
- i = n_cached++;
- } else {
- i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
- pixman_image_unref (cache[i].image);
- }
- cache[i].image = pixman_image_ref (image);
- cache[i].color = pattern->color;
-
-UNLOCK:
- CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
-#endif
- return image;
-}
-
-static pixman_image_t *
-_pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
- const cairo_rectangle_int_t *extents,
- int *ix, int *iy)
-{
- pixman_image_t *pixman_image;
- pixman_gradient_stop_t pixman_stops_static[2];
- pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
- pixman_transform_t pixman_transform;
- cairo_matrix_t matrix;
- cairo_circle_double_t extremes[2];
- pixman_point_fixed_t p1, p2;
- unsigned int i;
- cairo_int_status_t status;
-
- if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
- pixman_stops = _cairo_malloc_ab (pattern->n_stops,
- sizeof(pixman_gradient_stop_t));
- if (unlikely (pixman_stops == NULL))
- return NULL;
- }
-
- for (i = 0; i < pattern->n_stops; i++) {
- pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
- pixman_stops[i].color.red = pattern->stops[i].color.red_short;
- pixman_stops[i].color.green = pattern->stops[i].color.green_short;
- pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
- pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
- }
-
- _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
-
- p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
- p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
- p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
- p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
-
- if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
- pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
- pixman_stops,
- pattern->n_stops);
- } else {
- pixman_fixed_t r1, r2;
-
- r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
- r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
-
- pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
- pixman_stops,
- pattern->n_stops);
- }
-
- if (pixman_stops != pixman_stops_static)
- free (pixman_stops);
-
- if (unlikely (pixman_image == NULL))
- return NULL;
-
- *ix = *iy = 0;
- status = _cairo_matrix_to_pixman_matrix_offset (&matrix, pattern->base.filter,
- extents->x + extents->width/2.,
- extents->y + extents->height/2.,
- &pixman_transform, ix, iy);
- if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
- if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) ||
- ! pixman_image_set_transform (pixman_image, &pixman_transform))
- {
- pixman_image_unref (pixman_image);
- return NULL;
- }
- }
-
- {
- pixman_repeat_t pixman_repeat;
-
- switch (pattern->base.extend) {
- default:
- case CAIRO_EXTEND_NONE:
- pixman_repeat = PIXMAN_REPEAT_NONE;
- break;
- case CAIRO_EXTEND_REPEAT:
- pixman_repeat = PIXMAN_REPEAT_NORMAL;
- break;
- case CAIRO_EXTEND_REFLECT:
- pixman_repeat = PIXMAN_REPEAT_REFLECT;
- break;
- case CAIRO_EXTEND_PAD:
- pixman_repeat = PIXMAN_REPEAT_PAD;
- break;
- }
-
- pixman_image_set_repeat (pixman_image, pixman_repeat);
- }
-
- return pixman_image;
-}
-
-struct acquire_source_cleanup {
- cairo_surface_t *surface;
- cairo_image_surface_t *image;
- void *image_extra;
-};
-
-static void
-_acquire_source_cleanup (pixman_image_t *pixman_image,
- void *closure)
-{
- struct acquire_source_cleanup *data = closure;
-
- _cairo_surface_release_source_image (data->surface,
- data->image,
- data->image_extra);
- free (data);
-}
-
-static cairo_filter_t
-sampled_area (const cairo_surface_pattern_t *pattern,
- const cairo_rectangle_int_t *extents,
- cairo_rectangle_int_t *sample)
-{
- cairo_filter_t filter;
- double x1, x2, y1, y2;
- double pad;
-
- x1 = extents->x;
- y1 = extents->y;
- x2 = extents->x + (int) extents->width;
- y2 = extents->y + (int) extents->height;
-
- _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
- &x1, &y1, &x2, &y2,
- NULL);
-
- filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
- sample->x = floor (x1 - pad);
- sample->y = floor (y1 - pad);
- sample->width = ceil (x2 + pad) - sample->x;
- sample->height = ceil (y2 + pad) - sample->y;
-
- return filter;
-}
-
-static uint16_t
-expand_channel (uint16_t v, uint32_t bits)
-{
- int offset = 16 - bits;
- while (offset > 0) {
- v |= v >> bits;
- offset -= bits;
- bits += bits;
- }
- return v;
-}
-
-static pixman_image_t *
-_pixel_to_solid (cairo_image_surface_t *image, int x, int y)
-{
- uint32_t pixel;
- pixman_color_t color;
-
- switch (image->format) {
- default:
- ASSERT_NOT_REACHED;
- return NULL;
-
- case CAIRO_FORMAT_INVALID:
- return NULL;
-
- case CAIRO_FORMAT_A1:
- pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
- return pixel & (1 << (x&7)) ? _pixman_black_image () : _pixman_transparent_image ();
-
- case CAIRO_FORMAT_A8:
- color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
- color.alpha |= color.alpha << 8;
- if (color.alpha == 0)
- return _pixman_transparent_image ();
- if (color.alpha == 0xffff)
- return _pixman_black_image ();
-
- color.red = color.green = color.blue = 0;
- return pixman_image_create_solid_fill (&color);
-
- case CAIRO_FORMAT_RGB16_565:
- pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
- if (pixel == 0)
- return _pixman_black_image ();
- if (pixel == 0xffff)
- return _pixman_white_image ();
-
- color.alpha = 0xffff;
- color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
- color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
- color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
- return pixman_image_create_solid_fill (&color);
-
- case CAIRO_FORMAT_RGB30:
- pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
- pixel &= 0x3fffffff; /* ignore alpha bits */
- if (pixel == 0)
- return _pixman_black_image ();
- if (pixel == 0x3fffffff)
- return _pixman_white_image ();
-
- /* convert 10bpc to 16bpc */
- color.alpha = 0xffff;
- color.red = expand_channel((pixel >> 20) & 0x3fff, 10);
- color.green = expand_channel((pixel >> 10) & 0x3fff, 10);
- color.blue = expand_channel(pixel & 0x3fff, 10);
- return pixman_image_create_solid_fill (&color);
-
- case CAIRO_FORMAT_ARGB32:
- case CAIRO_FORMAT_RGB24:
- pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
- color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
- if (color.alpha == 0)
- return _pixman_transparent_image ();
- if (pixel == 0xffffffff)
- return _pixman_white_image ();
- if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
- return _pixman_black_image ();
-
- color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
- color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
- color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
- return pixman_image_create_solid_fill (&color);
- }
-}
-
-static pixman_image_t *
-_pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
- cairo_bool_t is_mask,
- const cairo_rectangle_int_t *extents,
- cairo_matrix_t *dst_device_transform,
- int *ix, int *iy)
-{
- pixman_transform_t pixman_transform;
- pixman_image_t *pixman_image;
- cairo_matrix_t m;
- cairo_rectangle_int_t sample;
- cairo_extend_t extend;
- cairo_filter_t filter;
- cairo_int_status_t status;
- cairo_bool_t undo_src_transform = FALSE;
-
- extend = pattern->base.extend;
- filter = sampled_area (pattern, extents, &sample);
-
- *ix = *iy = 0;
- pixman_image = NULL;
- if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE &&
- (! is_mask || ! pattern->base.has_component_alpha ||
- (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0))
- {
- cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
- cairo_surface_type_t type;
-
- if (_cairo_surface_is_snapshot (&source->base))
- source = (cairo_image_surface_t *) _cairo_surface_snapshot_get_target (&source->base);
-
- type = source->base.backend->type;
- if (type == CAIRO_SURFACE_TYPE_IMAGE) {
- if (extend != CAIRO_EXTEND_NONE &&
- sample.x >= 0 &&
- sample.y >= 0 &&
- sample.x + sample.width <= source->width &&
- sample.y + sample.height <= source->height)
- {
- extend = CAIRO_EXTEND_NONE;
- }
-
- if (sample.width == 1 && sample.height == 1) {
- if (sample.x < 0 ||
- sample.y < 0 ||
- sample.x >= source->width ||
- sample.y >= source->height)
- {
- if (extend == CAIRO_EXTEND_NONE)
- return _pixman_transparent_image ();
- }
- else
- {
- pixman_image = _pixel_to_solid (source, sample.x, sample.y);
- if (pixman_image)
- return pixman_image;
- }
- }
-
-#if PIXMAN_HAS_ATOMIC_OPS
- /* avoid allocating a 'pattern' image if we can reuse the original */
- *ix = *iy = 0;
- if (extend == CAIRO_EXTEND_NONE &&
- _cairo_matrix_is_pixman_translation (&pattern->base.matrix,
- filter, ix, iy))
- {
- return pixman_image_ref (source->pixman_image);
- }
-#endif
-
- pixman_image = pixman_image_create_bits (source->pixman_format,
- source->width,
- source->height,
- (uint32_t *) source->data,
- source->stride);
- if (unlikely (pixman_image == NULL))
- return NULL;
- } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
- cairo_surface_subsurface_t *sub;
- cairo_bool_t is_contained = FALSE;
-
- sub = (cairo_surface_subsurface_t *) source;
- source = (cairo_image_surface_t *) sub->target;
-
- if (sample.x >= 0 &&
- sample.y >= 0 &&
- sample.x + sample.width <= sub->extents.width &&
- sample.y + sample.height <= sub->extents.height)
- {
- is_contained = TRUE;
- }
-
- if (sample.width == 1 && sample.height == 1) {
- if (is_contained) {
- pixman_image = _pixel_to_solid (source,
- sub->extents.x + sample.x,
- sub->extents.y + sample.y);
- if (pixman_image)
- return pixman_image;
- } else {
- if (extend == CAIRO_EXTEND_NONE)
- return _pixman_transparent_image ();
- }
- }
-
-#if PIXMAN_HAS_ATOMIC_OPS
- *ix = sub->extents.x;
- *iy = sub->extents.y;
- if (is_contained &&
- _cairo_matrix_is_pixman_translation (&pattern->base.matrix,
- filter, ix, iy))
- {
- return pixman_image_ref (source->pixman_image);
- }
-#endif
-
- /* Avoid sub-byte offsets, force a copy in that case. */
- if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
- void *data = source->data
- + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8
- + sub->extents.y * source->stride;
- pixman_image = pixman_image_create_bits (source->pixman_format,
- sub->extents.width,
- sub->extents.height,
- data,
- source->stride);
- if (unlikely (pixman_image == NULL))
- return NULL;
- }
- }
- }
-
-#if PIXMAN_HAS_ATOMIC_OPS
- *ix = *iy = 0;
-#endif
-
- if (pixman_image == NULL) {
- struct acquire_source_cleanup *cleanup;
- cairo_image_surface_t *image;
- void *extra;
- cairo_status_t status;
-
- status = _cairo_surface_acquire_source_image_transformed (pattern->surface, dst_device_transform, &image, &extra);
- if (unlikely (status))
- return NULL;
-
- if (sample.width == 1 && sample.height == 1) {
- if (sample.x < 0 ||
- sample.y < 0 ||
- sample.x >= image->width ||
- sample.y >= image->height)
- {
- if (extend == CAIRO_EXTEND_NONE) {
- pixman_image = _pixman_transparent_image ();
- _cairo_surface_release_source_image (pattern->surface, image, extra);
- return pixman_image;
- }
- }
- else
- {
- pixman_image = _pixel_to_solid (image, sample.x, sample.y);
- if (pixman_image)
- {
- _cairo_surface_release_source_image (pattern->surface, image, extra);
- return pixman_image;
- }
- }
- }
-
- pixman_image = pixman_image_create_bits (image->pixman_format,
- image->width,
- image->height,
- (uint32_t *) image->data,
- image->stride);
- if (unlikely (pixman_image == NULL)) {
- _cairo_surface_release_source_image (pattern->surface, image, extra);
- return NULL;
- }
-
- cleanup = malloc (sizeof (*cleanup));
- if (unlikely (cleanup == NULL)) {
- _cairo_surface_release_source_image (pattern->surface, image, extra);
- pixman_image_unref (pixman_image);
- return NULL;
- }
-
- cleanup->surface = pattern->surface;
- cleanup->image = image;
- cleanup->image_extra = extra;
- pixman_image_set_destroy_function (pixman_image,
- _acquire_source_cleanup, cleanup);
- undo_src_transform = TRUE;
- }
-
- m = pattern->base.matrix;
- if (undo_src_transform) {
- cairo_matrix_t sm;
-
- cairo_matrix_init_scale (&sm,
- dst_device_transform->xx,
- dst_device_transform->yy);
- cairo_matrix_multiply (&m, &m, &sm);
- }
-
- status = _cairo_matrix_to_pixman_matrix_offset (&m, filter,
- extents->x + extents->width/2.,
- extents->y + extents->height/2.,
- &pixman_transform, ix, iy);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- {
- /* If the transform is an identity, we don't need to set it
- * and we can use any filtering, so choose the fastest one. */
- pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
- }
- else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS ||
- ! pixman_image_set_transform (pixman_image,
- &pixman_transform)))
- {
- pixman_image_unref (pixman_image);
- return NULL;
- }
- else
- {
- pixman_filter_t pixman_filter;
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- pixman_filter = PIXMAN_FILTER_FAST;
- break;
- case CAIRO_FILTER_GOOD:
- pixman_filter = PIXMAN_FILTER_GOOD;
- break;
- case CAIRO_FILTER_BEST:
- pixman_filter = PIXMAN_FILTER_BEST;
- break;
- case CAIRO_FILTER_NEAREST:
- pixman_filter = PIXMAN_FILTER_NEAREST;
- break;
- case CAIRO_FILTER_BILINEAR:
- pixman_filter = PIXMAN_FILTER_BILINEAR;
- break;
- case CAIRO_FILTER_GAUSSIAN:
- /* XXX: The GAUSSIAN value has no implementation in cairo
- * whatsoever, so it was really a mistake to have it in the
- * API. We could fix this by officially deprecating it, or
- * else inventing semantics and providing an actual
- * implementation for it. */
- default:
- pixman_filter = PIXMAN_FILTER_BEST;
- }
-
- pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
- }
-
- {
- pixman_repeat_t pixman_repeat;
-
- switch (extend) {
- default:
- case CAIRO_EXTEND_NONE:
- pixman_repeat = PIXMAN_REPEAT_NONE;
- break;
- case CAIRO_EXTEND_REPEAT:
- pixman_repeat = PIXMAN_REPEAT_NORMAL;
- break;
- case CAIRO_EXTEND_REFLECT:
- pixman_repeat = PIXMAN_REPEAT_REFLECT;
- break;
- case CAIRO_EXTEND_PAD:
- pixman_repeat = PIXMAN_REPEAT_PAD;
- break;
- }
-
- pixman_image_set_repeat (pixman_image, pixman_repeat);
- }
-
- if (pattern->base.has_component_alpha)
- pixman_image_set_component_alpha (pixman_image, TRUE);
-
- return pixman_image;
-}
-
-static pixman_image_t *
-_pixman_image_for_pattern (const cairo_pattern_t *pattern,
- cairo_bool_t is_mask,
- const cairo_rectangle_int_t *extents,
- cairo_matrix_t *dst_device_transform,
- int *tx, int *ty)
-{
- *tx = *ty = 0;
-
- if (pattern == NULL)
- return _pixman_white_image ();
-
- switch (pattern->type) {
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_PATTERN_TYPE_SOLID:
- return _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
-
- case CAIRO_PATTERN_TYPE_RADIAL:
- case CAIRO_PATTERN_TYPE_LINEAR:
- return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
- extents, tx, ty);
-
- case CAIRO_PATTERN_TYPE_SURFACE:
- return _pixman_image_for_surface ((const cairo_surface_pattern_t *) pattern,
- is_mask, extents, dst_device_transform, tx, ty);
-
- case CAIRO_PATTERN_TYPE_MESH: {
- cairo_surface_t *image;
- pixman_image_t *r;
- void * data;
- int width, height, stride;
-
- *tx = -extents->x;
- *ty = -extents->y;
- width = extents->width;
- height = extents->height;
-
- image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
- if (unlikely (image->status))
- return NULL;
-
- stride = cairo_image_surface_get_stride (image);
- data = cairo_image_surface_get_data (image);
-
- _cairo_mesh_pattern_rasterize ((cairo_mesh_pattern_t *) pattern,
- data, width, height, stride, *tx, *ty);
- r = pixman_image_ref (((cairo_image_surface_t *)image)->pixman_image);
- cairo_surface_destroy (image);
- return r;
- }
- }
-}
-
-static cairo_status_t
-_cairo_image_surface_fixup_unbounded (cairo_image_surface_t *dst,
- const cairo_composite_rectangles_t *rects,
- cairo_clip_t *clip)
-{
- cairo_surface_t *clip_surface = NULL;
- pixman_image_t *mask = NULL;
- pixman_box32_t boxes[4];
- int i, mask_x = 0, mask_y = 0, n_boxes = 0;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- if (clip != NULL) {
- int clip_x, clip_y;
-
- clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
- if (unlikely (clip_surface->status))
- return clip_surface->status;
-
- mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
- mask_x = -clip_x;
- mask_y = -clip_y;
- } else {
- if (rects->bounded.width == rects->unbounded.width &&
- rects->bounded.height == rects->unbounded.height)
- {
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
- /* wholly unbounded? */
- if (rects->bounded.width == 0 || rects->bounded.height == 0) {
- int x = rects->unbounded.x;
- int y = rects->unbounded.y;
- int width = rects->unbounded.width;
- int height = rects->unbounded.height;
-
- if (mask != NULL) {
- pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
- mask, NULL, dst->pixman_image,
- x + mask_x, y + mask_y,
- 0, 0,
- x, y,
- width, height);
- } else {
- pixman_color_t color = { 0, };
- pixman_box32_t box = { x, y, x + width, y + height };
-
- if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
- dst->pixman_image,
- &color,
- 1, &box))
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- cairo_surface_destroy (clip_surface);
- return status;
- }
-
- /* top */
- if (rects->bounded.y != rects->unbounded.y) {
- boxes[n_boxes].x1 = rects->unbounded.x;
- boxes[n_boxes].y1 = rects->unbounded.y;
- boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
- boxes[n_boxes].y2 = rects->bounded.y;
- n_boxes++;
- }
-
- /* left */
- if (rects->bounded.x != rects->unbounded.x) {
- boxes[n_boxes].x1 = rects->unbounded.x;
- boxes[n_boxes].y1 = rects->bounded.y;
- boxes[n_boxes].x2 = rects->bounded.x;
- boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
- n_boxes++;
- }
-
- /* right */
- if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
- boxes[n_boxes].x1 = rects->bounded.x + rects->bounded.width;
- boxes[n_boxes].y1 = rects->bounded.y;
- boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
- boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height;
- n_boxes++;
- }
-
- /* bottom */
- if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
- boxes[n_boxes].x1 = rects->unbounded.x;
- boxes[n_boxes].y1 = rects->bounded.y + rects->bounded.height;
- boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width;
- boxes[n_boxes].y2 = rects->unbounded.y + rects->unbounded.height;
- n_boxes++;
- }
-
- if (mask != NULL) {
- for (i = 0; i < n_boxes; i++) {
- pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
- mask, NULL, dst->pixman_image,
- boxes[i].x1 + mask_x, boxes[i].y1 + mask_y,
- 0, 0,
- boxes[i].x1, boxes[i].y1,
- boxes[i].x2 - boxes[i].x1, boxes[i].y2 - boxes[i].y1);
- }
- } else {
- pixman_color_t color = { 0, };
-
- if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
- dst->pixman_image,
- &color,
- n_boxes,
- boxes))
- {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
- }
-
- cairo_surface_destroy (clip_surface);
- return status;
-}
-
-static cairo_status_t
-_cairo_image_surface_fixup_unbounded_boxes (cairo_image_surface_t *dst,
- const cairo_composite_rectangles_t *extents,
- cairo_region_t *clip_region,
- cairo_boxes_t *boxes)
-{
- cairo_boxes_t clear;
- cairo_box_t box;
- cairo_status_t status;
- struct _cairo_boxes_chunk *chunk;
- int i;
-
- if (boxes->num_boxes <= 1 && clip_region == NULL)
- return _cairo_image_surface_fixup_unbounded (dst, extents, NULL);
-
- _cairo_boxes_init (&clear);
-
- box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
- box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
- box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
- box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
-
- if (clip_region == NULL) {
- cairo_boxes_t tmp;
-
- _cairo_boxes_init (&tmp);
-
- status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
- assert (status == CAIRO_STATUS_SUCCESS);
-
- tmp.chunks.next = &boxes->chunks;
- tmp.num_boxes += boxes->num_boxes;
-
- status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
- CAIRO_FILL_RULE_WINDING,
- &clear);
-
- tmp.chunks.next = NULL;
- } else {
- pixman_box32_t *pbox;
-
- pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
- _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
-
- status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
- assert (status == CAIRO_STATUS_SUCCESS);
-
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- for (i = 0; i < chunk->count; i++) {
- status = _cairo_boxes_add (&clear,
- CAIRO_ANTIALIAS_DEFAULT,
- &chunk->base[i]);
- if (unlikely (status)) {
- _cairo_boxes_fini (&clear);
- return status;
- }
- }
- }
-
- status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
- CAIRO_FILL_RULE_WINDING,
- &clear);
- }
-
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- for (chunk = &clear.chunks; chunk != NULL; chunk = chunk->next) {
- for (i = 0; i < chunk->count; i++) {
- int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
- int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
- int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
- int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
-
- pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
- PIXMAN_FORMAT_BPP (dst->pixman_format),
- x1, y1, x2 - x1, y2 - y1,
- 0);
- }
- }
- }
-
- _cairo_boxes_fini (&clear);
-
- return status;
-}
-
-static cairo_bool_t
-can_reduce_alpha_op (cairo_operator_t op)
-{
- int iop = op;
- switch (iop) {
- case CAIRO_OPERATOR_OVER:
- case CAIRO_OPERATOR_SOURCE:
- case CAIRO_OPERATOR_ADD:
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-static cairo_bool_t
-reduce_alpha_op (cairo_image_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *pattern)
-{
- return dst->base.is_clear &&
- dst->base.content == CAIRO_CONTENT_ALPHA &&
- _cairo_pattern_is_opaque_solid (pattern) &&
- can_reduce_alpha_op (op);
-}
-
-/* low level compositor */
-typedef cairo_status_t
-(*image_draw_func_t) (void *closure,
- pixman_image_t *dst,
- pixman_format_code_t dst_format,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- int dst_x,
- int dst_y,
- cairo_matrix_t *dst_device_transform,
- const cairo_composite_rectangles_t *extents);
-
-static pixman_image_t *
-_create_composite_mask_pattern (cairo_composite_rectangles_t *extents,
- image_draw_func_t draw_func,
- void *draw_closure,
- cairo_image_surface_t *dst)
-{
- cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
- cairo_bool_t need_clip_surface = ! _cairo_clip_is_region (extents->clip);
- pixman_image_t *mask;
- cairo_status_t status;
-
- if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
- clip_region = NULL;
-
- mask = pixman_image_create_bits (PIXMAN_a8, extents->bounded.width, extents->bounded.height,
- NULL, 0);
- if (unlikely (mask == NULL))
- return NULL;
-
- /* Is it worth setting the clip region here? */
- if (clip_region != NULL) {
- pixman_bool_t ret;
-
- pixman_region32_translate (&clip_region->rgn, -extents->bounded.x, -extents->bounded.y);
- ret = pixman_image_set_clip_region32 (mask, &clip_region->rgn);
- pixman_region32_translate (&clip_region->rgn, extents->bounded.x, extents->bounded.y);
-
- if (! ret) {
- pixman_image_unref (mask);
- return NULL;
- }
- }
-
- status = draw_func (draw_closure,
- mask, PIXMAN_a8,
- CAIRO_OPERATOR_ADD, NULL,
- extents->bounded.x, extents->bounded.y,
- &dst->base.device_transform,
- extents);
- if (unlikely (status)) {
- pixman_image_unref (mask);
- return NULL;
- }
-
- if (need_clip_surface) {
- cairo_surface_t *tmp;
-
- tmp = _cairo_image_surface_create_for_pixman_image (mask, PIXMAN_a8);
- if (unlikely (tmp->status)) {
- pixman_image_unref (mask);
- return NULL;
- }
-
- pixman_image_ref (mask);
-
- status = _cairo_clip_combine_with_surface (extents->clip, tmp,
- extents->bounded.x,
- extents->bounded.y);
- cairo_surface_destroy (tmp);
- if (unlikely (status)) {
- pixman_image_unref (mask);
- return NULL;
- }
- }
-
- if (clip_region != NULL)
- pixman_image_set_clip_region (mask, NULL);
-
- return mask;
-}
-
-/* Handles compositing with a clip surface when the operator allows
- * us to combine the clip with the mask
- */
-static cairo_status_t
-_clip_and_composite_with_mask (cairo_composite_rectangles_t *extents,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- image_draw_func_t draw_func,
- void *draw_closure,
- cairo_image_surface_t *dst)
-{
- pixman_image_t *mask;
-
- mask = _create_composite_mask_pattern (extents, draw_func, draw_closure, dst);
- if (unlikely (mask == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- if (pattern == NULL) {
- if (dst->pixman_format == PIXMAN_a8) {
- pixman_image_composite32 (_pixman_operator (op),
- mask, NULL, dst->pixman_image,
- 0, 0, 0, 0,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
- } else {
- pixman_image_t *src;
-
- src = _pixman_white_image ();
- if (unlikely (src == NULL)) {
- pixman_image_unref (mask);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- pixman_image_composite32 (_pixman_operator (op),
- src, mask, dst->pixman_image,
- 0, 0, 0, 0,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
- pixman_image_unref (src);
- }
- } else {
- pixman_image_t *src;
- int src_x, src_y;
-
- src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
- &dst->base.device_transform,
- &src_x, &src_y);
- if (unlikely (src == NULL)) {
- pixman_image_unref (mask);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- pixman_image_composite32 (_pixman_operator (op),
- src, mask, dst->pixman_image,
- extents->bounded.x + src_x, extents->bounded.y + src_y,
- 0, 0,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
- pixman_image_unref (src);
- }
-
- pixman_image_unref (mask);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Handles compositing with a clip surface when we have to do the operation
- * in two pieces and combine them together.
- */
-static cairo_status_t
-_clip_and_composite_combine (cairo_composite_rectangles_t *extents,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- image_draw_func_t draw_func,
- void *draw_closure,
- cairo_image_surface_t *dst)
-{
- pixman_image_t *tmp;
- cairo_surface_t *clip_surface;
- int clip_x, clip_y;
- cairo_status_t status;
-
- tmp = pixman_image_create_bits (dst->pixman_format,
- extents->bounded.width,
- extents->bounded.height,
- NULL, 0);
- if (unlikely (tmp == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- if (src == NULL) {
- status = (*draw_func) (draw_closure,
- tmp, dst->pixman_format,
- CAIRO_OPERATOR_ADD, NULL,
- extents->bounded.x, extents->bounded.y,
- &dst->base.device_transform,
- extents);
- } else {
- /* Initialize the temporary surface from the destination surface */
- if (! dst->base.is_clear) {
- pixman_image_composite32 (PIXMAN_OP_SRC,
- dst->pixman_image, NULL, tmp,
- extents->bounded.x,
- extents->bounded.y,
- 0, 0,
- 0, 0,
- extents->bounded.width,
- extents->bounded.height);
- }
-
- status = (*draw_func) (draw_closure,
- tmp, dst->pixman_format,
- op, src,
- extents->bounded.x, extents->bounded.y,
- &dst->base.device_transform,
- extents);
- }
- if (unlikely (status))
- goto CLEANUP_SURFACE;
-
- clip_surface = _cairo_clip_get_surface (extents->clip, &dst->base,
- &clip_x, &clip_y);
- if (unlikely (clip_surface->status))
- goto CLEANUP_SURFACE;
-
- if (! dst->base.is_clear) {
-#if PIXMAN_HAS_OP_LERP
- pixman_image_composite32 (PIXMAN_OP_LERP,
- tmp,
- ((cairo_image_surface_t *) clip_surface)->pixman_image,
- dst->pixman_image,
- 0, 0,
- extents->bounded.x - clip_x,
- extents->bounded.y - clip_y,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
-#else
- /* Punch the clip out of the destination */
- pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
- ((cairo_image_surface_t *) clip_surface)->pixman_image,
- NULL, dst->pixman_image,
- extents->bounded.x - clip_x,
- extents->bounded.y - clip_y,
- 0, 0,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
-
- /* Now add the two results together */
- pixman_image_composite32 (PIXMAN_OP_ADD,
- tmp,
- ((cairo_image_surface_t *) clip_surface)->pixman_image,
- dst->pixman_image,
- 0, 0,
- extents->bounded.x - clip_x,
- extents->bounded.y - clip_y,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
-#endif
- } else {
- pixman_image_composite32 (PIXMAN_OP_SRC,
- tmp,
- ((cairo_image_surface_t *) clip_surface)->pixman_image,
- dst->pixman_image,
- 0, 0,
- extents->bounded.x - clip_x,
- extents->bounded.y - clip_y,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
- }
-
- cairo_surface_destroy (clip_surface);
- CLEANUP_SURFACE:
- pixman_image_unref (tmp);
-
- return status;
-}
-
-/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
- * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
- */
-static cairo_status_t
-_clip_and_composite_source (cairo_composite_rectangles_t *extents,
- const cairo_pattern_t *pattern,
- image_draw_func_t draw_func,
- void *draw_closure,
- cairo_image_surface_t *dst)
-{
- pixman_image_t *mask, *src;
- int src_x, src_y;
-
- if (pattern == NULL) {
- cairo_status_t status;
-
- status = draw_func (draw_closure,
- dst->pixman_image, dst->pixman_format,
- CAIRO_OPERATOR_SOURCE, NULL,
- extents->bounded.x, extents->bounded.y,
- &dst->base.device_transform,
- extents);
- if (unlikely (status))
- return status;
-
- if (! _cairo_clip_is_region (extents->clip))
- status = _cairo_clip_combine_with_surface (extents->clip,
- &dst->base, 0, 0);
-
- return status;
- }
-
- /* Create a surface that is mask IN clip */
- mask = _create_composite_mask_pattern (extents, draw_func, draw_closure, dst);
- if (unlikely (mask == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
- &dst->base.device_transform,
- &src_x, &src_y);
- if (unlikely (src == NULL)) {
- pixman_image_unref (mask);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- if (! dst->base.is_clear) {
-#if PIXMAN_HAS_OP_LERP
- pixman_image_composite32 (PIXMAN_OP_LERP,
- src, mask, dst->pixman_image,
- extents->bounded.x + src_x, extents->bounded.y + src_y,
- 0, 0,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
-#else
- /* Compute dest' = dest OUT (mask IN clip) */
- pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
- mask, NULL, dst->pixman_image,
- 0, 0, 0, 0,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
-
- /* Now compute (src IN (mask IN clip)) ADD dest' */
- pixman_image_composite32 (PIXMAN_OP_ADD,
- src, mask, dst->pixman_image,
- extents->bounded.x + src_x, extents->bounded.y + src_y,
- 0, 0,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
-#endif
- } else {
- pixman_image_composite32 (PIXMAN_OP_SRC,
- src, mask, dst->pixman_image,
- extents->bounded.x + src_x, extents->bounded.y + src_y,
- 0, 0,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
- }
-
- pixman_image_unref (src);
- pixman_image_unref (mask);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-enum {
- NEED_CLIP_REGION = 0x1,
- NEED_CLIP_SURFACE = 0x2,
- FORCE_CLIP_REGION = 0x4,
-};
-
-static cairo_bool_t
-need_bounded_clip (cairo_composite_rectangles_t *extents)
-{
- unsigned int flags = NEED_CLIP_REGION;
- if (! _cairo_clip_is_region (extents->clip))
- flags |= NEED_CLIP_SURFACE;
- return flags;
-}
-
-static cairo_bool_t
-need_unbounded_clip (cairo_composite_rectangles_t *extents)
-{
- unsigned int flags = 0;
- if (! extents->is_bounded) {
- flags |= NEED_CLIP_REGION;
- if (! _cairo_clip_is_region (extents->clip))
- flags |= NEED_CLIP_SURFACE;
- }
- if (extents->clip->path != NULL)
- flags |= NEED_CLIP_SURFACE;
- return flags;
-}
-
-
-static cairo_status_t
-_clip_and_composite (cairo_image_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- image_draw_func_t draw_func,
- void *draw_closure,
- cairo_composite_rectangles_t*extents,
- unsigned int need_clip)
-{
- cairo_region_t *clip_region = NULL;
- cairo_status_t status;
-
- if (need_clip & NEED_CLIP_REGION) {
- clip_region = _cairo_clip_get_region (extents->clip);
- if ((need_clip & FORCE_CLIP_REGION) == 0 &&
- cairo_region_contains_rectangle (clip_region,
- &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
- clip_region = NULL;
- if (clip_region != NULL) {
- status = _cairo_image_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- return status;
- }
- }
-
- if (reduce_alpha_op (dst, op, src)) {
- op = CAIRO_OPERATOR_ADD;
- src = NULL;
- }
-
- if (op == CAIRO_OPERATOR_SOURCE) {
- status = _clip_and_composite_source (extents, src,
- draw_func, draw_closure, dst);
- } else {
- if (op == CAIRO_OPERATOR_CLEAR) {
- src = NULL;
- op = CAIRO_OPERATOR_DEST_OUT;
- }
-
- if (need_clip & NEED_CLIP_SURFACE) {
- if (extents->is_bounded) {
- status = _clip_and_composite_with_mask (extents, op, src,
- draw_func, draw_closure,
- dst);
- } else {
- status = _clip_and_composite_combine (extents, op, src,
- draw_func, draw_closure,
- dst);
- }
- } else {
- status = draw_func (draw_closure,
- dst->pixman_image, dst->pixman_format,
- op, src,
- 0, 0,
- &dst->base.device_transform,
- extents);
- }
- }
-
- if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
- status = _cairo_image_surface_fixup_unbounded (dst, extents,
- need_clip & NEED_CLIP_SURFACE ? extents->clip : NULL);
- }
-
- if (clip_region != NULL)
- _cairo_image_surface_unset_clip_region (dst);
-
- return status;
-}
-
-#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
-#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
-
-static cairo_bool_t
-_line_exceeds_16_16 (const cairo_line_t *line)
-{
- return
- line->p1.x <= CAIRO_FIXED_16_16_MIN ||
- line->p1.x >= CAIRO_FIXED_16_16_MAX ||
-
- line->p2.x <= CAIRO_FIXED_16_16_MIN ||
- line->p2.x >= CAIRO_FIXED_16_16_MAX ||
-
- line->p1.y <= CAIRO_FIXED_16_16_MIN ||
- line->p1.y >= CAIRO_FIXED_16_16_MAX ||
-
- line->p2.y <= CAIRO_FIXED_16_16_MIN ||
- line->p2.y >= CAIRO_FIXED_16_16_MAX;
-}
-
-static void
-_project_line_x_onto_16_16 (const cairo_line_t *line,
- cairo_fixed_t top,
- cairo_fixed_t bottom,
- pixman_line_fixed_t *out)
-{
- cairo_point_double_t p1, p2;
- double m;
-
- p1.x = _cairo_fixed_to_double (line->p1.x);
- p1.y = _cairo_fixed_to_double (line->p1.y);
-
- p2.x = _cairo_fixed_to_double (line->p2.x);
- p2.y = _cairo_fixed_to_double (line->p2.y);
-
- m = (p2.x - p1.x) / (p2.y - p1.y);
- out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
- out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
-}
-
-
-typedef struct {
- cairo_trapezoid_t *traps;
- int num_traps;
- cairo_antialias_t antialias;
-} composite_traps_info_t;
-
-static void
-_pixman_image_add_traps (pixman_image_t *image,
- int dst_x, int dst_y,
- composite_traps_info_t *info)
-{
- cairo_trapezoid_t *t = info->traps;
- int num_traps = info->num_traps;
- while (num_traps--) {
- pixman_trapezoid_t trap;
-
- /* top/bottom will be clamped to surface bounds */
- trap.top = _cairo_fixed_to_16_16 (t->top);
- trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
-
- /* However, all the other coordinates will have been left untouched so
- * as not to introduce numerical error. Recompute them if they
- * exceed the 16.16 limits.
- */
- if (unlikely (_line_exceeds_16_16 (&t->left))) {
- _project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
- trap.left.p1.y = trap.top;
- trap.left.p2.y = trap.bottom;
- } else {
- trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
- trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
- trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
- trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
- }
-
- if (unlikely (_line_exceeds_16_16 (&t->right))) {
- _project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
- trap.right.p1.y = trap.top;
- trap.right.p2.y = trap.bottom;
- } else {
- trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
- trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
- trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
- trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
- }
-
- pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
-
- t++;
- }
-}
-
-static cairo_status_t
-_composite_traps (void *closure,
- pixman_image_t *dst,
- pixman_format_code_t dst_format,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- int dst_x,
- int dst_y,
- cairo_matrix_t *dst_device_transform,
- const cairo_composite_rectangles_t *extents)
-{
- composite_traps_info_t *info = closure;
- pixman_image_t *src, *mask;
- pixman_format_code_t format;
- int src_x = 0, src_y = 0;
- cairo_status_t status;
-
- /* Special case adding trapezoids onto a mask surface; we want to avoid
- * creating an intermediate temporary mask unnecessarily.
- *
- * We make the assumption here that the portion of the trapezoids
- * contained within the surface is bounded by [dst_x,dst_y,width,height];
- * the Cairo core code passes bounds based on the trapezoid extents.
- */
- format = info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
- if (dst_format == format &&
- (pattern == NULL ||
- (op == CAIRO_OPERATOR_ADD && _cairo_pattern_is_opaque_solid (pattern))))
- {
- _pixman_image_add_traps (dst, dst_x, dst_y, info);
- return CAIRO_STATUS_SUCCESS;
- }
-
- src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
- dst_device_transform,
- &src_x, &src_y);
- if (unlikely (src == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- mask = pixman_image_create_bits (format,
- extents->bounded.width,
- extents->bounded.height,
- NULL, 0);
- if (unlikely (mask == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto CLEANUP_SOURCE;
- }
-
- _pixman_image_add_traps (mask, extents->bounded.x, extents->bounded.y, info);
- pixman_image_composite32 (_pixman_operator (op),
- src, mask, dst,
- extents->bounded.x + src_x, extents->bounded.y + src_y,
- 0, 0,
- extents->bounded.x - dst_x, extents->bounded.y - dst_y,
- extents->bounded.width, extents->bounded.height);
-
- pixman_image_unref (mask);
-
- status = CAIRO_STATUS_SUCCESS;
- CLEANUP_SOURCE:
- pixman_image_unref (src);
-
- return status;
-}
-
-static inline uint32_t
-color_to_uint32 (const cairo_color_t *color)
-{
- return
- (color->alpha_short >> 8 << 24) |
- (color->red_short >> 8 << 16) |
- (color->green_short & 0xff00) |
- (color->blue_short >> 8);
-}
-
-static inline cairo_bool_t
-color_to_pixel (const cairo_color_t *color,
- pixman_format_code_t format,
- uint32_t *pixel)
-{
- uint32_t c;
-
- if (!(format == PIXMAN_a8r8g8b8 ||
- format == PIXMAN_x8r8g8b8 ||
- format == PIXMAN_a8b8g8r8 ||
- format == PIXMAN_x8b8g8r8 ||
- format == PIXMAN_b8g8r8a8 ||
- format == PIXMAN_b8g8r8x8 ||
- format == PIXMAN_r5g6b5 ||
- format == PIXMAN_b5g6r5 ||
- format == PIXMAN_a8))
- {
- return FALSE;
- }
-
- c = color_to_uint32 (color);
-
- if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
- c = ((c & 0xff000000) >> 0) |
- ((c & 0x00ff0000) >> 16) |
- ((c & 0x0000ff00) >> 0) |
- ((c & 0x000000ff) << 16);
- }
-
- if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
- c = ((c & 0xff000000) >> 24) |
- ((c & 0x00ff0000) >> 8) |
- ((c & 0x0000ff00) << 8) |
- ((c & 0x000000ff) << 24);
- }
-
- if (format == PIXMAN_a8) {
- c = c >> 24;
- } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
- c = ((((c) >> 3) & 0x001f) |
- (((c) >> 5) & 0x07e0) |
- (((c) >> 8) & 0xf800));
- }
-
- *pixel = c;
- return TRUE;
-}
-
-static inline cairo_bool_t
-pattern_to_pixel (const cairo_solid_pattern_t *solid,
- cairo_operator_t op,
- pixman_format_code_t format,
- uint32_t *pixel)
-{
- if (op == CAIRO_OPERATOR_CLEAR) {
- *pixel = 0;
- return TRUE;
- }
-
- if (solid->base.type != CAIRO_PATTERN_TYPE_SOLID)
- return FALSE;
-
- if (op == CAIRO_OPERATOR_OVER) {
- if (solid->color.alpha_short >= 0xff00)
- op = CAIRO_OPERATOR_SOURCE;
- }
-
- if (op != CAIRO_OPERATOR_SOURCE)
- return FALSE;
-
- return color_to_pixel (&solid->color, format, pixel);
-}
-
-typedef struct _fill_span {
- cairo_span_renderer_t base;
-
- uint8_t *mask_data;
- pixman_image_t *src, *dst, *mask;
-} fill_span_renderer_t;
-
-static cairo_status_t
-_fill_span (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- fill_span_renderer_t *renderer = abstract_renderer;
- uint8_t *row;
- unsigned i;
-
- if (num_spans == 0)
- return CAIRO_STATUS_SUCCESS;
-
- row = renderer->mask_data - spans[0].x;
- for (i = 0; i < num_spans - 1; i++) {
- /* We implement setting the most common single pixel wide
- * span case to avoid the overhead of a memset call.
- * Open coding setting longer spans didn't show a
- * noticeable improvement over memset.
- */
- if (spans[i+1].x == spans[i].x + 1) {
- row[spans[i].x] = spans[i].coverage;
- } else {
- memset (row + spans[i].x,
- spans[i].coverage,
- spans[i+1].x - spans[i].x);
- }
- }
-
- do {
- pixman_image_composite32 (PIXMAN_OP_OVER,
- renderer->src, renderer->mask, renderer->dst,
- 0, 0, 0, 0,
- spans[0].x, y++,
- spans[i].x - spans[0].x, 1);
- } while (--height);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* avoid using region code to re-validate boxes */
-static cairo_status_t
-_fill_unaligned_boxes (cairo_image_surface_t *dst,
- const cairo_pattern_t *pattern,
- uint32_t pixel,
- const cairo_boxes_t *boxes,
- const cairo_composite_rectangles_t *extents)
-{
- uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
- fill_span_renderer_t renderer;
- cairo_rectangular_scan_converter_t converter;
- const struct _cairo_boxes_chunk *chunk;
- cairo_status_t status;
- int i;
-
- /* XXX
- * using composite for fill:
- * spiral-box-nonalign-evenodd-fill.512 2201957 2.202
- * spiral-box-nonalign-nonzero-fill.512 336726 0.337
- * spiral-box-pixalign-evenodd-fill.512 352256 0.352
- * spiral-box-pixalign-nonzero-fill.512 147056 0.147
- * using fill:
- * spiral-box-nonalign-evenodd-fill.512 3174565 3.175
- * spiral-box-nonalign-nonzero-fill.512 182710 0.183
- * spiral-box-pixalign-evenodd-fill.512 353863 0.354
- * spiral-box-pixalign-nonzero-fill.512 147402 0.147
- *
- * cairo-perf-trace seems to favour using fill.
- */
-
- renderer.base.render_rows = _fill_span;
- renderer.dst = dst->pixman_image;
-
- if ((unsigned) extents->bounded.width <= sizeof (buf)) {
- renderer.mask = pixman_image_create_bits (PIXMAN_a8,
- extents->bounded.width, 1,
- (uint32_t *) buf,
- sizeof (buf));
- } else {
- renderer.mask = pixman_image_create_bits (PIXMAN_a8,
- extents->bounded.width, 1,
- NULL, 0);
- }
- if (unlikely (renderer.mask == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- renderer.mask_data = (uint8_t *) pixman_image_get_data (renderer.mask);
-
- renderer.src = _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
- if (unlikely (renderer.src == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto CLEANUP_MASK;
- }
-
- _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
-
- /* first blit any aligned part of the boxes */
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- const cairo_box_t *box = chunk->base;
-
- for (i = 0; i < chunk->count; i++) {
- int x1 = _cairo_fixed_integer_ceil (box[i].p1.x);
- int y1 = _cairo_fixed_integer_ceil (box[i].p1.y);
- int x2 = _cairo_fixed_integer_floor (box[i].p2.x);
- int y2 = _cairo_fixed_integer_floor (box[i].p2.y);
-
- if (x2 > x1 && y2 > y1) {
- cairo_box_t b;
-
- pixman_fill ((uint32_t *) dst->data,
- dst->stride / sizeof (uint32_t),
- PIXMAN_FORMAT_BPP (dst->pixman_format),
- x1, y1, x2 - x1, y2 - y1,
- pixel);
-
- /*
- * Corners have to be included only once if the rects
- * are passed to the rectangular scan converter
- * because it can only handle disjoint rectangles.
- */
-
- /* top (including top-left and top-right corners) */
- if (! _cairo_fixed_is_integer (box[i].p1.y)) {
- b.p1.x = box[i].p1.x;
- b.p1.y = box[i].p1.y;
- b.p2.x = box[i].p2.x;
- b.p2.y = _cairo_fixed_from_int (y1);
-
- status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
- if (unlikely (status))
- goto CLEANUP_CONVERTER;
- }
-
- /* left (no corners) */
- if (! _cairo_fixed_is_integer (box[i].p1.x)) {
- b.p1.x = box[i].p1.x;
- b.p1.y = _cairo_fixed_from_int (y1);
- b.p2.x = _cairo_fixed_from_int (x1);
- b.p2.y = _cairo_fixed_from_int (y2);
-
- status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
- if (unlikely (status))
- goto CLEANUP_CONVERTER;
- }
-
- /* right (no corners) */
- if (! _cairo_fixed_is_integer (box[i].p2.x)) {
- b.p1.x = _cairo_fixed_from_int (x2);
- b.p1.y = _cairo_fixed_from_int (y1);
- b.p2.x = box[i].p2.x;
- b.p2.y = _cairo_fixed_from_int (y2);
-
- status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
- if (unlikely (status))
- goto CLEANUP_CONVERTER;
- }
-
- /* bottom (including bottom-left and bottom-right corners) */
- if (! _cairo_fixed_is_integer (box[i].p2.y)) {
- b.p1.x = box[i].p1.x;
- b.p1.y = _cairo_fixed_from_int (y2);
- b.p2.x = box[i].p2.x;
- b.p2.y = box[i].p2.y;
-
- status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
- if (unlikely (status))
- goto CLEANUP_CONVERTER;
- }
- } else {
- status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
- if (unlikely (status))
- goto CLEANUP_CONVERTER;
- }
- }
- }
-
- status = converter.base.generate (&converter.base, &renderer.base);
-
- CLEANUP_CONVERTER:
- converter.base.destroy (&converter.base);
- pixman_image_unref (renderer.src);
- CLEANUP_MASK:
- pixman_image_unref (renderer.mask);
-
- return status;
-}
-
-typedef struct _cairo_image_surface_span_renderer {
- cairo_span_renderer_t base;
-
- uint8_t *mask_data;
- uint32_t mask_stride;
-} cairo_image_surface_span_renderer_t;
-
-static cairo_status_t
-_cairo_image_surface_span (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
- uint8_t *row;
- unsigned i;
-
- if (num_spans == 0)
- return CAIRO_STATUS_SUCCESS;
-
- /* XXX will it be quicker to repeat the sparse memset,
- * or perform a simpler memcpy?
- * The fairly dense spiral benchmarks suggests that the sparse
- * memset is a win there as well.
- */
- row = renderer->mask_data + y * renderer->mask_stride;
- do {
- for (i = 0; i < num_spans - 1; i++) {
- if (! spans[i].coverage)
- continue;
-
- /* We implement setting rendering the most common single
- * pixel wide span case to avoid the overhead of a memset
- * call. Open coding setting longer spans didn't show a
- * noticeable improvement over memset. */
- if (spans[i+1].x == spans[i].x + 1) {
- row[spans[i].x] = spans[i].coverage;
- } else {
- memset (row + spans[i].x,
- spans[i].coverage,
- spans[i+1].x - spans[i].x);
- }
- }
- row += renderer->mask_stride;
- } while (--height);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_composite_unaligned_boxes (cairo_image_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- const cairo_boxes_t *boxes,
- const cairo_composite_rectangles_t *extents)
-{
- uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
- cairo_image_surface_span_renderer_t renderer;
- cairo_rectangular_scan_converter_t converter;
- pixman_image_t *mask, *src;
- cairo_status_t status;
- const struct _cairo_boxes_chunk *chunk;
- int i, src_x, src_y;
-
- /* The below code breaks for operator source. This can best be seen with
- * multiple boxes where black is drawn to dst outside of the boxes. */
- if (op == CAIRO_OPERATOR_SOURCE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- i = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8) * extents->bounded.height;
- if ((unsigned) i <= sizeof (buf)) {
- mask = pixman_image_create_bits (PIXMAN_a8,
- extents->bounded.width,
- extents->bounded.height,
- (uint32_t *) buf,
- CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8));
- memset (buf, 0, i);
- } else {
- mask = pixman_image_create_bits (PIXMAN_a8,
- extents->bounded.width,
- extents->bounded.height,
- NULL, 0);
- }
- if (unlikely (mask == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- renderer.base.render_rows = _cairo_image_surface_span;
- renderer.mask_stride = pixman_image_get_stride (mask);
- renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
- renderer.mask_data -= extents->bounded.y * renderer.mask_stride + extents->bounded.x;
-
- _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
-
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- const cairo_box_t *box = chunk->base;
-
- for (i = 0; i < chunk->count; i++) {
- status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
- if (unlikely (status))
- goto CLEANUP;
- }
- }
-
- status = converter.base.generate (&converter.base, &renderer.base);
- if (unlikely (status))
- goto CLEANUP;
-
- src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
- &dst->base.device_transform,
- &src_x, &src_y);
- if (unlikely (src == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto CLEANUP;
- }
-
- pixman_image_composite32 (_pixman_operator (op),
- src, mask, dst->pixman_image,
- extents->bounded.x + src_x, extents->bounded.y + src_y,
- 0, 0,
- extents->bounded.x, extents->bounded.y,
- extents->bounded.width, extents->bounded.height);
- pixman_image_unref (src);
-
- CLEANUP:
- converter.base.destroy (&converter.base);
- pixman_image_unref (mask);
-
- return status;
-}
-
-static cairo_bool_t
-is_recording_pattern (const cairo_pattern_t *pattern)
-{
- cairo_surface_t *surface;
-
- if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
- return FALSE;
-
- surface = ((const cairo_surface_pattern_t *) pattern)->surface;
- if (_cairo_surface_is_paginated (surface))
- surface = _cairo_paginated_surface_get_recording (surface);
- if (_cairo_surface_is_snapshot (surface))
- surface = _cairo_surface_snapshot_get_target (surface);
- return _cairo_surface_is_recording (surface);
-}
-
-static cairo_surface_t *
-recording_pattern_get_surface (const cairo_pattern_t *pattern)
-{
- cairo_surface_t *surface;
-
- surface = ((const cairo_surface_pattern_t *) pattern)->surface;
- if (_cairo_surface_is_paginated (surface))
- surface = _cairo_paginated_surface_get_recording (surface);
- if (_cairo_surface_is_snapshot (surface))
- surface = _cairo_surface_snapshot_get_target (surface);
- return surface;
-}
-
-static cairo_bool_t
-op_reduces_to_source (cairo_operator_t op,
- cairo_image_surface_t *dst)
-{
- if (op == CAIRO_OPERATOR_SOURCE)
- return TRUE;
-
- if (dst->base.is_clear)
- return op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD;
-
- return FALSE;
-}
-
-static cairo_bool_t
-recording_pattern_contains_sample (const cairo_pattern_t *pattern,
- const cairo_rectangle_int_t *extents)
-{
- cairo_rectangle_int_t area;
- cairo_recording_surface_t *surface;
-
- if (! is_recording_pattern (pattern))
- return FALSE;
-
- if (pattern->extend == CAIRO_EXTEND_NONE)
- return TRUE;
-
- surface = (cairo_recording_surface_t *) recording_pattern_get_surface (pattern);
- if (surface->unbounded)
- return TRUE;
-
- sampled_area ((cairo_surface_pattern_t *) pattern, extents, &area);
- if (area.x >= surface->extents.x &&
- area.y >= surface->extents.y &&
- area.x + area.width <= surface->extents.x + surface->extents.width &&
- area.y + area.height <= surface->extents.y + surface->extents.height)
- {
- return TRUE;
- }
-
- return FALSE;
-}
-
-static cairo_status_t
-_composite_boxes (cairo_image_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_boxes_t *boxes,
- const cairo_composite_rectangles_t *extents)
-{
- cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
- cairo_bool_t need_clip_mask = extents->clip->path != NULL;
- cairo_status_t status;
- struct _cairo_boxes_chunk *chunk;
- uint32_t pixel;
- int i;
-
- if (need_clip_mask &&
- (op == CAIRO_OPERATOR_SOURCE || ! extents->is_bounded))
- {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
- clip_region = NULL;
-
- if (! boxes->is_pixel_aligned) {
- if (need_clip_mask)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op,
- dst->pixman_format, &pixel))
- {
- return _fill_unaligned_boxes (dst, pattern, pixel, boxes, extents);
- }
- else
- {
- return _composite_unaligned_boxes (dst, op, pattern, boxes, extents);
- }
- }
-
- /* Are we just copying a recording surface? */
- if (! need_clip_mask &&
- op_reduces_to_source (op, dst) &&
- recording_pattern_contains_sample (pattern, &extents->bounded))
- {
- cairo_clip_t *recording_clip;
-
- /* XXX could also do tiling repeat modes... */
-
- /* first clear the area about to be overwritten */
- if (! dst->base.is_clear) {
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- cairo_box_t *box = chunk->base;
-
- for (i = 0; i < chunk->count; i++) {
- int x1 = _cairo_fixed_integer_part (box[i].p1.x);
- int y1 = _cairo_fixed_integer_part (box[i].p1.y);
- int x2 = _cairo_fixed_integer_part (box[i].p2.x);
- int y2 = _cairo_fixed_integer_part (box[i].p2.y);
-
- if (x2 == x1 || y2 == y1)
- continue;
-
- pixman_fill ((uint32_t *) dst->data,
- dst->stride / sizeof (uint32_t),
- PIXMAN_FORMAT_BPP (dst->pixman_format),
- x1, y1, x2 - x1, y2 - y1,
- 0);
- }
- }
- }
-
- recording_clip = _cairo_clip_from_boxes (boxes);
- status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (pattern),
- &pattern->matrix,
- &dst->base,
- recording_clip);
- _cairo_clip_destroy (recording_clip);
-
- return status;
- }
-
- status = CAIRO_STATUS_SUCCESS;
- if (! need_clip_mask &&
- pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, dst->pixman_format,
- &pixel))
- {
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- cairo_box_t *box = chunk->base;
-
- for (i = 0; i < chunk->count; i++) {
- int x1 = _cairo_fixed_integer_part (box[i].p1.x);
- int y1 = _cairo_fixed_integer_part (box[i].p1.y);
- int x2 = _cairo_fixed_integer_part (box[i].p2.x);
- int y2 = _cairo_fixed_integer_part (box[i].p2.y);
-
- if (x2 == x1 || y2 == y1)
- continue;
-
- pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
- PIXMAN_FORMAT_BPP (dst->pixman_format),
- x1, y1, x2 - x1, y2 - y1,
- pixel);
- }
- }
- }
- else
- {
- cairo_surface_t *clip_surface = NULL;
- pixman_image_t *src = NULL, *mask = NULL;
- int src_x, src_y, mask_x = 0, mask_y = 0;
- pixman_op_t pixman_op = _pixman_operator (op);
-
- if (need_clip_mask) {
- int clip_x, clip_y;
-
- clip_surface = _cairo_clip_get_surface (extents->clip,
- &dst->base,
- &clip_x, &clip_y);
- if (unlikely (clip_surface->status))
- return clip_surface->status;
-
- mask_x = -clip_x;
- mask_y = -clip_y;
-
- if (op == CAIRO_OPERATOR_CLEAR) {
- pattern = NULL;
- pixman_op = PIXMAN_OP_OUT_REVERSE;
- }
-
- mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
- }
-
- if (pattern != NULL) {
- src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
- &dst->base.device_transform,
- &src_x, &src_y);
- if (unlikely (src == NULL)) {
- cairo_surface_destroy (clip_surface);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
- } else {
- src = mask;
- src_x = mask_x;
- src_y = mask_y;
- mask = NULL;
- }
-
- for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- const cairo_box_t *box = chunk->base;
-
- for (i = 0; i < chunk->count; i++) {
- int x1 = _cairo_fixed_integer_part (box[i].p1.x);
- int y1 = _cairo_fixed_integer_part (box[i].p1.y);
- int x2 = _cairo_fixed_integer_part (box[i].p2.x);
- int y2 = _cairo_fixed_integer_part (box[i].p2.y);
-
- if (x2 == x1 || y2 == y1)
- continue;
-
- pixman_image_composite32 (pixman_op,
- src, mask, dst->pixman_image,
- x1 + src_x, y1 + src_y,
- x1 + mask_x, y1 + mask_y,
- x1, y1,
- x2 - x1, y2 - y1);
- }
- }
-
- cairo_surface_destroy (clip_surface);
- if (pattern != NULL)
- pixman_image_unref (src);
-
- if (! extents->is_bounded) {
- status =
- _cairo_image_surface_fixup_unbounded_boxes (dst, extents,
- clip_region, boxes);
- }
- }
-
- return status;
-}
-
-static cairo_status_t
-_clip_and_composite_polygon (cairo_image_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_polygon_t *polygon,
- cairo_fill_rule_t fill_rule,
- cairo_antialias_t antialias,
- cairo_composite_rectangles_t *extents);
-
-static cairo_status_t
-_clip_and_composite_boxes (cairo_image_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_boxes_t *boxes,
- cairo_composite_rectangles_t *extents)
-{
- cairo_traps_t traps;
- cairo_int_status_t status;
- composite_traps_info_t info;
-
- if (boxes->num_boxes == 0 && extents->is_bounded)
- return CAIRO_STATUS_SUCCESS;
-
- /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
- if (extents->clip->path != NULL && extents->is_bounded) {
- cairo_polygon_t polygon;
- cairo_fill_rule_t fill_rule;
- cairo_antialias_t antialias;
- cairo_clip_t *clip;
-
- clip = _cairo_clip_copy (extents->clip);
- clip = _cairo_clip_intersect_boxes (clip, boxes);
- status = _cairo_clip_get_polygon (clip, &polygon,
- &fill_rule, &antialias);
- _cairo_clip_path_destroy (clip->path);
- clip->path = NULL;
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- cairo_clip_t *saved_clip = extents->clip;
- extents->clip = clip;
- status = _clip_and_composite_polygon (dst, op, src,
- &polygon,
- fill_rule,
- antialias,
- extents);
- if (extents->clip != clip)
- clip = NULL;
- extents->clip = saved_clip;
- _cairo_polygon_fini (&polygon);
- }
- if (clip)
- _cairo_clip_destroy (clip);
-
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
- /* Use a fast path if the boxes are pixel aligned */
- status = _composite_boxes (dst, op, src, boxes, extents);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- /* Otherwise render via a mask and composite in the usual fashion. */
- status = _cairo_traps_init_boxes (&traps, boxes);
- if (unlikely (status))
- return status;
-
- info.num_traps = traps.num_traps;
- info.traps = traps.traps;
- info.antialias = CAIRO_ANTIALIAS_DEFAULT;
- status = _clip_and_composite (dst, op, src,
- _composite_traps, &info,
- extents, need_unbounded_clip (extents));
-
- _cairo_traps_fini (&traps);
- return status;
-}
-
-static cairo_bool_t
-_mono_edge_is_vertical (const cairo_line_t *line)
-{
- return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x);
-}
-
-static cairo_bool_t
-_traps_are_pixel_aligned (cairo_traps_t *traps,
- cairo_antialias_t antialias)
-{
- int i;
-
- if (antialias == CAIRO_ANTIALIAS_NONE) {
- for (i = 0; i < traps->num_traps; i++) {
- if (! _mono_edge_is_vertical (&traps->traps[i].left) ||
- ! _mono_edge_is_vertical (&traps->traps[i].right))
- {
- traps->maybe_region = FALSE;
- return FALSE;
- }
- }
- } else {
- 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 ||
- ! _cairo_fixed_is_integer (traps->traps[i].top) ||
- ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
- ! _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 FALSE;
- }
- }
- }
-
- return TRUE;
-}
-
-static void
-_boxes_for_traps (cairo_boxes_t *boxes,
- cairo_traps_t *traps,
- cairo_antialias_t antialias)
-{
- int i;
-
- _cairo_boxes_init (boxes);
-
- boxes->num_boxes = traps->num_traps;
- boxes->chunks.base = (cairo_box_t *) traps->traps;
- boxes->chunks.count = traps->num_traps;
- boxes->chunks.size = traps->num_traps;
-
- if (antialias != CAIRO_ANTIALIAS_NONE) {
- for (i = 0; i < traps->num_traps; i++) {
- /* Note the traps and boxes alias so we need to take the local copies first. */
- cairo_fixed_t x1 = traps->traps[i].left.p1.x;
- cairo_fixed_t x2 = traps->traps[i].right.p1.x;
- cairo_fixed_t y1 = traps->traps[i].top;
- cairo_fixed_t y2 = traps->traps[i].bottom;
-
- boxes->chunks.base[i].p1.x = x1;
- boxes->chunks.base[i].p1.y = y1;
- boxes->chunks.base[i].p2.x = x2;
- boxes->chunks.base[i].p2.y = y2;
-
- if (boxes->is_pixel_aligned) {
- boxes->is_pixel_aligned =
- _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
- _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
- }
- }
- } else {
- boxes->is_pixel_aligned = TRUE;
-
- for (i = 0; i < traps->num_traps; i++) {
- /* Note the traps and boxes alias so we need to take the local copies first. */
- cairo_fixed_t x1 = traps->traps[i].left.p1.x;
- cairo_fixed_t x2 = traps->traps[i].right.p1.x;
- cairo_fixed_t y1 = traps->traps[i].top;
- cairo_fixed_t y2 = traps->traps[i].bottom;
-
- /* round down here to match Pixman's behavior when using traps. */
- boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
- boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
- boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
- boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
- }
- }
-}
-
-static cairo_status_t
-_clip_and_composite_trapezoids (cairo_image_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_traps_t *traps,
- cairo_antialias_t antialias,
- cairo_composite_rectangles_t *extents)
-{
- composite_traps_info_t info;
- cairo_bool_t need_clip_surface = FALSE;
- cairo_status_t status;
-
- if (traps->num_traps == 0 && extents->is_bounded)
- return CAIRO_STATUS_SUCCESS;
-
- need_clip_surface = ! _cairo_clip_is_region (extents->clip);
-
- if (traps->has_intersections) {
- if (traps->is_rectangular)
- status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
- else if (traps->is_rectilinear)
- status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
- else
- status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
- if (unlikely (status))
- return status;
- }
-
- /* 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 (traps->maybe_region && _traps_are_pixel_aligned (traps, antialias) &&
- (! need_clip_surface ||
- (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
- {
- cairo_boxes_t boxes;
-
- _boxes_for_traps (&boxes, traps, antialias);
- return _clip_and_composite_boxes (dst, op, src,
- &boxes, extents);
- }
-
- /* No fast path, exclude self-intersections and clip trapezoids. */
- /* Otherwise render the trapezoids to a mask and composite in the usual
- * fashion.
- */
- info.traps = traps->traps;
- info.num_traps = traps->num_traps;
- info.antialias = antialias;
- return _clip_and_composite (dst, op, src,
- _composite_traps, &info,
- extents, need_unbounded_clip (extents));
-}
-
/* high level image interface */
cairo_bool_t
_cairo_image_surface_get_extents (void *abstract_surface,
@@ -3449,235 +859,10 @@ _cairo_image_surface_paint (void *abstract_surface,
const cairo_clip_t *clip)
{
cairo_image_surface_t *surface = abstract_surface;
- cairo_rectangle_int_t unbounded;
- cairo_composite_rectangles_t extents;
- cairo_status_t status;
- cairo_boxes_t boxes;
-
- _cairo_image_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
- op, source,
- clip);
- if (unlikely (status))
- return status;
-
- /* If the clip cannot be reduced to a set of boxes, we will need to
- * use a clipmask. Paint is special as it is the only operation that
- * does not implicitly use a mask, so we may be able to reduce this
- * operation to a fill...
- */
-
- status = _cairo_clip_to_boxes (extents.clip, &boxes);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _clip_and_composite_boxes (surface, op, source,
- &boxes, &extents);
- _cairo_boxes_fini (&boxes);
- }
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
-}
-
-static cairo_status_t
-_composite_mask (void *closure,
- pixman_image_t *dst,
- pixman_format_code_t dst_format,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- int dst_x,
- int dst_y,
- cairo_matrix_t *dst_device_transform,
- const cairo_composite_rectangles_t *extents)
-{
- const cairo_pattern_t *mask_pattern = closure;
- pixman_image_t *src, *mask = NULL;
- int src_x = 0, src_y = 0;
- int mask_x = 0, mask_y = 0;
-
- if (src_pattern != NULL) {
- src = _pixman_image_for_pattern (src_pattern, FALSE, &extents->bounded,
- dst_device_transform,
- &src_x, &src_y);
- if (unlikely (src == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents->bounded,
- dst_device_transform,
- &mask_x, &mask_y);
- if (unlikely (mask == NULL)) {
- pixman_image_unref (src);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- if (mask_pattern->has_component_alpha)
- pixman_image_set_component_alpha (mask, TRUE);
- } else {
- src = _pixman_image_for_pattern (mask_pattern, FALSE, &extents->bounded,
- dst_device_transform,
- &src_x, &src_y);
- if (unlikely (src == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
- extents->bounded.x + src_x, extents->bounded.y + src_y,
- extents->bounded.x + mask_x, extents->bounded.y + mask_y,
- extents->bounded.x - dst_x, extents->bounded.y - dst_y,
- extents->bounded.width, extents->bounded.height);
-
- if (mask != NULL)
- pixman_image_unref (mask);
- pixman_image_unref (src);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void do_unaligned_row(void (*blt)(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage),
- void *closure,
- const cairo_box_t *b,
- int tx, int y, int h,
- uint16_t coverage)
-{
- int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
- int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
- if (x2 > x1) {
- if (! _cairo_fixed_is_integer (b->p1.x)) {
- blt(closure, x1, y, 1, h,
- coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
- x1++;
- }
-
- if (x2 > x1)
- blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
-
- if (! _cairo_fixed_is_integer (b->p2.x))
- blt(closure, x2, y, 1, h,
- coverage * _cairo_fixed_fractional_part (b->p2.x));
- } else
- blt(closure, x1, y, 1, h,
- coverage * (b->p2.x - b->p1.x));
-}
-
-static void do_unaligned_box(void (*blt)(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage),
- void *closure,
- const cairo_box_t *b, int tx, int ty)
-{
- int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
- int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
- if (y2 > y1) {
- if (! _cairo_fixed_is_integer (b->p1.y)) {
- do_unaligned_row(blt, closure, b, tx, y1, 1,
- 256 - _cairo_fixed_fractional_part (b->p1.y));
- y1++;
- }
-
- if (y2 > y1)
- do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
-
- if (! _cairo_fixed_is_integer (b->p2.y))
- do_unaligned_row(blt, closure, b, tx, y2, 1,
- _cairo_fixed_fractional_part (b->p2.y));
- } else
- do_unaligned_row(blt, closure, b, tx, y1, 1,
- b->p2.y - b->p1.y);
-}
-
-struct composite_opacity_info {
- uint8_t op;
- pixman_image_t *dst;
- pixman_image_t *src;
- int src_x, src_y;
- double opacity;
-};
-
-static void composite_opacity(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage)
-{
- struct composite_opacity_info *info = closure;
- pixman_color_t color;
- pixman_image_t *mask;
-
- color.red = 0;
- color.green = 0;
- color.blue = 0;
- color.alpha = coverage * info->opacity;
-
- mask = pixman_image_create_solid_fill (&color);
- if (mask == NULL)
- return;
-
- if (info->src) {
- pixman_image_composite32 (info->op,
- info->src,
- mask,
- info->dst,
- x + info->src_x, y + info->src_y,
- 0, 0,
- x, y,
- w, h);
- } else {
- pixman_image_composite32 (info->op,
- mask,
- NULL,
- info->dst,
- 0, 0,
- 0, 0,
- x, y,
- w, h);
- }
-
- pixman_image_unref (mask);
+ return _cairo_compositor_paint (surface->compositor,
+ &surface->base, op, source, clip);
}
-static cairo_status_t
-_composite_opacity_boxes (void *closure,
- pixman_image_t *dst,
- pixman_format_code_t dst_format,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- int dst_x,
- int dst_y,
- cairo_matrix_t *dst_device_transform,
- const cairo_composite_rectangles_t *extents)
-{
- const cairo_solid_pattern_t *mask_pattern = closure;
- struct composite_opacity_info info;
- int i;
-
- info.op = _pixman_operator (op);
- info.dst = dst;
-
- if (src_pattern != NULL) {
- info.src = _pixman_image_for_pattern (src_pattern, TRUE, &extents->bounded,
- dst_device_transform,
- &info.src_x, &info.src_y);
- if (unlikely (info.src == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- } else
- info.src = NULL;
-
- info.opacity = mask_pattern->color.alpha;
-
- /* XXX for lots of boxes create a clip region for the fully opaque areas */
- for (i = 0; i < extents->clip->num_boxes; i++)
- do_unaligned_box(composite_opacity, &info,
- &extents->clip->boxes[i], dst_x, dst_y);
- if (info.src)
- pixman_image_unref (info.src);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
static cairo_int_status_t
_cairo_image_surface_mask (void *abstract_surface,
cairo_operator_t op,
@@ -3686,225 +871,8 @@ _cairo_image_surface_mask (void *abstract_surface,
const cairo_clip_t *clip)
{
cairo_image_surface_t *surface = abstract_surface;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
- cairo_status_t status;
-
- _cairo_image_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_mask (&extents, &unbounded,
- op, source, mask, clip);
- if (unlikely (status))
- return status;
-
- if (mask->type == CAIRO_PATTERN_TYPE_SOLID &&
- extents.clip->path == NULL &&
- ! _cairo_clip_is_region (extents.clip))
- {
- status = _clip_and_composite (surface, op, source,
- _composite_opacity_boxes, (void *) mask,
- &extents, need_bounded_clip (&extents));
- } else {
- status = _clip_and_composite (surface, op, source,
- _composite_mask, (void *) mask,
- &extents, need_bounded_clip (&extents));
- }
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
-}
-
-typedef struct {
- cairo_polygon_t *polygon;
- cairo_fill_rule_t fill_rule;
- cairo_antialias_t antialias;
-} composite_spans_info_t;
-
-//#define USE_BOTOR_SCAN_CONVERTER
-static cairo_status_t
-_composite_spans (void *closure,
- pixman_image_t *dst,
- pixman_format_code_t dst_format,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- int dst_x,
- int dst_y,
- cairo_matrix_t *dst_device_transform,
- const cairo_composite_rectangles_t *extents)
-{
- uint8_t mask_buf[CAIRO_STACK_BUFFER_SIZE];
- composite_spans_info_t *info = closure;
- cairo_image_surface_span_renderer_t renderer;
-#if USE_BOTOR_SCAN_CONVERTER
- cairo_box_t box;
- cairo_botor_scan_converter_t converter;
-#else
- cairo_scan_converter_t *converter;
-#endif
- pixman_image_t *mask;
- const cairo_rectangle_int_t *r = &extents->bounded;
- cairo_status_t status;
-
-#if USE_BOTOR_SCAN_CONVERTER
- box.p1.x = _cairo_fixed_from_int (r->x);
- box.p1.y = _cairo_fixed_from_int (r->y);
- box.p2.x = _cairo_fixed_from_int (r->x + r->width);
- box.p2.y = _cairo_fixed_from_int (r->y + r->height);
- _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
- status = converter.base.add_polygon (&converter.base, info->polygon);
-#else
- converter = _cairo_tor_scan_converter_create (r->x, r->y,
- r->x + r->width,
- r->y + r->height,
- info->fill_rule);
- status = converter->add_polygon (converter, info->polygon);
-#endif
- if (unlikely (status))
- goto CLEANUP_CONVERTER;
-
- /* TODO: support rendering to A1 surfaces (or: go add span
- * compositing to pixman.) */
-
- if (pattern == NULL &&
- dst_format == PIXMAN_a8 &&
- op == CAIRO_OPERATOR_SOURCE)
- {
- mask = dst;
- dst = NULL;
- }
- else
- {
- int stride = CAIRO_STRIDE_FOR_WIDTH_BPP (r->width, 8);
- uint8_t *data = mask_buf;
-
- if (r->height * stride <= (int) sizeof (mask_buf))
- memset (data, 0, r->height * stride);
- else
- data = NULL, stride = 0;
-
- mask = pixman_image_create_bits (PIXMAN_a8,
- r->width,
- r->height,
- (uint32_t *) data,
- stride);
- if (unlikely (mask == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto CLEANUP_CONVERTER;
- }
- }
-
- renderer.base.render_rows = _cairo_image_surface_span;
- renderer.mask_stride = pixman_image_get_stride (mask);
- renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
- if (dst != NULL)
- renderer.mask_data -= r->y * renderer.mask_stride + r->x;
- else
- renderer.mask_data -= dst_y * renderer.mask_stride + dst_x;
-
-#if USE_BOTOR_SCAN_CONVERTER
- status = converter.base.generate (&converter.base, &renderer.base);
-#else
- status = converter->generate (converter, &renderer.base);
-#endif
- if (unlikely (status))
- goto CLEANUP_RENDERER;
-
- if (dst != NULL) {
- pixman_image_t *src;
- int src_x, src_y;
-
- src = _pixman_image_for_pattern (pattern, FALSE, r,
- dst_device_transform,
- &src_x, &src_y);
- if (unlikely (src == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto CLEANUP_RENDERER;
- }
-
- pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
- r->x + src_x, r->y + src_y,
- 0, 0, /* mask.x, mask.y */
- r->x - dst_x, r->y - dst_y,
- r->width, r->height);
- pixman_image_unref (src);
- }
-
- CLEANUP_RENDERER:
- if (dst != NULL)
- pixman_image_unref (mask);
- CLEANUP_CONVERTER:
-#if USE_BOTOR_SCAN_CONVERTER
- converter.base.destroy (&converter.base);
-#else
- converter->destroy (converter);
-#endif
- return status;
-}
-
-static cairo_status_t
-_clip_and_composite_polygon (cairo_image_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_polygon_t *polygon,
- cairo_fill_rule_t fill_rule,
- cairo_antialias_t antialias,
- cairo_composite_rectangles_t *extents)
-{
- cairo_status_t status;
-
- if (_cairo_polygon_is_empty (polygon)) {
- cairo_boxes_t boxes;
-
- if (extents->is_bounded)
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_clip_to_boxes (extents->clip, &boxes);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- extents->is_bounded = _cairo_operator_bounded_by_either (op);
- extents->mask = extents->bounded = extents->unbounded;
- status = _clip_and_composite_boxes (dst,
- CAIRO_OPERATOR_CLEAR,
- &_cairo_pattern_clear.base,
- &boxes, extents);
- _cairo_boxes_fini (&boxes);
- }
-
- return status;
- }
-
- _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
- if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask))
- return CAIRO_STATUS_SUCCESS;
-
- if (antialias != CAIRO_ANTIALIAS_NONE) {
- composite_spans_info_t info;
-
- info.polygon = polygon;
- info.fill_rule = fill_rule;
- info.antialias = antialias;
-
- status = _clip_and_composite (dst, op, src,
- _composite_spans, &info,
- extents, need_unbounded_clip (extents));
- } else {
- cairo_traps_t traps;
-
- _cairo_traps_init (&traps);
-
- /* Fall back to trapezoid fills. */
- status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
- polygon,
- fill_rule);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _clip_and_composite_trapezoids (dst, op, src,
- &traps, antialias,
- extents);
- }
-
- _cairo_traps_fini (&traps);
- }
-
- return status;
+ return _cairo_compositor_mask (surface->compositor,
+ &surface->base, op, source, mask, clip);
}
static cairo_int_status_t
@@ -3920,56 +888,10 @@ _cairo_image_surface_stroke (void *abstract_surface,
const cairo_clip_t *clip)
{
cairo_image_surface_t *surface = abstract_surface;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
- cairo_int_status_t status;
-
- _cairo_image_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
- op, source,
- path, style, ctm,
- clip);
- if (unlikely (status))
- return status;
-
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
- cairo_boxes_t boxes;
-
- _cairo_boxes_init_with_clip (&boxes, extents.clip);
- status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
- style,
- ctm,
- antialias,
- &boxes);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- status = _clip_and_composite_boxes (surface, op, source,
- &boxes, &extents);
- }
- _cairo_boxes_fini (&boxes);
- }
-
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- cairo_polygon_t polygon;
-
- _cairo_polygon_init_with_clip (&polygon, extents.clip);
- status = _cairo_path_fixed_stroke_to_polygon (path,
- style,
- ctm, ctm_inverse,
- tolerance,
- &polygon);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- status = _clip_and_composite_polygon (surface, op, source, &polygon,
- CAIRO_FILL_RULE_WINDING,
- antialias,
- &extents);
- }
- _cairo_polygon_fini (&polygon);
- }
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
+ return _cairo_compositor_stroke (surface->compositor, &surface->base,
+ op, source, path,
+ style, ctm, ctm_inverse,
+ tolerance, antialias, clip);
}
static cairo_int_status_t
@@ -3983,291 +905,10 @@ _cairo_image_surface_fill (void *abstract_surface,
const cairo_clip_t *clip)
{
cairo_image_surface_t *surface = abstract_surface;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
- cairo_status_t status;
-
- _cairo_image_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
- op, source, path,
- clip);
- if (unlikely (status))
- return status;
-
- if (_cairo_path_fixed_fill_is_rectilinear (path)) {
- cairo_boxes_t boxes;
-
- _cairo_boxes_init_with_clip (&boxes, extents.clip);
- status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
- fill_rule,
- antialias,
- &boxes);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _clip_and_composite_boxes (surface, op, source,
- &boxes, &extents);
- }
- _cairo_boxes_fini (&boxes);
- } else {
- cairo_polygon_t polygon;
-
- assert (! _cairo_path_fixed_fill_is_empty (path));
-
- _cairo_polygon_init_with_clip (&polygon, extents.clip);
- status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _clip_and_composite_polygon (surface, op, source, &polygon,
- fill_rule, antialias,
- &extents);
- }
- _cairo_polygon_fini (&polygon);
- }
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
-}
-
-typedef struct {
- cairo_scaled_font_t *font;
- cairo_glyph_t *glyphs;
- int num_glyphs;
-} composite_glyphs_info_t;
-
-static cairo_status_t
-_composite_glyphs_via_mask (void *closure,
- pixman_image_t *dst,
- pixman_format_code_t dst_format,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- int dst_x,
- int dst_y,
- cairo_matrix_t *dst_device_transform,
- const cairo_composite_rectangles_t *extents)
-{
- composite_glyphs_info_t *info = closure;
- cairo_scaled_font_t *font = info->font;
- cairo_glyph_t *glyphs = info->glyphs;
- int num_glyphs = info->num_glyphs;
- pixman_image_t *mask = NULL;
- pixman_image_t *src;
- pixman_image_t *white;
- pixman_format_code_t mask_format = 0; /* silence gcc */
- cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence gcc */
- int src_x, src_y;
- int i;
-
- src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
- dst_device_transform,
- &src_x, &src_y);
- if (unlikely (src == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- white = _pixman_white_image ();
- if (unlikely (white == NULL)) {
- pixman_image_unref (src);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- _cairo_scaled_font_freeze_cache (font);
-
- for (i = 0; i < num_glyphs; i++) {
- int x, y;
- cairo_image_surface_t *glyph_surface;
- cairo_scaled_glyph_t *scaled_glyph;
-
- status = _cairo_scaled_glyph_lookup (font, glyphs[i].index,
- CAIRO_SCALED_GLYPH_INFO_SURFACE,
- &scaled_glyph);
-
- if (unlikely (status))
- goto CLEANUP;
-
- glyph_surface = scaled_glyph->surface;
-
- if (glyph_surface->width == 0 || glyph_surface->height == 0)
- continue;
-
- /* To start, create the mask using the format from the first
- * glyph. Later we'll deal with different formats. */
- if (mask == NULL) {
- mask_format = glyph_surface->pixman_format;
- mask = pixman_image_create_bits (mask_format,
- extents->bounded.width,
- extents->bounded.height,
- NULL, 0);
- if (unlikely (mask == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto CLEANUP;
- }
-
- if (PIXMAN_FORMAT_RGB (mask_format))
- pixman_image_set_component_alpha (mask, TRUE);
- }
-
- /* If we have glyphs of different formats, we "upgrade" the mask
- * to the wider of the formats. */
- if (glyph_surface->pixman_format != mask_format &&
- PIXMAN_FORMAT_BPP (mask_format) <
- PIXMAN_FORMAT_BPP (glyph_surface->pixman_format))
- {
- pixman_image_t *new_mask;
-
- mask_format = glyph_surface->pixman_format;
- new_mask = pixman_image_create_bits (mask_format,
- extents->bounded.width,
- extents->bounded.height,
- NULL, 0);
- if (unlikely (new_mask == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto CLEANUP;
- }
-
- pixman_image_composite32 (PIXMAN_OP_SRC,
- white, mask, new_mask,
- 0, 0, 0, 0, 0, 0,
- extents->bounded.width,
- extents->bounded.height);
-
- pixman_image_unref (mask);
- mask = new_mask;
- if (PIXMAN_FORMAT_RGB (mask_format))
- pixman_image_set_component_alpha (mask, TRUE);
- }
-
- /* round glyph locations to the nearest pixel */
- /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
- x = _cairo_lround (glyphs[i].x -
- glyph_surface->base.device_transform.x0);
- y = _cairo_lround (glyphs[i].y -
- glyph_surface->base.device_transform.y0);
- if (glyph_surface->pixman_format == mask_format) {
- pixman_image_composite32 (PIXMAN_OP_ADD,
- glyph_surface->pixman_image, NULL, mask,
- 0, 0, 0, 0,
- x - extents->bounded.x, y - extents->bounded.y,
- glyph_surface->width,
- glyph_surface->height);
- } else {
- pixman_image_composite32 (PIXMAN_OP_ADD,
- white, glyph_surface->pixman_image, mask,
- 0, 0, 0, 0,
- x - extents->bounded.x, y - extents->bounded.y,
- glyph_surface->width,
- glyph_surface->height);
- }
- }
-
- pixman_image_composite32 (_pixman_operator (op),
- src, mask, dst,
- extents->bounded.x + src_x, extents->bounded.y + src_y,
- 0, 0,
- extents->bounded.x - dst_x, extents->bounded.y - dst_y,
- extents->bounded.width, extents->bounded.height);
-
-CLEANUP:
- _cairo_scaled_font_thaw_cache (font);
- if (mask != NULL)
- pixman_image_unref (mask);
- pixman_image_unref (src);
- pixman_image_unref (white);
-
- return status;
-}
-
-static cairo_status_t
-_composite_glyphs (void *closure,
- pixman_image_t *dst,
- pixman_format_code_t dst_format,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- int dst_x,
- int dst_y,
- cairo_matrix_t *dst_device_transform,
- const cairo_composite_rectangles_t *extents)
-{
- composite_glyphs_info_t *info = closure;
- cairo_scaled_glyph_t *glyph_cache[64];
- pixman_op_t pixman_op = _pixman_operator (op);
- pixman_image_t *src = NULL;
- int src_x = 0, src_y = 0;
- cairo_status_t status;
- int i;
-
- if (pattern != NULL) {
- src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
- dst_device_transform,
- &src_x, &src_y);
- src_x -= dst_x;
- src_y -= dst_y;
- } else {
- src = _pixman_white_image ();
- }
- if (unlikely (src == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- memset (glyph_cache, 0, sizeof (glyph_cache));
- status = CAIRO_STATUS_SUCCESS;
-
- _cairo_scaled_font_freeze_cache (info->font);
- for (i = 0; i < info->num_glyphs; i++) {
- int x, y;
- cairo_image_surface_t *glyph_surface;
- cairo_scaled_glyph_t *scaled_glyph;
- unsigned long glyph_index = info->glyphs[i].index;
- int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
-
- scaled_glyph = glyph_cache[cache_index];
- if (scaled_glyph == NULL ||
- _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
- {
- status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
- CAIRO_SCALED_GLYPH_INFO_SURFACE,
- &scaled_glyph);
-
- if (unlikely (status))
- break;
-
- glyph_cache[cache_index] = scaled_glyph;
- }
-
- glyph_surface = scaled_glyph->surface;
- if (glyph_surface->width && glyph_surface->height) {
- int x1, y1, x2, y2;
-
- /* round glyph locations to the nearest pixel */
- /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
- x = _cairo_lround (info->glyphs[i].x -
- glyph_surface->base.device_transform.x0);
- y = _cairo_lround (info->glyphs[i].y -
- glyph_surface->base.device_transform.y0);
-
- x1 = x;
- if (x1 < extents->bounded.x)
- x1 = extents->bounded.x;
- x2 = x + glyph_surface->width;
- if (x2 > extents->bounded.x + extents->bounded.width)
- x2 = extents->bounded.x + extents->bounded.width;
-
- y1 = y;
- if (y1 < extents->bounded.y)
- y1 = extents->bounded.y;
- y2 = y + glyph_surface->height;
- if (y2 > extents->bounded.y + extents->bounded.height)
- y2 = extents->bounded.y + extents->bounded.height;
-
- pixman_image_composite32 (pixman_op,
- src, glyph_surface->pixman_image, dst,
- x1 + src_x, y1 + src_y,
- x1 - x, y1 - y,
- x1 - dst_x, y1 - dst_y,
- x2 - x1, y2 - y1);
- }
- }
- _cairo_scaled_font_thaw_cache (info->font);
-
- pixman_image_unref (src);
-
- return status;
+ return _cairo_compositor_fill (surface->compositor, &surface->base,
+ op, source, path,
+ fill_rule, tolerance, antialias,
+ clip);
}
static cairo_int_status_t
@@ -4277,49 +918,13 @@ _cairo_image_surface_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *num_remaining)
+ const cairo_clip_t *clip)
{
cairo_image_surface_t *surface = abstract_surface;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
- composite_glyphs_info_t glyph_info;
- cairo_status_t status;
- cairo_bool_t overlap;
- unsigned int flags;
-
- _cairo_image_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_glyphs (&extents, &unbounded,
- op, source,
- scaled_font,
- glyphs, num_glyphs,
- clip,
- &overlap);
- if (unlikely (status))
- return status;
-
- glyph_info.font = scaled_font;
- glyph_info.glyphs = glyphs;
- glyph_info.num_glyphs = num_glyphs;
-
- flags = 0;
- if (extents.mask.width > extents.unbounded.width ||
- extents.mask.height > extents.unbounded.height)
- {
- flags |= FORCE_CLIP_REGION;
- }
- status = _clip_and_composite (surface, op, source,
- overlap || extents.is_bounded == 0 ?
- _composite_glyphs_via_mask :
- _composite_glyphs,
- &glyph_info,
- &extents,
- need_bounded_clip (&extents) | flags);
-
- _cairo_composite_rectangles_fini (&extents);
-
- *num_remaining = 0;
- return status;
+ return _cairo_compositor_glyphs (surface->compositor, &surface->base,
+ op, source,
+ glyphs, num_glyphs, scaled_font,
+ clip);
}
void
@@ -4332,494 +937,6 @@ _cairo_image_surface_get_font_options (void *abstract_surface,
_cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
}
-/* legacy interface kept for compatibility until surface-fallback is removed */
-static cairo_status_t
-_cairo_image_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect_out,
- void **image_extra)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- image_rect_out->x = 0;
- image_rect_out->y = 0;
- image_rect_out->width = surface->width;
- image_rect_out->height = surface->height;
-
- *image_out = surface;
- *image_extra = NULL;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_image_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_image_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- if (src->backend == surface->base.backend) {
- *clone_offset_x = *clone_offset_y = 0;
- *clone_out = cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_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,
- cairo_region_t *clip_region)
-{
- cairo_image_surface_t *dst = abstract_dst;
- cairo_composite_rectangles_t extents;
- pixman_image_t *src;
- int src_offset_x, src_offset_y;
- cairo_status_t status;
-
- if (clip_region != NULL) {
- status = _cairo_image_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- return status;
- }
-
- extents.source.x = src_x;
- extents.source.y = src_y;
- extents.source.width = width;
- extents.source.height = height;
-
- extents.mask.x = mask_x;
- extents.mask.y = mask_y;
- extents.mask.width = width;
- extents.mask.height = height;
-
- extents.bounded.x = dst_x;
- extents.bounded.y = dst_y;
- extents.bounded.width = width;
- extents.bounded.height = height;
-
- extents.unbounded.x = 0;
- extents.unbounded.y = 0;
- extents.unbounded.width = dst->width;
- extents.unbounded.height = dst->height;
-
- if (clip_region != NULL) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_extents (clip_region, &rect);
- if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
- return CAIRO_STATUS_SUCCESS;
- }
-
- extents.is_bounded = _cairo_operator_bounded_by_either (op);
-
- src = _pixman_image_for_pattern (src_pattern, FALSE, &extents.source,
- &dst->base.device_transform,
- &src_offset_x, &src_offset_y);
- if (unlikely (src == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- status = CAIRO_STATUS_SUCCESS;
- if (mask_pattern != NULL) {
- pixman_image_t *mask;
- int mask_offset_x, mask_offset_y;
-
- mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents.mask,
- &dst->base.device_transform,
- &mask_offset_x, &mask_offset_y);
- if (unlikely (mask == NULL)) {
- pixman_image_unref (src);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- pixman_image_composite32 (_pixman_operator (op),
- src, mask, dst->pixman_image,
- src_x + src_offset_x,
- src_y + src_offset_y,
- mask_x + mask_offset_x,
- mask_y + mask_offset_y,
- dst_x, dst_y, width, height);
-
- pixman_image_unref (mask);
- } else {
- pixman_image_composite32 (_pixman_operator (op),
- src, NULL, dst->pixman_image,
- src_x + src_offset_x,
- src_y + src_offset_y,
- 0, 0,
- dst_x, dst_y, width, height);
- }
-
- pixman_image_unref (src);
-
- if (! extents.is_bounded)
- status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
-
- if (clip_region != NULL)
- _cairo_image_surface_unset_clip_region (dst);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- pixman_color_t pixman_color;
- pixman_box32_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
- pixman_box32_t *pixman_boxes = stack_boxes;
- int i;
-
- cairo_int_status_t status;
-
- if (CAIRO_INJECT_FAULT ())
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- pixman_color.red = color->red_short;
- pixman_color.green = color->green_short;
- pixman_color.blue = color->blue_short;
- pixman_color.alpha = color->alpha_short;
-
- if (num_rects > ARRAY_LENGTH (stack_boxes)) {
- pixman_boxes = _cairo_malloc_ab (num_rects, sizeof (pixman_box32_t));
- if (unlikely (pixman_boxes == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- for (i = 0; i < num_rects; i++) {
- pixman_boxes[i].x1 = rects[i].x;
- pixman_boxes[i].y1 = rects[i].y;
- pixman_boxes[i].x2 = rects[i].x + rects[i].width;
- pixman_boxes[i].y2 = rects[i].y + rects[i].height;
- }
-
- status = CAIRO_STATUS_SUCCESS;
- if (! pixman_image_fill_boxes (_pixman_operator (op),
- surface->pixman_image,
- &pixman_color,
- num_rects,
- pixman_boxes))
- {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- if (pixman_boxes != stack_boxes)
- free (pixman_boxes);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_composite_trapezoids (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *abstract_dst,
- cairo_antialias_t antialias,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps,
- cairo_region_t *clip_region)
-{
- cairo_image_surface_t *dst = abstract_dst;
- cairo_composite_rectangles_t extents;
- cairo_pattern_union_t source_pattern;
- composite_traps_info_t info;
- cairo_status_t status;
-
- if (height == 0 || width == 0)
- return CAIRO_STATUS_SUCCESS;
-
- if (CAIRO_INJECT_FAULT ())
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- extents.source.x = src_x;
- extents.source.y = src_y;
- extents.source.width = width;
- extents.source.height = height;
-
- extents.mask.x = dst_x;
- extents.mask.y = dst_y;
- extents.mask.width = width;
- extents.mask.height = height;
-
- extents.bounded.x = dst_x;
- extents.bounded.y = dst_y;
- extents.bounded.width = width;
- extents.bounded.height = height;
-
- extents.unbounded.x = 0;
- extents.unbounded.y = 0;
- extents.unbounded.width = dst->width;
- extents.unbounded.height = dst->height;
-
- if (clip_region != NULL) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_extents (clip_region, &rect);
- if (! _cairo_rectangle_intersect (&extents.unbounded, &rect))
- return CAIRO_STATUS_SUCCESS;
- }
-
- extents.is_bounded = _cairo_operator_bounded_by_either (op);
-
- if (clip_region != NULL) {
- status = _cairo_image_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- return status;
- }
-
- _cairo_pattern_init_static_copy (&source_pattern.base, pattern);
- cairo_matrix_translate (&source_pattern.base.matrix,
- src_x - extents.bounded.x,
- src_y - extents.bounded.y);
-
- info.traps = traps;
- info.num_traps = num_traps;
- info.antialias = antialias;
- status = _composite_traps (&info,
- dst->pixman_image,
- dst->pixman_format,
- op,
- &source_pattern.base,
- 0, 0,
- &dst->base.device_transform,
- &extents);
-
- if (status == CAIRO_STATUS_SUCCESS && ! extents.is_bounded)
- status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
-
- if (clip_region != NULL)
- _cairo_image_surface_unset_clip_region (dst);
-
- return status;
-}
-
-typedef struct _legacy_image_surface_span_renderer {
- cairo_span_renderer_t base;
-
- cairo_operator_t op;
- const cairo_pattern_t *pattern;
- cairo_antialias_t antialias;
- cairo_region_t *clip_region;
-
- pixman_image_t *mask;
- uint8_t *mask_data;
- uint32_t mask_stride;
-
- cairo_image_surface_t *dst;
- cairo_composite_rectangles_t composite_rectangles;
-} legacy_image_surface_span_renderer_t;
-
-void
-_cairo_image_surface_span_render_row (
- int y,
- const cairo_half_open_span_t *spans,
- unsigned num_spans,
- uint8_t *data,
- uint32_t stride)
-{
- uint8_t *row;
- unsigned i;
-
- if (num_spans == 0)
- return;
-
- row = data + y * stride;
- for (i = 0; i < num_spans - 1; i++) {
- if (! spans[i].coverage)
- continue;
-
- /* We implement setting the most common single pixel wide
- * span case to avoid the overhead of a memset call.
- * Open coding setting longer spans didn't show a
- * noticeable improvement over memset.
- */
- if (spans[i+1].x == spans[i].x + 1) {
- row[spans[i].x] = spans[i].coverage;
- } else {
- memset (row + spans[i].x,
- spans[i].coverage,
- spans[i+1].x - spans[i].x);
- }
- }
-}
-
-static cairo_status_t
-_cairo_image_surface_span_renderer_render_rows (
- void *abstract_renderer,
- int y,
- int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
- while (height--)
- _cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_image_surface_span_renderer_destroy (void *abstract_renderer)
-{
- legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
- if (renderer == NULL)
- return;
-
- pixman_image_unref (renderer->mask);
-
- free (renderer);
-}
-
-static cairo_status_t
-_cairo_image_surface_span_renderer_finish (void *abstract_renderer)
-{
- legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
- cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
- cairo_image_surface_t *dst = renderer->dst;
- pixman_image_t *src;
- int src_x, src_y;
- cairo_status_t status;
-
- if (renderer->clip_region != NULL) {
- status = _cairo_image_surface_set_clip_region (dst, renderer->clip_region);
- if (unlikely (status))
- return status;
- }
-
- src = _pixman_image_for_pattern (renderer->pattern, FALSE, &rects->bounded,
- &renderer->dst->base.device_transform,
- &src_x, &src_y);
- if (src == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- status = CAIRO_STATUS_SUCCESS;
- pixman_image_composite32 (_pixman_operator (renderer->op),
- src,
- renderer->mask,
- dst->pixman_image,
- rects->bounded.x + src_x,
- rects->bounded.y + src_y,
- 0, 0,
- rects->bounded.x, rects->bounded.y,
- rects->bounded.width, rects->bounded.height);
-
- if (! rects->is_bounded)
- status = _cairo_image_surface_fixup_unbounded (dst, rects, NULL);
-
- if (renderer->clip_region != NULL)
- _cairo_image_surface_unset_clip_region (dst);
-
- return status;
-}
-
-static cairo_bool_t
-_cairo_image_surface_check_span_renderer (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *abstract_dst,
- cairo_antialias_t antialias)
-{
- return TRUE;
- (void) op;
- (void) pattern;
- (void) abstract_dst;
- (void) antialias;
-}
-
-static cairo_span_renderer_t *
-_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,
- cairo_region_t *clip_region)
-{
- cairo_image_surface_t *dst = abstract_dst;
- legacy_image_surface_span_renderer_t *renderer;
-
- renderer = calloc(1, sizeof(*renderer));
- if (unlikely (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_rows = _cairo_image_surface_span_renderer_render_rows;
- renderer->op = op;
- renderer->pattern = pattern;
- renderer->antialias = antialias;
- renderer->dst = dst;
- renderer->clip_region = clip_region;
-
- renderer->composite_rectangles = *rects;
-
- /* TODO: support rendering to A1 surfaces (or: go add span
- * compositing to pixman.) */
- renderer->mask = pixman_image_create_bits (PIXMAN_a8,
- rects->bounded.width,
- rects->bounded.height,
- NULL, 0);
- if (renderer->mask == NULL) {
- free (renderer);
- return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- renderer->mask_stride = pixman_image_get_stride (renderer->mask);
- renderer->mask_data = (uint8_t *) pixman_image_get_data (renderer->mask) - rects->bounded.x - rects->bounded.y * renderer->mask_stride;
-
- return &renderer->base;
-}
-
-/**
- * _cairo_surface_is_image:
- * @surface: a #cairo_surface_t
- *
- * Checks if a surface is an #cairo_image_surface_t
- *
- * Return value: %TRUE if the surface is an image surface
- **/
-cairo_bool_t
-_cairo_surface_is_image (const cairo_surface_t *surface)
-{
- return surface->backend == &_cairo_image_surface_backend;
-}
-
const cairo_surface_backend_t _cairo_image_surface_backend = {
CAIRO_SURFACE_TYPE_IMAGE,
_cairo_image_surface_finish,
@@ -4833,32 +950,23 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
_cairo_image_surface_acquire_source_image,
_cairo_image_surface_release_source_image,
- _cairo_image_surface_acquire_dest_image,
- _cairo_image_surface_release_dest_image,
- _cairo_image_surface_clone_similar,
- _cairo_image_surface_composite,
- _cairo_image_surface_fill_rectangles,
- _cairo_image_surface_composite_trapezoids,
- _cairo_image_surface_create_span_renderer,
- _cairo_image_surface_check_span_renderer,
+ _cairo_image_surface_snapshot,
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_image_surface_get_extents,
- NULL, /* old_show_glyphs */
_cairo_image_surface_get_font_options,
+
NULL, /* flush */
NULL, /* mark dirty */
- NULL, /* font_fini */
- NULL, /* glyph_fini */
_cairo_image_surface_paint,
_cairo_image_surface_mask,
_cairo_image_surface_stroke,
_cairo_image_surface_fill,
+ NULL, /* fill-stroke */
_cairo_image_surface_glyphs,
- _cairo_image_surface_snapshot,
- NULL, /* is_similar */
};
/* A convenience function for when one needs to coerce an image
@@ -4908,7 +1016,7 @@ _cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface,
}
cairo_image_transparency_t
-_cairo_image_analyze_transparency (cairo_image_surface_t *image)
+_cairo_image_analyze_transparency (cairo_image_surface_t *image)
{
int x, y;
@@ -4918,6 +1026,9 @@ _cairo_image_analyze_transparency (cairo_image_surface_t *image)
if ((image->base.content & CAIRO_CONTENT_ALPHA) == 0)
return image->transparency = CAIRO_IMAGE_IS_OPAQUE;
+ if (image->base.is_clear)
+ return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
+
if ((image->base.content & CAIRO_CONTENT_COLOR) == 0) {
if (image->format == CAIRO_FORMAT_A1) {
return image->transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA;
diff --git a/src/cairo-mask-compositor.c b/src/cairo-mask-compositor.c
new file mode 100644
index 00000000..b34ffa25
--- /dev/null
+++ b/src/cairo-mask-compositor.c
@@ -0,0 +1,1412 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/* This compositor renders the shape to a mask using an image surface
+ * then calls composite.
+ */
+
+#include "cairoint.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-region-private.h"
+#include "cairo-surface-observer-private.h"
+#include "cairo-surface-offset-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-subsurface-private.h"
+
+typedef cairo_int_status_t
+(*draw_func_t) (const cairo_mask_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ const cairo_rectangle_int_t *src_sample,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip);
+
+static void do_unaligned_row(void (*blt)(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage),
+ void *closure,
+ const cairo_box_t *b,
+ int tx, int y, int h,
+ uint16_t coverage)
+{
+ int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
+ int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
+ if (x2 > x1) {
+ if (! _cairo_fixed_is_integer (b->p1.x)) {
+ blt(closure, x1, y, 1, h,
+ coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
+ x1++;
+ }
+
+ if (x2 > x1)
+ blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
+
+ if (! _cairo_fixed_is_integer (b->p2.x))
+ blt(closure, x2, y, 1, h,
+ coverage * _cairo_fixed_fractional_part (b->p2.x));
+ } else
+ blt(closure, x1, y, 1, h,
+ coverage * (b->p2.x - b->p1.x));
+}
+
+static void do_unaligned_box(void (*blt)(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage),
+ void *closure,
+ const cairo_box_t *b, int tx, int ty)
+{
+ int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
+ int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
+ if (y2 > y1) {
+ if (! _cairo_fixed_is_integer (b->p1.y)) {
+ do_unaligned_row(blt, closure, b, tx, y1, 1,
+ 256 - _cairo_fixed_fractional_part (b->p1.y));
+ y1++;
+ }
+
+ if (y2 > y1)
+ do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
+
+ if (! _cairo_fixed_is_integer (b->p2.y))
+ do_unaligned_row(blt, closure, b, tx, y2, 1,
+ _cairo_fixed_fractional_part (b->p2.y));
+ } else
+ do_unaligned_row(blt, closure, b, tx, y1, 1,
+ b->p2.y - b->p1.y);
+}
+
+struct blt_in {
+ const cairo_mask_compositor_t *compositor;
+ cairo_surface_t *dst;
+};
+
+static void blt_in(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage)
+{
+ struct blt_in *info = closure;
+ cairo_color_t color;
+ cairo_rectangle_int_t rect;
+
+ if (coverage == 0xffff)
+ return;
+
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+
+ _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff);
+ info->compositor->fill_rectangles (info->dst, CAIRO_OPERATOR_IN,
+ &color, &rect, 1);
+}
+
+static cairo_surface_t *
+create_composite_mask (const cairo_mask_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *draw_closure,
+ draw_func_t draw_func,
+ draw_func_t mask_func,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *surface;
+ cairo_int_status_t status;
+ struct blt_in info;
+ int i;
+
+ surface = _cairo_surface_create_similar_solid (dst,
+ CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height,
+ CAIRO_COLOR_TRANSPARENT);
+ if (unlikely (surface->status))
+ return surface;
+
+ if (mask_func) {
+ status = mask_func (compositor, surface, draw_closure,
+ CAIRO_OPERATOR_SOURCE, NULL, NULL,
+ extents->bounded.x, extents->bounded.y,
+ &extents->bounded, extents->clip);
+ if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
+ return surface;
+ }
+
+ /* Is it worth setting the clip region here? */
+ status = draw_func (compositor, surface, draw_closure,
+ CAIRO_OPERATOR_ADD, NULL, NULL,
+ extents->bounded.x, extents->bounded.y,
+ &extents->bounded, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (surface);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ info.compositor = compositor;
+ info.dst = surface;
+ for (i = 0; i < extents->clip->num_boxes; i++) {
+ cairo_box_t *b = &extents->clip->boxes[i];
+
+ if (! _cairo_fixed_is_integer (b->p1.x) ||
+ ! _cairo_fixed_is_integer (b->p1.y) ||
+ ! _cairo_fixed_is_integer (b->p2.x) ||
+ ! _cairo_fixed_is_integer (b->p2.y))
+ {
+ do_unaligned_box(blt_in, &info, b,
+ extents->bounded.x,
+ extents->bounded.y);
+ }
+ }
+
+ if (extents->clip->path != NULL) {
+ status = _cairo_clip_combine_with_surface (extents->clip, surface,
+ extents->bounded.x,
+ extents->bounded.y);
+ if (unlikely (status)) {
+ cairo_surface_destroy (surface);
+ return _cairo_surface_create_in_error (status);
+ }
+ }
+
+ return surface;
+}
+
+/* Handles compositing with a clip surface when the operator allows
+ * us to combine the clip with the mask
+ */
+static cairo_status_t
+clip_and_composite_with_mask (const cairo_mask_compositor_t *compositor,
+ void *draw_closure,
+ draw_func_t draw_func,
+ draw_func_t mask_func,
+ cairo_operator_t op,
+ cairo_pattern_t *pattern,
+ const cairo_composite_rectangles_t*extents)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_surface_t *mask, *src;
+ int src_x, src_y;
+
+ mask = create_composite_mask (compositor, dst, draw_closure,
+ draw_func, mask_func,
+ extents);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ if (pattern != NULL || dst->content != CAIRO_CONTENT_ALPHA) {
+ src = compositor->pattern_to_surface (dst,
+ &extents->source_pattern.base,
+ FALSE,
+ &extents->bounded,
+ &extents->source_sample_area,
+ &src_x, &src_y);
+ if (unlikely (src->status)) {
+ cairo_surface_destroy (mask);
+ return src->status;
+ }
+
+ compositor->composite (dst, op, src, mask,
+ extents->bounded.x + src_x,
+ extents->bounded.y + src_y,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+
+ cairo_surface_destroy (src);
+ } else {
+ compositor->composite (dst, op, mask, NULL,
+ 0, 0,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ }
+ cairo_surface_destroy (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Handles compositing with a clip surface when we have to do the operation
+ * in two pieces and combine them together.
+ */
+static cairo_status_t
+clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
+ void *draw_closure,
+ draw_func_t draw_func,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ const cairo_composite_rectangles_t*extents)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_surface_t *tmp, *clip;
+ cairo_status_t status;
+
+ tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (tmp->status))
+ return tmp->status;
+
+ compositor->composite (tmp, CAIRO_OPERATOR_SOURCE, dst, NULL,
+ extents->bounded.x, extents->bounded.y,
+ 0, 0,
+ 0, 0,
+ extents->bounded.width, extents->bounded.height);
+
+ status = draw_func (compositor, tmp, draw_closure, op,
+ pattern, &extents->source_sample_area,
+ extents->bounded.x, extents->bounded.y,
+ &extents->bounded, NULL);
+ if (unlikely (status))
+ goto cleanup;
+
+ clip = _cairo_clip_get_image (extents->clip, dst, &extents->bounded);
+ if (unlikely ((status = clip->status)))
+ goto cleanup;
+
+ if (dst->is_clear) {
+ compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
+ 0, 0,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ } else {
+ /* Punch the clip out of the destination */
+ compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, clip, NULL,
+ 0, 0,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+
+ /* Now add the two results together */
+ compositor->composite (dst, CAIRO_OPERATOR_ADD, tmp, clip,
+ 0, 0,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ }
+ cairo_surface_destroy (clip);
+
+cleanup:
+ cairo_surface_destroy (tmp);
+ return status;
+}
+
+/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
+ * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
+ */
+static cairo_status_t
+clip_and_composite_source (const cairo_mask_compositor_t *compositor,
+ void *draw_closure,
+ draw_func_t draw_func,
+ draw_func_t mask_func,
+ cairo_pattern_t *pattern,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_surface_t *mask, *src;
+ int src_x, src_y;
+
+ /* Create a surface that is mask IN clip */
+ mask = create_composite_mask (compositor, dst, draw_closure,
+ draw_func, mask_func,
+ extents);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ src = compositor->pattern_to_surface (dst,
+ pattern,
+ FALSE,
+ &extents->bounded,
+ &extents->source_sample_area,
+ &src_x, &src_y);
+ if (unlikely (src->status)) {
+ cairo_surface_destroy (mask);
+ return src->status;
+ }
+
+ if (dst->is_clear) {
+ compositor->composite (dst, CAIRO_OPERATOR_SOURCE, src, mask,
+ extents->bounded.x + src_x, extents->bounded.y + src_y,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ } else {
+ /* Compute dest' = dest OUT (mask IN clip) */
+ compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+ 0, 0, 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+
+ /* Now compute (src IN (mask IN clip)) ADD dest' */
+ compositor->composite (dst, CAIRO_OPERATOR_ADD, src, mask,
+ extents->bounded.x + src_x, extents->bounded.y + src_y,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ }
+
+ cairo_surface_destroy (src);
+ cairo_surface_destroy (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+can_reduce_alpha_op (cairo_operator_t op)
+{
+ int iop = op;
+ switch (iop) {
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_SOURCE:
+ case CAIRO_OPERATOR_ADD:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static cairo_bool_t
+reduce_alpha_op (cairo_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern)
+{
+ return dst->is_clear &&
+ dst->content == CAIRO_CONTENT_ALPHA &&
+ _cairo_pattern_is_opaque_solid (pattern) &&
+ can_reduce_alpha_op (op);
+}
+
+static cairo_status_t
+fixup_unbounded (const cairo_mask_compositor_t *compositor,
+ cairo_surface_t *dst,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_rectangle_int_t rects[4];
+ int n;
+
+ if (extents->bounded.width == extents->unbounded.width &&
+ extents->bounded.height == extents->unbounded.height)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ n = 0;
+ if (extents->bounded.width == 0 || extents->bounded.height == 0) {
+ rects[n].x = extents->unbounded.x;
+ rects[n].width = extents->unbounded.width;
+ rects[n].y = extents->unbounded.y;
+ rects[n].height = extents->unbounded.height;
+ n++;
+ } else {
+ /* top */
+ if (extents->bounded.y != extents->unbounded.y) {
+ rects[n].x = extents->unbounded.x;
+ rects[n].width = extents->unbounded.width;
+ rects[n].y = extents->unbounded.y;
+ rects[n].height = extents->bounded.y - extents->unbounded.y;
+ n++;
+ }
+ /* left */
+ if (extents->bounded.x != extents->unbounded.x) {
+ rects[n].x = extents->unbounded.x;
+ rects[n].width = extents->bounded.x - extents->unbounded.x;
+ rects[n].y = extents->bounded.y;
+ rects[n].height = extents->bounded.height;
+ n++;
+ }
+ /* right */
+ if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
+ rects[n].x = extents->bounded.x + extents->bounded.width;
+ rects[n].width = extents->unbounded.x + extents->unbounded.width - rects[n].x;
+ rects[n].y = extents->bounded.y;
+ rects[n].height = extents->bounded.height;
+ n++;
+ }
+ /* bottom */
+ if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
+ rects[n].x = extents->unbounded.x;
+ rects[n].width = extents->unbounded.width;
+ rects[n].y = extents->bounded.y + extents->bounded.height;
+ rects[n].height = extents->unbounded.y + extents->unbounded.height - rects[n].y;
+ n++;
+ }
+ }
+
+ return compositor->fill_rectangles (dst, CAIRO_OPERATOR_CLEAR,
+ CAIRO_COLOR_TRANSPARENT,
+ rects, n);
+}
+
+static cairo_status_t
+fixup_unbounded_with_mask (const cairo_mask_compositor_t *compositor,
+ cairo_surface_t *dst,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_clip_t *clip = extents->clip;
+ cairo_surface_t *mask;
+ int mask_x, mask_y;
+
+ mask = _cairo_clip_get_image (clip, dst, &extents->unbounded);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ mask_x = -extents->unbounded.x;
+ mask_y = -extents->unbounded.y;
+
+ /* top */
+ if (extents->bounded.y != extents->unbounded.y) {
+ int x = extents->unbounded.x;
+ int y = extents->unbounded.y;
+ int width = extents->unbounded.width;
+ int height = extents->bounded.y - y;
+
+ compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* left */
+ if (extents->bounded.x != extents->unbounded.x) {
+ int x = extents->unbounded.x;
+ int y = extents->bounded.y;
+ int width = extents->bounded.x - x;
+ int height = extents->bounded.height;
+
+ compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* right */
+ if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
+ int x = extents->bounded.x + extents->bounded.width;
+ int y = extents->bounded.y;
+ int width = extents->unbounded.x + extents->unbounded.width - x;
+ int height = extents->bounded.height;
+
+ compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* bottom */
+ if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
+ int x = extents->unbounded.x;
+ int y = extents->bounded.y + extents->bounded.height;
+ int width = extents->unbounded.width;
+ int height = extents->unbounded.y + extents->unbounded.height - y;
+
+ compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ cairo_surface_destroy (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+fixup_unbounded_boxes (const cairo_mask_compositor_t *compositor,
+ const cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_boxes_t clear;
+ cairo_region_t *clip_region;
+ cairo_box_t box;
+ cairo_status_t status;
+ struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ assert (boxes->is_pixel_aligned);
+
+ clip_region = NULL;
+ if (_cairo_clip_is_region (extents->clip) &&
+ (clip_region = _cairo_clip_get_region (extents->clip)) &&
+ cairo_region_contains_rectangle (clip_region,
+ &extents->bounded) == CAIRO_REGION_OVERLAP_IN)
+ clip_region = NULL;
+
+
+ if (boxes->num_boxes <= 1 && clip_region == NULL)
+ return fixup_unbounded (compositor, dst, extents);
+
+ _cairo_boxes_init (&clear);
+
+ box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+ box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+ box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+ box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+ if (clip_region == NULL) {
+ cairo_boxes_t tmp;
+
+ _cairo_boxes_init (&tmp);
+
+ status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ tmp.chunks.next = &boxes->chunks;
+ tmp.num_boxes += boxes->num_boxes;
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+
+ tmp.chunks.next = NULL;
+ } else {
+ pixman_box32_t *pbox;
+
+ pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
+ _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
+
+ status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ status = _cairo_boxes_add (&clear,
+ CAIRO_ANTIALIAS_DEFAULT,
+ &chunk->base[i]);
+ if (unlikely (status)) {
+ _cairo_boxes_fini (&clear);
+ return status;
+ }
+ }
+ }
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+ }
+
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = compositor->fill_boxes (dst,
+ CAIRO_OPERATOR_CLEAR,
+ CAIRO_COLOR_TRANSPARENT,
+ &clear);
+ }
+
+ _cairo_boxes_fini (&clear);
+
+ return status;
+}
+
+enum {
+ NEED_CLIP_REGION = 0x1,
+ NEED_CLIP_SURFACE = 0x2,
+ FORCE_CLIP_REGION = 0x4,
+};
+
+static cairo_bool_t
+need_bounded_clip (cairo_composite_rectangles_t *extents)
+{
+ unsigned int flags = NEED_CLIP_REGION;
+ if (! _cairo_clip_is_region (extents->clip))
+ flags |= NEED_CLIP_SURFACE;
+ return flags;
+}
+
+static cairo_bool_t
+need_unbounded_clip (cairo_composite_rectangles_t *extents)
+{
+ unsigned int flags = 0;
+ if (! extents->is_bounded) {
+ flags |= NEED_CLIP_REGION;
+ if (! _cairo_clip_is_region (extents->clip))
+ flags |= NEED_CLIP_SURFACE;
+ }
+ if (extents->clip->path != NULL)
+ flags |= NEED_CLIP_SURFACE;
+ return flags;
+}
+
+static cairo_status_t
+clip_and_composite (const cairo_mask_compositor_t *compositor,
+ draw_func_t draw_func,
+ draw_func_t mask_func,
+ void *draw_closure,
+ cairo_composite_rectangles_t*extents,
+ unsigned int need_clip)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_operator_t op = extents->op;
+ cairo_pattern_t *src = &extents->source_pattern.base;
+ cairo_region_t *clip_region = NULL;
+ cairo_status_t status;
+
+ compositor->acquire (dst);
+
+ if (need_clip & NEED_CLIP_REGION) {
+ clip_region = _cairo_clip_get_region (extents->clip);
+ if ((need_clip & FORCE_CLIP_REGION) == 0 &&
+ _cairo_composite_rectangles_can_reduce_clip (extents,
+ extents->clip))
+ clip_region = NULL;
+ if (clip_region != NULL) {
+ status = compositor->set_clip_region (dst, clip_region);
+ if (unlikely (status)) {
+ compositor->release (dst);
+ return status;
+ }
+ }
+ }
+
+ if (reduce_alpha_op (dst, op, &extents->source_pattern.base)) {
+ op = CAIRO_OPERATOR_ADD;
+ src = NULL;
+ }
+
+ if (op == CAIRO_OPERATOR_SOURCE) {
+ status = clip_and_composite_source (compositor,
+ draw_closure, draw_func, mask_func,
+ src, extents);
+ } else {
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ op = CAIRO_OPERATOR_DEST_OUT;
+ src = NULL;
+ }
+
+ if (need_clip & NEED_CLIP_SURFACE) {
+ if (extents->is_bounded) {
+ status = clip_and_composite_with_mask (compositor,
+ draw_closure,
+ draw_func,
+ mask_func,
+ op, src, extents);
+ } else {
+ status = clip_and_composite_combine (compositor,
+ draw_closure,
+ draw_func,
+ op, src, extents);
+ }
+ } else {
+ status = draw_func (compositor,
+ dst, draw_closure,
+ op, src, &extents->source_sample_area,
+ 0, 0,
+ &extents->bounded,
+ extents->clip);
+ }
+ }
+
+ if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
+ if (need_clip & NEED_CLIP_SURFACE)
+ status = fixup_unbounded_with_mask (compositor, dst, extents);
+ else
+ status = fixup_unbounded (compositor, dst, extents);
+ }
+
+ if (clip_region)
+ compositor->set_clip_region (dst, NULL);
+
+ compositor->release (dst);
+
+ return status;
+}
+
+static cairo_int_status_t
+trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_box_t box;
+
+ _cairo_boxes_extents (boxes, &box);
+ return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
+}
+
+static cairo_status_t
+upload_boxes (const cairo_mask_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_surface_t *dst = extents->surface;
+ const cairo_pattern_t *source = &extents->source_pattern.base;
+ const cairo_surface_pattern_t *pattern;
+ cairo_surface_t *src;
+ cairo_rectangle_int_t limit;
+ cairo_int_status_t status;
+ int tx, ty;
+
+ pattern = (const cairo_surface_pattern_t *) source;
+ src = pattern->surface;
+ if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (_cairo_surface_is_snapshot (src))
+ src = _cairo_surface_snapshot_get_target (src);
+ if (_cairo_surface_is_observer (src))
+ src = _cairo_surface_observer_get_target (src);
+ if (_cairo_surface_is_subsurface (src)) {
+ _cairo_surface_subsurface_offset (src, &tx, &ty);
+ src = _cairo_surface_subsurface_get_target (src);
+ }
+
+ /* Check that the data is entirely within the image */
+ if (extents->bounded.x + tx < 0 || extents->bounded.y + ty < 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_surface_get_extents (pattern->surface, &limit);
+ if (extents->bounded.x + extents->bounded.width + tx > limit.width ||
+ extents->bounded.y + extents->bounded.height + ty > limit.height)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE)
+ status = compositor->draw_image_boxes (dst,
+ (cairo_image_surface_t *)src,
+ boxes, tx, ty);
+ else
+ status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
+ tx, ty);
+
+ return status;
+}
+
+static cairo_status_t
+composite_boxes (const cairo_mask_compositor_t *compositor,
+ const cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_operator_t op = extents->op;
+ const cairo_pattern_t *source = &extents->source_pattern.base;
+ cairo_bool_t need_clip_mask = extents->clip->path != NULL;
+ cairo_status_t status;
+
+ if (need_clip_mask &&
+ (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ status = compositor->acquire (dst);
+ if (unlikely (status))
+ return status;
+
+ if (! need_clip_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) {
+ const cairo_color_t *color;
+
+ color = &((cairo_solid_pattern_t *) source)->color;
+ status = compositor->fill_boxes (dst, op, color, boxes);
+ } else {
+ cairo_surface_t *src, *mask = NULL;
+ int src_x, src_y;
+ int mask_x = 0, mask_y = 0;
+
+ if (need_clip_mask) {
+ mask = _cairo_clip_get_image (extents->clip, dst,
+ &extents->bounded);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ source = NULL;
+ op = CAIRO_OPERATOR_DEST_OUT;
+ }
+
+ mask_x = -extents->bounded.x;
+ mask_y = -extents->bounded.y;
+ }
+
+ if (source || mask == NULL) {
+ src = compositor->pattern_to_surface (dst, source, FALSE,
+ &extents->bounded,
+ &extents->source_sample_area,
+ &src_x, &src_y);
+ } else {
+ src = mask;
+ src_x = mask_x;
+ src_y = mask_y;
+ mask = NULL;
+ }
+
+ status = compositor->composite_boxes (dst, op, src, mask,
+ src_x, src_y,
+ mask_x, mask_y,
+ 0, 0,
+ boxes, &extents->bounded);
+
+ cairo_surface_destroy (src);
+ cairo_surface_destroy (mask);
+ }
+
+ if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
+ status = fixup_unbounded_boxes (compositor, extents, boxes);
+
+ compositor->release (dst);
+
+ return status;
+}
+
+static cairo_status_t
+clip_and_composite_boxes (const cairo_mask_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_int_status_t status;
+
+ if (boxes->num_boxes == 0) {
+ if (extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ return fixup_unbounded_boxes (compositor, extents, boxes);
+ }
+
+ if (! boxes->is_pixel_aligned)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = trim_extents_to_boxes (extents, boxes);
+ if (unlikely (status))
+ return status;
+
+ if (extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
+ extents->clip->path == NULL &&
+ (extents->op == CAIRO_OPERATOR_SOURCE ||
+ (dst->is_clear && (extents->op == CAIRO_OPERATOR_OVER ||
+ extents->op == CAIRO_OPERATOR_ADD))))
+ {
+ status = upload_boxes (compositor, extents, boxes);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+ return composite_boxes (compositor, extents, boxes);
+}
+
+/* high-level compositor interface */
+
+static cairo_int_status_t
+_cairo_mask_compositor_paint (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
+ cairo_boxes_t boxes;
+ cairo_int_status_t status;
+
+ _cairo_clip_steal_boxes (extents->clip, &boxes);
+ status = clip_and_composite_boxes (compositor, extents, &boxes);
+ _cairo_clip_unsteal_boxes (extents->clip, &boxes);
+
+ return status;
+}
+
+struct composite_opacity_info {
+ const cairo_mask_compositor_t *compositor;
+ uint8_t op;
+ cairo_surface_t *dst;
+ cairo_surface_t *src;
+ int src_x, src_y;
+ double opacity;
+};
+
+static void composite_opacity(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage)
+{
+ struct composite_opacity_info *info = closure;
+ const cairo_mask_compositor_t *compositor = info->compositor;
+ cairo_surface_t *mask;
+ int mask_x, mask_y;
+ cairo_color_t color;
+ cairo_solid_pattern_t solid;
+
+ _cairo_color_init_rgba (&color, 0, 0, 0, info->opacity * coverage);
+ _cairo_pattern_init_solid (&solid, &color);
+ mask = compositor->pattern_to_surface (info->dst, &solid.base, TRUE,
+ &_cairo_unbounded_rectangle,
+ &_cairo_unbounded_rectangle,
+ &mask_x, &mask_y);
+ if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
+ if (info->src) {
+ compositor->composite (info->dst, info->op, info->src, mask,
+ x + info->src_x, y + info->src_y,
+ mask_x, mask_y,
+ x, y,
+ w, h);
+ } else {
+ compositor->composite (info->dst, info->op, mask, NULL,
+ mask_x, mask_y,
+ 0, 0,
+ x, y,
+ w, h);
+ }
+ }
+
+ cairo_surface_destroy (mask);
+}
+
+static cairo_int_status_t
+composite_opacity_boxes (const cairo_mask_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ const cairo_pattern_t *src_pattern,
+ const cairo_rectangle_int_t *src_sample,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ const cairo_solid_pattern_t *mask_pattern = closure;
+ struct composite_opacity_info info;
+ int i;
+
+ assert (clip);
+
+ info.compositor = compositor;
+ info.op = op;
+ info.dst = dst;
+
+ if (src_pattern != NULL) {
+ info.src = compositor->pattern_to_surface (dst, src_pattern, FALSE,
+ extents, src_sample,
+ &info.src_x, &info.src_y);
+ if (unlikely (info.src->status))
+ return info.src->status;
+ } else
+ info.src = NULL;
+
+ info.opacity = mask_pattern->color.alpha / (double) 0xffff;
+
+ /* XXX for lots of boxes create a clip region for the fully opaque areas */
+ for (i = 0; i < clip->num_boxes; i++)
+ do_unaligned_box(composite_opacity, &info,
+ &clip->boxes[i], dst_x, dst_y);
+ cairo_surface_destroy (info.src);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+struct composite_box_info {
+ const cairo_mask_compositor_t *compositor;
+ cairo_surface_t *dst;
+ cairo_surface_t *src;
+ int src_x, src_y;
+ uint8_t op;
+};
+
+static void composite_box(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage)
+{
+ struct composite_box_info *info = closure;
+ const cairo_mask_compositor_t *compositor = info->compositor;
+
+ if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) {
+ cairo_surface_t *mask;
+ cairo_color_t color;
+ cairo_solid_pattern_t solid;
+ int mask_x, mask_y;
+
+ _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double)0xffff);
+ _cairo_pattern_init_solid (&solid, &color);
+
+ mask = compositor->pattern_to_surface (info->dst, &solid.base, FALSE,
+ &_cairo_unbounded_rectangle,
+ &_cairo_unbounded_rectangle,
+ &mask_x, &mask_y);
+
+ if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
+ compositor->composite (info->dst, info->op, info->src, mask,
+ x + info->src_x, y + info->src_y,
+ mask_x, mask_y,
+ x, y,
+ w, h);
+ }
+
+ cairo_surface_destroy (mask);
+ } else {
+ compositor->composite (info->dst, info->op, info->src, NULL,
+ x + info->src_x, y + info->src_y,
+ 0, 0,
+ x, y,
+ w, h);
+ }
+}
+
+static cairo_int_status_t
+composite_mask_clip_boxes (const cairo_mask_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ const cairo_pattern_t *src_pattern,
+ const cairo_rectangle_int_t *src_sample,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t *composite = closure;
+ struct composite_box_info info;
+ int i;
+
+ assert (src_pattern == NULL);
+ assert (op == CAIRO_OPERATOR_SOURCE);
+
+ info.compositor = compositor;
+ info.op = CAIRO_OPERATOR_SOURCE;
+ info.dst = dst;
+ info.src = compositor->pattern_to_surface (dst,
+ &composite->mask_pattern.base,
+ FALSE, extents,
+ &composite->mask_sample_area,
+ &info.src_x, &info.src_y);
+ if (unlikely (info.src->status))
+ return info.src->status;
+
+ info.src_x += dst_x;
+ info.src_y += dst_y;
+
+ for (i = 0; i < clip->num_boxes; i++)
+ do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
+
+ cairo_surface_destroy (info.src);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_mask (const cairo_mask_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ const cairo_pattern_t *src_pattern,
+ const cairo_rectangle_int_t *src_sample,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t *composite = closure;
+ cairo_surface_t *src, *mask;
+ int src_x, src_y;
+ int mask_x, mask_y;
+
+ if (src_pattern != NULL) {
+ src = compositor->pattern_to_surface (dst, src_pattern, FALSE,
+ extents, src_sample,
+ &src_x, &src_y);
+ if (unlikely (src->status))
+ return src->status;
+
+ mask = compositor->pattern_to_surface (dst, &composite->mask_pattern.base, TRUE,
+ extents, &composite->mask_sample_area,
+ &mask_x, &mask_y);
+ if (unlikely (mask->status)) {
+ cairo_surface_destroy (src);
+ return mask->status;
+ }
+
+ compositor->composite (dst, op, src, mask,
+ extents->x + src_x, extents->y + src_y,
+ extents->x + mask_x, extents->y + mask_y,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+
+ cairo_surface_destroy (mask);
+ cairo_surface_destroy (src);
+ } else {
+ src = compositor->pattern_to_surface (dst, &composite->mask_pattern.base, FALSE,
+ extents, &composite->mask_sample_area,
+ &src_x, &src_y);
+ if (unlikely (src->status))
+ return src->status;
+
+ compositor->composite (dst, op, src, NULL,
+ extents->x + src_x, extents->y + src_y,
+ 0, 0,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+
+ cairo_surface_destroy (src);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_mask_compositor_mask (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
+ cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
+ extents->clip->path == NULL &&
+ ! _cairo_clip_is_region (extents->clip)) {
+ status = clip_and_composite (compositor,
+ composite_opacity_boxes,
+ composite_opacity_boxes,
+ &extents->mask_pattern.solid,
+ extents, need_unbounded_clip (extents));
+ } else {
+ status = clip_and_composite (compositor,
+ composite_mask,
+ extents->clip->path == NULL ? composite_mask_clip_boxes : NULL,
+ extents,
+ extents, need_bounded_clip (extents));
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_mask_compositor_stroke (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
+ cairo_surface_t *mask;
+ cairo_surface_pattern_t pattern;
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init_with_clip (&boxes, extents->clip);
+ status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+ style,
+ ctm,
+ antialias,
+ &boxes);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = clip_and_composite_boxes (compositor, extents, &boxes);
+ _cairo_boxes_fini (&boxes);
+ }
+
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ mask = cairo_surface_create_similar_image (extents->surface,
+ CAIRO_FORMAT_A8,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ status = _cairo_surface_offset_stroke (mask,
+ extents->bounded.x,
+ extents->bounded.y,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
+ path, style, ctm, ctm_inverse,
+ tolerance, antialias,
+ extents->clip);
+ if (unlikely (status)) {
+ cairo_surface_destroy (mask);
+ return status;
+ }
+
+ _cairo_pattern_init_for_surface (&pattern, mask);
+ cairo_surface_destroy (mask);
+
+ cairo_matrix_init_translate (&pattern.base.matrix,
+ -extents->bounded.x,
+ -extents->bounded.y);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ pattern.base.extend = CAIRO_EXTEND_NONE;
+ status = _cairo_surface_mask (extents->surface,
+ extents->op,
+ &extents->source_pattern.base,
+ &pattern.base,
+ extents->clip);
+ _cairo_pattern_fini (&pattern.base);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_mask_compositor_fill (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
+ cairo_surface_t *mask;
+ cairo_surface_pattern_t pattern;
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_fill_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init_with_clip (&boxes, extents->clip);
+ status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+ fill_rule,
+ antialias,
+ &boxes);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = clip_and_composite_boxes (compositor, extents, &boxes);
+ _cairo_boxes_fini (&boxes);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ mask = cairo_surface_create_similar_image (extents->surface,
+ CAIRO_FORMAT_A8,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ status = _cairo_surface_offset_fill (mask,
+ extents->bounded.x,
+ extents->bounded.y,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
+ path, fill_rule, tolerance, antialias,
+ extents->clip);
+ if (unlikely (status)) {
+ cairo_surface_destroy (mask);
+ return status;
+ }
+
+ _cairo_pattern_init_for_surface (&pattern, mask);
+ cairo_surface_destroy (mask);
+
+ cairo_matrix_init_translate (&pattern.base.matrix,
+ -extents->bounded.x,
+ -extents->bounded.y);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ pattern.base.extend = CAIRO_EXTEND_NONE;
+ status = _cairo_surface_mask (extents->surface,
+ extents->op,
+ &extents->source_pattern.base,
+ &pattern.base,
+ extents->clip);
+ _cairo_pattern_fini (&pattern.base);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_mask_compositor_glyphs (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_bool_t overlap)
+{
+ cairo_surface_t *mask;
+ cairo_surface_pattern_t pattern;
+ cairo_int_status_t status;
+
+ mask = cairo_surface_create_similar_image (extents->surface,
+ CAIRO_FORMAT_A8,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ status = _cairo_surface_offset_glyphs (mask,
+ extents->bounded.x,
+ extents->bounded.y,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
+ scaled_font, glyphs, num_glyphs,
+ extents->clip);
+ if (unlikely (status)) {
+ cairo_surface_destroy (mask);
+ return status;
+ }
+
+ _cairo_pattern_init_for_surface (&pattern, mask);
+ cairo_surface_destroy (mask);
+
+ cairo_matrix_init_translate (&pattern.base.matrix,
+ -extents->bounded.x,
+ -extents->bounded.y);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ pattern.base.extend = CAIRO_EXTEND_NONE;
+ status = _cairo_surface_mask (extents->surface,
+ extents->op,
+ &extents->source_pattern.base,
+ &pattern.base,
+ extents->clip);
+ _cairo_pattern_fini (&pattern.base);
+
+ return status;
+}
+
+void
+_cairo_mask_compositor_init (cairo_mask_compositor_t *compositor,
+ const cairo_compositor_t *delegate)
+{
+ compositor->base.delegate = delegate;
+
+ compositor->base.paint = _cairo_mask_compositor_paint;
+ compositor->base.mask = _cairo_mask_compositor_mask;
+ compositor->base.fill = _cairo_mask_compositor_fill;
+ compositor->base.stroke = _cairo_mask_compositor_stroke;
+ compositor->base.glyphs = _cairo_mask_compositor_glyphs;
+}
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index 195438c8..25211357 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -889,6 +889,9 @@ _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
{
double a, b, c, d, f, g, h, i, j;
+ if (_cairo_matrix_has_unity_scale (matrix))
+ return radius;
+
_cairo_matrix_get_affine (matrix,
&a, &b,
&c, &d,
@@ -1043,6 +1046,9 @@ _cairo_matrix_is_pixman_translation (const cairo_matrix_t *matrix,
if (!_cairo_matrix_is_translation (matrix))
return FALSE;
+ if (matrix->x0 == 0. && matrix->y0 == 0.)
+ return TRUE;
+
tx = matrix->x0 + *x_offset;
ty = matrix->y0 + *y_offset;
diff --git a/src/cairo-mesh-pattern-rasterizer.c b/src/cairo-mesh-pattern-rasterizer.c
index 9c9d0ece..82b16e73 100644
--- a/src/cairo-mesh-pattern-rasterizer.c
+++ b/src/cairo-mesh-pattern-rasterizer.c
@@ -36,6 +36,7 @@
#include "cairoint.h"
+#include "cairo-array-private.h"
#include "cairo-pattern-private.h"
/*
diff --git a/src/cairo-mime-surface.c b/src/cairo-mime-surface.c
index f23c451a..e19852f7 100644
--- a/src/cairo-mime-surface.c
+++ b/src/cairo-mime-surface.c
@@ -97,6 +97,7 @@
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
+#include "cairo-surface-backend-private.h"
typedef struct _cairo_mime_surface {
cairo_surface_t base;
@@ -221,32 +222,25 @@ static const cairo_surface_backend_t cairo_mime_surface_backend = {
_cairo_mime_surface_acquire_source_image,
_cairo_mime_surface_release_source_image,
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ _cairo_mime_surface_snapshot,
+
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_mime_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 */
-
NULL, /* paint */
NULL, /* mask */
NULL, /* stroke */
NULL, /* fill */
NULL, /* glyphs */
-
- _cairo_mime_surface_snapshot,
};
cairo_surface_t *
diff --git a/src/cairo-mono-scan-converter.c b/src/cairo-mono-scan-converter.c
new file mode 100644
index 00000000..98b7631f
--- /dev/null
+++ b/src/cairo-mono-scan-converter.c
@@ -0,0 +1,607 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/*
+ * Copyright (c) 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "cairoint.h"
+#include "cairo-spans-private.h"
+#include "cairo-error-private.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+struct quorem {
+ int32_t quo;
+ int32_t rem;
+};
+
+struct edge {
+ struct edge *next, *prev;
+
+ int32_t height_left;
+ int32_t dir;
+ int32_t vertical;
+
+ int32_t dy;
+ struct quorem x;
+ struct quorem dxdy;
+};
+
+/* A collection of sorted and vertically clipped edges of the polygon.
+ * Edges are moved from the polygon to an active list while scan
+ * converting. */
+struct polygon {
+ /* The vertical clip extents. */
+ int32_t ymin, ymax;
+
+ int num_edges;
+ struct edge *edges;
+
+ /* Array of edges all starting in the same bucket. An edge is put
+ * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when
+ * it is added to the polygon. */
+ struct edge **y_buckets;
+
+ struct edge *y_buckets_embedded[64];
+ struct edge edges_embedded[32];
+};
+
+struct mono_scan_converter {
+ struct polygon polygon[1];
+
+ /* Leftmost edge on the current scan line. */
+ struct edge head, tail;
+ int is_vertical;
+
+ cairo_half_open_span_t *spans;
+ cairo_half_open_span_t spans_embedded[64];
+ int num_spans;
+
+ /* Clip box. */
+ int32_t xmin, xmax;
+ int32_t ymin, ymax;
+};
+
+#define I(x) _cairo_fixed_integer_round_down(x)
+
+/* Compute the floored division a/b. Assumes / and % perform symmetric
+ * division. */
+inline static struct quorem
+floored_divrem(int a, int b)
+{
+ struct quorem qr;
+ qr.quo = a/b;
+ qr.rem = a%b;
+ if ((a^b)<0 && qr.rem) {
+ qr.quo -= 1;
+ qr.rem += b;
+ }
+ return qr;
+}
+
+/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric
+ * division. */
+static struct quorem
+floored_muldivrem(int x, int a, int b)
+{
+ struct quorem qr;
+ long long xa = (long long)x*a;
+ qr.quo = xa/b;
+ qr.rem = xa%b;
+ if ((xa>=0) != (b>=0) && qr.rem) {
+ qr.quo -= 1;
+ qr.rem += b;
+ }
+ return qr;
+}
+
+static cairo_status_t
+polygon_init (struct polygon *polygon, int ymin, int ymax)
+{
+ unsigned h = ymax - ymin;
+
+ polygon->y_buckets = polygon->y_buckets_embedded;
+ if (h > ARRAY_LENGTH (polygon->y_buckets_embedded)) {
+ polygon->y_buckets = _cairo_malloc_ab (h, sizeof (struct edge *));
+ if (unlikely (NULL == polygon->y_buckets))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ memset (polygon->y_buckets, 0, h * sizeof (struct edge *));
+
+ polygon->ymin = ymin;
+ polygon->ymax = ymax;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+polygon_fini (struct polygon *polygon)
+{
+ if (polygon->y_buckets != polygon->y_buckets_embedded)
+ free (polygon->y_buckets);
+
+ if (polygon->edges != polygon->edges_embedded)
+ free (polygon->edges);
+}
+
+static void
+_polygon_insert_edge_into_its_y_bucket(struct polygon *polygon,
+ struct edge *e,
+ int y)
+{
+ struct edge **ptail = &polygon->y_buckets[y - polygon->ymin];
+ if (*ptail)
+ (*ptail)->prev = e;
+ e->next = *ptail;
+ e->prev = NULL;
+ *ptail = e;
+}
+
+inline static void
+polygon_add_edge (struct polygon *polygon,
+ const cairo_edge_t *edge)
+{
+ struct edge *e;
+ cairo_fixed_t dx;
+ cairo_fixed_t dy;
+ int y, ytop, ybot;
+ int ymin = polygon->ymin;
+ int ymax = polygon->ymax;
+
+ y = I(edge->top);
+ ytop = MAX(y, ymin);
+
+ y = I(edge->bottom);
+ ybot = MIN(y, ymax);
+
+ if (ybot <= ytop)
+ return;
+
+ e = polygon->edges + polygon->num_edges++;
+ e->height_left = ybot - ytop;
+ e->dir = edge->dir;
+
+ dx = edge->line.p2.x - edge->line.p1.x;
+ dy = edge->line.p2.y - edge->line.p1.y;
+
+ if (dx == 0) {
+ e->vertical = TRUE;
+ e->x.quo = edge->line.p1.x;
+ e->x.rem = 0;
+ e->dxdy.quo = 0;
+ e->dxdy.rem = 0;
+ e->dy = 0;
+ } else {
+ e->vertical = FALSE;
+ e->dxdy = floored_muldivrem (dx, CAIRO_FIXED_ONE, dy);
+ e->dy = dy;
+
+ e->x = floored_muldivrem (ytop * CAIRO_FIXED_ONE + CAIRO_FIXED_FRAC_MASK/2 - edge->line.p1.y,
+ dx, dy);
+ e->x.quo += edge->line.p1.x;
+ e->x.rem -= dy;
+ }
+
+ _polygon_insert_edge_into_its_y_bucket (polygon, e, ytop);
+}
+
+static struct edge *
+merge_sorted_edges (struct edge *head_a, struct edge *head_b)
+{
+ struct edge *head, **next, *prev;
+ int32_t x;
+
+ prev = head_a->prev;
+ next = &head;
+ if (head_a->x.quo <= head_b->x.quo) {
+ head = head_a;
+ } else {
+ head = head_b;
+ head_b->prev = prev;
+ goto start_with_b;
+ }
+
+ do {
+ x = head_b->x.quo;
+ while (head_a != NULL && head_a->x.quo <= x) {
+ prev = head_a;
+ next = &head_a->next;
+ head_a = head_a->next;
+ }
+
+ head_b->prev = prev;
+ *next = head_b;
+ if (head_a == NULL)
+ return head;
+
+start_with_b:
+ x = head_a->x.quo;
+ while (head_b != NULL && head_b->x.quo <= x) {
+ prev = head_b;
+ next = &head_b->next;
+ head_b = head_b->next;
+ }
+
+ head_a->prev = prev;
+ *next = head_a;
+ if (head_b == NULL)
+ return head;
+ } while (1);
+}
+
+static struct edge *
+sort_edges (struct edge *list,
+ unsigned int level,
+ struct edge **head_out)
+{
+ struct edge *head_other, *remaining;
+ unsigned int i;
+
+ head_other = list->next;
+
+ if (head_other == NULL) {
+ *head_out = list;
+ return NULL;
+ }
+
+ remaining = head_other->next;
+ if (list->x.quo <= head_other->x.quo) {
+ *head_out = list;
+ head_other->next = NULL;
+ } else {
+ *head_out = head_other;
+ head_other->prev = list->prev;
+ head_other->next = list;
+ list->prev = head_other;
+ list->next = NULL;
+ }
+
+ for (i = 0; i < level && remaining; i++) {
+ remaining = sort_edges (remaining, i, &head_other);
+ *head_out = merge_sorted_edges (*head_out, head_other);
+ }
+
+ return remaining;
+}
+
+static struct edge *
+merge_unsorted_edges (struct edge *head, struct edge *unsorted)
+{
+ sort_edges (unsorted, UINT_MAX, &unsorted);
+ return merge_sorted_edges (head, unsorted);
+}
+
+inline static void
+active_list_merge_edges (struct mono_scan_converter *c, struct edge *edges)
+{
+ struct edge *e;
+
+ for (e = edges; c->is_vertical && e; e = e->next)
+ c->is_vertical = e->vertical;
+
+ c->head.next = merge_unsorted_edges (c->head.next, edges);
+}
+
+inline static void
+add_span (struct mono_scan_converter *c, int x1, int x2)
+{
+ int n;
+
+ if (x1 < c->xmin)
+ x1 = c->xmin;
+ if (x2 > c->xmax)
+ x2 = c->xmax;
+ if (x2 <= x1)
+ return;
+
+ n = c->num_spans++;
+ c->spans[n].x = x1;
+ c->spans[n].coverage = 255;
+
+ n = c->num_spans++;
+ c->spans[n].x = x2;
+ c->spans[n].coverage = 0;
+}
+
+inline static void
+row (struct mono_scan_converter *c, unsigned int mask)
+{
+ struct edge *edge = c->head.next;
+ int xstart = INT_MIN, prev_x = INT_MIN;
+ int winding = 0;
+
+ c->num_spans = 0;
+ while (&c->tail != edge) {
+ struct edge *next = edge->next;
+ int xend = I(edge->x.quo);
+
+ if (--edge->height_left) {
+ edge->x.quo += edge->dxdy.quo;
+ edge->x.rem += edge->dxdy.rem;
+ if (edge->x.rem >= 0) {
+ ++edge->x.quo;
+ edge->x.rem -= edge->dy;
+ }
+
+ if (edge->x.quo < prev_x) {
+ struct edge *pos = edge->prev;
+ pos->next = next;
+ next->prev = pos;
+ do {
+ pos = pos->prev;
+ } while (edge->x.quo < pos->x.quo);
+ pos->next->prev = edge;
+ edge->next = pos->next;
+ edge->prev = pos;
+ pos->next = edge;
+ } else
+ prev_x = edge->x.quo;
+ } else {
+ edge->prev->next = next;
+ next->prev = edge->prev;
+ }
+
+ winding += edge->dir;
+ if ((winding & mask) == 0) {
+ if (I(next->x.quo) != xend) {
+ add_span (c, xstart, xend);
+ xstart = INT_MIN;
+ }
+ } else if (xstart == INT_MIN)
+ xstart = xend;
+
+ edge = next;
+ }
+}
+
+inline static void dec (struct edge *e, int h)
+{
+ e->height_left -= h;
+ if (e->height_left == 0) {
+ e->prev->next = e->next;
+ e->next->prev = e->prev;
+ }
+}
+
+static cairo_status_t
+_mono_scan_converter_init(struct mono_scan_converter *c,
+ int xmin, int ymin,
+ int xmax, int ymax)
+{
+ cairo_status_t status;
+
+ status = polygon_init (c->polygon, ymin, ymax);
+ if (unlikely (status))
+ return status;
+
+ if (xmax - xmin > ARRAY_LENGTH(c->spans_embedded)) {
+ c->spans = _cairo_malloc_ab (xmax - xmin,
+ sizeof (cairo_half_open_span_t));
+ if (unlikely (c->spans == NULL)) {
+ polygon_fini (c->polygon);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ } else
+ c->spans = c->spans_embedded;
+
+ c->xmin = xmin;
+ c->xmax = xmax;
+ c->ymin = ymin;
+ c->ymax = ymax;
+
+ c->head.vertical = 1;
+ c->head.height_left = INT_MAX;
+ c->head.x.quo = INT_MIN;
+ c->head.prev = NULL;
+ c->head.next = &c->tail;
+ c->tail.prev = &c->head;
+ c->tail.next = NULL;
+ c->tail.x.quo = INT_MAX;
+ c->tail.height_left = INT_MAX;
+ c->tail.vertical = 1;
+
+ c->is_vertical = 1;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_mono_scan_converter_fini(struct mono_scan_converter *self)
+{
+ if (self->spans != self->spans_embedded)
+ free (self->spans);
+
+ polygon_fini(self->polygon);
+}
+
+static cairo_status_t
+mono_scan_converter_allocate_edges(struct mono_scan_converter *c,
+ int num_edges)
+
+{
+ c->polygon->num_edges = 0;
+ c->polygon->edges = c->polygon->edges_embedded;
+ if (num_edges > ARRAY_LENGTH (c->polygon->edges_embedded)) {
+ c->polygon->edges = _cairo_malloc_ab (num_edges, sizeof (struct edge));
+ if (unlikely (c->polygon->edges == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+mono_scan_converter_add_edge (struct mono_scan_converter *c,
+ const cairo_edge_t *edge)
+{
+ polygon_add_edge (c->polygon, edge);
+}
+
+static void
+step_edges (struct mono_scan_converter *c, int count)
+{
+ struct edge *edge;
+
+ for (edge = c->head.next; edge != &c->tail; edge = edge->next) {
+ edge->height_left -= count;
+ if (! edge->height_left) {
+ edge->prev->next = edge->next;
+ edge->next->prev = edge->prev;
+ }
+ }
+}
+
+static cairo_status_t
+mono_scan_converter_render(struct mono_scan_converter *c,
+ unsigned int winding_mask,
+ cairo_span_renderer_t *renderer)
+{
+ struct polygon *polygon = c->polygon;
+ int i, j, h = c->ymax - c->ymin;
+ cairo_status_t status;
+
+ for (i = 0; i < h; i = j) {
+ j = i + 1;
+
+ if (polygon->y_buckets[i])
+ active_list_merge_edges (c, polygon->y_buckets[i]);
+
+ if (c->is_vertical) {
+ int min_height;
+ struct edge *e;
+
+ e = c->head.next;
+ min_height = e->height_left;
+ while (e != &c->tail) {
+ if (e->height_left < min_height)
+ min_height = e->height_left;
+ e = e->next;
+ }
+
+ while (min_height >= 2 && polygon->y_buckets[j] == NULL)
+ j++;
+ if (j != i + 1)
+ step_edges (c, j - (i + 1));
+ }
+
+ row (c, winding_mask);
+ if (c->num_spans) {
+ status = renderer->render_rows (renderer, c->ymin+i, j-i,
+ c->spans, c->num_spans);
+ if (unlikely (status))
+ return status;
+ }
+
+ /* XXX recompute after dropping edges? */
+ if (c->head.next == &c->tail)
+ c->is_vertical = 1;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+struct _cairo_mono_scan_converter {
+ cairo_scan_converter_t base;
+
+ struct mono_scan_converter converter[1];
+ cairo_fill_rule_t fill_rule;
+};
+
+typedef struct _cairo_mono_scan_converter cairo_mono_scan_converter_t;
+
+static void
+_cairo_mono_scan_converter_destroy (void *converter)
+{
+ cairo_mono_scan_converter_t *self = converter;
+ _mono_scan_converter_fini (self->converter);
+ free(self);
+}
+
+cairo_status_t
+_cairo_mono_scan_converter_add_polygon (void *converter,
+ const cairo_polygon_t *polygon)
+{
+ cairo_mono_scan_converter_t *self = converter;
+ cairo_status_t status;
+ int i;
+
+#if 0
+ FILE *file = fopen ("polygon.txt", "w");
+ _cairo_debug_print_polygon (file, polygon);
+ fclose (file);
+#endif
+
+ status = mono_scan_converter_allocate_edges (self->converter,
+ polygon->num_edges);
+ if (unlikely (status))
+ return status;
+
+ for (i = 0; i < polygon->num_edges; i++)
+ mono_scan_converter_add_edge (self->converter, &polygon->edges[i]);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_mono_scan_converter_generate (void *converter,
+ cairo_span_renderer_t *renderer)
+{
+ cairo_mono_scan_converter_t *self = converter;
+
+ return mono_scan_converter_render (self->converter,
+ self->fill_rule == CAIRO_FILL_RULE_WINDING ? ~0 : 1,
+ renderer);
+}
+
+cairo_scan_converter_t *
+_cairo_mono_scan_converter_create (int xmin,
+ int ymin,
+ int xmax,
+ int ymax,
+ cairo_fill_rule_t fill_rule)
+{
+ cairo_mono_scan_converter_t *self;
+ cairo_status_t status;
+
+ self = malloc (sizeof(struct _cairo_mono_scan_converter));
+ if (unlikely (self == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto bail_nomem;
+ }
+
+ self->base.destroy = _cairo_mono_scan_converter_destroy;
+ self->base.generate = _cairo_mono_scan_converter_generate;
+
+ status = _mono_scan_converter_init (self->converter,
+ xmin, ymin, xmax, ymax);
+ if (unlikely (status))
+ goto bail;
+
+ self->fill_rule = fill_rule;
+
+ return &self->base;
+
+ bail:
+ self->base.destroy(&self->base);
+ bail_nomem:
+ return _cairo_scan_converter_create_in_error (status);
+}
diff --git a/src/cairo-no-compositor.c b/src/cairo-no-compositor.c
new file mode 100644
index 00000000..1602a12f
--- /dev/null
+++ b/src/cairo-no-compositor.c
@@ -0,0 +1,107 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-compositor-private.h"
+
+static cairo_int_status_t
+_cairo_no_compositor_paint (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ ASSERT_NOT_REACHED;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_no_compositor_mask (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ ASSERT_NOT_REACHED;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_no_compositor_stroke (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ ASSERT_NOT_REACHED;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_no_compositor_fill (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ ASSERT_NOT_REACHED;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_no_compositor_glyphs (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_bool_t overlap)
+{
+ ASSERT_NOT_REACHED;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+const cairo_compositor_t __cairo_no_compositor = {
+ NULL,
+ _cairo_no_compositor_paint,
+ _cairo_no_compositor_mask,
+ _cairo_no_compositor_stroke,
+ _cairo_no_compositor_fill,
+ _cairo_no_compositor_glyphs,
+};
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index 0adda365..cc7e300c 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -37,6 +37,8 @@
#include "cairoint.h"
#include "cairo-output-stream-private.h"
+
+#include "cairo-array-private.h"
#include "cairo-error-private.h"
#include "cairo-compiler-private.h"
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index d9c6c2f9..0418e67b 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -347,11 +347,10 @@ _paint_page (cairo_paginated_surface_t *surface)
CAIRO_PAGINATED_MODE_ANALYZE);
status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
analysis);
- if (status || analysis->status) {
- if (status == CAIRO_INT_STATUS_SUCCESS)
- status = analysis->status;
+ if (status)
goto FAIL;
- }
+
+ assert (analysis->status == CAIRO_STATUS_SUCCESS);
if (surface->backend->set_bounding_box) {
cairo_box_t bbox;
@@ -674,33 +673,23 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
_cairo_paginated_surface_acquire_source_image,
_cairo_paginated_surface_release_source_image,
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ _cairo_paginated_surface_snapshot,
+
_cairo_paginated_surface_copy_page,
_cairo_paginated_surface_show_page,
+
_cairo_paginated_surface_get_extents,
- NULL, /* old_show_glyphs */
_cairo_paginated_surface_get_font_options,
+
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
- NULL, /* scaled_font_fini */
- NULL, /* scaled_glyph_fini */
+
_cairo_paginated_surface_paint,
_cairo_paginated_surface_mask,
_cairo_paginated_surface_stroke,
_cairo_paginated_surface_fill,
- NULL, /* show_glyphs */
- _cairo_paginated_surface_snapshot,
- NULL, /* is_similar */
NULL, /* fill_stroke */
- NULL, /* create_solid_pattern_surface */
- NULL, /* can_repaint_solid_pattern_surface */
+ NULL, /* show_glyphs */
_cairo_paginated_surface_has_show_text_glyphs,
_cairo_paginated_surface_show_text_glyphs
};
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index 1fc9a06a..087a7d0e 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -40,7 +40,6 @@
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
-
typedef struct _cairo_path_bounder {
cairo_point_t current_point;
cairo_bool_t has_extents;
@@ -161,8 +160,9 @@ _cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
cairo_box_t box_extents;
double dx, dy;
+ _cairo_stroke_style_max_distance_from_path (style, path, ctm, &dx, &dy);
+
box_extents = path->extents;
- _cairo_stroke_style_max_distance_from_path (style, ctm, &dx, &dy);
box_extents.p1.x -= _cairo_fixed_from_double (dx);
box_extents.p1.y -= _cairo_fixed_from_double (dy);
box_extents.p2.x += _cairo_fixed_from_double (dx);
@@ -183,23 +183,17 @@ _cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
double tolerance,
cairo_rectangle_int_t *extents)
{
- cairo_traps_t traps;
- cairo_box_t bbox;
+ cairo_polygon_t polygon;
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);
+ _cairo_polygon_init (&polygon, NULL, 0);
+ status = _cairo_path_fixed_stroke_to_polygon (path,
+ stroke_style,
+ ctm, ctm_inverse,
+ tolerance,
+ &polygon);
+ _cairo_box_round_to_rectangle (&polygon.extents, extents);
+ _cairo_polygon_fini (&polygon);
return status;
}
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index ce4c86a4..83393070 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -40,9 +40,14 @@
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-region-private.h"
+#include "cairo-traps-private.h"
typedef struct cairo_filler {
cairo_polygon_t *polygon;
+ double tolerance;
+
+ cairo_box_t limit;
+ cairo_bool_t has_limits;
cairo_point_t current_point;
cairo_point_t last_move_to;
@@ -86,13 +91,38 @@ _cairo_filler_move_to (void *closure,
if (unlikely (status))
return status;
- /* make sure that the closure represents a degenerate path */
+ /* make sure that the closure represents a degenerate path */
filler->current_point = *point;
filler->last_move_to = *point;
return CAIRO_STATUS_SUCCESS;
}
+static cairo_status_t
+_cairo_filler_curve_to (void *closure,
+ const cairo_point_t *p1,
+ const cairo_point_t *p2,
+ const cairo_point_t *p3)
+{
+ cairo_filler_t *filler = closure;
+ cairo_spline_t spline;
+
+ if (filler->has_limits) {
+ if (! _cairo_spline_intersects (&filler->current_point, p1, p2, p3,
+ &filler->limit))
+ return _cairo_filler_line_to (filler, p3);
+ }
+
+ if (! _cairo_spline_init (&spline,
+ (cairo_spline_add_point_func_t)_cairo_filler_line_to, filler,
+ &filler->current_point, p1, p2, p3))
+ {
+ return _cairo_filler_line_to (closure, p3);
+ }
+
+ return _cairo_spline_decompose (&spline, filler->tolerance);
+}
+
cairo_status_t
_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
double tolerance,
@@ -102,18 +132,25 @@ _cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
cairo_status_t status;
filler.polygon = polygon;
+ filler.tolerance = tolerance;
+
+ filler.has_limits = FALSE;
+ if (polygon->num_limits) {
+ filler.has_limits = TRUE;
+ filler.limit = polygon->limit;
+ }
/* make sure that the closure represents a degenerate path */
filler.current_point.x = 0;
filler.current_point.y = 0;
filler.last_move_to = filler.current_point;
- status = _cairo_path_fixed_interpret_flat (path,
- _cairo_filler_move_to,
- _cairo_filler_line_to,
- _cairo_filler_close,
- &filler,
- tolerance);
+ status = _cairo_path_fixed_interpret (path,
+ _cairo_filler_move_to,
+ _cairo_filler_line_to,
+ _cairo_filler_curve_to,
+ _cairo_filler_close,
+ &filler);
if (unlikely (status))
return status;
@@ -179,7 +216,7 @@ _cairo_path_fixed_fill_rectilinear_to_polygon (const cairo_path_fixed_t *path,
cairo_status_t status;
if (antialias != CAIRO_ANTIALIAS_NONE)
- return _cairo_path_fixed_fill_to_polygon (path, 0., polygon);
+ return _cairo_path_fixed_fill_to_polygon (path, 0., polygon);
filler.polygon = polygon;
@@ -213,22 +250,12 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
return CAIRO_STATUS_SUCCESS;
_cairo_polygon_init (&polygon, traps->limits, traps->num_limits);
-
- status = _cairo_path_fixed_fill_to_polygon (path,
- tolerance,
- &polygon);
+ status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
if (unlikely (status || polygon.num_edges == 0))
goto CLEANUP;
- if (_cairo_path_fixed_fill_is_rectilinear (path)) {
- status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (traps,
- &polygon,
- fill_rule);
- } else {
- status = _cairo_bentley_ottmann_tessellate_polygon (traps,
- &polygon,
- fill_rule);
- }
+ status = _cairo_bentley_ottmann_tessellate_polygon (traps,
+ &polygon, fill_rule);
CLEANUP:
_cairo_polygon_fini (&polygon);
diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h
index e24b1c79..9b7b4037 100644
--- a/src/cairo-path-fixed-private.h
+++ b/src/cairo-path-fixed-private.h
@@ -182,4 +182,8 @@ _cairo_path_fixed_fill_maybe_region (const cairo_path_fixed_t *path)
path->current_point.y == path->last_move_point.y;
}
+cairo_private cairo_bool_t
+_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
+ cairo_box_t *box);
+
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index d67954f8..c257d73b 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -584,6 +584,18 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
cairo_status_t status;
cairo_point_t point[3];
+ /* If this curves does not move, replace it with a line-to.
+ * This frequently happens with rounded-rectangles and r==0.
+ */
+ if (path->current_point.x == x2 && path->current_point.y == y2) {
+ if (x1 == x2 && x0 == x2 && y1 == y2 && y0 == y2)
+ return _cairo_path_fixed_line_to (path, x2, y2);
+
+ /* We may want to check for the absence of a cusp, in which case
+ * we can also replace the curve-to with a line-to.
+ */
+ }
+
/* make sure subpaths are started properly */
if (! path->has_current_point) {
status = _cairo_path_fixed_move_to (path, x0, y0);
@@ -1270,6 +1282,51 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
return FALSE;
}
+cairo_bool_t
+_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
+ cairo_box_t *box)
+{
+ const cairo_path_buf_t *buf = cairo_path_head (path);
+
+ if (! path->fill_is_rectilinear)
+ return FALSE;
+
+ /* Do we have the right number of ops? */
+ if (buf->num_ops != 5)
+ return FALSE;
+
+ /* Check whether the ops are those that would be used for a rectangle */
+ if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
+ buf->op[1] != CAIRO_PATH_OP_LINE_TO ||
+ buf->op[2] != CAIRO_PATH_OP_LINE_TO ||
+ buf->op[3] != CAIRO_PATH_OP_LINE_TO ||
+ buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH)
+ {
+ return FALSE;
+ }
+
+ /* Ok, we may have a box, if the points line up */
+ if (buf->points[0].y == buf->points[1].y &&
+ buf->points[1].x == buf->points[2].x &&
+ buf->points[2].y == buf->points[3].y &&
+ buf->points[3].x == buf->points[0].x)
+ {
+ _canonical_box (box, &buf->points[0], &buf->points[2]);
+ return TRUE;
+ }
+
+ if (buf->points[0].x == buf->points[1].x &&
+ buf->points[1].y == buf->points[2].y &&
+ buf->points[2].x == buf->points[3].x &&
+ buf->points[3].y == buf->points[0].y)
+ {
+ _canonical_box (box, &buf->points[0], &buf->points[2]);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/*
* Check whether the given path contains a single rectangle
* that is logically equivalent to:
diff --git a/src/cairo-path-stroke-boxes.c b/src/cairo-path-stroke-boxes.c
index de3a628a..794250b1 100644
--- a/src/cairo-path-stroke-boxes.c
+++ b/src/cairo-path-stroke-boxes.c
@@ -234,29 +234,31 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
}
/* Perform the adjustments of the endpoints. */
- if (a->y == b->y) {
- if (a->x < b->x) {
- if (lengthen_initial)
- a->x -= half_line_width;
- if (lengthen_final)
- b->x += half_line_width;
- } else {
- if (lengthen_initial)
- a->x += half_line_width;
- if (lengthen_final)
- b->x -= half_line_width;
- }
- } else {
- if (a->y < b->y) {
- if (lengthen_initial)
- a->y -= half_line_width;
- if (lengthen_final)
- b->y += half_line_width;
+ if (lengthen_initial | lengthen_final) {
+ if (a->y == b->y) {
+ if (a->x < b->x) {
+ if (lengthen_initial)
+ a->x -= half_line_width;
+ if (lengthen_final)
+ b->x += half_line_width;
+ } else {
+ if (lengthen_initial)
+ a->x += half_line_width;
+ if (lengthen_final)
+ b->x -= half_line_width;
+ }
} else {
- if (lengthen_initial)
- a->y += half_line_width;
- if (lengthen_final)
- b->y -= half_line_width;
+ if (a->y < b->y) {
+ if (lengthen_initial)
+ a->y -= half_line_width;
+ if (lengthen_final)
+ b->y += half_line_width;
+ } else {
+ if (lengthen_initial)
+ a->y += half_line_width;
+ if (lengthen_final)
+ b->y -= half_line_width;
+ }
}
}
@@ -291,7 +293,6 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
}
stroker->num_segments = 0;
-
return CAIRO_STATUS_SUCCESS;
}
@@ -606,6 +607,7 @@ _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path,
{
cairo_rectilinear_stroker_t rectilinear_stroker;
cairo_int_status_t status;
+ cairo_box_t box;
assert (_cairo_path_fixed_stroke_is_rectilinear (path));
@@ -616,6 +618,46 @@ _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+ if (! rectilinear_stroker.dash.dashed &&
+ _cairo_path_fixed_is_stroke_box (path, &box))
+ {
+ cairo_box_t b;
+
+ /* top */
+ b.p1.x = box.p1.x - rectilinear_stroker.half_line_width;
+ b.p2.x = box.p2.x + rectilinear_stroker.half_line_width;
+ b.p1.y = box.p1.y - rectilinear_stroker.half_line_width;
+ b.p2.y = box.p1.y + rectilinear_stroker.half_line_width;
+ status = _cairo_boxes_add (boxes, antialias, &b);
+ assert (status == CAIRO_INT_STATUS_SUCCESS);
+
+ /* left (excluding top/bottom) */
+ b.p1.x = box.p1.x - rectilinear_stroker.half_line_width;
+ b.p2.x = box.p1.x + rectilinear_stroker.half_line_width;
+ b.p1.y = box.p1.y + rectilinear_stroker.half_line_width;
+ b.p2.y = box.p2.y - rectilinear_stroker.half_line_width;
+ status = _cairo_boxes_add (boxes, antialias, &b);
+ assert (status == CAIRO_INT_STATUS_SUCCESS);
+
+ /* right (excluding top/bottom) */
+ b.p1.x = box.p2.x - rectilinear_stroker.half_line_width;
+ b.p2.x = box.p2.x + rectilinear_stroker.half_line_width;
+ b.p1.y = box.p1.y + rectilinear_stroker.half_line_width;
+ b.p2.y = box.p2.y - rectilinear_stroker.half_line_width;
+ status = _cairo_boxes_add (boxes, antialias, &b);
+ assert (status == CAIRO_INT_STATUS_SUCCESS);
+
+ /* bottom */
+ b.p1.x = box.p1.x - rectilinear_stroker.half_line_width;
+ b.p2.x = box.p2.x + rectilinear_stroker.half_line_width;
+ b.p1.y = box.p2.y - rectilinear_stroker.half_line_width;
+ b.p2.y = box.p2.y + rectilinear_stroker.half_line_width;
+ status = _cairo_boxes_add (boxes, antialias, &b);
+ assert (status == CAIRO_INT_STATUS_SUCCESS);
+
+ goto done;
+ }
+
if (boxes->num_limits) {
_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
boxes->limits,
@@ -647,8 +689,8 @@ _cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path,
if (unlikely (status))
goto BAIL;
+done:
_cairo_rectilinear_stroker_fini (&rectilinear_stroker);
-
return CAIRO_STATUS_SUCCESS;
BAIL:
diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index 3b8a67da..9128a003 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -104,6 +104,7 @@ within_tolerance (const cairo_point_t *p1,
const cairo_point_t *p2,
cairo_uint64_t tolerance)
{
+ return FALSE;
return _cairo_int64_lt (point_distance_sq (p1, p2), tolerance);
}
@@ -115,6 +116,7 @@ contour_add_point (struct stroker *stroker,
if (! within_tolerance (point, _cairo_contour_last_point (&c->contour),
stroker->contour_tolerance))
_cairo_contour_add_point (&c->contour, point);
+ //*_cairo_contour_last_point (&c->contour) = *point;
}
static void
@@ -789,7 +791,7 @@ outer_join (struct stroker *stroker,
* Make sure the miter point line lies between the two
* faces by comparing the slopes
*/
- if (1 || slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
+ if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
slope_compare_sgn (fdx2, fdy2, mdx, mdy))
{
cairo_point_t p;
@@ -1091,6 +1093,7 @@ line_to (void *closure,
cairo_stroke_face_t start;
cairo_point_t *p1 = &stroker->current_face.point;
cairo_slope_t dev_slope;
+ int move_last = 0;
stroker->has_initial_sub_path = TRUE;
@@ -1105,15 +1108,21 @@ line_to (void *closure,
compute_face (p1, &dev_slope, stroker, &start);
if (stroker->has_current_face) {
- int clockwise = join_is_clockwise (&stroker->current_face, &start);
- /* Join with final face from previous segment */
- if (! within_tolerance (&stroker->current_face.ccw, &start.ccw,
- stroker->contour_tolerance) ||
- ! within_tolerance (&stroker->current_face.cw, &start.cw,
- stroker->contour_tolerance))
- {
- outer_join (stroker, &stroker->current_face, &start, clockwise);
- inner_join (stroker, &stroker->current_face, &start, clockwise);
+ int clockwise = _cairo_slope_compare (&stroker->current_face.dev_vector,
+ &start.dev_vector);
+ if (clockwise == 0) {
+ move_last = 1;
+ } else {
+ clockwise = clockwise < 0;
+ /* Join with final face from previous segment */
+ if (! within_tolerance (&stroker->current_face.ccw, &start.ccw,
+ stroker->contour_tolerance) ||
+ ! within_tolerance (&stroker->current_face.cw, &start.cw,
+ stroker->contour_tolerance))
+ {
+ outer_join (stroker, &stroker->current_face, &start, clockwise);
+ inner_join (stroker, &stroker->current_face, &start, clockwise);
+ }
}
} else {
if (! stroker->has_first_face) {
@@ -1134,8 +1143,13 @@ line_to (void *closure,
stroker->current_face.cw.x += dev_slope.dx;
stroker->current_face.cw.y += dev_slope.dy;
- contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
- contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
+ if (move_last) {
+ *_cairo_contour_last_point (&stroker->cw.contour) = stroker->current_face.cw;
+ *_cairo_contour_last_point (&stroker->ccw.contour) = stroker->current_face.ccw;
+ } else {
+ contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
+ contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
+ }
return CAIRO_STATUS_SUCCESS;
}
@@ -1187,6 +1201,37 @@ spline_to (void *closure,
} else {
compute_face (point, tangent, stroker, &face);
+ if (face.dev_slope.x * stroker->current_face.dev_slope.x +
+ face.dev_slope.y * stroker->current_face.dev_slope.y < 0)
+ {
+ const cairo_point_t *inpt, *outpt;
+ struct stroke_contour *outer;
+ int clockwise = join_is_clockwise (&stroker->current_face, &face);
+
+ stroker->current_face.cw.x += face.point.x - stroker->current_face.point.x;
+ stroker->current_face.cw.y += face.point.y - stroker->current_face.point.y;
+ contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
+
+ stroker->current_face.ccw.x += face.point.x - stroker->current_face.point.x;
+ stroker->current_face.ccw.y += face.point.y - stroker->current_face.point.y;
+ contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
+
+ if (clockwise) {
+ inpt = &stroker->current_face.cw;
+ outpt = &face.cw;
+ outer = &stroker->cw;
+ } else {
+ inpt = &stroker->current_face.ccw;
+ outpt = &face.ccw;
+ outer = &stroker->ccw;
+ }
+ add_fan (stroker,
+ &stroker->current_face.dev_vector,
+ &face.dev_vector,
+ &stroker->current_face.point, inpt, outpt,
+ clockwise, outer);
+ }
+
contour_add_point (stroker, &stroker->cw, &face.cw);
contour_add_point (stroker, &stroker->ccw, &face.ccw);
}
@@ -1328,6 +1373,8 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
stroker.has_initial_sub_path = FALSE;
#if DEBUG
+ remove ("contours.txt");
+ remove ("polygons.txt");
_cairo_contour_init (&stroker.path, 0);
#endif
_cairo_contour_init (&stroker.cw.contour, 1);
diff --git a/src/cairo-path-stroke-tristrip.c b/src/cairo-path-stroke-tristrip.c
new file mode 100644
index 00000000..337d814b
--- /dev/null
+++ b/src/cairo-path-stroke-tristrip.c
@@ -0,0 +1,1088 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#define _BSD_SOURCE /* for hypot() */
+#include "cairoint.h"
+
+#include "cairo-box-private.h"
+#include "cairo-boxes-private.h"
+#include "cairo-error-private.h"
+#include "cairo-path-fixed-private.h"
+#include "cairo-slope-private.h"
+#include "cairo-tristrip-private.h"
+
+struct stroker {
+ cairo_stroke_style_t style;
+
+ cairo_tristrip_t *strip;
+
+ const cairo_matrix_t *ctm;
+ const cairo_matrix_t *ctm_inverse;
+ double tolerance;
+ cairo_bool_t ctm_det_positive;
+
+ cairo_pen_t pen;
+
+ cairo_bool_t has_sub_path;
+
+ cairo_point_t first_point;
+
+ cairo_bool_t has_current_face;
+ cairo_stroke_face_t current_face;
+
+ cairo_bool_t has_first_face;
+ cairo_stroke_face_t first_face;
+
+ cairo_box_t limit;
+ cairo_bool_t has_limits;
+};
+
+static inline double
+normalize_slope (double *dx, double *dy);
+
+static void
+compute_face (const cairo_point_t *point,
+ const cairo_slope_t *dev_slope,
+ struct stroker *stroker,
+ cairo_stroke_face_t *face);
+
+static void
+translate_point (cairo_point_t *point, const cairo_point_t *offset)
+{
+ point->x += offset->x;
+ point->y += offset->y;
+}
+
+static int
+slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
+{
+ double c = (dx1 * dy2 - dx2 * dy1);
+
+ if (c > 0) return 1;
+ if (c < 0) return -1;
+ return 0;
+}
+
+static inline int
+range_step (int i, int step, int max)
+{
+ i += step;
+ if (i < 0)
+ i = max - 1;
+ if (i >= max)
+ i = 0;
+ return i;
+}
+
+/*
+ * Construct a fan around the midpoint using the vertices from pen between
+ * inpt and outpt.
+ */
+static void
+add_fan (struct stroker *stroker,
+ const cairo_slope_t *in_vector,
+ const cairo_slope_t *out_vector,
+ const cairo_point_t *midpt,
+ const cairo_point_t *inpt,
+ const cairo_point_t *outpt,
+ cairo_bool_t clockwise)
+{
+ int start, stop, step, i, npoints;
+
+ if (clockwise) {
+ step = 1;
+
+ start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
+ in_vector);
+ if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
+ in_vector) < 0)
+ start = range_step (start, 1, stroker->pen.num_vertices);
+
+ stop = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
+ out_vector);
+ if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
+ out_vector) > 0)
+ {
+ stop = range_step (stop, -1, stroker->pen.num_vertices);
+ if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
+ in_vector) < 0)
+ return;
+ }
+
+ npoints = stop - start;
+ } else {
+ step = -1;
+
+ start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
+ in_vector);
+ if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
+ in_vector) < 0)
+ start = range_step (start, -1, stroker->pen.num_vertices);
+
+ stop = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
+ out_vector);
+ if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
+ out_vector) > 0)
+ {
+ stop = range_step (stop, 1, stroker->pen.num_vertices);
+ if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
+ in_vector) < 0)
+ return;
+ }
+
+ npoints = start - stop;
+ }
+ stop = range_step (stop, step, stroker->pen.num_vertices);
+ if (npoints < 0)
+ npoints += stroker->pen.num_vertices;
+ if (npoints <= 1)
+ return;
+
+ for (i = start;
+ i != stop;
+ i = range_step (i, step, stroker->pen.num_vertices))
+ {
+ cairo_point_t p = *midpt;
+ translate_point (&p, &stroker->pen.vertices[i].point);
+ //contour_add_point (stroker, c, &p);
+ }
+}
+
+static int
+join_is_clockwise (const cairo_stroke_face_t *in,
+ const cairo_stroke_face_t *out)
+{
+ return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0;
+}
+
+static void
+inner_join (struct stroker *stroker,
+ const cairo_stroke_face_t *in,
+ const cairo_stroke_face_t *out,
+ int clockwise)
+{
+ const cairo_point_t *outpt;
+
+ if (clockwise) {
+ outpt = &out->ccw;
+ } else {
+ outpt = &out->cw;
+ }
+ //contour_add_point (stroker, inner, &in->point);
+ //contour_add_point (stroker, inner, outpt);
+}
+
+static void
+inner_close (struct stroker *stroker,
+ const cairo_stroke_face_t *in,
+ cairo_stroke_face_t *out)
+{
+ const cairo_point_t *inpt;
+
+ if (join_is_clockwise (in, out)) {
+ inpt = &out->ccw;
+ } else {
+ inpt = &out->cw;
+ }
+
+ //contour_add_point (stroker, inner, &in->point);
+ //contour_add_point (stroker, inner, inpt);
+ //*_cairo_contour_first_point (&inner->contour) =
+ //*_cairo_contour_last_point (&inner->contour);
+}
+
+static void
+outer_close (struct stroker *stroker,
+ const cairo_stroke_face_t *in,
+ const cairo_stroke_face_t *out)
+{
+ const cairo_point_t *inpt, *outpt;
+ int clockwise;
+
+ if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
+ in->ccw.x == out->ccw.x && out->ccw.y == out->ccw.y)
+ {
+ return;
+ }
+ clockwise = join_is_clockwise (in, out);
+ if (clockwise) {
+ inpt = &in->cw;
+ outpt = &out->cw;
+ } else {
+ inpt = &in->ccw;
+ outpt = &out->ccw;
+ }
+
+ switch (stroker->style.line_join) {
+ case CAIRO_LINE_JOIN_ROUND:
+ /* construct a fan around the common midpoint */
+ add_fan (stroker,
+ &in->dev_vector,
+ &out->dev_vector,
+ &in->point, inpt, outpt,
+ clockwise);
+ break;
+
+ case CAIRO_LINE_JOIN_MITER:
+ default: {
+ /* dot product of incoming slope vector with outgoing slope vector */
+ double in_dot_out = -in->usr_vector.x * out->usr_vector.x +
+ -in->usr_vector.y * out->usr_vector.y;
+ double ml = stroker->style.miter_limit;
+
+ /* Check the miter limit -- lines meeting at an acute angle
+ * can generate long miters, the limit converts them to bevel
+ *
+ * Consider the miter join formed when two line segments
+ * meet at an angle psi:
+ *
+ * /.\
+ * /. .\
+ * /./ \.\
+ * /./psi\.\
+ *
+ * We can zoom in on the right half of that to see:
+ *
+ * |\
+ * | \ psi/2
+ * | \
+ * | \
+ * | \
+ * | \
+ * miter \
+ * length \
+ * | \
+ * | .\
+ * | . \
+ * |. line \
+ * \ width \
+ * \ \
+ *
+ *
+ * The right triangle in that figure, (the line-width side is
+ * shown faintly with three '.' characters), gives us the
+ * following expression relating miter length, angle and line
+ * width:
+ *
+ * 1 /sin (psi/2) = miter_length / line_width
+ *
+ * The right-hand side of this relationship is the same ratio
+ * in which the miter limit (ml) is expressed. We want to know
+ * when the miter length is within the miter limit. That is
+ * when the following condition holds:
+ *
+ * 1/sin(psi/2) <= ml
+ * 1 <= ml sin(psi/2)
+ * 1 <= ml² sin²(psi/2)
+ * 2 <= ml² 2 sin²(psi/2)
+ * 2·sin²(psi/2) = 1-cos(psi)
+ * 2 <= ml² (1-cos(psi))
+ *
+ * in · out = |in| |out| cos (psi)
+ *
+ * in and out are both unit vectors, so:
+ *
+ * in · out = cos (psi)
+ *
+ * 2 <= ml² (1 - in · out)
+ *
+ */
+ if (2 <= ml * ml * (1 - in_dot_out)) {
+ double x1, y1, x2, y2;
+ double mx, my;
+ double dx1, dx2, dy1, dy2;
+ double ix, iy;
+ double fdx1, fdy1, fdx2, fdy2;
+ double mdx, mdy;
+
+ /*
+ * we've got the points already transformed to device
+ * space, but need to do some computation with them and
+ * also need to transform the slope from user space to
+ * device space
+ */
+ /* outer point of incoming line face */
+ x1 = _cairo_fixed_to_double (inpt->x);
+ y1 = _cairo_fixed_to_double (inpt->y);
+ dx1 = in->usr_vector.x;
+ dy1 = in->usr_vector.y;
+ cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
+
+ /* outer point of outgoing line face */
+ x2 = _cairo_fixed_to_double (outpt->x);
+ y2 = _cairo_fixed_to_double (outpt->y);
+ dx2 = out->usr_vector.x;
+ dy2 = out->usr_vector.y;
+ cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+
+ /*
+ * Compute the location of the outer corner of the miter.
+ * That's pretty easy -- just the intersection of the two
+ * outer edges. We've got slopes and points on each
+ * of those edges. Compute my directly, then compute
+ * mx by using the edge with the larger dy; that avoids
+ * dividing by values close to zero.
+ */
+ my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
+ (dx1 * dy2 - dx2 * dy1));
+ if (fabs (dy1) >= fabs (dy2))
+ mx = (my - y1) * dx1 / dy1 + x1;
+ else
+ mx = (my - y2) * dx2 / dy2 + x2;
+
+ /*
+ * When the two outer edges are nearly parallel, slight
+ * perturbations in the position of the outer points of the lines
+ * caused by representing them in fixed point form can cause the
+ * intersection point of the miter to move a large amount. If
+ * that moves the miter intersection from between the two faces,
+ * then draw a bevel instead.
+ */
+
+ ix = _cairo_fixed_to_double (in->point.x);
+ iy = _cairo_fixed_to_double (in->point.y);
+
+ /* slope of one face */
+ fdx1 = x1 - ix; fdy1 = y1 - iy;
+
+ /* slope of the other face */
+ fdx2 = x2 - ix; fdy2 = y2 - iy;
+
+ /* slope from the intersection to the miter point */
+ mdx = mx - ix; mdy = my - iy;
+
+ /*
+ * Make sure the miter point line lies between the two
+ * faces by comparing the slopes
+ */
+ if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
+ slope_compare_sgn (fdx2, fdy2, mdx, mdy))
+ {
+ cairo_point_t p;
+
+ p.x = _cairo_fixed_from_double (mx);
+ p.y = _cairo_fixed_from_double (my);
+
+ //*_cairo_contour_last_point (&outer->contour) = p;
+ //*_cairo_contour_first_point (&outer->contour) = p;
+ return;
+ }
+ }
+ break;
+ }
+
+ case CAIRO_LINE_JOIN_BEVEL:
+ break;
+ }
+ //contour_add_point (stroker, outer, outpt);
+}
+
+static void
+outer_join (struct stroker *stroker,
+ const cairo_stroke_face_t *in,
+ const cairo_stroke_face_t *out,
+ int clockwise)
+{
+ const cairo_point_t *inpt, *outpt;
+
+ if (in->cw.x == out->cw.x && in->cw.y == out->cw.y &&
+ in->ccw.x == out->ccw.x && out->ccw.y == out->ccw.y)
+ {
+ return;
+ }
+ if (clockwise) {
+ inpt = &in->cw;
+ outpt = &out->cw;
+ } else {
+ inpt = &in->ccw;
+ outpt = &out->ccw;
+ }
+
+ switch (stroker->style.line_join) {
+ case CAIRO_LINE_JOIN_ROUND:
+ /* construct a fan around the common midpoint */
+ add_fan (stroker,
+ &in->dev_vector,
+ &out->dev_vector,
+ &in->point, inpt, outpt,
+ clockwise);
+ break;
+
+ case CAIRO_LINE_JOIN_MITER:
+ default: {
+ /* dot product of incoming slope vector with outgoing slope vector */
+ double in_dot_out = -in->usr_vector.x * out->usr_vector.x +
+ -in->usr_vector.y * out->usr_vector.y;
+ double ml = stroker->style.miter_limit;
+
+ /* Check the miter limit -- lines meeting at an acute angle
+ * can generate long miters, the limit converts them to bevel
+ *
+ * Consider the miter join formed when two line segments
+ * meet at an angle psi:
+ *
+ * /.\
+ * /. .\
+ * /./ \.\
+ * /./psi\.\
+ *
+ * We can zoom in on the right half of that to see:
+ *
+ * |\
+ * | \ psi/2
+ * | \
+ * | \
+ * | \
+ * | \
+ * miter \
+ * length \
+ * | \
+ * | .\
+ * | . \
+ * |. line \
+ * \ width \
+ * \ \
+ *
+ *
+ * The right triangle in that figure, (the line-width side is
+ * shown faintly with three '.' characters), gives us the
+ * following expression relating miter length, angle and line
+ * width:
+ *
+ * 1 /sin (psi/2) = miter_length / line_width
+ *
+ * The right-hand side of this relationship is the same ratio
+ * in which the miter limit (ml) is expressed. We want to know
+ * when the miter length is within the miter limit. That is
+ * when the following condition holds:
+ *
+ * 1/sin(psi/2) <= ml
+ * 1 <= ml sin(psi/2)
+ * 1 <= ml² sin²(psi/2)
+ * 2 <= ml² 2 sin²(psi/2)
+ * 2·sin²(psi/2) = 1-cos(psi)
+ * 2 <= ml² (1-cos(psi))
+ *
+ * in · out = |in| |out| cos (psi)
+ *
+ * in and out are both unit vectors, so:
+ *
+ * in · out = cos (psi)
+ *
+ * 2 <= ml² (1 - in · out)
+ *
+ */
+ if (2 <= ml * ml * (1 - in_dot_out)) {
+ double x1, y1, x2, y2;
+ double mx, my;
+ double dx1, dx2, dy1, dy2;
+ double ix, iy;
+ double fdx1, fdy1, fdx2, fdy2;
+ double mdx, mdy;
+
+ /*
+ * we've got the points already transformed to device
+ * space, but need to do some computation with them and
+ * also need to transform the slope from user space to
+ * device space
+ */
+ /* outer point of incoming line face */
+ x1 = _cairo_fixed_to_double (inpt->x);
+ y1 = _cairo_fixed_to_double (inpt->y);
+ dx1 = in->usr_vector.x;
+ dy1 = in->usr_vector.y;
+ cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
+
+ /* outer point of outgoing line face */
+ x2 = _cairo_fixed_to_double (outpt->x);
+ y2 = _cairo_fixed_to_double (outpt->y);
+ dx2 = out->usr_vector.x;
+ dy2 = out->usr_vector.y;
+ cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+
+ /*
+ * Compute the location of the outer corner of the miter.
+ * That's pretty easy -- just the intersection of the two
+ * outer edges. We've got slopes and points on each
+ * of those edges. Compute my directly, then compute
+ * mx by using the edge with the larger dy; that avoids
+ * dividing by values close to zero.
+ */
+ my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
+ (dx1 * dy2 - dx2 * dy1));
+ if (fabs (dy1) >= fabs (dy2))
+ mx = (my - y1) * dx1 / dy1 + x1;
+ else
+ mx = (my - y2) * dx2 / dy2 + x2;
+
+ /*
+ * When the two outer edges are nearly parallel, slight
+ * perturbations in the position of the outer points of the lines
+ * caused by representing them in fixed point form can cause the
+ * intersection point of the miter to move a large amount. If
+ * that moves the miter intersection from between the two faces,
+ * then draw a bevel instead.
+ */
+
+ ix = _cairo_fixed_to_double (in->point.x);
+ iy = _cairo_fixed_to_double (in->point.y);
+
+ /* slope of one face */
+ fdx1 = x1 - ix; fdy1 = y1 - iy;
+
+ /* slope of the other face */
+ fdx2 = x2 - ix; fdy2 = y2 - iy;
+
+ /* slope from the intersection to the miter point */
+ mdx = mx - ix; mdy = my - iy;
+
+ /*
+ * Make sure the miter point line lies between the two
+ * faces by comparing the slopes
+ */
+ if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
+ slope_compare_sgn (fdx2, fdy2, mdx, mdy))
+ {
+ cairo_point_t p;
+
+ p.x = _cairo_fixed_from_double (mx);
+ p.y = _cairo_fixed_from_double (my);
+
+ //*_cairo_contour_last_point (&outer->contour) = p;
+ return;
+ }
+ }
+ break;
+ }
+
+ case CAIRO_LINE_JOIN_BEVEL:
+ break;
+ }
+ //contour_add_point (stroker,outer, outpt);
+}
+
+static void
+add_cap (struct stroker *stroker,
+ const cairo_stroke_face_t *f)
+{
+ switch (stroker->style.line_cap) {
+ case CAIRO_LINE_CAP_ROUND: {
+ cairo_slope_t slope;
+
+ slope.dx = -f->dev_vector.dx;
+ slope.dy = -f->dev_vector.dy;
+
+ add_fan (stroker, &f->dev_vector, &slope,
+ &f->point, &f->ccw, &f->cw,
+ FALSE);
+ break;
+ }
+
+ case CAIRO_LINE_CAP_SQUARE: {
+ double dx, dy;
+ cairo_slope_t fvector;
+ cairo_point_t quad[4];
+
+ dx = f->usr_vector.x;
+ dy = f->usr_vector.y;
+ dx *= stroker->style.line_width / 2.0;
+ dy *= stroker->style.line_width / 2.0;
+ cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
+ fvector.dx = _cairo_fixed_from_double (dx);
+ fvector.dy = _cairo_fixed_from_double (dy);
+
+ quad[0] = f->ccw;
+ quad[1].x = f->ccw.x + fvector.dx;
+ quad[1].y = f->ccw.y + fvector.dy;
+ quad[2].x = f->cw.x + fvector.dx;
+ quad[2].y = f->cw.y + fvector.dy;
+ quad[3] = f->cw;
+
+ //contour_add_point (stroker, c, &quad[1]);
+ //contour_add_point (stroker, c, &quad[2]);
+ }
+
+ case CAIRO_LINE_CAP_BUTT:
+ default:
+ break;
+ }
+ //contour_add_point (stroker, c, &f->cw);
+}
+
+static void
+add_leading_cap (struct stroker *stroker,
+ const cairo_stroke_face_t *face)
+{
+ cairo_stroke_face_t reversed;
+ cairo_point_t t;
+
+ reversed = *face;
+
+ /* The initial cap needs an outward facing vector. Reverse everything */
+ reversed.usr_vector.x = -reversed.usr_vector.x;
+ reversed.usr_vector.y = -reversed.usr_vector.y;
+ reversed.dev_vector.dx = -reversed.dev_vector.dx;
+ reversed.dev_vector.dy = -reversed.dev_vector.dy;
+
+ t = reversed.cw;
+ reversed.cw = reversed.ccw;
+ reversed.ccw = t;
+
+ add_cap (stroker, &reversed);
+}
+
+static void
+add_trailing_cap (struct stroker *stroker,
+ const cairo_stroke_face_t *face)
+{
+ add_cap (stroker, face);
+}
+
+static inline double
+normalize_slope (double *dx, double *dy)
+{
+ double dx0 = *dx, dy0 = *dy;
+ double mag;
+
+ assert (dx0 != 0.0 || dy0 != 0.0);
+
+ if (dx0 == 0.0) {
+ *dx = 0.0;
+ if (dy0 > 0.0) {
+ mag = dy0;
+ *dy = 1.0;
+ } else {
+ mag = -dy0;
+ *dy = -1.0;
+ }
+ } else if (dy0 == 0.0) {
+ *dy = 0.0;
+ if (dx0 > 0.0) {
+ mag = dx0;
+ *dx = 1.0;
+ } else {
+ mag = -dx0;
+ *dx = -1.0;
+ }
+ } else {
+ mag = hypot (dx0, dy0);
+ *dx = dx0 / mag;
+ *dy = dy0 / mag;
+ }
+
+ return mag;
+}
+
+static void
+compute_face (const cairo_point_t *point,
+ const cairo_slope_t *dev_slope,
+ struct stroker *stroker,
+ cairo_stroke_face_t *face)
+{
+ double face_dx, face_dy;
+ cairo_point_t offset_ccw, offset_cw;
+ double slope_dx, slope_dy;
+
+ slope_dx = _cairo_fixed_to_double (dev_slope->dx);
+ slope_dy = _cairo_fixed_to_double (dev_slope->dy);
+ face->length = normalize_slope (&slope_dx, &slope_dy);
+ face->dev_slope.x = slope_dx;
+ face->dev_slope.y = slope_dy;
+
+ /*
+ * rotate to get a line_width/2 vector along the face, note that
+ * the vector must be rotated the right direction in device space,
+ * but by 90° in user space. So, the rotation depends on
+ * whether the ctm reflects or not, and that can be determined
+ * by looking at the determinant of the matrix.
+ */
+ if (! _cairo_matrix_is_identity (stroker->ctm_inverse)) {
+ /* Normalize the matrix! */
+ cairo_matrix_transform_distance (stroker->ctm_inverse,
+ &slope_dx, &slope_dy);
+ normalize_slope (&slope_dx, &slope_dy);
+
+ if (stroker->ctm_det_positive) {
+ face_dx = - slope_dy * (stroker->style.line_width / 2.0);
+ face_dy = slope_dx * (stroker->style.line_width / 2.0);
+ } else {
+ face_dx = slope_dy * (stroker->style.line_width / 2.0);
+ face_dy = - slope_dx * (stroker->style.line_width / 2.0);
+ }
+
+ /* back to device space */
+ cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
+ } else {
+ face_dx = - slope_dy * (stroker->style.line_width / 2.0);
+ face_dy = slope_dx * (stroker->style.line_width / 2.0);
+ }
+
+ offset_ccw.x = _cairo_fixed_from_double (face_dx);
+ offset_ccw.y = _cairo_fixed_from_double (face_dy);
+ offset_cw.x = -offset_ccw.x;
+ offset_cw.y = -offset_ccw.y;
+
+ face->ccw = *point;
+ translate_point (&face->ccw, &offset_ccw);
+
+ face->point = *point;
+
+ face->cw = *point;
+ translate_point (&face->cw, &offset_cw);
+
+ face->usr_vector.x = slope_dx;
+ face->usr_vector.y = slope_dy;
+
+ face->dev_vector = *dev_slope;
+}
+
+static void
+add_caps (struct stroker *stroker)
+{
+ /* check for a degenerative sub_path */
+ if (stroker->has_sub_path &&
+ ! stroker->has_first_face &&
+ ! stroker->has_current_face &&
+ stroker->style.line_cap == CAIRO_LINE_CAP_ROUND)
+ {
+ /* pick an arbitrary slope to use */
+ cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
+ cairo_stroke_face_t face;
+
+ /* arbitrarily choose first_point */
+ compute_face (&stroker->first_point, &slope, stroker, &face);
+
+ add_leading_cap (stroker, &face);
+ add_trailing_cap (stroker, &face);
+
+ /* ensure the circle is complete */
+ //_cairo_contour_add_point (&stroker->ccw.contour,
+ //_cairo_contour_first_point (&stroker->ccw.contour));
+ } else {
+ if (stroker->has_current_face)
+ add_trailing_cap (stroker, &stroker->current_face);
+
+ //_cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour);
+ //_cairo_contour_reset (&stroker->ccw.contour);
+
+ if (stroker->has_first_face) {
+ //_cairo_contour_add_point (&stroker->ccw.contour,
+ //&stroker->first_face.cw);
+ add_leading_cap (stroker, &stroker->first_face);
+ //_cairo_polygon_add_contour (stroker->polygon,
+ //&stroker->ccw.contour);
+ //_cairo_contour_reset (&stroker->ccw.contour);
+ }
+ }
+}
+
+static cairo_status_t
+move_to (void *closure,
+ const cairo_point_t *point)
+{
+ struct stroker *stroker = closure;
+
+ /* Cap the start and end of the previous sub path as needed */
+ add_caps (stroker);
+
+ stroker->has_first_face = FALSE;
+ stroker->has_current_face = FALSE;
+ stroker->has_sub_path = FALSE;
+
+ stroker->first_point = *point;
+
+ stroker->current_face.point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+line_to (void *closure,
+ const cairo_point_t *point)
+{
+ struct stroker *stroker = closure;
+ cairo_stroke_face_t start;
+ cairo_point_t *p1 = &stroker->current_face.point;
+ cairo_slope_t dev_slope;
+
+ stroker->has_sub_path = TRUE;
+
+ if (p1->x == point->x && p1->y == point->y)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_slope_init (&dev_slope, p1, point);
+ compute_face (p1, &dev_slope, stroker, &start);
+
+ if (stroker->has_current_face) {
+ int clockwise = join_is_clockwise (&stroker->current_face, &start);
+ /* Join with final face from previous segment */
+ outer_join (stroker, &stroker->current_face, &start, clockwise);
+ inner_join (stroker, &stroker->current_face, &start, clockwise);
+ } else {
+ if (! stroker->has_first_face) {
+ /* Save sub path's first face in case needed for closing join */
+ stroker->first_face = start;
+ _cairo_tristrip_move_to (stroker->strip, &start.cw);
+ stroker->has_first_face = TRUE;
+ }
+ stroker->has_current_face = TRUE;
+
+ _cairo_tristrip_add_point (stroker->strip, &start.cw);
+ _cairo_tristrip_add_point (stroker->strip, &start.ccw);
+ }
+
+ stroker->current_face = start;
+ stroker->current_face.point = *point;
+ stroker->current_face.ccw.x += dev_slope.dx;
+ stroker->current_face.ccw.y += dev_slope.dy;
+ stroker->current_face.cw.x += dev_slope.dx;
+ stroker->current_face.cw.y += dev_slope.dy;
+
+ _cairo_tristrip_add_point (stroker->strip, &stroker->current_face.cw);
+ _cairo_tristrip_add_point (stroker->strip, &stroker->current_face.ccw);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+spline_to (void *closure,
+ const cairo_point_t *point,
+ const cairo_slope_t *tangent)
+{
+ struct stroker *stroker = closure;
+ cairo_stroke_face_t face;
+
+ if (tangent->dx == 0 && tangent->dy == 0) {
+ const cairo_point_t *inpt, *outpt;
+ cairo_point_t t;
+ int clockwise;
+
+ face = stroker->current_face;
+
+ face.usr_vector.x = -face.usr_vector.x;
+ face.usr_vector.y = -face.usr_vector.y;
+ face.dev_vector.dx = -face.dev_vector.dx;
+ face.dev_vector.dy = -face.dev_vector.dy;
+
+ t = face.cw;
+ face.cw = face.ccw;
+ face.ccw = t;
+
+ clockwise = join_is_clockwise (&stroker->current_face, &face);
+ if (clockwise) {
+ inpt = &stroker->current_face.cw;
+ outpt = &face.cw;
+ } else {
+ inpt = &stroker->current_face.ccw;
+ outpt = &face.ccw;
+ }
+
+ add_fan (stroker,
+ &stroker->current_face.dev_vector,
+ &face.dev_vector,
+ &stroker->current_face.point, inpt, outpt,
+ clockwise);
+ } else {
+ compute_face (point, tangent, stroker, &face);
+
+ if (face.dev_slope.x * stroker->current_face.dev_slope.x +
+ face.dev_slope.y * stroker->current_face.dev_slope.y < 0)
+ {
+ const cairo_point_t *inpt, *outpt;
+ int clockwise = join_is_clockwise (&stroker->current_face, &face);
+
+ stroker->current_face.cw.x += face.point.x - stroker->current_face.point.x;
+ stroker->current_face.cw.y += face.point.y - stroker->current_face.point.y;
+ //contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw);
+
+ stroker->current_face.ccw.x += face.point.x - stroker->current_face.point.x;
+ stroker->current_face.ccw.y += face.point.y - stroker->current_face.point.y;
+ //contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw);
+
+ if (clockwise) {
+ inpt = &stroker->current_face.cw;
+ outpt = &face.cw;
+ } else {
+ inpt = &stroker->current_face.ccw;
+ outpt = &face.ccw;
+ }
+ add_fan (stroker,
+ &stroker->current_face.dev_vector,
+ &face.dev_vector,
+ &stroker->current_face.point, inpt, outpt,
+ clockwise);
+ }
+
+ _cairo_tristrip_add_point (stroker->strip, &face.cw);
+ _cairo_tristrip_add_point (stroker->strip, &face.ccw);
+ }
+
+ stroker->current_face = face;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+curve_to (void *closure,
+ const cairo_point_t *b,
+ const cairo_point_t *c,
+ const cairo_point_t *d)
+{
+ struct stroker *stroker = closure;
+ cairo_spline_t spline;
+ cairo_stroke_face_t face;
+
+ if (stroker->has_limits) {
+ if (! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
+ &stroker->limit))
+ return line_to (closure, d);
+ }
+
+ if (! _cairo_spline_init (&spline, spline_to, stroker,
+ &stroker->current_face.point, b, c, d))
+ return line_to (closure, d);
+
+ compute_face (&stroker->current_face.point, &spline.initial_slope,
+ stroker, &face);
+
+ if (stroker->has_current_face) {
+ int clockwise = join_is_clockwise (&stroker->current_face, &face);
+ /* Join with final face from previous segment */
+ outer_join (stroker, &stroker->current_face, &face, clockwise);
+ inner_join (stroker, &stroker->current_face, &face, clockwise);
+ } else {
+ if (! stroker->has_first_face) {
+ /* Save sub path's first face in case needed for closing join */
+ stroker->first_face = face;
+ _cairo_tristrip_move_to (stroker->strip, &face.cw);
+ stroker->has_first_face = TRUE;
+ }
+ stroker->has_current_face = TRUE;
+
+ _cairo_tristrip_add_point (stroker->strip, &face.cw);
+ _cairo_tristrip_add_point (stroker->strip, &face.ccw);
+ }
+ stroker->current_face = face;
+
+ return _cairo_spline_decompose (&spline, stroker->tolerance);
+}
+
+static cairo_status_t
+close_path (void *closure)
+{
+ struct stroker *stroker = closure;
+ cairo_status_t status;
+
+ status = line_to (stroker, &stroker->first_point);
+ if (unlikely (status))
+ return status;
+
+ if (stroker->has_first_face && stroker->has_current_face) {
+ /* Join first and final faces of sub path */
+ outer_close (stroker, &stroker->current_face, &stroker->first_face);
+ inner_close (stroker, &stroker->current_face, &stroker->first_face);
+ } else {
+ /* Cap the start and end of the sub path as needed */
+ add_caps (stroker);
+ }
+
+ stroker->has_sub_path = FALSE;
+ stroker->has_first_face = FALSE;
+ stroker->has_current_face = FALSE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_int_status_t
+_cairo_path_fixed_stroke_to_tristrip (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t*style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_tristrip_t *strip)
+{
+ struct stroker stroker;
+ cairo_int_status_t status;
+ int i;
+
+ if (style->num_dashes)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ stroker.style = *style;
+ stroker.ctm = ctm;
+ stroker.ctm_inverse = ctm_inverse;
+ stroker.tolerance = tolerance;
+
+ stroker.ctm_det_positive =
+ _cairo_matrix_compute_determinant (ctm) >= 0.0;
+
+ status = _cairo_pen_init (&stroker.pen,
+ style->line_width / 2.0,
+ tolerance, ctm);
+ if (unlikely (status))
+ return status;
+
+ if (stroker.pen.num_vertices <= 1)
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+ stroker.has_current_face = FALSE;
+ stroker.has_first_face = FALSE;
+ stroker.has_sub_path = FALSE;
+
+ stroker.has_limits = strip->num_limits > 0;
+ stroker.limit = strip->limits[0];
+ for (i = 1; i < strip->num_limits; i++)
+ _cairo_box_add_box (&stroker.limit, &strip->limits[i]);
+
+ stroker.strip = strip;
+
+ status = _cairo_path_fixed_interpret (path,
+ move_to,
+ line_to,
+ curve_to,
+ close_path,
+ &stroker);
+ /* Cap the start and end of the final sub path as needed */
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ add_caps (&stroker);
+
+ _cairo_pen_fini (&stroker.pen);
+
+ return status;
+}
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index c4382912..f25cfe4f 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -45,6 +45,7 @@
#include "cairo-path-fixed-private.h"
#include "cairo-slope-private.h"
#include "cairo-stroke-dash-private.h"
+#include "cairo-traps-private.h"
typedef struct cairo_stroker {
cairo_stroke_style_t style;
@@ -125,6 +126,7 @@ _cairo_stroker_init (cairo_stroker_t *stroker,
static void
_cairo_stroker_limit (cairo_stroker_t *stroker,
+ const cairo_path_fixed_t *path,
const cairo_box_t *boxes,
int num_boxes)
{
@@ -139,8 +141,8 @@ _cairo_stroker_limit (cairo_stroker_t *stroker,
* of the bounds but which might generate rendering that's within bounds.
*/
- _cairo_stroke_style_max_distance_from_path (&stroker->style, stroker->ctm,
- &dx, &dy);
+ _cairo_stroke_style_max_distance_from_path (&stroker->style, path,
+ stroker->ctm, &dx, &dy);
fdx = _cairo_fixed_from_double (dx);
fdy = _cairo_fixed_from_double (dy);
@@ -1293,7 +1295,8 @@ _cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t *path,
stroker.closure = polygon;
if (polygon->num_limits)
- _cairo_stroker_limit (&stroker, polygon->limits, polygon->num_limits);
+ _cairo_stroker_limit (&stroker, path,
+ polygon->limits, polygon->num_limits);
status = _cairo_path_fixed_interpret (path,
_cairo_stroker_move_to,
@@ -1328,7 +1331,6 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
cairo_polygon_t polygon;
_cairo_polygon_init (&polygon, traps->limits, traps->num_limits);
-
status = _cairo_path_fixed_stroke_to_polygon (path,
stroke_style,
ctm,
diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h
index 46a8ad6e..8be319e1 100644
--- a/src/cairo-pattern-private.h
+++ b/src/cairo-pattern-private.h
@@ -40,6 +40,8 @@
#include "cairo-types-private.h"
#include "cairo-list-private.h"
+#include <stdio.h> /* FILE* */
+
CAIRO_BEGIN_DECLS
typedef struct _cairo_pattern_observer cairo_pattern_observer_t;
@@ -59,19 +61,19 @@ struct _cairo_pattern_observer {
};
struct _cairo_pattern {
- cairo_pattern_type_t type;
cairo_reference_count_t ref_count;
cairo_status_t status;
cairo_user_data_array_t user_data;
+ cairo_list_t observers;
+
+ cairo_pattern_type_t type;
- cairo_matrix_t matrix;
cairo_filter_t filter;
cairo_extend_t extend;
- double opacity;
-
cairo_bool_t has_component_alpha;
- cairo_list_t observers;
+ cairo_matrix_t matrix;
+ double opacity;
};
struct _cairo_solid_pattern {
@@ -265,46 +267,19 @@ _cairo_mesh_pattern_coord_box (const cairo_mesh_pattern_t *mesh,
double *out_xmax,
double *out_ymax);
-enum {
- CAIRO_PATTERN_ACQUIRE_NONE = 0x0,
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT = 0x1,
-};
-cairo_private cairo_int_status_t
-_cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- unsigned int flags,
- cairo_surface_t **surface_out,
- cairo_surface_attributes_t *attributes);
-
-cairo_private void
-_cairo_pattern_release_surface (const cairo_pattern_t *pattern,
- cairo_surface_t *surface,
- cairo_surface_attributes_t *attributes);
-
-cairo_private cairo_int_status_t
-_cairo_pattern_acquire_surfaces (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,
- unsigned int width,
- unsigned int height,
- unsigned int flags,
- cairo_surface_t **src_out,
- cairo_surface_t **mask_out,
- cairo_surface_attributes_t *src_attributes,
- cairo_surface_attributes_t *mask_attributes);
+cairo_private_no_warn cairo_filter_t
+_cairo_pattern_sampled_area (const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ cairo_rectangle_int_t *sample);
cairo_private void
_cairo_pattern_get_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents);
+cairo_private cairo_int_status_t
+_cairo_pattern_get_ink_extents (const cairo_pattern_t *pattern,
+ cairo_rectangle_int_t *extents);
+
cairo_private unsigned long
_cairo_pattern_hash (const cairo_pattern_t *pattern);
@@ -353,7 +328,8 @@ _cairo_mesh_pattern_rasterize (const cairo_mesh_pattern_t *mesh,
double x_offset,
double y_offset);
-
+cairo_private void
+_cairo_debug_print_pattern (FILE *file, const cairo_pattern_t *pattern);
CAIRO_END_DECLS
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 19aa9783..f91de265 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -29,11 +29,14 @@
*/
#include "cairoint.h"
+
+#include "cairo-array-private.h"
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
+#include "cairo-image-surface-private.h"
#include "cairo-path-private.h"
#include "cairo-pattern-private.h"
-#include "cairo-image-surface-private.h"
+#include "cairo-recording-surface-private.h"
#include <float.h>
@@ -61,55 +64,85 @@
static freed_pool_t freed_pattern_pool[5];
static const cairo_solid_pattern_t _cairo_pattern_nil = {
- { CAIRO_PATTERN_TYPE_SOLID, /* type */
+ {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
{ 0, 0, 0, NULL }, /* user_data */
- { 1., 0., 0., 1., 0., 0., }, /* matrix */
+ { NULL, NULL }, /* observers */
+
+ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_FILTER_DEFAULT, /* filter */
- CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
+ CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */
+ FALSE, /* has component alpha */
+ { 1., 0., 0., 1., 0., 0., }, /* matrix */
+ 1.0 /* opacity */
+ }
};
static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = {
- { CAIRO_PATTERN_TYPE_SOLID, /* type */
+ {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NULL_POINTER, /* status */
{ 0, 0, 0, NULL }, /* user_data */
- { 1., 0., 0., 1., 0., 0., }, /* matrix */
+ { NULL, NULL }, /* observers */
+
+ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_FILTER_DEFAULT, /* filter */
- CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
+ CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */
+ FALSE, /* has component alpha */
+ { 1., 0., 0., 1., 0., 0., }, /* matrix */
+ 1.0 /* opacity */
+ }
};
const cairo_solid_pattern_t _cairo_pattern_black = {
- { CAIRO_PATTERN_TYPE_SOLID, /* type */
+ {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_SUCCESS, /* status */
{ 0, 0, 0, NULL }, /* user_data */
+ { NULL, NULL }, /* observers */
+
+ CAIRO_PATTERN_TYPE_SOLID, /* type */
+ CAIRO_FILTER_NEAREST, /* filter */
+ CAIRO_EXTEND_REPEAT, /* extend */
+ FALSE, /* has component alpha */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
- CAIRO_FILTER_DEFAULT, /* filter */
- CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
+ 1.0 /* opacity */
+ },
{ 0., 0., 0., 1., 0, 0, 0, 0xffff },/* color (double rgba, short rgba) */
};
const cairo_solid_pattern_t _cairo_pattern_clear = {
- { CAIRO_PATTERN_TYPE_SOLID, /* type */
+ {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_SUCCESS, /* status */
{ 0, 0, 0, NULL }, /* user_data */
+ { NULL, NULL }, /* observers */
+
+ CAIRO_PATTERN_TYPE_SOLID, /* type */
+ CAIRO_FILTER_NEAREST, /* filter */
+ CAIRO_EXTEND_REPEAT, /* extend */
+ FALSE, /* has component alpha */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
- CAIRO_FILTER_DEFAULT, /* filter */
- CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
+ 1.0 /* opacity */
+ },
{ 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */
};
const cairo_solid_pattern_t _cairo_pattern_white = {
- { CAIRO_PATTERN_TYPE_SOLID, /* type */
+ {
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_SUCCESS, /* status */
{ 0, 0, 0, NULL }, /* user_data */
+ { NULL, NULL }, /* observers */
+
+ CAIRO_PATTERN_TYPE_SOLID, /* type */
+ CAIRO_FILTER_NEAREST, /* filter */
+ CAIRO_EXTEND_REPEAT, /* extend */
+ FALSE, /* has component alpha */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
- CAIRO_FILTER_DEFAULT, /* filter */
- CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
+ 1.0 /* opacity */
+ },
{ 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */
};
@@ -249,7 +282,6 @@ _cairo_mesh_pattern_init_copy (cairo_mesh_pattern_t *pattern,
*pattern = *other;
_cairo_array_init (&pattern->patches, sizeof (cairo_mesh_patch_t));
-
return _cairo_array_append_multiple (&pattern->patches,
_cairo_array_index_const (&other->patches, 0),
_cairo_array_num_elements (&other->patches));
@@ -477,7 +509,6 @@ _cairo_pattern_create_copy (cairo_pattern_t **pattern_out,
return CAIRO_STATUS_SUCCESS;
}
-
void
_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
const cairo_color_t *color)
@@ -2049,477 +2080,6 @@ _cairo_pattern_transform (cairo_pattern_t *pattern,
cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
}
-static void
-_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
- double offset_x,
- double offset_y,
- int width,
- int height,
- cairo_bool_t *is_horizontal,
- cairo_bool_t *is_vertical)
-{
- cairo_point_double_t point0, point1;
- double a, b, c, d, tx, ty;
- double scale, start, dx, dy;
- cairo_fixed_t factors[3];
- int i;
-
- /* To classify a pattern as horizontal or vertical, we first
- * compute the (fixed point) factors at the corners of the
- * pattern. We actually only need 3/4 corners, so we skip the
- * fourth.
- */
- point0 = pattern->pd1;
- point1 = pattern->pd2;
-
- _cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
-
- dx = point1.x - point0.x;
- dy = point1.y - point0.y;
- scale = dx * dx + dy * dy;
- scale = (scale) ? 1.0 / scale : 1.0;
-
- start = dx * point0.x + dy * point0.y;
-
- for (i = 0; i < 3; i++) {
- double qx_device = (i % 2) * (width - 1) + offset_x;
- double qy_device = (i / 2) * (height - 1) + offset_y;
-
- /* transform fragment into pattern space */
- double qx = a * qx_device + c * qy_device + tx;
- double qy = b * qx_device + d * qy_device + ty;
-
- factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale);
- }
-
- /* We consider a pattern to be vertical if the fixed point factor
- * at the two upper corners is the same. We could accept a small
- * change, but determining what change is acceptable would require
- * sorting the stops in the pattern and looking at the differences.
- *
- * Horizontal works the same way with the two left corners.
- */
-
- *is_vertical = factors[1] == factors[0];
- *is_horizontal = factors[2] == factors[0];
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **out,
- cairo_surface_attributes_t *attr)
-{
- cairo_image_surface_t *image;
- pixman_image_t *pixman_image;
- pixman_transform_t pixman_transform;
- cairo_circle_double_t extremes[2];
- pixman_point_fixed_t p1, p2;
- cairo_int_status_t status;
- cairo_bool_t repeat = FALSE;
- int ix, iy;
- pixman_gradient_stop_t pixman_stops_static[2];
- pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
- unsigned int i;
- int clone_offset_x, clone_offset_y;
- cairo_matrix_t matrix = pattern->base.matrix;
-
- if (CAIRO_INJECT_FAULT ())
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
- pixman_stops = _cairo_malloc_ab (pattern->n_stops,
- sizeof(pixman_gradient_stop_t));
- if (unlikely (pixman_stops == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- for (i = 0; i < pattern->n_stops; i++) {
- pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
- pixman_stops[i].color.red = pattern->stops[i].color.red_short;
- pixman_stops[i].color.green = pattern->stops[i].color.green_short;
- pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
- pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
- }
-
- _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
-
- p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
- p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
- p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
- p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
-
- if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
- pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
- pixman_stops,
- pattern->n_stops);
- } else {
- pixman_fixed_t r1, r2;
-
- r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
- r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
-
- pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
- pixman_stops,
- pattern->n_stops);
- }
-
- if (pixman_stops != pixman_stops_static)
- free (pixman_stops);
-
- if (unlikely (pixman_image == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- if (_cairo_surface_is_image (dst))
- {
- image = (cairo_image_surface_t *)
- _cairo_image_surface_create_for_pixman_image (pixman_image,
- PIXMAN_a8r8g8b8);
- if (image->base.status)
- {
- pixman_image_unref (pixman_image);
- return image->base.status;
- }
-
- attr->x_offset = attr->y_offset = 0;
- attr->matrix = matrix;
- attr->extend = pattern->base.extend;
- attr->filter = CAIRO_FILTER_NEAREST;
- attr->has_component_alpha = pattern->base.has_component_alpha;
-
- *out = &image->base;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
- cairo_bool_t is_horizontal;
- cairo_bool_t is_vertical;
-
- _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern,
- x, y, width, height,
- &is_horizontal, &is_vertical);
- if (is_horizontal) {
- height = 1;
- repeat = TRUE;
- }
- /* width-1 repeating patterns are quite slow with scan-line based
- * compositing code, so we use a wider strip and spend some extra
- * expense in computing the gradient. It's possible that for narrow
- * gradients we'd be better off using a 2 or 4 pixel strip; the
- * wider the gradient, the more it's worth spending extra time
- * computing a sample.
- */
- if (is_vertical && width > 8) {
- width = 8;
- repeat = TRUE;
- }
- }
-
- if (! pixman_image_set_filter (pixman_image, PIXMAN_FILTER_BILINEAR,
- NULL, 0))
- {
- pixman_image_unref (pixman_image);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- image = (cairo_image_surface_t *)
- cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
- if (image->base.status) {
- pixman_image_unref (pixman_image);
- return image->base.status;
- }
-
- ix = x;
- iy = y;
- status = _cairo_matrix_to_pixman_matrix_offset (&matrix,
- pattern->base.filter,
- width/2., height/2.,
- &pixman_transform,
- &ix, &iy);
- if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
- if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) ||
- ! pixman_image_set_transform (pixman_image, &pixman_transform))
- {
- cairo_surface_destroy (&image->base);
- pixman_image_unref (pixman_image);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
- }
-
- switch (pattern->base.extend) {
- case CAIRO_EXTEND_NONE:
- pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NONE);
- break;
- case CAIRO_EXTEND_REPEAT:
- pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NORMAL);
- break;
- case CAIRO_EXTEND_REFLECT:
- pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_REFLECT);
- break;
- case CAIRO_EXTEND_PAD:
- pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_PAD);
- break;
- }
-
- pixman_image_composite32 (PIXMAN_OP_SRC,
- pixman_image,
- NULL,
- image->pixman_image,
- ix, iy,
- 0, 0,
- 0, 0,
- width, height);
-
- pixman_image_unref (pixman_image);
-
- _cairo_debug_check_image_surface_is_defined (&image->base);
-
- status = _cairo_surface_clone_similar (dst, &image->base,
- 0, 0, width, height,
- &clone_offset_x,
- &clone_offset_y,
- out);
-
- cairo_surface_destroy (&image->base);
-
- attr->x_offset = -x;
- attr->y_offset = -y;
- cairo_matrix_init_identity (&attr->matrix);
- attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
- attr->filter = CAIRO_FILTER_NEAREST;
- attr->has_component_alpha = pattern->base.has_component_alpha;
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_mesh (const cairo_mesh_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **out,
- cairo_surface_attributes_t *attr)
-{
- cairo_surface_t *image;
- void *data;
- cairo_status_t status;
- int clone_offset_x, clone_offset_y;
- int stride;
-
- image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
- if (unlikely (image->status))
- return image->status;
-
- stride = cairo_image_surface_get_stride (image);
- data = cairo_image_surface_get_data (image);
-
- _cairo_mesh_pattern_rasterize (pattern, data, width, height, stride, -x, -y);
-
- attr->x_offset = -x;
- attr->y_offset = -y;
- attr->filter = CAIRO_FILTER_NEAREST;
- attr->extend = pattern->base.extend;
- cairo_matrix_init_identity (&attr->matrix);
- attr->has_component_alpha = pattern->base.has_component_alpha;
-
- if (_cairo_surface_is_image (dst)) {
- *out = image;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- status = _cairo_surface_clone_similar (dst, image,
- 0, 0, width, height,
- &clone_offset_x,
- &clone_offset_y, out);
-
- cairo_surface_destroy (image);
-
- return status;
-}
-
-/* We maintain a small cache here, because we don't want to constantly
- * recreate surfaces for simple solid colors. */
-#define MAX_SURFACE_CACHE_SIZE 16
-static struct {
- struct _cairo_pattern_solid_surface_cache{
- cairo_color_t color;
- cairo_surface_t *surface;
- } cache[MAX_SURFACE_CACHE_SIZE];
- int size;
-} solid_surface_cache;
-
-static cairo_bool_t
-_cairo_pattern_solid_surface_matches (
- const struct _cairo_pattern_solid_surface_cache *cache,
- const cairo_solid_pattern_t *pattern,
- cairo_surface_t *dst)
-{
- if (cairo_surface_get_content (cache->surface) != _cairo_color_get_content (&pattern->color))
- return FALSE;
-
- if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
- return FALSE;
-
- if (! _cairo_surface_is_similar (cache->surface, dst))
- return FALSE;
-
- return TRUE;
-}
-
-static cairo_bool_t
-_cairo_pattern_solid_surface_matches_color (
- const struct _cairo_pattern_solid_surface_cache *cache,
- const cairo_solid_pattern_t *pattern,
- cairo_surface_t *dst)
-{
- if (! _cairo_color_equal (&cache->color, &pattern->color))
- return FALSE;
-
- return _cairo_pattern_solid_surface_matches (cache, pattern, dst);
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **out,
- cairo_surface_attributes_t *attribs)
-{
- static int i;
-
- cairo_surface_t *surface, *to_destroy = NULL;
- cairo_status_t status;
-
- CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
-
- /* Check cache first */
- if (i < solid_surface_cache.size &&
- _cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
- pattern,
- dst))
- {
- goto DONE;
- }
-
- for (i = 0 ; i < solid_surface_cache.size; i++) {
- if (_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
- pattern,
- dst))
- {
- goto DONE;
- }
- }
-
- /* Choose a surface to repaint/evict */
- surface = NULL;
- if (solid_surface_cache.size == MAX_SURFACE_CACHE_SIZE) {
- i = rand () % MAX_SURFACE_CACHE_SIZE;
- surface = solid_surface_cache.cache[i].surface;
-
- if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
- pattern,
- dst))
- {
- /* Reuse the surface instead of evicting */
- status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
- if (unlikely (status))
- goto EVICT;
-
- cairo_surface_reference (surface);
- }
- else
- {
- EVICT:
- surface = NULL;
- }
- }
-
- if (surface == NULL) {
- /* Not cached, need to create new */
- surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
- if (surface == NULL) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto UNLOCK;
- }
- if (unlikely (surface->status)) {
- status = surface->status;
- goto UNLOCK;
- }
-
- if (unlikely (! _cairo_surface_is_similar (surface, dst)))
- {
- /* In the rare event of a substitute surface being returned,
- * don't cache the fallback.
- */
- *out = surface;
- goto NOCACHE;
- }
- }
-
- if (i == solid_surface_cache.size)
- solid_surface_cache.size++;
-
- to_destroy = solid_surface_cache.cache[i].surface;
- solid_surface_cache.cache[i].surface = surface;
- solid_surface_cache.cache[i].color = pattern->color;
-
-DONE:
- *out = cairo_surface_reference (solid_surface_cache.cache[i].surface);
-
-NOCACHE:
- attribs->x_offset = attribs->y_offset = 0;
- cairo_matrix_init_identity (&attribs->matrix);
- attribs->extend = CAIRO_EXTEND_REPEAT;
- attribs->filter = CAIRO_FILTER_NEAREST;
- attribs->has_component_alpha = pattern->base.has_component_alpha;
-
- status = CAIRO_STATUS_SUCCESS;
-
-UNLOCK:
- CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
-
- if (to_destroy)
- cairo_surface_destroy (to_destroy);
-
- return status;
-}
-
-static void
-_cairo_pattern_reset_solid_surface_cache (void)
-{
- CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
-
- /* remove surfaces starting from the end so that solid_surface_cache.cache
- * is always in a consistent state when we release the mutex. */
- while (solid_surface_cache.size) {
- cairo_surface_t *surface;
-
- solid_surface_cache.size--;
- surface = solid_surface_cache.cache[solid_surface_cache.size].surface;
- solid_surface_cache.cache[solid_surface_cache.size].surface = NULL;
-
- /* release the lock to avoid the possibility of a recursive
- * deadlock when the surface destroy closure gets called */
- CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
- cairo_surface_destroy (surface);
- CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
- }
-
- CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
-}
-
static cairo_bool_t
_linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear)
{
@@ -3546,7 +3106,7 @@ _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern)
static cairo_bool_t
_surface_is_opaque (const cairo_surface_pattern_t *pattern,
- const cairo_rectangle_int_t *r)
+ const cairo_rectangle_int_t *sample)
{
if (pattern->surface->content & CAIRO_CONTENT_ALPHA)
return FALSE;
@@ -3554,16 +3114,16 @@ _surface_is_opaque (const cairo_surface_pattern_t *pattern,
if (pattern->base.extend != CAIRO_EXTEND_NONE)
return TRUE;
- if (r != NULL) {
+ if (sample != NULL) {
cairo_rectangle_int_t extents;
if (! _cairo_surface_get_extents (pattern->surface, &extents))
return TRUE;
- if (r->x >= extents.x &&
- r->y >= extents.y &&
- r->x + r->width <= extents.x + extents.width &&
- r->y + r->height <= extents.y + extents.height)
+ if (sample->x >= extents.x &&
+ sample->y >= extents.y &&
+ sample->x + sample->width <= extents.x + extents.width &&
+ sample->y + sample->height <= extents.y + extents.height)
{
return TRUE;
}
@@ -3587,7 +3147,7 @@ _surface_is_clear (const cairo_surface_pattern_t *pattern)
static cairo_bool_t
_gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *sample)
{
unsigned int i;
@@ -3608,14 +3168,14 @@ _gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
if (_linear_pattern_is_degenerate (linear))
return FALSE;
- if (extents == NULL)
+ if (sample == NULL)
return FALSE;
_cairo_linear_pattern_box_to_parameter (linear,
- extents->x,
- extents->y,
- extents->x + extents->width,
- extents->y + extents->height,
+ sample->x,
+ sample->y,
+ sample->x + sample->width,
+ sample->y + sample->height,
t);
if (t[0] < 0.0 || t[1] > 1.0)
@@ -3642,7 +3202,7 @@ _gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
**/
cairo_bool_t
_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *sample)
{
const cairo_pattern_union_t *pattern;
@@ -3654,10 +3214,10 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_pattern_is_opaque_solid (abstract_pattern);
case CAIRO_PATTERN_TYPE_SURFACE:
- return _surface_is_opaque (&pattern->surface, extents);
+ return _surface_is_opaque (&pattern->surface, sample);
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
- return _gradient_is_opaque (&pattern->gradient.base, extents);
+ return _gradient_is_opaque (&pattern->gradient.base, sample);
case CAIRO_PATTERN_TYPE_MESH:
return FALSE;
}
@@ -3749,437 +3309,53 @@ _cairo_pattern_analyze_filter (const cairo_pattern_t *pattern,
return optimized_filter;
}
-
-static double
-_pixman_nearest_sample (double d)
-{
- return ceil (d - .5);
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- unsigned int flags,
- cairo_surface_t **out,
- cairo_surface_attributes_t *attr)
+cairo_filter_t
+_cairo_pattern_sampled_area (const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ cairo_rectangle_int_t *sample)
{
- cairo_surface_t *surface;
- cairo_rectangle_int_t extents;
- cairo_rectangle_int_t sampled_area;
- double x1, y1, x2, y2;
- int tx, ty;
+ cairo_filter_t filter;
+ double x1, x2, y1, y2;
double pad;
- cairo_bool_t is_identity;
- cairo_bool_t is_bounded;
- cairo_int_status_t status;
-
- surface = cairo_surface_reference (pattern->surface);
-
- is_identity = FALSE;
- attr->matrix = pattern->base.matrix;
- attr->extend = pattern->base.extend;
- attr->filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
- attr->has_component_alpha = pattern->base.has_component_alpha;
-
- attr->x_offset = attr->y_offset = tx = ty = 0;
- if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
- cairo_matrix_init_identity (&attr->matrix);
- attr->x_offset = tx;
- attr->y_offset = ty;
- is_identity = TRUE;
- } else if (attr->filter == CAIRO_FILTER_NEAREST) {
- /*
- * For NEAREST, we can remove the fractional translation component
- * from the transformation - this ensures that the pattern will always
- * hit fast-paths in the backends for simple transformations that
- * become (almost) identity, without loss of quality.
- */
- attr->matrix.x0 = 0;
- attr->matrix.y0 = 0;
- if (_cairo_matrix_is_pixel_exact (&attr->matrix)) {
- /* The rounding here is rather peculiar as it needs to match the
- * rounding performed on the sample coordinate used by pixman.
- */
- attr->matrix.x0 = _pixman_nearest_sample (pattern->base.matrix.x0);
- attr->matrix.y0 = _pixman_nearest_sample (pattern->base.matrix.y0);
- } else {
- attr->matrix.x0 = pattern->base.matrix.x0;
- attr->matrix.y0 = pattern->base.matrix.y0;
- }
- if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
- cairo_matrix_init_identity (&attr->matrix);
- attr->x_offset = tx;
- attr->y_offset = ty;
- is_identity = TRUE;
- }
+ filter = _cairo_pattern_analyze_filter (pattern, &pad);
+ if (pad == 0.0 && _cairo_matrix_is_identity (&pattern->matrix)) {
+ *sample = *extents;
+ return filter;
}
- /* XXX: Hack:
- *
- * The way we currently support CAIRO_EXTEND_REFLECT is to create
- * an image twice bigger on each side, and create a pattern of four
- * images such that the new image, when repeated, has the same effect
- * of reflecting the original pattern.
- */
- if (flags & CAIRO_PATTERN_ACQUIRE_NO_REFLECT &&
- attr->extend == CAIRO_EXTEND_REFLECT)
- {
- cairo_t *cr;
- cairo_surface_t *src;
- int w, h;
-
- is_bounded = _cairo_surface_get_extents (surface, &extents);
- assert (is_bounded);
-
- status = _cairo_surface_clone_similar (dst, surface,
- extents.x, extents.y,
- extents.width, extents.height,
- &extents.x, &extents.y, &src);
- if (unlikely (status))
- goto BAIL;
-
- w = 2 * extents.width;
- h = 2 * extents.height;
-
- if (is_identity) {
- attr->x_offset = -x;
- x += tx;
- while (x <= -w)
- x += w;
- while (x >= w)
- x -= w;
- extents.x += x;
- tx = x = 0;
-
- attr->y_offset = -y;
- y += ty;
- while (y <= -h)
- y += h;
- while (y >= h)
- y -= h;
- extents.y += y;
- ty = y = 0;
- }
-
- cairo_surface_destroy (surface);
- 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;
- }
-
- surface->device_transform = pattern->surface->device_transform;
- surface->device_transform_inverse = pattern->surface->device_transform_inverse;
-
- cr = cairo_create (surface);
-
- cairo_set_source_surface (cr, src, -extents.x, -extents.y);
- cairo_paint (cr);
-
- cairo_scale (cr, -1, +1);
- cairo_set_source_surface (cr, src, extents.x-w, -extents.y);
- cairo_paint (cr);
- cairo_set_source_surface (cr, src, extents.x, -extents.y);
- cairo_paint (cr);
-
- cairo_scale (cr, +1, -1);
- cairo_set_source_surface (cr, src, extents.x-w, extents.y-h);
- cairo_paint (cr);
- cairo_set_source_surface (cr, src, extents.x, extents.y-h);
- cairo_paint (cr);
- cairo_set_source_surface (cr, src, extents.x-w, extents.y);
- cairo_paint (cr);
- cairo_set_source_surface (cr, src, extents.x, extents.y);
- cairo_paint (cr);
-
- cairo_scale (cr, -1, +1);
- cairo_set_source_surface (cr, src, -extents.x, extents.y-h);
- cairo_paint (cr);
- cairo_set_source_surface (cr, src, -extents.x, extents.y);
- cairo_paint (cr);
-
- status = cairo_status (cr);
- cairo_destroy (cr);
-
- cairo_surface_destroy (src);
-
- if (unlikely (status))
- goto BAIL;
-
- attr->extend = CAIRO_EXTEND_REPEAT;
- }
-
- /* 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.
- */
- x1 = x;
- y1 = y;
- x2 = x + (int) width;
- y2 = y + (int) height;
- if (! is_identity) {
- _cairo_matrix_transform_bounding_box (&attr->matrix,
- &x1, &y1, &x2, &y2,
- NULL);
- }
-
- sampled_area.x = floor (x1 - pad);
- sampled_area.y = floor (y1 - pad);
- sampled_area.width = ceil (x2 + pad) - sampled_area.x;
- sampled_area.height = ceil (y2 + pad) - sampled_area.y;
-
- sampled_area.x += tx;
- sampled_area.y += ty;
-
- if ( _cairo_surface_get_extents (surface, &extents)) {
- if (attr->extend == CAIRO_EXTEND_NONE) {
- /* Never acquire a larger area than the source itself */
- _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.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;
- }
- }
- }
-
- status = _cairo_surface_clone_similar (dst, surface,
- extents.x, extents.y,
- extents.width, extents.height,
- &x, &y, out);
- if (unlikely (status))
- goto BAIL;
-
- if (x != 0 || y != 0) {
- if (is_identity) {
- attr->x_offset -= x;
- attr->y_offset -= y;
- } else {
- cairo_matrix_t m;
-
- x -= attr->x_offset;
- y -= attr->y_offset;
- attr->x_offset = 0;
- attr->y_offset = 0;
-
- cairo_matrix_init_translate (&m, -x, -y);
- cairo_matrix_multiply (&attr->matrix, &attr->matrix, &m);
- }
- }
-
- /* reduce likelihood of range overflow with large downscaling */
- if (! is_identity) {
- cairo_matrix_t m;
- cairo_status_t invert_status;
-
- m = attr->matrix;
- invert_status = cairo_matrix_invert (&m);
- assert (invert_status == CAIRO_STATUS_SUCCESS);
-
- if (m.x0 != 0. || m.y0 != 0.) {
- /* pixman also limits the [xy]_offset to 16 bits so evenly
- * spread the bits between the two.
- */
- x = floor (m.x0 / 2);
- y = floor (m.y0 / 2);
- attr->x_offset -= x;
- attr->y_offset -= y;
- cairo_matrix_init_translate (&m, x, y);
- cairo_matrix_multiply (&attr->matrix, &m, &attr->matrix);
- }
- }
-
- BAIL:
- cairo_surface_destroy (surface);
- return status;
-}
-
-/**
- * _cairo_pattern_acquire_surface:
- * @pattern: a #cairo_pattern_t
- * @dst: destination surface
- * @x: X coordinate in source corresponding to left side of destination area
- * @y: Y coordinate in source corresponding to top side of destination area
- * @width: width of destination area
- * @height: height of destination area
- * @surface_out: location to store a pointer to a surface
- * @attributes: surface attributes that destination backend should apply to
- * the returned surface
- *
- * A convenience function to obtain a surface to use as the source for
- * drawing on @dst.
- *
- * Note that this function is only suitable for use when the destination
- * surface is pixel based and 1 device unit maps to one pixel.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out.
- **/
-cairo_int_status_t
-_cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- unsigned int flags,
- cairo_surface_t **surface_out,
- cairo_surface_attributes_t *attributes)
-{
- if (unlikely (pattern->status)) {
- *surface_out = NULL;
- return pattern->status;
- }
+ x1 = extents->x;
+ y1 = extents->y;
+ x2 = extents->x + (int) extents->width;
+ y2 = extents->y + (int) extents->height;
- switch (pattern->type) {
- case CAIRO_PATTERN_TYPE_SOLID:
- return _cairo_pattern_acquire_surface_for_solid ((cairo_solid_pattern_t *) pattern,
- dst, x, y, width, height,
- surface_out,
- attributes);
-
- case CAIRO_PATTERN_TYPE_LINEAR:
- case CAIRO_PATTERN_TYPE_RADIAL:
- return _cairo_pattern_acquire_surface_for_gradient ((cairo_gradient_pattern_t *) pattern,
- dst, x, y, width, height,
- surface_out,
- attributes);
-
- case CAIRO_PATTERN_TYPE_SURFACE:
- return _cairo_pattern_acquire_surface_for_surface ((cairo_surface_pattern_t *) pattern,
- dst, x, y, width, height,
- flags,
- surface_out,
- attributes);
-
- case CAIRO_PATTERN_TYPE_MESH:
- return _cairo_pattern_acquire_surface_for_mesh ((cairo_mesh_pattern_t *) pattern,
- dst, x, y, width, height,
- surface_out,
- attributes);
-
- default:
- ASSERT_NOT_REACHED;
- return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
- }
-}
-
-/**
- * _cairo_pattern_release_surface:
- * @pattern: a #cairo_pattern_t
- * @surface: a surface obtained by _cairo_pattern_acquire_surface
- * @attributes: attributes obtained by _cairo_pattern_acquire_surface
- *
- * Releases resources obtained by _cairo_pattern_acquire_surface.
- **/
-void
-_cairo_pattern_release_surface (const cairo_pattern_t *pattern,
- cairo_surface_t *surface,
- cairo_surface_attributes_t *attributes)
-{
- cairo_surface_destroy (surface);
-}
-
-cairo_int_status_t
-_cairo_pattern_acquire_surfaces (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,
- unsigned int width,
- unsigned int height,
- unsigned int flags,
- cairo_surface_t **src_out,
- cairo_surface_t **mask_out,
- cairo_surface_attributes_t *src_attributes,
- cairo_surface_attributes_t *mask_attributes)
-{
- cairo_int_status_t status;
- cairo_pattern_union_t src_tmp;
-
- if (unlikely (src->status))
- return src->status;
- if (unlikely (mask != NULL && mask->status))
- return mask->status;
-
- /* If src and mask are both solid, then the mask alpha can be
- * combined into src and mask can be ignored. */
-
- if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
- mask &&
- ! mask->has_component_alpha &&
- mask->type == CAIRO_PATTERN_TYPE_SOLID)
- {
- cairo_color_t combined;
- cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
- cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
-
- combined = src_solid->color;
- _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
-
- _cairo_pattern_init_solid (&src_tmp.solid, &combined);
-
- src = &src_tmp.base;
- mask = NULL;
- }
+ _cairo_matrix_transform_bounding_box (&pattern->matrix,
+ &x1, &y1, &x2, &y2,
+ NULL);
+ if (x1 > CAIRO_RECT_INT_MIN)
+ sample->x = floor (x1 - pad);
+ else
+ sample->x = CAIRO_RECT_INT_MIN;
- status = _cairo_pattern_acquire_surface (src, dst,
- src_x, src_y,
- width, height,
- flags,
- src_out, src_attributes);
- if (unlikely (status))
- goto BAIL;
+ if (y1 > CAIRO_RECT_INT_MIN)
+ sample->y = floor (y1 - pad);
+ else
+ sample->y = CAIRO_RECT_INT_MIN;
- if (mask == NULL) {
- *mask_out = NULL;
- goto BAIL;
- }
+ if (x2 < CAIRO_RECT_INT_MAX)
+ sample->width = ceil (x2 + pad);
+ else
+ sample->width = CAIRO_RECT_INT_MAX;
- status = _cairo_pattern_acquire_surface (mask, dst,
- mask_x, mask_y,
- width, height,
- flags,
- mask_out, mask_attributes);
- if (unlikely (status))
- _cairo_pattern_release_surface (src, *src_out, src_attributes);
+ if (y2 < CAIRO_RECT_INT_MAX)
+ sample->height = ceil (y2 + pad);
+ else
+ sample->height = CAIRO_RECT_INT_MAX;
- BAIL:
- if (src == &src_tmp.base)
- _cairo_pattern_fini (&src_tmp.base);
+ sample->width -= sample->x;
+ sample->height -= sample->y;
- return status;
+ return filter;
}
/**
@@ -4381,7 +3557,7 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
*
* Return the "target-space" inked extents of @pattern in @extents.
**/
-void
+cairo_int_status_t
_cairo_pattern_get_ink_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents)
{
@@ -4392,33 +3568,28 @@ _cairo_pattern_get_ink_extents (const cairo_pattern_t *pattern,
(const cairo_surface_pattern_t *) pattern;
cairo_surface_t *surface = surface_pattern->surface;
- if (surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
+ if (_cairo_surface_is_recording (surface)) {
cairo_matrix_t imatrix;
- double x1, y1, x2, y2, width, height;
+ cairo_box_t box;
cairo_status_t status;
- cairo_recording_surface_ink_extents (surface, &x1, &y1, &width, &height);
imatrix = pattern->matrix;
status = cairo_matrix_invert (&imatrix);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
- x2 = x1 + width;
- y2 = y1 + height;
- _cairo_matrix_transform_bounding_box (&imatrix,
- &x1, &y1, &x2, &y2,
- NULL);
- x1 = floor (x1);
- y1 = floor (y1);
- x2 = ceil (x2);
- y2 = ceil (y2);
- extents->x = x1; extents->width = x2 - x1;
- extents->y = y1; extents->height = y2 - y1;
- return;
+ status = _cairo_recording_surface_get_ink_bbox ((cairo_recording_surface_t *)surface,
+ &box, &imatrix);
+ if (unlikely (status))
+ return status;
+
+ _cairo_box_round_to_rectangle (&box, extents);
+ return CAIRO_STATUS_SUCCESS;
}
}
- return _cairo_pattern_get_extents (pattern, extents);
+ _cairo_pattern_get_extents (pattern, extents);
+ return CAIRO_STATUS_SUCCESS;
}
static unsigned long
@@ -5200,6 +4371,88 @@ _cairo_pattern_reset_static_data (void)
for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++)
_freed_pool_reset (&freed_pattern_pool[i]);
+}
+
+static void
+_cairo_debug_print_surface_pattern (FILE *file,
+ const cairo_surface_pattern_t *pattern)
+{
+ printf (" surface type: %d\n", pattern->surface->type);
+}
+
+static void
+_cairo_debug_print_linear_pattern (FILE *file,
+ const cairo_linear_pattern_t *pattern)
+{
+}
+
+static void
+_cairo_debug_print_radial_pattern (FILE *file,
+ const cairo_radial_pattern_t *pattern)
+{
+}
+
+static void
+_cairo_debug_print_mesh_pattern (FILE *file,
+ const cairo_mesh_pattern_t *pattern)
+{
+}
+
+void
+_cairo_debug_print_pattern (FILE *file, const cairo_pattern_t *pattern)
+{
+ const char *s;
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID: s = "solid"; break;
+ case CAIRO_PATTERN_TYPE_SURFACE: s = "surface"; break;
+ case CAIRO_PATTERN_TYPE_LINEAR: s = "linear"; break;
+ case CAIRO_PATTERN_TYPE_RADIAL: s = "radial"; break;
+ case CAIRO_PATTERN_TYPE_MESH: s = "mesh"; break;
+ default: s = "invalid"; ASSERT_NOT_REACHED; break;
+ }
- _cairo_pattern_reset_solid_surface_cache ();
+ fprintf (file, "pattern: %s\n", s);
+ if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+ return;
+
+ switch (pattern->extend) {
+ case CAIRO_EXTEND_NONE: s = "none"; break;
+ case CAIRO_EXTEND_REPEAT: s = "repeat"; break;
+ case CAIRO_EXTEND_REFLECT: s = "reflect"; break;
+ case CAIRO_EXTEND_PAD: s = "pad"; break;
+ default: s = "invalid"; ASSERT_NOT_REACHED; break;
+ }
+ fprintf (file, " extend: %s\n", s);
+
+ switch (pattern->filter) {
+ case CAIRO_FILTER_FAST: s = "fast"; break;
+ case CAIRO_FILTER_GOOD: s = "good"; break;
+ case CAIRO_FILTER_BEST: s = "best"; break;
+ case CAIRO_FILTER_NEAREST: s = "nearest"; break;
+ case CAIRO_FILTER_BILINEAR: s = "bilinear"; break;
+ case CAIRO_FILTER_GAUSSIAN: s = "guassian"; break;
+ default: s = "invalid"; ASSERT_NOT_REACHED; break;
+ }
+ fprintf (file, " filter: %s\n", s);
+ fprintf (file, " matrix: [%g %g %g %g %g %g]\n",
+ pattern->matrix.xx, pattern->matrix.yx,
+ pattern->matrix.xy, pattern->matrix.yy,
+ pattern->matrix.x0, pattern->matrix.y0);
+ switch (pattern->type) {
+ default:
+ case CAIRO_PATTERN_TYPE_SOLID:
+ break;
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ _cairo_debug_print_surface_pattern (file, (cairo_surface_pattern_t *)pattern);
+ break;
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ _cairo_debug_print_linear_pattern (file, (cairo_linear_pattern_t *)pattern);
+ break;
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ _cairo_debug_print_radial_pattern (file, (cairo_radial_pattern_t *)pattern);
+ break;
+ case CAIRO_PATTERN_TYPE_MESH:
+ _cairo_debug_print_mesh_pattern (file, (cairo_mesh_pattern_t *)pattern);
+ break;
+ }
}
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c
index 58c64721..fceaf1cc 100644
--- a/src/cairo-pdf-operators.c
+++ b/src/cairo-pdf-operators.c
@@ -769,7 +769,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
const cairo_matrix_t *ctm_inverse,
const char *pdf_operator)
{
- cairo_status_t status;
+ cairo_int_status_t status;
cairo_matrix_t m, path_transform;
cairo_bool_t has_ctm = TRUE;
double scale = 1.0;
diff --git a/src/cairo-pdf-shading.c b/src/cairo-pdf-shading.c
index 6b7bcea1..646e2cd4 100644
--- a/src/cairo-pdf-shading.c
+++ b/src/cairo-pdf-shading.c
@@ -39,6 +39,8 @@
#if CAIRO_HAS_PDF_OPERATORS
#include "cairo-pdf-shading-private.h"
+
+#include "cairo-array-private.h"
#include "cairo-error-private.h"
#include <float.h>
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index b115fd1e..3f2d0470 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -41,10 +41,13 @@
#define _BSD_SOURCE /* for snprintf() */
#include "cairoint.h"
+
#include "cairo-pdf.h"
#include "cairo-pdf-surface-private.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-pdf-shading-private.h"
+
+#include "cairo-array-private.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-default-context-private.h"
@@ -1122,17 +1125,19 @@ _get_source_surface_size (cairo_surface_t *source,
*height = extents->height;
} else {
cairo_rectangle_int_t surf_extents;
- double x, y, w, h;
+ cairo_box_t box;
cairo_bool_t bounded;
if (_cairo_surface_is_snapshot (source))
source = _cairo_surface_snapshot_get_target (source);
- cairo_recording_surface_ink_extents (source, &x, &y,&w, &h);
- extents->x = floor (x);
- extents->y = floor (y);
- extents->width = ceil (x + w) - extents->x;
- extents->height = ceil (y + h) - extents->y;
+ status = _cairo_recording_surface_get_ink_bbox ((cairo_recording_surface_t *)source,
+ &box, NULL);
+ if (unlikely (status))
+ return status;
+
+ _cairo_box_round_to_rectangle (&box, extents);
+
bounded = _cairo_surface_get_extents (source, &surf_extents);
*width = surf_extents.width;
*height = surf_extents.height;
@@ -2358,16 +2363,9 @@ _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface,
_cairo_pattern_init_for_surface (&pad_pattern, &image->base);
cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
pad_pattern.base.extend = CAIRO_EXTEND_PAD;
- status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
- &pad_pattern.base,
- NULL,
- pad_image,
- 0, 0,
- 0, 0,
- 0, 0,
- rect.width,
- rect.height,
- NULL);
+ status = _cairo_surface_paint (pad_image,
+ CAIRO_OPERATOR_SOURCE, &pad_pattern.base,
+ NULL);
_cairo_pattern_fini (&pad_pattern.base);
if (unlikely (status))
goto BAIL;
@@ -5917,11 +5915,10 @@ _cairo_pdf_surface_paint (void *abstract_surface,
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_int_status_t status;
- _cairo_pdf_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_paint (&extents,
+ &surface->base,
op, source, clip);
if (unlikely (status))
return status;
@@ -6037,11 +6034,10 @@ _cairo_pdf_surface_mask (void *abstract_surface,
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_smask_group_t *group;
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_int_status_t status;
- _cairo_pdf_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_mask (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_mask (&extents,
+ &surface->base,
op, source, mask, clip);
if (unlikely (status))
return status;
@@ -6166,11 +6162,10 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_int_status_t status;
- _cairo_pdf_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ &surface->base,
op, source,
path, style, ctm,
clip);
@@ -6305,10 +6300,9 @@ _cairo_pdf_surface_fill (void *abstract_surface,
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
- _cairo_pdf_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_fill (&extents,
+ &surface->base,
op, source, path,
clip);
if (unlikely (status))
@@ -6471,7 +6465,6 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
cairo_int_status_t status;
cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res;
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
/* During analysis we return unsupported and let the _fill and
* _stroke functions that are on the fallback path do the analysis
@@ -6498,8 +6491,8 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
/* Compute the operation extents using the stroke which will naturally
* be larger than the fill extents.
*/
- _cairo_pdf_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ &surface->base,
stroke_op, stroke_source,
path, stroke_style, stroke_ctm,
clip);
@@ -6630,12 +6623,11 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_bool_t overlap;
cairo_int_status_t status;
- _cairo_pdf_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_glyphs (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+ &surface->base,
op, source,
scaled_font,
glyphs, num_glyphs,
@@ -6798,37 +6790,24 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
NULL, /* acquire_source_image */
NULL, /* release_source_image */
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ NULL, /* snapshot */
+
NULL, /* _cairo_pdf_surface_copy_page */
_cairo_pdf_surface_show_page,
+
_cairo_pdf_surface_get_extents,
- NULL, /* old_show_glyphs */
_cairo_pdf_surface_get_font_options,
+
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
- NULL, /* scaled_font_fini */
- NULL, /* scaled_glyph_fini */
/* Here are the drawing functions */
-
_cairo_pdf_surface_paint,
_cairo_pdf_surface_mask,
_cairo_pdf_surface_stroke,
_cairo_pdf_surface_fill,
- NULL, /* show_glyphs */
- NULL, /* snapshot */
-
- NULL, /* is_compatible */
_cairo_pdf_surface_fill_stroke,
- NULL, /* create_solid_pattern_surface */
- NULL, /* can_repaint_solid_pattern_surface */
+ NULL, /* show_glyphs */
_cairo_pdf_surface_has_show_text_glyphs,
_cairo_pdf_surface_show_text_glyphs,
};
diff --git a/src/cairo-polygon-intersect.c b/src/cairo-polygon-intersect.c
index e2ed6e97..d9d0cf26 100644
--- a/src/cairo-polygon-intersect.c
+++ b/src/cairo-polygon-intersect.c
@@ -1454,13 +1454,78 @@ _cairo_polygon_intersect (cairo_polygon_t *a, int winding_a,
}
assert (j == num_events);
- //fprintf(stderr, "a "); _cairo_debug_print_polygon(stderr,a);
- //fprintf(stderr, "b "); _cairo_debug_print_polygon(stderr,b);
+#if 0
+ {
+ FILE *file = fopen ("clip_a.txt", "w");
+ _cairo_debug_print_polygon (file, a);
+ fclose (file);
+ }
+ {
+ FILE *file = fopen ("clip_b.txt", "w");
+ _cairo_debug_print_polygon (file, b);
+ fclose (file);
+ }
+#endif
a->num_edges = 0;
status = intersection_sweep (event_ptrs, num_events, a);
if (events != stack_events)
free (events);
+#if 0
+ {
+ FILE *file = fopen ("clip_result.txt", "w");
+ _cairo_debug_print_polygon (file, a);
+ fclose (file);
+ }
+#endif
+
+ return status;
+}
+
+cairo_status_t
+_cairo_polygon_intersect_with_boxes (cairo_polygon_t *polygon,
+ cairo_fill_rule_t *winding,
+ cairo_box_t *boxes,
+ int num_boxes)
+{
+ cairo_polygon_t b;
+ cairo_status_t status;
+ int n;
+
+ if (num_boxes == 0) {
+ polygon->num_edges = 0;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ for (n = 0; n < num_boxes; n++) {
+ if (polygon->extents.p1.x >= boxes[n].p1.x &&
+ polygon->extents.p2.x <= boxes[n].p2.x &&
+ polygon->extents.p1.y >= boxes[n].p1.y &&
+ polygon->extents.p2.y <= boxes[n].p2.y)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ _cairo_polygon_init (&b, NULL, 0);
+ for (n = 0; n < num_boxes; n++) {
+ cairo_point_t p1, p2;
+
+ p1.y = boxes[n].p1.y;
+ p2.y = boxes[n].p2.y;
+
+ p2.x = p1.x = boxes[n].p1.x;
+ _cairo_polygon_add_external_edge (&b, &p1, &p2);
+
+ p2.x = p1.x = boxes[n].p2.x;
+ _cairo_polygon_add_external_edge (&b, &p2, &p1);
+ }
+
+ status = _cairo_polygon_intersect (polygon, *winding,
+ &b, CAIRO_FILL_RULE_WINDING);
+ _cairo_polygon_fini (&b);
+
+ *winding = CAIRO_FILL_RULE_WINDING;
return status;
}
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index 6436712b..a44cba3f 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -127,19 +127,19 @@ _cairo_polygon_init_boxes (cairo_polygon_t *polygon,
polygon->num_limits = 0;
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
- for (i = 0; i < chunk->count; i++) {
- cairo_point_t p1, p2;
-
- p1 = chunk->base[i].p1;
- p2.x = p1.x;
- p2.y = chunk->base[i].p2.y;
- _cairo_polygon_add_edge (polygon, &p1, &p2, 1);
-
- p1 = chunk->base[i].p2;
- p2.x = p1.x;
- p2.y = chunk->base[i].p1.y;
- _cairo_polygon_add_edge (polygon, &p1, &p2, 1);
- }
+ for (i = 0; i < chunk->count; i++) {
+ cairo_point_t p1, p2;
+
+ p1 = chunk->base[i].p1;
+ p2.x = p1.x;
+ p2.y = chunk->base[i].p2.y;
+ _cairo_polygon_add_edge (polygon, &p1, &p2, 1);
+
+ p1 = chunk->base[i].p2;
+ p2.x = p1.x;
+ p2.y = chunk->base[i].p1.y;
+ _cairo_polygon_add_edge (polygon, &p1, &p2, 1);
+ }
}
return polygon->status;
@@ -491,3 +491,29 @@ _cairo_polygon_add_contour (cairo_polygon_t *polygon,
return polygon->status;
}
+
+void
+_cairo_polygon_translate (cairo_polygon_t *polygon, int dx, int dy)
+{
+ int n;
+
+ dx = _cairo_fixed_from_int (dx);
+ dy = _cairo_fixed_from_int (dy);
+
+ polygon->extents.p1.x += dx;
+ polygon->extents.p2.x += dx;
+ polygon->extents.p1.y += dy;
+ polygon->extents.p2.y += dy;
+
+ for (n = 0; n < polygon->num_edges; n++) {
+ cairo_edge_t *e = &polygon->edges[n];
+
+ e->top += dy;
+ e->bottom += dy;
+
+ e->line.p1.x += dx;
+ e->line.p2.x += dx;
+ e->line.p1.y += dy;
+ e->line.p2.y += dy;
+ }
+}
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index a8048871..dcd21612 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -55,10 +55,14 @@
#define _BSD_SOURCE /* for ctime_r(), snprintf(), strdup() */
#include "cairoint.h"
+
#include "cairo-ps.h"
#include "cairo-ps-surface-private.h"
+
#include "cairo-pdf-operators-private.h"
#include "cairo-pdf-shading-private.h"
+
+#include "cairo-array-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
@@ -79,7 +83,7 @@
#include <zlib.h>
#include <errno.h>
-#define DEBUG_PS 0
+#define DEBUG_PS 1
#if DEBUG_PS
#define DEBUG_FALLBACK(s) \
@@ -1153,41 +1157,40 @@ _extract_ps_surface (cairo_surface_t *surface,
cairo_ps_surface_t **ps_surface)
{
cairo_surface_t *target;
- cairo_status_t status_ignored;
if (surface->status)
return FALSE;
if (surface->finished) {
if (set_error_on_failure)
- status_ignored = _cairo_surface_set_error (surface,
- _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ _cairo_surface_set_error (surface,
+ _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return FALSE;
}
if (! _cairo_surface_is_paginated (surface)) {
if (set_error_on_failure)
- status_ignored = _cairo_surface_set_error (surface,
- _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+ _cairo_surface_set_error (surface,
+ _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
return FALSE;
}
target = _cairo_paginated_surface_get_target (surface);
if (target->status) {
if (set_error_on_failure)
- status_ignored = _cairo_surface_set_error (surface, target->status);
+ _cairo_surface_set_error (surface, target->status);
return FALSE;
}
if (target->finished) {
if (set_error_on_failure)
- status_ignored = _cairo_surface_set_error (surface,
- _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ _cairo_surface_set_error (surface,
+ _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return FALSE;
}
if (! _cairo_surface_is_ps (target)) {
if (set_error_on_failure)
- status_ignored = _cairo_surface_set_error (surface,
- _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+ _cairo_surface_set_error (surface,
+ _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
return FALSE;
}
@@ -1783,7 +1786,7 @@ mask_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *mask)
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
/* check if mask if opaque or bilevel alpha */
- if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface, surface_pattern) == CAIRO_STATUS_SUCCESS) {
+ if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface, surface_pattern) == CAIRO_INT_STATUS_SUCCESS) {
surface->ps_level_used = CAIRO_PS_LEVEL_3;
return TRUE;
}
@@ -3780,17 +3783,18 @@ _cairo_ps_surface_paint (void *abstract_surface,
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_status_t status;
- _cairo_ps_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_paint (&extents,
+ &surface->base,
op, source, clip);
if (unlikely (status))
return status;
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+ status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+ goto cleanup_composite;
+ }
assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
@@ -3801,7 +3805,7 @@ _cairo_ps_surface_paint (void *abstract_surface,
status = _cairo_ps_surface_set_clip (surface, &extents);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_NONE ||
@@ -3809,26 +3813,28 @@ _cairo_ps_surface_paint (void *abstract_surface,
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
_cairo_output_stream_printf (stream, "q\n");
status = _cairo_ps_surface_paint_surface (surface,
(cairo_surface_pattern_t *) source,
&extents.bounded, op, FALSE);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
_cairo_output_stream_printf (stream, "Q\n");
} else {
status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
_cairo_output_stream_printf (stream, "0 0 %f %f rectfill\n",
surface->width, surface->height);
}
- return CAIRO_STATUS_SUCCESS;
+cleanup_composite:
+ _cairo_composite_rectangles_fini (&extents);
+ return status;
}
static cairo_int_status_t
@@ -3841,17 +3847,18 @@ _cairo_ps_surface_mask (void *abstract_surface,
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_status_t status;
- _cairo_ps_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_mask (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_mask (&extents,
+ &surface->base,
op, source, mask, clip);
if (unlikely (status))
return status;
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_ps_surface_analyze_operation (surface, op, source, mask, &extents.bounded);
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+ status = _cairo_ps_surface_analyze_operation (surface, op, source, mask, &extents.bounded);
+ goto cleanup_composite;
+ }
assert (_cairo_ps_surface_operation_supported (surface, op, source, mask, &extents.bounded));
@@ -3862,22 +3869,24 @@ _cairo_ps_surface_mask (void *abstract_surface,
status = _cairo_ps_surface_set_clip (surface, &extents);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
_cairo_output_stream_printf (stream, "q\n");
status = _cairo_ps_surface_paint_surface (surface,
(cairo_surface_pattern_t *) mask,
&extents.bounded, op, TRUE);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
_cairo_output_stream_printf (stream, "Q\n");
- return CAIRO_STATUS_SUCCESS;
+cleanup_composite:
+ _cairo_composite_rectangles_fini (&extents);
+ return status;
}
static cairo_int_status_t
@@ -3894,11 +3903,10 @@ _cairo_ps_surface_stroke (void *abstract_surface,
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_int_status_t status;
- _cairo_ps_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ &surface->base,
op, source,
path, style, ctm,
clip);
@@ -3906,21 +3914,27 @@ _cairo_ps_surface_stroke (void *abstract_surface,
return status;
/* use the more accurate extents */
- if (extents.is_bounded) {
+ {
+ cairo_rectangle_int_t r;
+ cairo_box_t b;
+
status = _cairo_path_fixed_stroke_extents (path, style,
ctm, ctm_inverse,
tolerance,
- &extents.mask);
+ &r);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
- if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
- return CAIRO_STATUS_SUCCESS;
+ _cairo_box_from_rectangle (&b, &r);
+ status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
+ if (unlikely (status))
+ goto cleanup_composite;
}
-
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+ status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+ goto cleanup_composite;
+ }
assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
@@ -3931,17 +3945,21 @@ _cairo_ps_surface_stroke (void *abstract_surface,
status = _cairo_ps_surface_set_clip (surface, &extents);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
+
+ status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
+ path,
+ style,
+ ctm,
+ ctm_inverse);
- return _cairo_pdf_operators_stroke (&surface->pdf_operators,
- path,
- style,
- ctm,
- ctm_inverse);
+cleanup_composite:
+ _cairo_composite_rectangles_fini (&extents);
+ return status;
}
static cairo_int_status_t
@@ -3956,29 +3974,35 @@ _cairo_ps_surface_fill (void *abstract_surface,
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_int_status_t status;
- _cairo_ps_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_fill (&extents,
+ &surface->base,
op, source, path,
clip);
if (unlikely (status))
return status;
/* use the more accurate extents */
- if (extents.is_bounded) {
+ {
+ cairo_rectangle_int_t r;
+ cairo_box_t b;
+
_cairo_path_fixed_fill_extents (path,
fill_rule,
tolerance,
- &extents.mask);
+ &r);
- if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
- return CAIRO_STATUS_SUCCESS;
+ _cairo_box_from_rectangle (&b, &r);
+ status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
+ if (unlikely (status))
+ goto cleanup_composite;
}
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+ status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+ goto cleanup_composite;
+ }
assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
@@ -3989,11 +4013,11 @@ _cairo_ps_surface_fill (void *abstract_surface,
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
status = _cairo_ps_surface_set_clip (surface, &extents);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_NONE ||
@@ -4005,26 +4029,28 @@ _cairo_ps_surface_fill (void *abstract_surface,
path,
fill_rule);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
status = _cairo_ps_surface_paint_surface (surface,
(cairo_surface_pattern_t *) source,
&extents.bounded, op, FALSE);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
_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.bounded, op);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
status = _cairo_pdf_operators_fill (&surface->pdf_operators,
path,
fill_rule);
}
+cleanup_composite:
+ _cairo_composite_rectangles_fini (&extents);
return status;
}
@@ -4050,26 +4076,23 @@ _cairo_ps_surface_show_text_glyphs (void *abstract_surface,
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_bool_t overlap;
cairo_status_t status;
- _cairo_ps_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_glyphs (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+ &surface->base,
op, source,
scaled_font,
glyphs, num_glyphs,
clip,
&overlap);
- if (unlikely (status)) {
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- return CAIRO_INT_STATUS_SUCCESS;
-
+ if (unlikely (status))
return status;
- }
- if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+ status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded);
+ goto cleanup_composite;
+ }
assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded));
@@ -4080,18 +4103,22 @@ _cairo_ps_surface_show_text_glyphs (void *abstract_surface,
status = _cairo_ps_surface_set_clip (surface, &extents);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
if (unlikely (status))
- return status;
+ goto cleanup_composite;
+
+ status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
+ utf8, utf8_len,
+ glyphs, num_glyphs,
+ clusters, num_clusters,
+ cluster_flags,
+ scaled_font);
- return _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
- utf8, utf8_len,
- glyphs, num_glyphs,
- clusters, num_clusters,
- cluster_flags,
- scaled_font);
+cleanup_composite:
+ _cairo_composite_rectangles_fini (&extents);
+ return status;
}
static void
@@ -4222,23 +4249,16 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
NULL, /* acquire_source_image */
NULL, /* release_source_image */
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ NULL, /* snapshot */
+
NULL, /* cairo_ps_surface_copy_page */
_cairo_ps_surface_show_page,
+
_cairo_ps_surface_get_extents,
- NULL, /* old_show_glyphs */
_cairo_ps_surface_get_font_options,
+
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
- NULL, /* scaled_font_fini */
- NULL, /* scaled_glyph_fini */
/* Here are the drawing functions */
@@ -4246,13 +4266,8 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
_cairo_ps_surface_mask,
_cairo_ps_surface_stroke,
_cairo_ps_surface_fill,
+ NULL, /* fill-stroke */
NULL, /* show_glyphs */
- NULL, /* snapshot */
-
- NULL, /* is_compatible */
- NULL, /* fill_stroke */
- NULL, /* create_solid_pattern_surface */
- NULL, /* can_repaint_solid_pattern_surface */
_cairo_ps_surface_has_show_text_glyphs,
_cairo_ps_surface_show_text_glyphs,
};
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index bbe5fa7e..b04c4213 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -60,13 +60,22 @@ _cairo_quartz_image_surface_create_similar (void *asurface,
int width,
int height)
{
- cairo_surface_t *result;
cairo_surface_t *isurf =
_cairo_image_surface_create_with_content (content, width, height);
- if (cairo_surface_status(isurf))
- return isurf;
+ cairo_surface_t *result = cairo_quartz_image_surface_create (isurf);
+ cairo_surface_destroy (isurf);
- result = cairo_quartz_image_surface_create (isurf);
+ return result;
+}
+
+static cairo_surface_t *
+_cairo_quartz_image_surface_create_similar_image (void *asurface,
+ cairo_format_t format,
+ int width,
+ int height)
+{
+ cairo_surface_t *isurf = cairo_image_surface_create (format, width, height);
+ cairo_surface_t *result = cairo_quartz_image_surface_create (isurf);
cairo_surface_destroy (isurf);
return result;
@@ -96,23 +105,19 @@ _cairo_quartz_image_surface_acquire_source_image (void *asurface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_quartz_image_surface_acquire_dest_image (void *asurface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect,
- void **image_extra)
+static cairo_surface_t *
+_cairo_quartz_image_surface_map_to_image (void *asurface,
+ const cairo_rectangle_int_t *extents)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
+ return _cairo_surface_create_for_rectangle_int (surface->imageSurface, extents);
+}
- *image_out = surface->imageSurface;
- image_rect->x = 0;
- image_rect->y = 0;
- image_rect->width = surface->width;
- image_rect->height = surface->height;
- *image_extra = NULL;
-
- return CAIRO_STATUS_SUCCESS;
+static cairo_int_status_t
+_cairo_quartz_image_surface_unmap_image (void *asurface,
+ cairo_image_surface_t *image)
+{
+ cairo_surface_destroy (&image->base);
}
static cairo_bool_t
@@ -123,7 +128,7 @@ _cairo_quartz_image_surface_get_extents (void *asurface,
extents->x = 0;
extents->y = 0;
- extents->width = surface->width;
+ extents->width = surface->width;
extents->height = surface->height;
return TRUE;
}
@@ -139,6 +144,8 @@ _cairo_quartz_image_surface_flush (void *asurface)
CGImageRef oldImage = surface->image;
CGImageRef newImage = NULL;
+ /* XXX only flush if the image has been modified. */
+
/* To be released by the ReleaseCallback */
cairo_surface_reference ((cairo_surface_t*) surface->imageSurface);
@@ -158,6 +165,82 @@ _cairo_quartz_image_surface_flush (void *asurface)
return CAIRO_STATUS_SUCCESS;
}
+static cairo_int_status_t
+_cairo_quartz_image_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_clip_t *clip)
+{
+ cairo_quartz_image_surface_t *surface = abstract_surface;
+ return _cairo_surface_paint (&surface->imageSurface->base,
+ op, source, clip);
+}
+
+static cairo_int_status_t
+_cairo_quartz_image_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ const cairo_clip_t *clip)
+{
+ cairo_quartz_image_surface_t *surface = abstract_surface;
+ return _cairo_surface_mask (&surface->imageSurface->base,
+ op, source, mask, clip);
+}
+
+static cairo_int_status_t
+_cairo_quartz_image_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
+{
+ cairo_quartz_image_surface_t *surface = abstract_surface;
+ return _cairo_surface_stroke (&surface->imageSurface->base,
+ op, source, path,
+ style, ctm, ctm_inverse,
+ tolerance, antialias, clip);
+}
+
+static cairo_int_status_t
+_cairo_quartz_image_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
+{
+ cairo_quartz_image_surface_t *surface = abstract_surface;
+ return _cairo_surface_fill (&surface->imageSurface->base,
+ op, source, path,
+ fill_rule, tolerance, antialias,
+ clip);
+}
+
+static cairo_int_status_t
+_cairo_quartz_image_surface_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,
+ const cairo_clip_t *clip)
+{
+ cairo_quartz_image_surface_t *surface = abstract_surface;
+ return _cairo_surface_show_glyphs (&surface->imageSurface->base,
+ op, source,
+ glyphs, num_glyphs, scaled_font,
+ clip, num_remaining);
+}
+
+
static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
_cairo_quartz_image_surface_finish,
@@ -165,39 +248,29 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
_cairo_default_context_create,
_cairo_quartz_image_surface_create_similar,
- NULL, /* create_similar_image */
- NULL, /* map_to_image */
- NULL, /* unmap_image */
+ _cairo_quartz_image_surface_create_similar_image,
+ _cairo_quartz_image_surface_map_to_image,
+ _cairo_quartz_image_surface_unmap_image,
_cairo_quartz_image_surface_acquire_source_image,
NULL, /* release_source_image */
- _cairo_quartz_image_surface_acquire_dest_image,
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ NULL, /* snapshot */
+
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_quartz_image_surface_get_extents,
- NULL, /* old_show_glyphs */
NULL, /* get_font_options */
+
_cairo_quartz_image_surface_flush,
NULL, /* mark_dirty_rectangle */
- NULL, /* scaled_font_fini */
- NULL, /* scaled_glyph_fini */
-
- NULL, /* paint */
- NULL, /* mask */
- NULL, /* stroke */
- NULL, /* fill */
- NULL, /* surface_show_glyphs */
- NULL, /* snapshot */
- NULL, /* is_similar */
- NULL /* fill_stroke */
+ _cairo_quartz_image_surface_paint,
+ _cairo_quartz_image_surface_mask,
+ _cairo_quartz_image_surface_stroke,
+ _cairo_quartz_image_surface_fill,
+ NULL /* fill-stroke */
+ _cairo_quartz_image_surface_glyphs,
};
/**
@@ -227,6 +300,9 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface)
cairo_format_t format;
unsigned char *data;
+ if (surface->status)
+ return surface;
+
if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_IMAGE)
return SURFACE_ERROR_TYPE_MISMATCH;
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 0f015c81..60ce8d17 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -39,10 +39,13 @@
#include "cairo-quartz-private.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-pattern-private.h"
+#include "cairo-surface-backend-private.h"
#include "cairo-surface-clipper-private.h"
#include <dlfcn.h>
@@ -500,8 +503,7 @@ _cairo_cgcontext_set_cairo_operator (CGContextRef context, cairo_operator_t op)
{
CGBlendMode blendmode;
- if (op == CAIRO_OPERATOR_DEST)
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ assert (op != CAIRO_OPERATOR_DEST);
/* Quartz doesn't support SATURATE at all. COLOR_DODGE and
* COLOR_BURN in Quartz follow the ISO32000 definition, but cairo
@@ -538,8 +540,7 @@ _cairo_quartz_surface_set_cairo_operator (cairo_quartz_surface_t *surface, cairo
* fallbacks, but we have to workaround operators which behave
* differently in Quartz. */
if (surface->base.content == CAIRO_CONTENT_ALPHA) {
- if (op == CAIRO_OPERATOR_ATOP)
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ assert (op != CAIRO_OPERATOR_ATOP); /* filtered by surface layer */
if (op == CAIRO_OPERATOR_SOURCE ||
op == CAIRO_OPERATOR_IN ||
@@ -794,7 +795,7 @@ _cairo_surface_to_cgimage (cairo_surface_t *source,
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source;
if (IS_EMPTY (surface)) {
*image_out = NULL;
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) {
@@ -924,8 +925,6 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
status = _cairo_surface_to_cgimage (pat_surf, &image);
if (unlikely (status))
return status;
- if (unlikely (image == NULL))
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
info = malloc (sizeof (SurfacePatternDrawInfo));
if (unlikely (!info))
@@ -1082,11 +1081,12 @@ _cairo_quartz_setup_gradient_source (cairo_quartz_drawing_state_t *state,
static cairo_int_status_t
_cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
- cairo_quartz_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_clip_t *clip)
+ cairo_composite_rectangles_int_t *extents)
{
+ cairo_quartz_surface_t *surface = extents->surface;
+ cairo_operator_t op = extents->op;
+ const cairo_pattern_t *source = &extents->surface_pattern.base;
+ const cairo_clip_t *clip = extents->clip;
cairo_bool_t needs_temp;
cairo_status_t status;
@@ -1205,8 +1205,6 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
status = _cairo_surface_to_cgimage (pat_surf, &img);
if (unlikely (status))
return status;
- if (unlikely (img == NULL))
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
state->image = img;
@@ -1318,8 +1316,10 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
static void
_cairo_quartz_teardown_state (cairo_quartz_drawing_state_t *state,
- cairo_quartz_surface_t *surface)
+ cairo_composite_rectangles_int_t *extents)
{
+ cairo_quartz_surface_t *surfce = (cairo_quartz_surface_t *)extents;
+
if (state->layer) {
CGContextDrawLayerInRect (surface->cgContext,
state->clipRect,
@@ -1383,7 +1383,6 @@ _cairo_quartz_draw_source (cairo_quartz_drawing_state_t *state,
}
}
-
/*
* get source/dest image implementation
*/
@@ -1552,39 +1551,28 @@ _cairo_quartz_surface_release_source_image (void *abstract_surface,
}
-static cairo_status_t
-_cairo_quartz_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect,
- void **image_extra)
+static cairo_surface_t *
+_cairo_quartz_surface_map_to_image (void *abstract_surface,
+ const cairo_rectangle_int_t *extents)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
- cairo_int_status_t status;
-
- ND ((stderr, "%p _cairo_quartz_surface_acquire_dest_image\n", surface));
+ cairo_image_surface_t *image;
+ cairo_surface_t *surface;
- status = _cairo_quartz_get_image (surface, image_out);
+ status = _cairo_quartz_get_image (surface, &image);
if (unlikely (status))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return _cairo_surace_create_in_error (status);
- *image_rect = surface->extents;
- *image_extra = NULL;
+ surface = _cairo_surface_create_for_rectangle_int (&image->base, extents);
+ cairo_surface_destroy (&image->base);
- return CAIRO_STATUS_SUCCESS;
+ return surface;
}
-static void
-_cairo_quartz_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
+static cairo_int_status_t
+_cairo_quartz_surface_unmap_image (void *abstract_surface,
+ cairo_image_surface_t *image)
{
- //cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
-
- //ND ((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface));
-
cairo_surface_destroy (&image->base);
}
@@ -1624,173 +1612,218 @@ _cairo_quartz_surface_create_similar (void *abstract_surface,
return similar;
}
-static cairo_status_t
-_cairo_quartz_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
+static cairo_bool_t
+_cairo_quartz_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *extents)
{
- cairo_quartz_surface_t *new_surface = NULL;
- cairo_format_t new_format;
- CGImageRef quartz_image = NULL;
- cairo_status_t status;
+ cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
- *clone_out = NULL;
+ *extents = surface->extents;
+ return TRUE;
+}
- // verify width and height of surface
- if (!_cairo_quartz_verify_surface_size (width, height))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+static cairo_int_status_t
+_cairo_quartz_cg_paint (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_int_t *extents)
+{
+ cairo_quartz_drawing_state_t state;
+ cairo_int_status_t rv;
- if (width == 0 || height == 0) {
- *clone_out = &_cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA,
- width, height)->base;
- *clone_offset_x = 0;
- *clone_offset_y = 0;
- return CAIRO_STATUS_SUCCESS;
- }
+ ND ((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type));
- if (_cairo_surface_is_quartz (src)) {
- cairo_quartz_surface_t *qsurf = (cairo_quartz_surface_t *) src;
+ rv = _cairo_quartz_setup_state (&state, extents);
+ if (unlikely (rv))
+ goto BAIL;
- if (IS_EMPTY (qsurf)) {
- *clone_out = &_cairo_quartz_surface_create_internal (NULL,
- CAIRO_CONTENT_COLOR_ALPHA,
- qsurf->extents.width,
- qsurf->extents.height)->base;
- *clone_offset_x = 0;
- *clone_offset_y = 0;
- return CAIRO_STATUS_SUCCESS;
- }
- }
+ _cairo_quartz_draw_source (&state, extents->op);
+
+BAIL:
+ _cairo_quartz_teardown_state (&state, extents);
+
+ ND ((stderr, "-- paint\n"));
+ return rv;
+}
- status = _cairo_surface_to_cgimage (src, &quartz_image);
+static cairo_int_status_t
+_cairo_quartz_cg_mask_with_surface (cairo_composite_extents_t *extents,
+ cairo_surface_t *mask_surf,
+ const cairo_matrix_t *mask_mat,
+ CGInterpolationQuality filter)
+{
+ cairo_quartz_surface_t *surface = extents->surface;
+ cairo_operator_t op = extents->op;
+ const cairo_pattern_t *source = &extents->surface_pattern.base;
+ cairo_clip_t *clip = extents->clip;
+ CGRect rect;
+ CGImageRef img;
+ cairo_status_t status;
+ CGAffineTransform mask_matrix;
+ cairo_quartz_drawing_state_t state;
+
+ status = _cairo_surface_to_cgimage (mask_surf, &img);
if (unlikely (status))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return status;
- new_format = CAIRO_FORMAT_ARGB32; /* assumed */
- if (_cairo_surface_is_image (src))
- new_format = ((cairo_image_surface_t *) src)->format;
+ status = _cairo_quartz_setup_state (&state, extents);
+ if (unlikely (status))
+ goto BAIL;
- new_surface = (cairo_quartz_surface_t *)
- cairo_quartz_surface_create (new_format, width, height);
+ rect = CGRectMake (0.0, 0.0, CGImageGetWidth (img), CGImageGetHeight (img));
+ _cairo_quartz_cairo_matrix_to_quartz (mask_mat, &mask_matrix);
- if (quartz_image == NULL)
- goto FINISH;
+ /* ClipToMask is essentially drawing an image, so we need to flip the CTM
+ * to get the image to appear oriented the right way */
+ CGContextConcatCTM (state.cgMaskContext, CGAffineTransformInvert (mask_matrix));
+ CGContextTranslateCTM (state.cgMaskContext, 0.0, rect.size.height);
+ CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
- if (!new_surface || new_surface->base.status) {
- CGImageRelease (quartz_image);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
+ state.filter = filter;
- CGContextSaveGState (new_surface->cgContext);
+ CGContextSetInterpolationQuality (state.cgMaskContext, filter);
+ CGContextSetShouldAntialias (state.cgMaskContext, filter != kCGInterpolationNone);
- _cairo_quartz_surface_set_cairo_operator (new_surface, CAIRO_OPERATOR_SOURCE);
+ CGContextClipToMask (state.cgMaskContext, rect, img);
- CGContextTranslateCTM (new_surface->cgContext, -src_x, -src_y);
- CGContextDrawImage (new_surface->cgContext,
- CGRectMake (0, 0, CGImageGetWidth (quartz_image), CGImageGetHeight (quartz_image)),
- quartz_image);
+ CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
+ CGContextTranslateCTM (state.cgMaskContext, 0.0, -rect.size.height);
+ CGContextConcatCTM (state.cgMaskContext, mask_matrix);
- CGContextRestoreGState (new_surface->cgContext);
+ _cairo_quartz_draw_source (&state, extents->op);
- CGImageRelease (quartz_image);
+BAIL:
+ _cairo_quartz_teardown_state (&state, extents);
-FINISH:
- *clone_offset_x = src_x;
- *clone_offset_y = src_y;
- *clone_out = &new_surface->base;
+ CGImageRelease (img);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
-static cairo_bool_t
-_cairo_quartz_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *extents)
+static cairo_int_status_t
+_cairo_quartz_cg_mask_with_solid (cairo_quartz_surface_t *surface,
+ cairo_composite_rectangles_t *extents)
{
- cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+ cairo_quartz_drawing_state_t state;
+ double alpha = extents->mask_pattern.solid.color.alpha;
+ cairo_status_t status;
- *extents = surface->extents;
- return TRUE;
+ status = _cairo_quartz_setup_state (&state, extents);
+ if (unlikely (status))
+ return status;
+
+ CGContextSetAlpha (surface->cgContext, alpha);
+ _cairo_quartz_draw_source (&state, extents->op);
+
+ _cairo_quartz_teardown_state (&state, extents);
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
-_cairo_quartz_surface_paint_cg (cairo_quartz_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_clip_t *clip)
+_cairo_quartz_cg_mask (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_int_t *extents)
{
- cairo_quartz_drawing_state_t state;
- cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
+ cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)extents->surface;
+ cairo_operator_t op = extents->op;
+ const cairo_pattern_t *source = &extents->source_pattern.base;
+ const cairo_pattern_t *mask = &extents->mask_pattern.base;
+ cairo_surface_t *mask_surf;
+ cairo_matrix_t matrix;
+ cairo_status_t status;
+ cairo_bool_t need_temp;
+ CGInterpolationQuality filter;
- ND ((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type));
+ ND ((stderr, "%p _cairo_quartz_surface_mask op %d source->type %d mask->type %d\n", surface, op, source->type, mask->type));
- if (IS_EMPTY (surface))
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ if (mask->type == CAIRO_PATTERN_TYPE_SOLID)
+ return _cairo_quartz_cg_mask_with_solid (surface, extents);
- rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
- if (unlikely (rv))
- goto BAIL;
+ need_temp = (mask->type != CAIRO_PATTERN_TYPE_SURFACE ||
+ mask->extend != CAIRO_EXTEND_NONE);
- _cairo_quartz_draw_source (&state, op);
+ filter = _cairo_quartz_filter_to_quartz (source->filter);
-BAIL:
- _cairo_quartz_teardown_state (&state, surface);
+ if (! need_temp) {
+ mask_surf = extents->mask_pattern.surface.surface;
- ND ((stderr, "-- paint\n"));
- return rv;
-}
+ /* When an opaque surface used as a mask in Quartz, its
+ * luminosity is used as the alpha value, so we con only use
+ * surfaces with alpha without creating a temporary mask. */
+ need_temp = ! (mask_surf->content & CAIRO_CONTENT_ALPHA);
+ }
-static cairo_int_status_t
-_cairo_quartz_surface_paint (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_clip_t *clip)
-{
- cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
- cairo_int_status_t rv;
- cairo_image_surface_t *image;
+ if (! need_temp) {
+ CGInterpolationQuality mask_filter;
+ cairo_bool_t simple_transform;
- rv = _cairo_quartz_surface_paint_cg (surface,
- op,
- source,
- clip);
+ matrix = mask->matrix;
- if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED))
- return rv;
+ mask_filter = _cairo_quartz_filter_to_quartz (mask->filter);
+ if (mask_filter == kCGInterpolationNone) {
+ simple_transform = _cairo_matrix_is_translation (&matrix);
+ if (simple_transform) {
+ matrix.x0 = ceil (matrix.x0 - 0.5);
+ matrix.y0 = ceil (matrix.y0 - 0.5);
+ }
+ } else {
+ simple_transform = _cairo_matrix_is_integer_translation (&matrix,
+ NULL,
+ NULL);
+ }
- rv = _cairo_quartz_get_image (surface, &image);
- if (likely (rv == CAIRO_STATUS_SUCCESS)) {
- rv = _cairo_surface_paint (&image->base, op, source, clip);
- cairo_surface_destroy (&image->base);
+ /* Quartz only allows one interpolation to be set for mask and
+ * source, so we can skip the temp surface only if the source
+ * filtering makes the mask look correct. */
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE)
+ need_temp = ! (simple_transform || filter == mask_filter);
+ else
+ filter = mask_filter;
}
- return rv;
+ if (need_temp) {
+ /* Render the mask to a surface */
+ mask_surf = _cairo_quartz_surface_create_similar (surface,
+ CAIRO_CONTENT_ALPHA,
+ surface->extents.width,
+ surface->extents.height);
+ status = mask_surf->status;
+ if (unlikely (status))
+ goto BAIL;
+
+ /* mask_surf is clear, so use OVER instead of SOURCE to avoid a
+ * temporary layer or fallback to cairo-image. */
+ status = _cairo_surface_paint (mask_surf, CAIRO_OPERATOR_OVER, mask, NULL);
+ if (unlikely (status))
+ goto BAIL;
+
+ cairo_matrix_init_identity (&matrix);
+ }
+
+ status = _cairo_quartz_cg_mask_with_surface (extents,
+ mask_surf, &matrix, filter);
+
+BAIL:
+
+ if (need_temp)
+ cairo_surface_destroy (mask_surf);
+
+ return status;
}
static cairo_int_status_t
-_cairo_quartz_surface_fill_cg (cairo_quartz_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
+_cairo_quartz_cg_fill (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_int_t *extents,
+ const 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 *)extents->surface;
cairo_quartz_drawing_state_t state;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
ND ((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type));
- if (IS_EMPTY (surface))
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
- rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
+ rv = _cairo_quartz_setup_state (&state, extents);
if (unlikely (rv))
goto BAIL;
@@ -1810,75 +1843,34 @@ _cairo_quartz_surface_fill_cg (cairo_quartz_surface_t *surface,
else
CGContextEOClip (state.cgMaskContext);
- _cairo_quartz_draw_source (&state, op);
+ _cairo_quartz_draw_source (&state, extents->op);
}
BAIL:
- _cairo_quartz_teardown_state (&state, surface);
+ _cairo_quartz_teardown_state (&state, extents);
ND ((stderr, "-- fill\n"));
return rv;
}
static cairo_int_status_t
-_cairo_quartz_surface_fill (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
- cairo_int_status_t rv;
- cairo_image_surface_t *image;
-
- rv = _cairo_quartz_surface_fill_cg (surface,
- op,
- source,
- path,
- fill_rule,
- tolerance,
- antialias,
- clip);
-
- if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED))
- return rv;
-
- rv = _cairo_quartz_get_image (surface, &image);
- if (likely (rv == CAIRO_STATUS_SUCCESS)) {
- rv = _cairo_surface_fill (&image->base, op, source,
- path, fill_rule, tolerance, antialias,
- clip);
- cairo_surface_destroy (&image->base);
- }
-
- return rv;
-}
-
-static cairo_int_status_t
-_cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
+_cairo_quartz_cg_stroke (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_int_t *extents,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
{
+ cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)extents->surface;
cairo_quartz_drawing_state_t state;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
CGAffineTransform strokeTransform, invStrokeTransform;
ND ((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type));
- if (IS_EMPTY (surface))
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
- rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
+ rv = _cairo_quartz_setup_state (&state, extents);
if (unlikely (rv))
goto BAIL;
@@ -1930,63 +1922,26 @@ _cairo_quartz_surface_stroke_cg (cairo_quartz_surface_t *surface,
_cairo_quartz_cairo_matrix_to_quartz (ctm_inverse, &invStrokeTransform);
CGContextConcatCTM (state.cgMaskContext, invStrokeTransform);
- _cairo_quartz_draw_source (&state, op);
+ _cairo_quartz_draw_source (&state, extents->op);
}
BAIL:
- _cairo_quartz_teardown_state (&state, surface);
+ _cairo_quartz_teardown_state (&state, extents);
ND ((stderr, "-- stroke\n"));
return rv;
}
-static cairo_int_status_t
-_cairo_quartz_surface_stroke (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
- cairo_int_status_t rv;
- cairo_image_surface_t *image;
-
- rv = _cairo_quartz_surface_stroke_cg (surface, op, source,
- path, style, ctm, ctm_inverse,
- tolerance, antialias,
- clip);
-
- if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED))
- return rv;
-
- rv = _cairo_quartz_get_image (surface, &image);
- if (likely (rv == CAIRO_STATUS_SUCCESS)) {
- rv = _cairo_surface_stroke (&image->base, op, source,
- path, style, ctm, ctm_inverse,
- tolerance, antialias,
- clip);
- cairo_surface_destroy (&image->base);
- }
-
- return rv;
-}
-
#if CAIRO_HAS_QUARTZ_FONT
static cairo_int_status_t
-_cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs)
+_cairo_quartz_cg_glyphs (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_int_t *extents,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_bool_t overlap)
{
+ cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)_surface;
CGAffineTransform textTransform, invTextTransform;
CGGlyph glyphs_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
CGSize cg_advances_static[CAIRO_STACK_ARRAY_LENGTH (CGSize)];
@@ -1995,23 +1950,17 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
COMPILE_TIME_ASSERT (sizeof (CGGlyph) <= sizeof (CGSize));
cairo_quartz_drawing_state_t state;
- cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
+ cairo_int_status_t rv = CAIRO_INT_STATUS_UNSUPPORTED;
cairo_quartz_float_t xprev, yprev;
int i;
CGFontRef cgfref = NULL;
cairo_bool_t didForceFontSmoothing = FALSE;
- if (IS_EMPTY (surface))
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
- if (num_glyphs <= 0)
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ)
return CAIRO_INT_STATUS_UNSUPPORTED;
- rv = _cairo_quartz_setup_state (&state, surface, op, source, clip);
+ rv = _cairo_quartz_setup_state (&state, extents);
if (unlikely (rv))
goto BAIL;
@@ -2106,13 +2055,13 @@ _cairo_quartz_surface_show_glyphs_cg (cairo_quartz_surface_t *surface,
CGContextTranslateCTM (state.cgMaskContext, -glyphs[0].x, -glyphs[0].y);
if (state.action != DO_DIRECT)
- _cairo_quartz_draw_source (&state, op);
+ _cairo_quartz_draw_source (&state, extents->op);
BAIL:
if (didForceFontSmoothing)
CGContextSetAllowsFontSmoothingPtr (state.cgMaskContext, FALSE);
- _cairo_quartz_teardown_state (&state, surface);
+ _cairo_quartz_teardown_state (&state, extents);
if (cg_glyphs != glyphs_static)
free (cg_glyphs);
@@ -2121,254 +2070,90 @@ BAIL:
}
#endif /* CAIRO_HAS_QUARTZ_FONT */
-static cairo_int_status_t
-_cairo_quartz_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,
- const cairo_clip_t *clip,
- int *remaining_glyphs)
-{
- cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
- cairo_int_status_t rv = CAIRO_INT_STATUS_UNSUPPORTED;
- cairo_image_surface_t *image;
+static const cairo_compositor_t _cairo_quartz_cg_compositor = {
+ &_cairo_fallback_compositor,
+ _cairo_quartz_cg_paint,
+ _cairo_quartz_cg_mask,
+ _cairo_quartz_cg_stroke,
+ _cairo_quartz_cg_fill,
#if CAIRO_HAS_QUARTZ_FONT
- rv = _cairo_quartz_surface_show_glyphs_cg (surface, op, source,
- glyphs, num_glyphs,
- scaled_font, clip, remaining_glyphs);
-
- if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED))
- return rv;
-
+ _cairo_quartz_cg_glyphs,
+#else
+ NULL,
#endif
+};
- rv = _cairo_quartz_get_image (surface, &image);
- if (likely (rv == CAIRO_STATUS_SUCCESS)) {
- rv = _cairo_surface_show_text_glyphs (&image->base, op, source,
- NULL, 0,
- glyphs, num_glyphs,
- NULL, 0, 0,
- scaled_font, clip);
- cairo_surface_destroy (&image->base);
- }
-
- return rv;
+static cairo_int_status_t
+_cairo_quartz_surface_paint (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_clip_t *clip)
+{
+ return _cairo_compositor_paint (&_cairo_quartz_cg_compositor,
+ surface, op, source, clip);
}
static cairo_int_status_t
-_cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_surface_t *mask_surf,
- const cairo_matrix_t *mask_mat,
- CGInterpolationQuality filter,
- const cairo_clip_t *clip)
+_cairo_quartz_surface_mask (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ const cairo_clip_t *clip)
{
- CGRect rect;
- CGImageRef img;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- CGAffineTransform mask_matrix;
- cairo_quartz_drawing_state_t state;
-
- if (IS_EMPTY (surface))
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
- status = _cairo_surface_to_cgimage (mask_surf, &img);
- if (unlikely (status))
- return status;
-
- status = _cairo_quartz_setup_state (&state, surface, op, source, clip);
- if (unlikely (status))
- goto BAIL;
-
- if (unlikely (img == NULL))
- goto BAIL;
-
- rect = CGRectMake (0.0, 0.0, CGImageGetWidth (img), CGImageGetHeight (img));
- _cairo_quartz_cairo_matrix_to_quartz (mask_mat, &mask_matrix);
-
- /* ClipToMask is essentially drawing an image, so we need to flip the CTM
- * to get the image to appear oriented the right way */
- CGContextConcatCTM (state.cgMaskContext, CGAffineTransformInvert (mask_matrix));
- CGContextTranslateCTM (state.cgMaskContext, 0.0, rect.size.height);
- CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
-
- state.filter = filter;
-
- CGContextSetInterpolationQuality (state.cgMaskContext, filter);
- CGContextSetShouldAntialias (state.cgMaskContext, filter != kCGInterpolationNone);
-
- CGContextClipToMask (state.cgMaskContext, rect, img);
-
- CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0);
- CGContextTranslateCTM (state.cgMaskContext, 0.0, -rect.size.height);
- CGContextConcatCTM (state.cgMaskContext, mask_matrix);
-
- _cairo_quartz_draw_source (&state, op);
-
-BAIL:
- _cairo_quartz_teardown_state (&state, surface);
-
- CGImageRelease (img);
-
- return status;
+ return _cairo_compositor_mask (&_cairo_quartz_cg_compositor,
+ surface, op, source, mask,
+ clip);
}
static cairo_int_status_t
-_cairo_quartz_surface_mask_with_solid (cairo_quartz_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- double alpha,
- const cairo_clip_t *clip)
+_cairo_quartz_surface_fill (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
{
- cairo_quartz_drawing_state_t state;
- cairo_status_t status;
-
- status = _cairo_quartz_setup_state (&state, surface, op, source, clip);
- if (unlikely (status))
- goto BAIL;
-
- CGContextSetAlpha (surface->cgContext, alpha);
- _cairo_quartz_draw_source (&state, op);
-
-BAIL:
- _cairo_quartz_teardown_state (&state, surface);
-
- return status;
+ return _cairo_compositor_fill (&_cairo_quartz_cg_compositor,
+ surface, op, source, path,
+ fill_rule, tolerance, antialias,
+ clip);
}
static cairo_int_status_t
-_cairo_quartz_surface_mask_cg (cairo_quartz_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask,
- const cairo_clip_t *clip)
+_cairo_quartz_surface_stroke (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
{
- cairo_surface_t *mask_surf;
- cairo_matrix_t matrix;
- cairo_status_t status;
- cairo_bool_t need_temp;
- CGInterpolationQuality filter;
-
- ND ((stderr, "%p _cairo_quartz_surface_mask op %d source->type %d mask->type %d\n", surface, op, source->type, mask->type));
-
- if (IS_EMPTY (surface))
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
- if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
- const cairo_solid_pattern_t *mask_solid;
-
- mask_solid = (const cairo_solid_pattern_t *) mask;
- return _cairo_quartz_surface_mask_with_solid (surface, op, source,
- mask_solid->color.alpha,
- clip);
- }
-
- need_temp = (mask->type != CAIRO_PATTERN_TYPE_SURFACE ||
- mask->extend != CAIRO_EXTEND_NONE);
-
- filter = _cairo_quartz_filter_to_quartz (source->filter);
-
- if (! need_temp) {
- mask_surf = ((const cairo_surface_pattern_t *) mask)->surface;
-
- /* When an opaque surface used as a mask in Quartz, its
- * luminosity is used as the alpha value, so we con only use
- * surfaces with alpha without creating a temporary mask. */
- need_temp = ! (mask_surf->content & CAIRO_CONTENT_ALPHA);
- }
-
- if (! need_temp) {
- CGInterpolationQuality mask_filter;
- cairo_bool_t simple_transform;
-
- matrix = mask->matrix;
-
- mask_filter = _cairo_quartz_filter_to_quartz (mask->filter);
- if (mask_filter == kCGInterpolationNone) {
- simple_transform = _cairo_matrix_is_translation (&matrix);
- if (simple_transform) {
- matrix.x0 = ceil (matrix.x0 - 0.5);
- matrix.y0 = ceil (matrix.y0 - 0.5);
- }
- } else {
- simple_transform = _cairo_matrix_is_integer_translation (&matrix,
- NULL,
- NULL);
- }
-
- /* Quartz only allows one interpolation to be set for mask and
- * source, so we can skip the temp surface only if the source
- * filtering makes the mask look correct. */
- if (source->type == CAIRO_PATTERN_TYPE_SURFACE)
- need_temp = ! (simple_transform || filter == mask_filter);
- else
- filter = mask_filter;
- }
-
- if (need_temp) {
- /* Render the mask to a surface */
- mask_surf = _cairo_quartz_surface_create_similar (surface,
- CAIRO_CONTENT_ALPHA,
- surface->extents.width,
- surface->extents.height);
- status = mask_surf->status;
- if (unlikely (status))
- goto BAIL;
-
- /* mask_surf is clear, so use OVER instead of SOURCE to avoid a
- * temporary layer or fallback to cairo-image. */
- status = _cairo_surface_paint (mask_surf, CAIRO_OPERATOR_OVER, mask, NULL);
- if (unlikely (status))
- goto BAIL;
-
- cairo_matrix_init_identity (&matrix);
- }
-
- status = _cairo_quartz_surface_mask_with_surface (surface, op, source,
- mask_surf,
- &matrix,
- filter,
- clip);
-
-BAIL:
-
- if (need_temp)
- cairo_surface_destroy (mask_surf);
-
- return status;
+ return _cairo_compositor_stroke (&_cairo_quartz_cg_compositor,
+ surface, op, source, path,
+ style, ctm,ctm_inverse,
+ tolerance, antialias, clip);
}
static cairo_int_status_t
-_cairo_quartz_surface_mask (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask,
- const cairo_clip_t *clip)
+_cairo_quartz_surface_glyphs (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ const cairo_clip_t *clip,
+ int *remaining_glyphs)
{
- cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
- cairo_int_status_t rv;
- cairo_image_surface_t *image;
-
- rv = _cairo_quartz_surface_mask_cg (surface,
- op,
- source,
- mask,
- clip);
-
- if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED))
- return rv;
-
- rv = _cairo_quartz_get_image (surface, &image);
- if (likely (rv == CAIRO_STATUS_SUCCESS)) {
- rv = _cairo_surface_mask (&image->base, op, source, mask, clip);
- cairo_surface_destroy (&image->base);
- }
-
- return rv;
+ return _cairo_compositor_glyphs (&_cairo_quartz_cg_compositor,
+ surface, op, source,
+ glyphs, num_glyphs, scaled_font,
+ clip, remaining_glyphs);
}
static cairo_status_t
@@ -2422,38 +2207,28 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
_cairo_quartz_surface_create_similar,
NULL, /* similar image */
- NULL, /* map to image */
- NULL, /* unmap image */
+ _cairo_quartz_surface_map_to_image,
+ _cairo_quartz_surface_unmap_image,
_cairo_quartz_surface_acquire_source_image,
_cairo_quartz_surface_release_source_image,
- _cairo_quartz_surface_acquire_dest_image,
- _cairo_quartz_surface_release_dest_image,
- _cairo_quartz_surface_clone_similar,
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ _cairo_quartz_surface_snapshot,
+
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_quartz_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 */
_cairo_quartz_surface_paint,
_cairo_quartz_surface_mask,
_cairo_quartz_surface_stroke,
_cairo_quartz_surface_fill,
- _cairo_quartz_surface_show_glyphs,
-
- _cairo_quartz_surface_snapshot,
- NULL, /* is_similar */
- NULL /* fill_stroke */
+ NULL /* fill-stroke */
+ _cairo_quartz_surface_glyphs,
};
cairo_quartz_surface_t *
@@ -2578,7 +2353,6 @@ cairo_quartz_surface_create (cairo_format_t format,
int stride;
int bitsPerComponent;
- // verify width and height of surface
if (!_cairo_quartz_verify_surface_size (width, height))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h
index ea38c198..6e93eab0 100644
--- a/src/cairo-recording-surface-private.h
+++ b/src/cairo-recording-surface-private.h
@@ -40,6 +40,7 @@
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
#include "cairo-pattern-private.h"
+#include "cairo-surface-backend-private.h"
typedef enum {
/* The 5 basic drawing operations. */
@@ -178,6 +179,11 @@ _cairo_recording_surface_get_bbox (cairo_recording_surface_t *recording,
cairo_box_t *bbox,
const cairo_matrix_t *transform);
+cairo_private cairo_status_t
+_cairo_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
+ cairo_box_t *bbox,
+ const cairo_matrix_t *transform);
+
static inline cairo_bool_t
_cairo_recording_surface_get_bounds (cairo_surface_t *surface,
cairo_rectangle_t *extents)
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 6d4cb379..7a18b53a 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -77,6 +77,8 @@
*/
#include "cairoint.h"
+
+#include "cairo-array-private.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-clip-private.h"
#include "cairo-combsort-private.h"
@@ -86,6 +88,7 @@
#include "cairo-image-surface-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-wrapper-private.h"
+#include "cairo-traps-private.h"
typedef enum {
CAIRO_RECORDING_REPLAY,
@@ -493,42 +496,6 @@ _cairo_recording_surface_finish (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_recording_surface_acquire_source_image_transformed (void *abstract_surface,
- cairo_matrix_t *device_transform,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_status_t status;
- cairo_recording_surface_t *surface = abstract_surface;
- cairo_surface_t *image;
- double width;
- double height;
-
- width = surface->extents.width * device_transform->xx;
- height = surface->extents.height * device_transform->yy;
- image = _cairo_image_surface_create_with_content (surface->base.content,
- width, height);
- if (unlikely (image->status))
- return image->status;
-
- cairo_surface_set_device_offset (image,
- -surface->extents.x,
- -surface->extents.y);
-
- _cairo_surface_set_device_scale (image,
- device_transform->xx, device_transform->yy);
- status = _cairo_recording_surface_replay (&surface->base, image);
- if (unlikely (status)) {
- cairo_surface_destroy (image);
- return status;
- }
-
- *image_out = (cairo_image_surface_t *) image;
- *image_extra = NULL;
- return CAIRO_STATUS_SUCCESS;
-}
-
struct proxy {
cairo_surface_t base;
cairo_surface_t *image;
@@ -680,15 +647,6 @@ _command_init (cairo_recording_surface_t *surface,
return status;
}
-static const cairo_rectangle_int_t *
-_cairo_recording_surface_extents (cairo_recording_surface_t *surface)
-{
- if (surface->unbounded)
- return &_cairo_unbounded_rectangle;
-
- return &surface->extents;
-}
-
static void
_cairo_recording_surface_break_self_copy_loop (cairo_recording_surface_t *surface)
{
@@ -713,7 +671,6 @@ _cairo_recording_surface_paint (void *abstract_surface,
cairo_recording_surface_t *surface = abstract_surface;
cairo_command_paint_t *command;
cairo_composite_rectangles_t composite;
- const cairo_rectangle_int_t *extents;
if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) {
if (surface->optimize_clears) {
@@ -723,8 +680,8 @@ _cairo_recording_surface_paint (void *abstract_surface,
}
}
- extents = _cairo_recording_surface_extents (surface);
- status = _cairo_composite_rectangles_init_for_paint (&composite, extents,
+ status = _cairo_composite_rectangles_init_for_paint (&composite,
+ &surface->base,
op, source,
clip);
if (unlikely (status))
@@ -776,10 +733,9 @@ _cairo_recording_surface_mask (void *abstract_surface,
cairo_recording_surface_t *surface = abstract_surface;
cairo_command_mask_t *command;
cairo_composite_rectangles_t composite;
- const cairo_rectangle_int_t *extents;
- extents = _cairo_recording_surface_extents (surface);
- status = _cairo_composite_rectangles_init_for_mask (&composite, extents,
+ status = _cairo_composite_rectangles_init_for_mask (&composite,
+ &surface->base,
op, source, mask,
clip);
if (unlikely (status))
@@ -842,10 +798,9 @@ _cairo_recording_surface_stroke (void *abstract_surface,
cairo_recording_surface_t *surface = abstract_surface;
cairo_command_stroke_t *command;
cairo_composite_rectangles_t composite;
- const cairo_rectangle_int_t *extents;
- extents = _cairo_recording_surface_extents (surface);
- status = _cairo_composite_rectangles_init_for_stroke (&composite, extents,
+ status = _cairo_composite_rectangles_init_for_stroke (&composite,
+ &surface->base,
op, source,
path, style, ctm,
clip);
@@ -918,10 +873,9 @@ _cairo_recording_surface_fill (void *abstract_surface,
cairo_recording_surface_t *surface = abstract_surface;
cairo_command_fill_t *command;
cairo_composite_rectangles_t composite;
- const cairo_rectangle_int_t *extents;
- extents = _cairo_recording_surface_extents (surface);
- status = _cairo_composite_rectangles_init_for_fill (&composite, extents,
+ status = _cairo_composite_rectangles_init_for_fill (&composite,
+ &surface->base,
op, source, path,
clip);
if (unlikely (status))
@@ -996,10 +950,9 @@ _cairo_recording_surface_show_text_glyphs (void *abstract_surface,
cairo_recording_surface_t *surface = abstract_surface;
cairo_command_show_text_glyphs_t *command;
cairo_composite_rectangles_t composite;
- const cairo_rectangle_int_t *extents;
- extents = _cairo_recording_surface_extents (surface);
- status = _cairo_composite_rectangles_init_for_glyphs (&composite, extents,
+ status = _cairo_composite_rectangles_init_for_glyphs (&composite,
+ &surface->base,
op, source,
scaled_font,
glyphs, num_glyphs,
@@ -1121,6 +1074,9 @@ _cairo_recording_surface_snapshot (void *abstract_other)
surface->bbtree.left = surface->bbtree.right = NULL;
surface->bbtree.chain = INVALID_CHAIN;
+ surface->indices = NULL;
+ surface->num_indices = 0;
+
_cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
status = _cairo_recording_surface_replay (&other->base, &surface->base);
if (unlikely (status)) {
@@ -1128,9 +1084,6 @@ _cairo_recording_surface_snapshot (void *abstract_other)
return _cairo_surface_create_in_error (status);
}
- surface->indices = NULL;
- surface->num_indices = 0;
-
return &surface->base;
}
@@ -1160,23 +1113,16 @@ static const cairo_surface_backend_t cairo_recording_surface_backend = {
_cairo_recording_surface_acquire_source_image,
_cairo_recording_surface_release_source_image,
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ _cairo_recording_surface_snapshot,
+
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_recording_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 */
/* Here are the 5 basic drawing operations, (which are in some
* sense the only things that cairo_recording_surface should need to
@@ -1187,18 +1133,10 @@ static const cairo_surface_backend_t cairo_recording_surface_backend = {
_cairo_recording_surface_mask,
_cairo_recording_surface_stroke,
_cairo_recording_surface_fill,
+ NULL, /* fill-stroke */
NULL,
-
- _cairo_recording_surface_snapshot,
-
- NULL, /* is_similar */
- NULL, /* fill_stroke */
- NULL, /* create_solid_pattern_surface */
- NULL, /* can_repaint_solid_pattern_surface */
-
_cairo_recording_surface_has_show_text_glyphs,
_cairo_recording_surface_show_text_glyphs,
- _cairo_recording_surface_acquire_source_image_transformed
};
cairo_int_status_t
@@ -1723,3 +1661,30 @@ _cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface,
return _recording_surface_get_ink_bbox (surface, bbox, transform);
}
+
+cairo_status_t
+_cairo_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
+ cairo_box_t *bbox,
+ const cairo_matrix_t *transform)
+{
+ return _recording_surface_get_ink_bbox (surface, bbox, transform);
+}
+
+cairo_bool_t
+cairo_recording_surface_get_extents (cairo_surface_t *surface,
+ cairo_rectangle_t *extents)
+{
+ cairo_recording_surface_t *record;
+
+ if (surface->status || ! _cairo_surface_is_recording (surface)) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return FALSE;
+ }
+
+ record = (cairo_recording_surface_t *)surface;
+ if (record->unbounded)
+ return FALSE;
+
+ *extents = record->extents_pixels;
+ return TRUE;
+}
diff --git a/src/cairo-rectangular-scan-converter.c b/src/cairo-rectangular-scan-converter.c
index 56e552b7..b4214c88 100644
--- a/src/cairo-rectangular-scan-converter.c
+++ b/src/cairo-rectangular-scan-converter.c
@@ -379,18 +379,20 @@ _active_edges_to_spans (sweep_line_t *sweep)
for (cell = sweep->coverage.head.next; cell != &sweep->coverage.tail; cell = cell->next) {
if (cell->x != prev_x && coverage != prev_coverage) {
int n = sweep->num_spans++;
+ int c = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
sweep->spans[n].x = prev_x;
- sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
- sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8;
+ sweep->spans[n].inverse = 0;
+ sweep->spans[n].coverage = c - (c >> 8);
prev_coverage = coverage;
}
coverage += cell->covered;
if (coverage != prev_coverage) {
int n = sweep->num_spans++;
+ int c = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
sweep->spans[n].x = cell->x;
- sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
- sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8;
+ sweep->spans[n].inverse = 0;
+ sweep->spans[n].coverage = c - (c >> 8);
prev_coverage = coverage;
}
coverage += cell->uncovered;
@@ -401,13 +403,16 @@ _active_edges_to_spans (sweep_line_t *sweep)
if (sweep->num_spans) {
if (prev_x <= sweep->xmax) {
int n = sweep->num_spans++;
+ int c = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
sweep->spans[n].x = prev_x;
- sweep->spans[n].coverage = coverage;
+ sweep->spans[n].inverse = 0;
+ sweep->spans[n].coverage = c - (c >> 8);
}
if (coverage && prev_x < sweep->xmax) {
int n = sweep->num_spans++;
sweep->spans[n].x = sweep->xmax;
+ sweep->spans[n].inverse = 1;
sweep->spans[n].coverage = 0;
}
}
@@ -489,13 +494,13 @@ generate (cairo_rectangular_scan_converter_t *self,
cairo_status_t status;
sweep_line_init (&sweep_line);
- sweep_line.xmin = self->xmin;
- sweep_line.xmax = self->xmax;
+ sweep_line.xmin = _cairo_fixed_integer_part (self->extents.p1.x);
+ sweep_line.xmax = _cairo_fixed_integer_part (self->extents.p2.x);
sweep_line.start = rectangles;
if ((status = setjmp (sweep_line.jmpbuf)))
- goto BAIL;
+ goto out;
- sweep_line.current_y = self->ymin;
+ sweep_line.current_y = _cairo_fixed_integer_part (self->extents.p1.y);
start = *sweep_line.start++;
do {
if (start->top_y != sweep_line.current_y) {
@@ -554,9 +559,7 @@ generate (cairo_rectangular_scan_converter_t *self,
goto out;
}
- sweep_line.current_y++;
-
- do {
+ while (++sweep_line.current_y < _cairo_fixed_integer_part (self->extents.p2.y)) {
if (stop->bottom_y != sweep_line.current_y) {
render_rows (&sweep_line, renderer,
stop->bottom_y - sweep_line.current_y);
@@ -572,16 +575,9 @@ generate (cairo_rectangular_scan_converter_t *self,
goto out;
} while (stop->bottom_y == sweep_line.current_y);
- sweep_line.current_y++;
- } while (TRUE);
+ }
out:
- status = renderer->render_rows (renderer,
- sweep_line.current_y,
- self->ymax - sweep_line.current_y,
- NULL, 0);
-
- BAIL:
sweep_line_fini (&sweep_line);
return status;
@@ -611,18 +607,18 @@ static void generate_row(cairo_span_renderer_t *renderer,
}
if (! _cairo_fixed_is_integer (r->right)) {
- spans[num_spans].x = x2;
+ spans[num_spans].x = x2++;
spans[num_spans].coverage =
coverage * _cairo_fixed_fractional_part (r->right) >> 8;
num_spans++;
}
} else {
- spans[num_spans].x = x1;
+ spans[num_spans].x = x2++;
spans[num_spans].coverage = coverage * (r->right - r->left) >> 8;
num_spans++;
}
- spans[num_spans].x = x2 + 1;
+ spans[num_spans].x = x2;
spans[num_spans].coverage = 0;
num_spans++;
@@ -668,7 +664,8 @@ _cairo_rectangular_scan_converter_generate (void *converter,
if (unlikely (self->num_rectangles == 0)) {
return renderer->render_rows (renderer,
- self->ymin, self->ymax - self->ymin,
+ _cairo_fixed_integer_part (self->extents.p1.y),
+ _cairo_fixed_integer_part (self->extents.p2.y - self->extents.p1.y),
NULL, 0);
}
@@ -743,17 +740,22 @@ _cairo_rectangular_scan_converter_add_box (cairo_rectangular_scan_converter_t *s
if (unlikely (rectangle == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- rectangle->left = box->p1.x;
- rectangle->right = box->p2.x;
rectangle->dir = dir;
+ rectangle->left = MAX (box->p1.x, self->extents.p1.x);
+ rectangle->right = MIN (box->p2.x, self->extents.p2.x);
+ if (unlikely (rectangle->right <= rectangle->left)) {
+ self->tail->count--;
+ return CAIRO_STATUS_SUCCESS;
+ }
- rectangle->top = box->p1.y;
- rectangle->top_y = _cairo_fixed_integer_floor (box->p1.y);
- rectangle->bottom = box->p2.y;
- rectangle->bottom_y = _cairo_fixed_integer_floor (box->p2.y);
- assert (rectangle->bottom_y >= rectangle->top_y);
-
- self->num_rectangles++;
+ rectangle->top = MAX (box->p1.y, self->extents.p1.y);
+ rectangle->top_y = _cairo_fixed_integer_floor (rectangle->top);
+ rectangle->bottom = MIN (box->p2.y, self->extents.p2.y);
+ rectangle->bottom_y = _cairo_fixed_integer_floor (rectangle->bottom);
+ if (likely (rectangle->bottom > rectangle->top))
+ self->num_rectangles++;
+ else
+ self->tail->count--;
return CAIRO_STATUS_SUCCESS;
}
@@ -775,14 +777,9 @@ _cairo_rectangular_scan_converter_init (cairo_rectangular_scan_converter_t *self
const cairo_rectangle_int_t *extents)
{
self->base.destroy = _cairo_rectangular_scan_converter_destroy;
- self->base.add_edge = NULL;
- self->base.add_polygon = NULL;
self->base.generate = _cairo_rectangular_scan_converter_generate;
- self->xmin = extents->x;
- self->xmax = extents->x + extents->width;
- self->ymin = extents->y;
- self->ymax = extents->y + extents->height;
+ _cairo_box_from_rectangle (&self->extents, extents);
self->chunks.base = self->buf;
self->chunks.next = NULL;
diff --git a/src/cairo-reference-count-private.h b/src/cairo-reference-count-private.h
index 0cb5695d..75fdf353 100644
--- a/src/cairo-reference-count-private.h
+++ b/src/cairo-reference-count-private.h
@@ -45,6 +45,7 @@ typedef struct {
} cairo_reference_count_t;
#define _cairo_reference_count_inc(RC) _cairo_atomic_int_inc (&(RC)->ref_count)
+#define _cairo_reference_count_dec(RC) _cairo_atomic_int_dec (&(RC)->ref_count)
#define _cairo_reference_count_dec_and_test(RC) _cairo_atomic_int_dec_and_test (&(RC)->ref_count)
#define CAIRO_REFERENCE_COUNT_INIT(RC, VALUE) ((RC)->ref_count = (VALUE))
diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h
index 029377b1..da7b3469 100644
--- a/src/cairo-scaled-font-private.h
+++ b/src/cairo-scaled-font-private.h
@@ -45,6 +45,8 @@
#include "cairo-mutex-type-private.h"
#include "cairo-reference-count-private.h"
+CAIRO_BEGIN_DECLS
+
typedef struct _cairo_scaled_glyph_page cairo_scaled_glyph_page_t;
struct _cairo_scaled_font {
@@ -112,20 +114,70 @@ struct _cairo_scaled_font {
cairo_bool_t cache_frozen;
cairo_bool_t global_cache_frozen;
- /*
- * One surface backend may store data in each glyph.
- * Whichever surface manages to store its pointer here
- * first gets to store data in each glyph
- */
- const cairo_surface_backend_t *surface_backend;
- void *surface_private;
+ cairo_list_t dev_privates;
/* font backend managing this scaled font */
const cairo_scaled_font_backend_t *backend;
cairo_list_t link;
};
+struct _cairo_scaled_font_private {
+ cairo_list_t link;
+ const void *key;
+ void (*destroy) (cairo_scaled_font_private_t *,
+ cairo_scaled_font_t *);
+};
+
+struct _cairo_scaled_glyph {
+ cairo_hash_entry_t hash_entry;
+
+ cairo_text_extents_t metrics; /* user-space metrics */
+ cairo_text_extents_t fs_metrics; /* font-space metrics */
+ cairo_box_t bbox; /* device-space bounds */
+ int16_t x_advance; /* device-space rounded X advance */
+ int16_t y_advance; /* device-space rounded Y advance */
+
+ unsigned int has_info;
+ cairo_image_surface_t *surface; /* device-space image */
+ cairo_path_fixed_t *path; /* device-space outline */
+ cairo_surface_t *recording_surface; /* device-space recording-surface */
+
+ const void *dev_private_key;
+ void *dev_private;
+ cairo_list_t dev_privates;
+};
+
+struct _cairo_scaled_glyph_private {
+ cairo_list_t link;
+ const void *key;
+ void (*destroy) (cairo_scaled_glyph_private_t *,
+ cairo_scaled_glyph_t *,
+ cairo_scaled_font_t *);
+};
+
+cairo_private cairo_scaled_font_private_t *
+_cairo_scaled_font_find_private (cairo_scaled_font_t *scaled_font,
+ const void *key);
+
+cairo_private void
+_cairo_scaled_font_attach_private (cairo_scaled_font_t *scaled_font,
+ cairo_scaled_font_private_t *priv,
+ const void *key,
+ void (*destroy) (cairo_scaled_font_private_t *,
+ cairo_scaled_font_t *));
+
+cairo_private cairo_scaled_glyph_private_t *
+_cairo_scaled_glyph_find_private (cairo_scaled_glyph_t *scaled_glyph,
+ const void *key);
+
cairo_private void
-_cairo_scaled_font_revoke_ownership (cairo_scaled_font_t *scaled_font);
+_cairo_scaled_glyph_attach_private (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_scaled_glyph_private_t *priv,
+ const void *key,
+ void (*destroy) (cairo_scaled_glyph_private_t *,
+ cairo_scaled_glyph_t *,
+ cairo_scaled_font_t *));
+
+CAIRO_END_DECLS
#endif /* CAIRO_SCALED_FONT_PRIVATE_H */
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 5b775469..be612a9b 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -43,6 +43,7 @@
#include "cairo-image-surface-private.h"
#include "cairo-pattern-private.h"
#include "cairo-scaled-font-private.h"
+#include "cairo-surface-backend-private.h"
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
#define ISFINITE(x) isfinite (x)
@@ -199,10 +200,13 @@ static void
_cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph)
{
- const cairo_surface_backend_t *surface_backend = scaled_font->surface_backend;
-
- if (surface_backend != NULL && surface_backend->scaled_glyph_fini != NULL)
- surface_backend->scaled_glyph_fini (scaled_glyph, scaled_font);
+ while (! cairo_list_is_empty (&scaled_glyph->dev_privates)) {
+ cairo_scaled_glyph_private_t *private =
+ cairo_list_first_entry (&scaled_glyph->dev_privates,
+ cairo_scaled_glyph_private_t,
+ link);
+ private->destroy (private, scaled_glyph, scaled_font);
+ }
if (scaled_glyph->surface != NULL)
cairo_surface_destroy (&scaled_glyph->surface->base);
@@ -243,8 +247,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
{ NULL, NULL }, /* pages */
FALSE, /* cache_frozen */
FALSE, /* global_cache_frozen */
- NULL, /* surface_backend */
- NULL, /* surface_private */
+ { NULL, NULL }, /* privates */
NULL /* backend */
};
@@ -445,6 +448,8 @@ _cairo_scaled_glyph_page_destroy (void *closure)
cairo_scaled_font_t *scaled_font;
unsigned int n;
+ assert (! cairo_list_is_empty (&page->link));
+
scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
for (n = 0; n < page->num_glyphs; n++) {
_cairo_hash_table_remove (scaled_font->glyphs,
@@ -734,8 +739,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
CAIRO_MUTEX_INIT (scaled_font->mutex);
- scaled_font->surface_backend = NULL;
- scaled_font->surface_private = NULL;
+ cairo_list_init (&scaled_font->dev_privates);
scaled_font->backend = backend;
cairo_list_init (&scaled_font->link);
@@ -826,9 +830,13 @@ _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
CAIRO_MUTEX_FINI (scaled_font->mutex);
- if (scaled_font->surface_backend != NULL &&
- scaled_font->surface_backend->scaled_font_fini != NULL)
- scaled_font->surface_backend->scaled_font_fini (scaled_font);
+ while (! cairo_list_is_empty (&scaled_font->dev_privates)) {
+ cairo_scaled_font_private_t *private =
+ cairo_list_first_entry (&scaled_font->dev_privates,
+ cairo_scaled_font_private_t,
+ link);
+ private->destroy (private, scaled_font);
+ }
if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL)
scaled_font->backend->fini (scaled_font);
@@ -836,30 +844,77 @@ _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
_cairo_user_data_array_fini (&scaled_font->user_data);
}
-/* XXX: allow multiple backends to share the font */
void
-_cairo_scaled_font_revoke_ownership (cairo_scaled_font_t *scaled_font)
+_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
{
- if (scaled_font->surface_backend == NULL)
- return;
+ /* Release the lock to avoid the possibility of a recursive
+ * deadlock when the scaled font destroy closure gets called. */
+ CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
+ _cairo_scaled_font_fini_internal (scaled_font);
+ CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+}
- _cairo_scaled_font_reset_cache (scaled_font);
+void
+_cairo_scaled_font_attach_private (cairo_scaled_font_t *scaled_font,
+ cairo_scaled_font_private_t *private,
+ const void *key,
+ void (*destroy) (cairo_scaled_font_private_t *,
+ cairo_scaled_font_t *))
+{
+ private->key = key;
+ private->destroy = destroy;
+ cairo_list_add (&private->link, &scaled_font->dev_privates);
+}
+
+cairo_scaled_font_private_t *
+_cairo_scaled_font_find_private (cairo_scaled_font_t *scaled_font,
+ const void *key)
+{
+ cairo_scaled_font_private_t *priv;
- if (scaled_font->surface_backend->scaled_font_fini != NULL)
- scaled_font->surface_backend->scaled_font_fini (scaled_font);
+ cairo_list_foreach_entry (priv, cairo_scaled_font_private_t,
+ &scaled_font->dev_privates, link)
+ {
+ if (priv->key == key) {
+ if (priv->link.prev != &scaled_font->dev_privates)
+ cairo_list_move (&priv->link, &scaled_font->dev_privates);
+ return priv;
+ }
+ }
- scaled_font->surface_backend = NULL;
- scaled_font->surface_private = NULL;
+ return NULL;
}
void
-_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+_cairo_scaled_glyph_attach_private (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_scaled_glyph_private_t *private,
+ const void *key,
+ void (*destroy) (cairo_scaled_glyph_private_t *,
+ cairo_scaled_glyph_t *,
+ cairo_scaled_font_t *))
{
- /* Release the lock to avoid the possibility of a recursive
- * deadlock when the scaled font destroy closure gets called. */
- CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
- _cairo_scaled_font_fini_internal (scaled_font);
- CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+ private->key = key;
+ private->destroy = destroy;
+ cairo_list_add (&private->link, &scaled_glyph->dev_privates);
+}
+
+cairo_scaled_glyph_private_t *
+_cairo_scaled_glyph_find_private (cairo_scaled_glyph_t *scaled_glyph,
+ const void *key)
+{
+ cairo_scaled_glyph_private_t *priv;
+
+ cairo_list_foreach_entry (priv, cairo_scaled_glyph_private_t,
+ &scaled_glyph->dev_privates, link)
+ {
+ if (priv->key == key) {
+ if (priv->link.prev != &scaled_glyph->dev_privates)
+ cairo_list_move (&priv->link, &scaled_glyph->dev_privates);
+ return priv;
+ }
+ }
+
+ return NULL;
}
/**
@@ -2209,6 +2264,8 @@ _cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t *scaled_font,
extents->height = ceil (y1 + pad) - extents->y;
}
+#if 0
+/* XXX win32 */
cairo_status_t
_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t op,
@@ -2399,6 +2456,7 @@ CLEANUP_MASK:
cairo_surface_destroy (mask);
return _cairo_scaled_font_set_error (scaled_font, status);
}
+#endif
/* Add a single-device-unit rectangle to a path. */
static cairo_status_t
@@ -2844,6 +2902,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
memset (scaled_glyph, 0, sizeof (cairo_scaled_glyph_t));
_cairo_scaled_glyph_set_index (scaled_glyph, index);
+ cairo_list_init (&scaled_glyph->dev_privates);
/* ask backend to initialize metrics and shape fields */
status =
diff --git a/src/cairo-script-private.h b/src/cairo-script-private.h
index 698a54e3..5b506f50 100644
--- a/src/cairo-script-private.h
+++ b/src/cairo-script-private.h
@@ -37,10 +37,11 @@
#define CAIRO_SCRIPT_PRIVATE_H
#include "cairo.h"
+#include "cairo-script.h"
#include "cairo-compiler-private.h"
#include "cairo-output-stream-private.h"
-#include "cairo-script.h"
+#include "cairo-types-private.h"
CAIRO_BEGIN_DECLS
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 56e9d80a..7199cd13 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -81,7 +81,7 @@
typedef struct _cairo_script_context cairo_script_context_t;
typedef struct _cairo_script_surface cairo_script_surface_t;
typedef struct _cairo_script_implicit_context cairo_script_implicit_context_t;
-typedef struct _cairo_script_surface_font_private cairo_script_surface_font_private_t;
+typedef struct _cairo_script_font cairo_script_font_t;
typedef struct _operand {
enum {
@@ -121,8 +121,9 @@ struct _cairo_script_context {
cairo_list_t defines;
};
-struct _cairo_script_surface_font_private {
- cairo_script_context_t *ctx;
+struct _cairo_script_font {
+ cairo_scaled_font_private_t base;
+
cairo_bool_t has_sfnt;
unsigned long id;
unsigned long subset_glyph_index;
@@ -173,7 +174,8 @@ _cairo_script_surface_create_internal (cairo_script_context_t *ctx,
cairo_surface_t *passthrough);
static void
-_cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
+_cairo_script_scaled_font_fini (cairo_scaled_font_private_t *abstract_private,
+ cairo_scaled_font_t *scaled_font);
static void
_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr);
@@ -2022,14 +2024,11 @@ _device_destroy (void *abstract_device)
cairo_status_t status;
while (! cairo_list_is_empty (&ctx->fonts)) {
- cairo_script_surface_font_private_t *font;
+ cairo_script_font_t *font;
- font = cairo_list_first_entry (&ctx->fonts,
- cairo_script_surface_font_private_t,
- link);
+ font = cairo_list_first_entry (&ctx->fonts, cairo_script_font_t, link);
+ cairo_list_del (&font->base.link);
cairo_list_del (&font->link);
- if (font->parent->surface_private == font)
- font->parent->surface_private = NULL;
free (font);
}
@@ -2733,31 +2732,39 @@ _emit_font_options (cairo_script_surface_t *surface,
}
static void
-_cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+_cairo_script_scaled_font_fini (cairo_scaled_font_private_t *abstract_private,
+ cairo_scaled_font_t *scaled_font)
{
- cairo_script_surface_font_private_t *font_private;
+ cairo_script_font_t *priv = (cairo_script_font_t *)abstract_private;
+ cairo_script_context_t *ctx = (cairo_script_context_t *)abstract_private->key;
+ cairo_status_t status;
- font_private = scaled_font->surface_private;
- if (font_private != NULL) {
- cairo_status_t status;
- cairo_device_t *device;
+ status = cairo_device_acquire (&ctx->base);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ _cairo_output_stream_printf (ctx->stream,
+ "/f%lu undef /sf%lu undef\n",
+ priv->id,
+ priv->id);
- status = cairo_device_acquire (device = &font_private->ctx->base);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- _cairo_output_stream_printf (font_private->ctx->stream,
- "/f%lu undef /sf%lu undef\n",
- font_private->id,
- font_private->id);
+ _bitmap_release_id (&ctx->font_id, priv->id);
+ cairo_device_release (&ctx->base);
+ }
- _bitmap_release_id (&font_private->ctx->font_id, font_private->id);
- cairo_list_del (&font_private->link);
- free (font_private);
+ cairo_list_del (&priv->link);
+ cairo_list_del (&priv->base.link);
+ free (priv);
+}
- cairo_device_release (device);
- }
+static cairo_script_font_t *
+_cairo_script_font_get (cairo_script_context_t *ctx, cairo_scaled_font_t *font)
+{
+ return (cairo_script_font_t *) _cairo_scaled_font_find_private (font, ctx);
+}
- scaled_font->surface_private = NULL;
- }
+static long unsigned
+_cairo_script_font_id (cairo_script_context_t *ctx, cairo_scaled_font_t *font)
+{
+ return _cairo_script_font_get (ctx, font)->id;
}
static cairo_status_t
@@ -2766,7 +2773,6 @@ _emit_type42_font (cairo_script_surface_t *surface,
{
cairo_script_context_t *ctx = to_context (surface);
const cairo_scaled_font_backend_t *backend;
- cairo_script_surface_font_private_t *font_private;
cairo_output_stream_t *base85_stream;
cairo_output_stream_t *zlib_stream;
cairo_status_t status, status2;
@@ -2824,27 +2830,29 @@ _emit_type42_font (cairo_script_surface_t *surface,
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
- font_private = scaled_font->surface_private;
_cairo_output_stream_printf (ctx->stream,
"~> >> font dup /f%lu exch def set-font-face",
- font_private->id);
+ _cairo_script_font_id (ctx, scaled_font));
return status;
}
static cairo_status_t
_emit_scaled_font_init (cairo_script_surface_t *surface,
- cairo_scaled_font_t *scaled_font)
+ cairo_scaled_font_t *scaled_font,
+ cairo_script_font_t **font_out)
{
cairo_script_context_t *ctx = to_context (surface);
- cairo_script_surface_font_private_t *font_private;
+ cairo_script_font_t *font_private;
cairo_int_status_t status;
- font_private = malloc (sizeof (cairo_script_surface_font_private_t));
+ font_private = malloc (sizeof (cairo_script_font_t));
if (unlikely (font_private == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- font_private->ctx = ctx;
+ _cairo_scaled_font_attach_private (scaled_font, &font_private->base, ctx,
+ _cairo_script_scaled_font_fini);
+
font_private->parent = scaled_font;
font_private->subset_glyph_index = 0;
font_private->has_sfnt = TRUE;
@@ -2858,16 +2866,17 @@ _emit_scaled_font_init (cairo_script_surface_t *surface,
return status;
}
- scaled_font->surface_private = font_private;
- scaled_font->surface_backend = &_cairo_script_surface_backend;
-
status = _emit_context (surface);
- if (unlikely (status))
+ if (unlikely (status)) {
+ free (font_private);
return status;
+ }
status = _emit_type42_font (surface, scaled_font);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+ *font_out = font_private;
return status;
+ }
font_private->has_sfnt = FALSE;
_cairo_output_stream_printf (ctx->stream,
@@ -2883,6 +2892,7 @@ _emit_scaled_font_init (cairo_script_surface_t *surface,
scaled_font->fs_extents.max_y_advance,
font_private->id);
+ *font_out = font_private;
return CAIRO_STATUS_SUCCESS;
}
@@ -2895,7 +2905,7 @@ _emit_scaled_font (cairo_script_surface_t *surface,
cairo_font_options_t options;
cairo_bool_t matrix_updated = FALSE;
cairo_status_t status;
- cairo_script_surface_font_private_t *font_private;
+ cairo_script_font_t *font_private;
cairo_scaled_font_get_ctm (scaled_font, &matrix);
status = _emit_scaling_matrix (surface, &matrix, &matrix_updated);
@@ -2907,13 +2917,7 @@ _emit_scaled_font (cairo_script_surface_t *surface,
surface->cr.current_scaled_font = scaled_font;
- if (! (scaled_font->surface_backend == NULL ||
- scaled_font->surface_backend == &_cairo_script_surface_backend))
- {
- _cairo_scaled_font_revoke_ownership (scaled_font);
- }
-
- font_private = scaled_font->surface_private;
+ font_private = _cairo_script_font_get (ctx, scaled_font);
if (font_private == NULL) {
cairo_scaled_font_get_font_matrix (scaled_font, &matrix);
status = _emit_font_matrix (surface, &matrix);
@@ -2925,13 +2929,10 @@ _emit_scaled_font (cairo_script_surface_t *surface,
if (unlikely (status))
return status;
- status = _emit_scaled_font_init (surface, scaled_font);
+ status = _emit_scaled_font_init (surface, scaled_font, &font_private);
if (unlikely (status))
return status;
- font_private = scaled_font->surface_private;
- assert (font_private != NULL);
-
assert (target_is_active (surface));
_cairo_output_stream_printf (ctx->stream,
" /scaled-font get /sf%lu exch def\n",
@@ -2948,17 +2949,17 @@ _emit_scaled_font (cairo_script_surface_t *surface,
static cairo_status_t
_emit_scaled_glyph_vector (cairo_script_surface_t *surface,
cairo_scaled_font_t *scaled_font,
+ cairo_script_font_t *font_private,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_script_context_t *ctx = to_context (surface);
- cairo_script_surface_font_private_t *font_private;
cairo_script_implicit_context_t old_cr;
cairo_status_t status;
unsigned long index;
- font_private = scaled_font->surface_private;
index = ++font_private->subset_glyph_index;
- scaled_glyph->surface_private = (void *) index;
+ scaled_glyph->dev_private_key = ctx;
+ scaled_glyph->dev_private = (void *) index;
_cairo_output_stream_printf (ctx->stream,
"%lu <<\n"
@@ -2997,16 +2998,16 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface,
static cairo_status_t
_emit_scaled_glyph_bitmap (cairo_script_surface_t *surface,
cairo_scaled_font_t *scaled_font,
+ cairo_script_font_t *font_private,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_script_context_t *ctx = to_context (surface);
- cairo_script_surface_font_private_t *font_private;
cairo_status_t status;
unsigned long index;
- font_private = scaled_font->surface_private;
index = ++font_private->subset_glyph_index;
- scaled_glyph->surface_private = (void *) index;
+ scaled_glyph->dev_private_key = ctx;
+ scaled_glyph->dev_private = (void *) index;
_cairo_output_stream_printf (ctx->stream,
"%lu <<\n"
@@ -3049,15 +3050,10 @@ static cairo_status_t
_emit_scaled_glyph_prologue (cairo_script_surface_t *surface,
cairo_scaled_font_t *scaled_font)
{
- cairo_script_surface_font_private_t *font_private;
-
- assert (scaled_font->surface_backend == &_cairo_script_surface_backend);
-
- font_private = scaled_font->surface_private;
+ cairo_script_context_t *ctx = to_context (surface);
- _cairo_output_stream_printf (to_context (surface)->stream,
- "f%lu /glyphs get\n",
- font_private->id);
+ _cairo_output_stream_printf (ctx->stream, "f%lu /glyphs get\n",
+ _cairo_script_font_id (ctx, scaled_font));
return CAIRO_STATUS_SUCCESS;
}
@@ -3068,7 +3064,8 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
cairo_glyph_t *glyphs,
unsigned int num_glyphs)
{
- cairo_script_surface_font_private_t *font_private;
+ cairo_script_context_t *ctx = to_context (surface);
+ cairo_script_font_t *font_private;
cairo_status_t status;
unsigned int n;
cairo_bool_t have_glyph_prologue = FALSE;
@@ -3076,7 +3073,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
if (num_glyphs == 0)
return CAIRO_STATUS_SUCCESS;
- font_private = scaled_font->surface_private;
+ font_private = _cairo_script_font_get (ctx, scaled_font);
if (font_private->has_sfnt)
return CAIRO_STATUS_SUCCESS;
@@ -3091,7 +3088,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
if (unlikely (status))
break;
- if (scaled_glyph->surface_private != NULL)
+ if (scaled_glyph->dev_private_key == ctx)
continue;
status = _cairo_scaled_glyph_lookup (scaled_font,
@@ -3111,7 +3108,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
}
status = _emit_scaled_glyph_vector (surface,
- scaled_font,
+ scaled_font, font_private,
scaled_glyph);
if (unlikely (status))
break;
@@ -3137,6 +3134,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
status = _emit_scaled_glyph_bitmap (surface,
scaled_font,
+ font_private,
scaled_glyph);
if (unlikely (status))
break;
@@ -3234,7 +3232,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
{
cairo_script_surface_t *surface = abstract_surface;
cairo_script_context_t *ctx = to_context (surface);
- cairo_script_surface_font_private_t *font_private;
+ cairo_script_font_t *font_private;
cairo_scaled_glyph_t *scaled_glyph;
cairo_matrix_t matrix;
cairo_status_t status;
@@ -3289,7 +3287,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
iy -= scaled_font->font_matrix.y0;
_cairo_scaled_font_freeze_cache (scaled_font);
- font_private = scaled_font->surface_private;
+ font_private = _cairo_script_font_get (ctx, scaled_font);
_cairo_output_stream_printf (ctx->stream,
"[%f %f ",
@@ -3309,7 +3307,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
goto BAIL;
}
- if ((long unsigned) scaled_glyph->surface_private > 256)
+ if ((long unsigned) scaled_glyph->dev_private > 256)
break;
}
}
@@ -3378,7 +3376,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
if (font_private->has_sfnt)
c = glyphs[n].index;
else
- c = (uint8_t) (long unsigned) scaled_glyph->surface_private;
+ c = (uint8_t) (long unsigned) scaled_glyph->dev_private;
_cairo_output_stream_write (base85_stream, &c, 1);
} else {
@@ -3387,7 +3385,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
glyphs[n].index);
else
_cairo_output_stream_printf (ctx->stream, " %lu",
- (long unsigned) scaled_glyph->surface_private);
+ (long unsigned) scaled_glyph->dev_private);
}
dx = scaled_glyph->metrics.x_advance;
@@ -3512,40 +3510,23 @@ _cairo_script_surface_backend = {
_cairo_script_surface_acquire_source_image,
_cairo_script_surface_release_source_image,
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ _cairo_script_surface_snapshot,
+
_cairo_script_surface_copy_page,
_cairo_script_surface_show_page,
+
_cairo_script_surface_get_extents,
- NULL, /* old_show_glyphs */
NULL, /* get_font_options */
+
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
- _cairo_script_surface_scaled_font_fini,
- NULL, /* scaled_glyph_fini */
- /* The 5 high level operations */
_cairo_script_surface_paint,
_cairo_script_surface_mask,
_cairo_script_surface_stroke,
_cairo_script_surface_fill,
- NULL,
-
- _cairo_script_surface_snapshot,
-
- NULL, /* is_similar */
- /* XXX need fill-stroke for passthrough */
- NULL, /* fill_stroke */
- NULL, /* create_solid_pattern_surface */
- NULL, /* can_repaint_solid_pattern_surface */
-
- /* The alternate high-level text operation */
+ NULL, /* fill/stroke */
+ NULL, /* glyphs */
_cairo_script_surface_has_show_text_glyphs,
_cairo_script_surface_show_text_glyphs
};
diff --git a/src/cairo-slope.c b/src/cairo-slope.c
index 827037f7..cc5f30cb 100644
--- a/src/cairo-slope.c
+++ b/src/cairo-slope.c
@@ -89,9 +89,9 @@ _cairo_slope_compare (const cairo_slope_t *a, const cairo_slope_t *b)
*/
if ((a->dx ^ b->dx) < 0 || (a->dy ^ b->dy) < 0) {
if (a->dx > 0 || (a->dx == 0 && a->dy > 0))
- return +1;
- else
return -1;
+ else
+ return +1;
}
/* Finally, for identical slopes, we obviously return 0. */
diff --git a/src/cairo-spans-compositor-private.h b/src/cairo-spans-compositor-private.h
new file mode 100644
index 00000000..41756392
--- /dev/null
+++ b/src/cairo-spans-compositor-private.h
@@ -0,0 +1,96 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * 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.uk>
+ */
+
+#ifndef CAIRO_SPANS_COMPOSITOR_PRIVATE_H
+#define CAIRO_SPANS_COMPOSITOR_PRIVATE_H
+
+#include "cairo-compositor-private.h"
+#include "cairo-types-private.h"
+#include "cairo-spans-private.h"
+
+CAIRO_BEGIN_DECLS
+
+typedef struct _cairo_abstract_span_renderer {
+ cairo_span_renderer_t base;
+ char data[2048];
+} cairo_abstract_span_renderer_t;
+
+struct cairo_spans_compositor {
+ cairo_compositor_t base;
+
+ /* pixel-aligned fast paths */
+ cairo_int_status_t (*fill_boxes) (void *surface,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes);
+
+ cairo_surface_t * (*pattern_to_surface) (cairo_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y);
+
+ cairo_int_status_t (*composite_boxes) (void *surface,
+ cairo_operator_t op,
+ cairo_surface_t *source,
+ cairo_surface_t *mask,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ cairo_boxes_t *boxes,
+ const cairo_rectangle_int_t *extents);
+
+ /* general shape masks using a span renderer */
+ cairo_int_status_t (*renderer_init) (cairo_abstract_span_renderer_t *renderer,
+ const cairo_composite_rectangles_t *extents,
+ cairo_bool_t needs_clip);
+
+ void (*renderer_fini) (cairo_abstract_span_renderer_t *renderer,
+ cairo_int_status_t status);
+};
+
+cairo_private void
+_cairo_spans_compositor_init (cairo_spans_compositor_t *compositor,
+ const cairo_compositor_t *delegate);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_SPANS_COMPOSITOR_PRIVATE_H */
diff --git a/src/cairo-spans-compositor.c b/src/cairo-spans-compositor.c
new file mode 100644
index 00000000..4320a3ec
--- /dev/null
+++ b/src/cairo-spans-compositor.c
@@ -0,0 +1,1007 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-clip-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-paginated-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-region-private.h"
+#include "cairo-recording-surface-private.h"
+#include "cairo-spans-compositor-private.h"
+#include "cairo-surface-subsurface-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-observer-private.h"
+
+typedef struct {
+ cairo_polygon_t *polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+} composite_spans_info_t;
+
+static cairo_int_status_t
+composite_polygon (const cairo_spans_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_polygon_t *polygon,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias);
+
+static cairo_int_status_t
+composite_boxes (const cairo_spans_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes);
+
+static cairo_int_status_t
+clip_and_composite_polygon (const cairo_spans_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_polygon_t *polygon,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias);
+static cairo_surface_t *
+get_clip_surface (const cairo_spans_compositor_t *compositor,
+ cairo_surface_t *dst,
+ const cairo_clip_t *clip,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_composite_rectangles_t composite;
+ cairo_surface_t *surface;
+ cairo_box_t box;
+ cairo_polygon_t polygon;
+ const cairo_clip_path_t *clip_path;
+ cairo_antialias_t antialias;
+ cairo_fill_rule_t fill_rule;
+ cairo_int_status_t status;
+
+ assert (clip->path);
+
+ surface = _cairo_surface_create_similar_solid (dst,
+ CAIRO_CONTENT_ALPHA,
+ extents->width,
+ extents->height,
+ CAIRO_COLOR_TRANSPARENT);
+
+ _cairo_box_from_rectangle (&box, extents);
+ _cairo_polygon_init (&polygon, &box, 1);
+
+ clip_path = clip->path;
+ status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
+ clip_path->tolerance,
+ &polygon);
+ if (unlikely (status))
+ goto cleanup_polygon;
+
+ polygon.limits = NULL;
+ polygon.num_limits = 0;
+
+ antialias = clip_path->antialias;
+ fill_rule = clip_path->fill_rule;
+ clip_path = clip_path->prev;
+ while (clip_path) {
+ if (clip_path->antialias == antialias) {
+ cairo_polygon_t next;
+
+ _cairo_polygon_init (&next, NULL, 0);
+ status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
+ clip_path->tolerance,
+ &next);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = _cairo_polygon_intersect (&polygon, fill_rule,
+ &next, clip_path->fill_rule);
+ _cairo_polygon_fini (&next);
+ if (unlikely (status))
+ goto cleanup_polygon;
+
+ fill_rule = CAIRO_FILL_RULE_WINDING;
+ }
+
+ clip_path = clip_path->prev;
+ }
+
+ _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
+ status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
+ &polygon,
+ NULL);
+ if (unlikely (status))
+ goto cleanup_polygon;
+
+ status = composite_polygon (compositor, &composite,
+ &polygon, fill_rule, antialias);
+ _cairo_composite_rectangles_fini (&composite);
+ _cairo_polygon_fini (&polygon);
+ if (unlikely (status))
+ goto error;
+
+ _cairo_polygon_init (&polygon, &box, 1);
+
+ clip_path = clip->path;
+ antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT;
+ clip_path = clip_path->prev;
+ while (clip_path) {
+ if (clip_path->antialias == antialias) {
+ if (polygon.num_edges == 0) {
+ status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
+ clip_path->tolerance,
+ &polygon);
+
+ fill_rule = clip_path->fill_rule;
+ polygon.limits = NULL;
+ polygon.num_limits = 0;
+ } else {
+ cairo_polygon_t next;
+
+ _cairo_polygon_init (&next, NULL, 0);
+ status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
+ clip_path->tolerance,
+ &next);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = _cairo_polygon_intersect (&polygon, fill_rule,
+ &next, clip_path->fill_rule);
+ _cairo_polygon_fini (&next);
+ fill_rule = CAIRO_FILL_RULE_WINDING;
+ }
+ if (unlikely (status))
+ goto error;
+ }
+
+ clip_path = clip_path->prev;
+ }
+
+ if (polygon.num_edges) {
+ _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
+ status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
+ CAIRO_OPERATOR_IN,
+ &_cairo_pattern_white.base,
+ &polygon,
+ NULL);
+ if (unlikely (status))
+ goto cleanup_polygon;
+
+ status = composite_polygon (compositor, &composite,
+ &polygon, fill_rule, antialias);
+ _cairo_composite_rectangles_fini (&composite);
+ _cairo_polygon_fini (&polygon);
+ if (unlikely (status))
+ goto error;
+ }
+
+ return surface;
+
+cleanup_polygon:
+ _cairo_polygon_fini (&polygon);
+error:
+ cairo_surface_destroy (surface);
+ return _cairo_surface_create_in_error (status);
+}
+
+static cairo_int_status_t
+fixup_unbounded_mask (const cairo_spans_compositor_t *compositor,
+ const cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_composite_rectangles_t composite;
+ cairo_surface_t *clip;
+ cairo_int_status_t status;
+
+ clip = get_clip_surface (compositor, extents->surface, extents->clip,
+ &extents->unbounded);
+ if (unlikely (clip->status))
+ return clip->status;
+
+ status = _cairo_composite_rectangles_init_for_boxes (&composite,
+ extents->surface,
+ CAIRO_OPERATOR_DEST_OUT,
+ &_cairo_pattern_white.base,
+ boxes,
+ NULL);
+ if (unlikely (status))
+ goto cleanup_clip;
+
+ _cairo_pattern_init_for_surface (&composite.mask_pattern.surface, clip);
+ composite.mask_pattern.base.filter = CAIRO_FILTER_NEAREST;
+ composite.mask_pattern.base.extend = CAIRO_EXTEND_NONE;
+
+ status = composite_boxes (compositor, &composite, boxes);
+
+ _cairo_pattern_fini (&composite.mask_pattern.base);
+ _cairo_composite_rectangles_fini (&composite);
+
+cleanup_clip:
+ cairo_surface_destroy (clip);
+ return status;
+}
+
+static cairo_int_status_t
+fixup_unbounded_polygon (const cairo_spans_compositor_t *compositor,
+ const cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_polygon_t polygon, intersect;
+ cairo_composite_rectangles_t composite;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+ cairo_int_status_t status;
+
+ /* Can we treat the clip as a regular clear-polygon and use it to fill? */
+ status = _cairo_clip_get_polygon (extents->clip, &polygon,
+ &fill_rule, &antialias);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ status= _cairo_polygon_init_boxes (&intersect, boxes);
+ if (unlikely (status))
+ goto cleanup_polygon;
+
+ status = _cairo_polygon_intersect (&polygon, fill_rule,
+ &intersect, CAIRO_FILL_RULE_WINDING);
+ _cairo_polygon_fini (&intersect);
+
+ if (unlikely (status))
+ goto cleanup_polygon;
+
+ status = _cairo_composite_rectangles_init_for_polygon (&composite,
+ extents->surface,
+ CAIRO_OPERATOR_DEST_OUT,
+ &_cairo_pattern_white.base,
+ &polygon,
+ NULL);
+ if (unlikely (status))
+ goto cleanup_polygon;
+
+ status = composite_polygon (compositor, &composite,
+ &polygon, fill_rule, antialias);
+
+ _cairo_composite_rectangles_fini (&composite);
+cleanup_polygon:
+ _cairo_polygon_fini (&polygon);
+
+ return status;
+}
+
+static cairo_int_status_t
+fixup_unbounded_boxes (const cairo_spans_compositor_t *compositor,
+ const cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_boxes_t tmp, clear;
+ cairo_box_t box;
+ cairo_int_status_t status;
+
+ assert (boxes->is_pixel_aligned);
+
+ if (extents->bounded.width == extents->unbounded.width &&
+ extents->bounded.height == extents->unbounded.height)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ /* subtract the drawn boxes from the unbounded area */
+ _cairo_boxes_init (&clear);
+
+ box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+ box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+ box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+ box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+ if (boxes->num_boxes) {
+ _cairo_boxes_init (&tmp);
+
+ status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
+ assert (status == CAIRO_INT_STATUS_SUCCESS);
+
+ tmp.chunks.next = &boxes->chunks;
+ tmp.num_boxes += boxes->num_boxes;
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+ tmp.chunks.next = NULL;
+ if (unlikely (status))
+ goto error;
+ } else {
+ box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
+ box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+
+ status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
+ assert (status == CAIRO_INT_STATUS_SUCCESS);
+ }
+
+ /* Now intersect with the clip boxes */
+ if (extents->clip->num_boxes) {
+ _cairo_boxes_init_for_array (&tmp,
+ extents->clip->boxes,
+ extents->clip->num_boxes);
+ status = _cairo_boxes_intersect (&clear, &tmp, &clear);
+ if (unlikely (status))
+ goto error;
+ }
+
+ /* If we have a clip polygon, we need to intersect with that as well */
+ if (extents->clip->path) {
+ status = fixup_unbounded_polygon (compositor, extents, &clear);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ status = fixup_unbounded_mask (compositor, extents, &clear);
+ } else {
+ status = compositor->fill_boxes (extents->surface,
+ CAIRO_OPERATOR_CLEAR,
+ CAIRO_COLOR_TRANSPARENT,
+ &clear);
+ }
+
+error:
+ _cairo_boxes_fini (&clear);
+ return status;
+}
+
+static cairo_surface_t *
+unwrap_surface (const cairo_pattern_t *pattern)
+{
+ cairo_surface_t *surface;
+
+ surface = ((const cairo_surface_pattern_t *) pattern)->surface;
+ if (_cairo_surface_is_paginated (surface))
+ surface = _cairo_paginated_surface_get_recording (surface);
+ if (_cairo_surface_is_snapshot (surface))
+ surface = _cairo_surface_snapshot_get_target (surface);
+ if (_cairo_surface_is_observer (surface))
+ surface = _cairo_surface_observer_get_target (surface);
+ return surface;
+}
+
+static cairo_bool_t
+is_recording_pattern (const cairo_pattern_t *pattern)
+{
+ cairo_surface_t *surface;
+
+ if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
+ return FALSE;
+
+ surface = ((const cairo_surface_pattern_t *) pattern)->surface;
+ return _cairo_surface_is_recording (surface);
+}
+
+static cairo_bool_t
+recording_pattern_contains_sample (const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *sample)
+{
+ cairo_recording_surface_t *surface;
+
+ if (! is_recording_pattern (pattern))
+ return FALSE;
+
+ if (pattern->extend == CAIRO_EXTEND_NONE)
+ return TRUE;
+
+ surface = (cairo_recording_surface_t *) unwrap_surface (pattern);
+ if (surface->unbounded)
+ return TRUE;
+
+ if (sample->x >= surface->extents.x &&
+ sample->y >= surface->extents.y &&
+ sample->x + sample->width <= surface->extents.x + surface->extents.width &&
+ sample->y + sample->height <= surface->extents.y + surface->extents.height)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static cairo_bool_t
+op_reduces_to_source (const cairo_composite_rectangles_t *extents)
+{
+ if (extents->op == CAIRO_OPERATOR_SOURCE)
+ return TRUE;
+
+ if (extents->surface->is_clear)
+ return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
+
+ return FALSE;
+}
+
+static cairo_int_status_t
+composite_aligned_boxes (const cairo_spans_compositor_t *compositor,
+ const cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_operator_t op = extents->op;
+ const cairo_pattern_t *source = &extents->source_pattern.base;
+ cairo_int_status_t status;
+ cairo_bool_t need_clip_mask = extents->clip->path != NULL;
+ cairo_bool_t op_is_source;
+ cairo_bool_t no_mask;
+ cairo_bool_t inplace;
+
+ if (need_clip_mask && ! extents->is_bounded)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ op_is_source = op_reduces_to_source (extents);
+ no_mask = extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
+ CAIRO_ALPHA_IS_OPAQUE (extents->mask_pattern.solid.color.alpha);
+ inplace = ! need_clip_mask && op_is_source && no_mask;
+
+ if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) {
+ /* SOURCE with a mask is actually a LERP in cairo semantics */
+ /* XXX push this choice down to the backend */
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ /* Are we just copying a recording surface? */
+ if (inplace &&
+ recording_pattern_contains_sample (&extents->source_pattern.base,
+ &extents->source_sample_area))
+ {
+ cairo_clip_t *recording_clip;
+ const cairo_pattern_t *source = &extents->source_pattern.base;
+
+ /* XXX could also do tiling repeat modes... */
+
+ /* first clear the area about to be overwritten */
+ if (! dst->is_clear)
+ status = compositor->fill_boxes (dst,
+ CAIRO_OPERATOR_CLEAR,
+ CAIRO_COLOR_TRANSPARENT,
+ boxes);
+
+ recording_clip = _cairo_clip_from_boxes (boxes);
+ status = _cairo_recording_surface_replay_with_clip (unwrap_surface (source),
+ &source->matrix,
+ dst, recording_clip);
+ _cairo_clip_destroy (recording_clip);
+
+ return status;
+ }
+
+ if (! need_clip_mask && no_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) {
+ const cairo_color_t *color;
+
+ color = &((cairo_solid_pattern_t *) source)->color;
+ if (op_is_source)
+ op = CAIRO_OPERATOR_SOURCE;
+ status = compositor->fill_boxes (dst, op, color, boxes);
+#if 0
+ } else if (inplace && source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ status = upload_inplace (compositor, extents, boxes);
+#endif
+ } else {
+ cairo_surface_t *src;
+ cairo_surface_t *mask = NULL;
+ int src_x, src_y;
+ int mask_x = 0, mask_y = 0;
+
+ /* All typical cases will have been resolved before now... */
+ if (need_clip_mask) {
+ mask = get_clip_surface (compositor, dst, extents->clip,
+ &extents->bounded);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ mask_x = -extents->bounded.x;
+ mask_y = -extents->bounded.y;
+ }
+
+ /* XXX but this is still ugly */
+ if (! no_mask) {
+ src = compositor->pattern_to_surface (dst,
+ &extents->mask_pattern.base,
+ TRUE,
+ &extents->bounded,
+ &extents->mask_sample_area,
+ &src_x, &src_y);
+ if (unlikely (src->status)) {
+ cairo_surface_destroy (mask);
+ return src->status;
+ }
+
+ if (mask != NULL) {
+ status = compositor->composite_boxes (mask, CAIRO_OPERATOR_IN,
+ src, NULL,
+ src_x, src_y,
+ 0, 0,
+ mask_x, mask_y,
+ boxes, &extents->bounded);
+
+ cairo_surface_destroy (src);
+ } else {
+ mask = src;
+ mask_x = src_x;
+ mask_y = src_y;
+ }
+ }
+
+ if (mask && op == CAIRO_OPERATOR_CLEAR) {
+ source = &_cairo_pattern_white.base;
+ op = CAIRO_OPERATOR_DEST_OUT;
+ }
+
+ src = compositor->pattern_to_surface (dst, source, FALSE,
+ &extents->bounded,
+ &extents->source_sample_area,
+ &src_x, &src_y);
+ if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
+ status = compositor->composite_boxes (dst, op, src, mask,
+ src_x, src_y,
+ mask_x, mask_y,
+ 0, 0,
+ boxes, &extents->bounded);
+ cairo_surface_destroy (src);
+ } else
+ status = src->status;
+
+ cairo_surface_destroy (mask);
+ }
+
+ if (status == CAIRO_INT_STATUS_SUCCESS && ! extents->is_bounded)
+ status = fixup_unbounded_boxes (compositor, extents, boxes);
+
+ return status;
+}
+
+static cairo_bool_t
+composite_needs_clip (const cairo_composite_rectangles_t *composit,
+ const cairo_box_t *extents)
+{
+ cairo_bool_t needs_clip;
+
+ needs_clip = ! composit->is_bounded;
+ if (needs_clip)
+ needs_clip = ! _cairo_clip_contains_box (composit->clip, extents);
+
+ return needs_clip;
+}
+
+static cairo_int_status_t
+composite_boxes (const cairo_spans_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_abstract_span_renderer_t renderer;
+ cairo_rectangular_scan_converter_t converter;
+ const struct _cairo_boxes_chunk *chunk;
+ cairo_int_status_t status;
+ cairo_box_t box;
+
+ _cairo_box_from_rectangle (&box, &extents->bounded);
+ if (composite_needs_clip (extents, &box))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ const cairo_box_t *box = chunk->base;
+ int i;
+
+ for (i = 0; i < chunk->count; i++) {
+ status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
+ if (unlikely (status))
+ goto cleanup_converter;
+ }
+ }
+
+ status = compositor->renderer_init (&renderer, extents, FALSE);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = converter.base.generate (&converter.base, &renderer.base);
+ compositor->renderer_fini (&renderer, status);
+
+cleanup_converter:
+ converter.base.destroy (&converter.base);
+ return status;
+}
+
+static cairo_int_status_t
+composite_polygon (const cairo_spans_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_polygon_t *polygon,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias)
+{
+ cairo_abstract_span_renderer_t renderer;
+ cairo_scan_converter_t *converter;
+ cairo_bool_t needs_clip;
+ cairo_int_status_t status;
+
+ needs_clip = composite_needs_clip (extents, &polygon->extents);
+ if (needs_clip) {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ converter = _cairo_clip_tor_scan_converter_create (extents->clip,
+ polygon,
+ fill_rule, antialias);
+ } else {
+ const cairo_rectangle_int_t *r = &extents->bounded;
+
+ if (antialias == CAIRO_ANTIALIAS_FAST) {
+ converter = _cairo_tor22_scan_converter_create (r->x, r->y,
+ r->x + r->width,
+ r->y + r->height,
+ fill_rule, antialias);
+ status = _cairo_tor22_scan_converter_add_polygon (converter, polygon);
+ } else if (antialias == CAIRO_ANTIALIAS_NONE) {
+ converter = _cairo_mono_scan_converter_create (r->x, r->y,
+ r->x + r->width,
+ r->y + r->height,
+ fill_rule);
+ status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
+ } else {
+ converter = _cairo_tor_scan_converter_create (r->x, r->y,
+ r->x + r->width,
+ r->y + r->height,
+ fill_rule, antialias);
+ status = _cairo_tor_scan_converter_add_polygon (converter, polygon);
+ }
+ }
+ if (unlikely (status))
+ goto cleanup_converter;
+
+ status = compositor->renderer_init (&renderer, extents, needs_clip);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = converter->generate (converter, &renderer.base);
+ compositor->renderer_fini (&renderer, status);
+
+cleanup_converter:
+ converter->destroy (converter);
+ return status;
+}
+
+static cairo_int_status_t
+trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_box_t box;
+
+ _cairo_boxes_extents (boxes, &box);
+ return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
+}
+
+static cairo_int_status_t
+trim_extents_to_polygon (cairo_composite_rectangles_t *extents,
+ cairo_polygon_t *polygon)
+{
+ return _cairo_composite_rectangles_intersect_mask_extents (extents,
+ &polygon->extents);
+}
+
+static cairo_int_status_t
+clip_and_composite_boxes (const cairo_spans_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_int_status_t status;
+ cairo_polygon_t polygon;
+
+ status = trim_extents_to_boxes (extents, boxes);
+ if (unlikely (status))
+ return status;
+
+ if (boxes->num_boxes == 0) {
+ if (extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ return fixup_unbounded_boxes (compositor, extents, boxes);
+ }
+
+ /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
+ if (extents->clip->path != NULL && extents->is_bounded) {
+ cairo_polygon_t polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+ cairo_clip_t *clip;
+
+ clip = _cairo_clip_copy (extents->clip);
+ clip = _cairo_clip_intersect_boxes (clip, boxes);
+ status = _cairo_clip_get_polygon (clip, &polygon,
+ &fill_rule, &antialias);
+ _cairo_clip_path_destroy (clip->path);
+ clip->path = NULL;
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ cairo_clip_t *saved_clip = extents->clip;
+ extents->clip = clip;
+
+ status = clip_and_composite_polygon (compositor, extents, &polygon,
+ fill_rule, antialias);
+
+ clip = extents->clip;
+ extents->clip = saved_clip;
+
+ _cairo_polygon_fini (&polygon);
+ }
+ _cairo_clip_destroy (clip);
+
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+ if (boxes->is_pixel_aligned) {
+ status = composite_aligned_boxes (compositor, extents, boxes);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+ status = composite_boxes (compositor, extents, boxes);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ status = _cairo_polygon_init_boxes (&polygon, boxes);
+ if (unlikely (status))
+ return status;
+
+ status = composite_polygon (compositor, extents, &polygon,
+ CAIRO_FILL_RULE_WINDING,
+ CAIRO_ANTIALIAS_DEFAULT);
+ _cairo_polygon_fini (&polygon);
+
+ return status;
+}
+
+static cairo_int_status_t
+clip_and_composite_polygon (const cairo_spans_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_polygon_t *polygon,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias)
+{
+ cairo_int_status_t status;
+
+ if (_cairo_polygon_is_empty (polygon)) {
+ cairo_boxes_t boxes;
+
+ if (extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_boxes_init (&boxes);
+ return fixup_unbounded_boxes (compositor, extents, &boxes);
+ }
+
+#if 0 /* XXX not accurate currently... */
+ if (antialias == CAIRO_ANTIALIAS_NONE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+#endif
+
+ if (extents->is_bounded && extents->clip->path) {
+ cairo_polygon_t clipper;
+ cairo_antialias_t clip_antialias;
+ cairo_fill_rule_t clip_fill_rule;
+
+ status = _cairo_clip_get_polygon (extents->clip,
+ &clipper,
+ &clip_fill_rule,
+ &clip_antialias);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ cairo_clip_t *old_clip;
+
+ if (clip_antialias == antialias) {
+ status = _cairo_polygon_intersect (polygon, fill_rule,
+ &clipper, clip_fill_rule);
+ _cairo_polygon_fini (&clipper);
+ if (unlikely (status))
+ return status;
+
+ old_clip = extents->clip;
+ extents->clip = _cairo_clip_copy_region (extents->clip);
+ _cairo_clip_destroy (old_clip);
+ } else {
+ _cairo_polygon_fini (&clipper);
+ }
+ }
+ }
+
+ status = trim_extents_to_polygon (extents, polygon);
+ if (unlikely (status))
+ return status;
+
+ return composite_polygon (compositor, extents,
+ polygon, fill_rule, antialias);
+}
+
+/* high-level compositor interface */
+
+static cairo_int_status_t
+_cairo_spans_compositor_paint (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
+ cairo_boxes_t boxes;
+ cairo_int_status_t status;
+
+ _cairo_clip_steal_boxes (extents->clip, &boxes);
+ status = clip_and_composite_boxes (compositor, extents, &boxes);
+ _cairo_clip_unsteal_boxes (extents->clip, &boxes);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_spans_compositor_mask (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
+ cairo_int_status_t status;
+ cairo_boxes_t boxes;
+
+ _cairo_clip_steal_boxes (extents->clip, &boxes);
+ status = clip_and_composite_boxes (compositor, extents, &boxes);
+ _cairo_clip_unsteal_boxes (extents->clip, &boxes);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_spans_compositor_stroke (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
+ _cairo_boxes_limit (&boxes,
+ extents->clip->boxes,
+ extents->clip->num_boxes);
+
+ status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+ style,
+ ctm,
+ antialias,
+ &boxes);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = clip_and_composite_boxes (compositor, extents, &boxes);
+ _cairo_boxes_fini (&boxes);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ cairo_polygon_t polygon;
+
+ if (extents->mask.width > extents->unbounded.width ||
+ extents->mask.height > extents->unbounded.height)
+ {
+ _cairo_polygon_init_with_clip (&polygon, extents->clip);
+ }
+ else
+ {
+ _cairo_polygon_init_with_clip (&polygon, NULL);
+ }
+ status = _cairo_path_fixed_stroke_to_polygon (path,
+ style,
+ ctm, ctm_inverse,
+ tolerance,
+ &polygon);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ status = clip_and_composite_polygon (compositor, extents, &polygon,
+ CAIRO_FILL_RULE_WINDING,
+ antialias);
+ }
+ _cairo_polygon_fini (&polygon);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_spans_compositor_fill (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_fill_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
+ _cairo_boxes_limit (&boxes,
+ extents->clip->boxes,
+ extents->clip->num_boxes);
+ status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+ fill_rule,
+ antialias,
+ &boxes);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = clip_and_composite_boxes (compositor, extents, &boxes);
+ _cairo_boxes_fini (&boxes);
+ }
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ cairo_polygon_t polygon;
+
+ if (extents->mask.width > extents->unbounded.width ||
+ extents->mask.height > extents->unbounded.height)
+ {
+ cairo_box_t limits;
+ _cairo_box_from_rectangle (&limits, &extents->unbounded);
+ _cairo_polygon_init (&polygon, &limits, 1);
+ }
+ else
+ {
+ _cairo_polygon_init (&polygon, NULL, 0);
+ }
+
+ status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
+ extents->clip->boxes,
+ extents->clip->num_boxes);
+ }
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ if (extents->is_bounded) {
+ if (extents->clip->boxes != &extents->clip->embedded_box)
+ free (extents->clip->boxes);
+
+ extents->clip->num_boxes = 1;
+ extents->clip->boxes = &extents->clip->embedded_box;
+ extents->clip->boxes[0] = polygon.extents;
+ }
+ status = clip_and_composite_polygon (compositor, extents, &polygon,
+ fill_rule, antialias);
+ }
+ _cairo_polygon_fini (&polygon);
+ }
+
+ return status;
+}
+
+void
+_cairo_spans_compositor_init (cairo_spans_compositor_t *compositor,
+ const cairo_compositor_t *delegate)
+{
+ compositor->base.delegate = delegate;
+
+ compositor->base.paint = _cairo_spans_compositor_paint;
+ compositor->base.mask = _cairo_spans_compositor_mask;
+ compositor->base.fill = _cairo_spans_compositor_fill;
+ compositor->base.stroke = _cairo_spans_compositor_stroke;
+ compositor->base.glyphs = NULL;
+}
diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
index 00a4df86..c42b5afa 100644
--- a/src/cairo-spans-private.h
+++ b/src/cairo-spans-private.h
@@ -36,11 +36,9 @@
/* A structure representing an open-ended horizontal span of constant
* pixel coverage. */
typedef struct _cairo_half_open_span {
- /* The inclusive x-coordinate of the start of the span. */
- int x;
-
- /* The pixel coverage for the pixels to the right. */
- int coverage;
+ int32_t x; /* The inclusive x-coordinate of the start of the span. */
+ uint8_t coverage; /* The pixel coverage for the pixels to the right. */
+ uint8_t inverse; /* between regular mask and clip */
} cairo_half_open_span_t;
/* Span renderer interface. Instances of renderers are provided by
@@ -73,17 +71,6 @@ struct _cairo_scan_converter {
/* Destroy this scan converter. */
cairo_destroy_func_t destroy;
- /* Add a single edge to the converter. */
- cairo_status_t (*add_edge) (void *abstract_converter,
- const cairo_point_t *p1,
- const cairo_point_t *p2,
- int top, int bottom,
- int dir);
-
- /* Add a polygon (set of edges) to the converter. */
- cairo_status_t (*add_polygon) (void *abstract_converter,
- const cairo_polygon_t *polygon);
-
/* Generates coverage spans for rows for the added edges and calls
* the renderer function for each row. After generating spans the
* only valid thing to do with the converter is to destroy it. */
@@ -101,13 +88,43 @@ _cairo_tor_scan_converter_create (int xmin,
int ymin,
int xmax,
int ymax,
- cairo_fill_rule_t fill_rule);
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias);
+cairo_private cairo_status_t
+_cairo_tor_scan_converter_add_polygon (void *converter,
+ const cairo_polygon_t *polygon);
+
+cairo_private cairo_scan_converter_t *
+_cairo_tor22_scan_converter_create (int xmin,
+ int ymin,
+ int xmax,
+ int ymax,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias);
+cairo_private cairo_status_t
+_cairo_tor22_scan_converter_add_polygon (void *converter,
+ const cairo_polygon_t *polygon);
+
+cairo_private cairo_scan_converter_t *
+_cairo_mono_scan_converter_create (int xmin,
+ int ymin,
+ int xmax,
+ int ymax,
+ cairo_fill_rule_t fill_rule);
+cairo_private cairo_status_t
+_cairo_mono_scan_converter_add_polygon (void *converter,
+ const cairo_polygon_t *polygon);
+
+cairo_private cairo_scan_converter_t *
+_cairo_clip_tor_scan_converter_create (cairo_clip_t *clip,
+ cairo_polygon_t *polygon,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias);
typedef struct _cairo_rectangular_scan_converter {
cairo_scan_converter_t base;
- int xmin, xmax;
- int ymin, ymax;
+ cairo_box_t extents;
struct _cairo_rectangular_scan_converter_chunk {
struct _cairo_rectangular_scan_converter_chunk *next;
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
index f6586506..b8d41800 100644
--- a/src/cairo-spans.c
+++ b/src/cairo-spans.c
@@ -32,87 +32,6 @@
#include "cairo-fixed-private.h"
#include "cairo-types-private.h"
-static cairo_scan_converter_t *
-_create_scan_converter (cairo_fill_rule_t fill_rule,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects)
-{
- if (antialias == CAIRO_ANTIALIAS_NONE) {
- ASSERT_NOT_REACHED;
- return NULL;
- }
-
- return _cairo_tor_scan_converter_create (rects->bounded.x,
- rects->bounded.y,
- rects->bounded.x + rects->bounded.width,
- rects->bounded.y + rects->bounded.height,
- fill_rule);
-}
-
-/* XXX Add me to the compositor interface. Ok, first create the compositor
- * interface, and then add this with associated fallback!
- */
-cairo_status_t
-_cairo_surface_composite_polygon (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_fill_rule_t fill_rule,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects,
- cairo_polygon_t *polygon,
- cairo_region_t *clip_region)
-{
- cairo_span_renderer_t *renderer;
- cairo_scan_converter_t *converter;
- cairo_status_t status;
- cairo_clip_path_t *clip_path = rects->clip->path;
-
- if (rects->is_bounded) {
- if (polygon->num_edges == 0)
- return CAIRO_STATUS_SUCCESS;
-
- if (clip_path) { /* XXX */
- cairo_polygon_t clipper;
- cairo_fill_rule_t clipper_fill_rule;
- cairo_antialias_t clipper_antialias;
-
- if (_cairo_clip_get_polygon (rects->clip, &clipper,
- &clipper_fill_rule,
- &clipper_antialias) == CAIRO_INT_STATUS_SUCCESS) {
- if (clipper_antialias != CAIRO_ANTIALIAS_NONE &&
- _cairo_polygon_intersect (polygon, fill_rule,
- &clipper, clipper_fill_rule) == CAIRO_STATUS_SUCCESS)
- {
- rects->clip->path = NULL;
- }
-
- _cairo_polygon_fini (&clipper);
- }
- }
- }
-
- converter = _create_scan_converter (fill_rule, antialias, rects);
- status = converter->add_polygon (converter, polygon);
- if (unlikely (status))
- goto CLEANUP_CONVERTER;
-
- renderer = _cairo_surface_create_span_renderer (op, pattern, surface,
- antialias, rects,
- clip_region);
- status = converter->generate (converter, renderer);
- if (unlikely (status))
- goto CLEANUP_RENDERER;
-
- status = renderer->finish (renderer);
-
- CLEANUP_RENDERER:
- renderer->destroy (renderer);
- CLEANUP_CONVERTER:
- converter->destroy (converter);
- rects->clip->path = clip_path;
- return status;
-}
-
static void
_cairo_nil_destroy (void *abstract)
{
@@ -120,31 +39,6 @@ _cairo_nil_destroy (void *abstract)
}
static cairo_status_t
-_cairo_nil_scan_converter_add_polygon (void *abstract_converter,
- const cairo_polygon_t *polygon)
-{
- (void) abstract_converter;
- (void) polygon;
- return _cairo_scan_converter_status (abstract_converter);
-}
-
-static cairo_status_t
-_cairo_nil_scan_converter_add_edge (void *abstract_converter,
- const cairo_point_t *p1,
- const cairo_point_t *p2,
- int top, int bottom,
- int dir)
-{
- (void) abstract_converter;
- (void) p1;
- (void) p2;
- (void) top;
- (void) bottom;
- (void) dir;
- return _cairo_scan_converter_status (abstract_converter);
-}
-
-static cairo_status_t
_cairo_nil_scan_converter_generate (void *abstract_converter,
cairo_span_renderer_t *renderer)
{
@@ -168,8 +62,6 @@ _cairo_scan_converter_set_error (void *abstract_converter,
if (error == CAIRO_STATUS_SUCCESS)
ASSERT_NOT_REACHED;
if (converter->status == CAIRO_STATUS_SUCCESS) {
- converter->add_polygon = _cairo_nil_scan_converter_add_polygon;
- converter->add_edge = _cairo_nil_scan_converter_add_edge;
converter->generate = _cairo_nil_scan_converter_generate;
converter->status = error;
}
diff --git a/src/cairo-spline.c b/src/cairo-spline.c
index 2467178f..34ad5856 100644
--- a/src/cairo-spline.c
+++ b/src/cairo-spline.c
@@ -36,15 +36,61 @@
#include "cairoint.h"
+#include "cairo-box-private.h"
#include "cairo-slope-private.h"
cairo_bool_t
+_cairo_spline_intersects (const cairo_point_t *a,
+ const cairo_point_t *b,
+ const cairo_point_t *c,
+ const cairo_point_t *d,
+ const cairo_box_t *box)
+{
+ cairo_box_t bounds;
+
+ if (_cairo_box_contains_point (box, a) ||
+ _cairo_box_contains_point (box, b) ||
+ _cairo_box_contains_point (box, c) ||
+ _cairo_box_contains_point (box, d))
+ {
+ return TRUE;
+ }
+
+ bounds.p2 = bounds.p1 = *a;
+ _cairo_box_add_point (&bounds, b);
+ _cairo_box_add_point (&bounds, c);
+ _cairo_box_add_point (&bounds, d);
+
+ if (bounds.p2.x <= box->p1.x || bounds.p1.x >= box->p2.x ||
+ bounds.p2.y <= box->p1.y || bounds.p1.y >= box->p2.y)
+ {
+ return FALSE;
+ }
+
+#if 0 /* worth refining? */
+ bounds.p2 = bounds.p1 = *a;
+ _cairo_box_add_curve_to (&bounds, b, c, d);
+ if (bounds.p2.x <= box->p1.x || bounds.p1.x >= box->p2.x ||
+ bounds.p2.y <= box->p1.y || bounds.p1.y >= box->p2.y)
+ {
+ return FALSE;
+ }
+#endif
+
+ return TRUE;
+}
+
+cairo_bool_t
_cairo_spline_init (cairo_spline_t *spline,
cairo_spline_add_point_func_t add_point_func,
void *closure,
const cairo_point_t *a, const cairo_point_t *b,
const cairo_point_t *c, const cairo_point_t *d)
{
+ /* If both tangents are zero, this is just a straight line */
+ if (a->x == b->x && a->y == b->y && c->x == d->x && c->y == d->y)
+ return FALSE;
+
spline->add_point_func = add_point_func;
spline->closure = closure;
@@ -69,6 +115,8 @@ _cairo_spline_init (cairo_spline_t *spline,
else
return FALSE; /* just treat this as a straight-line from a -> d */
+ /* XXX if the initial, final and vector are all equal, this is just a line */
+
return TRUE;
}
@@ -213,7 +261,6 @@ _cairo_spline_decompose (cairo_spline_t *spline, double tolerance)
{
cairo_spline_knots_t s1;
cairo_status_t status;
- cairo_slope_t slope;
s1 = spline->knots;
spline->last_point = s1.a;
@@ -221,8 +268,8 @@ _cairo_spline_decompose (cairo_spline_t *spline, double tolerance)
if (unlikely (status))
return status;
- _cairo_slope_init (&slope, &spline->knots.c, &spline->knots.d);
- return spline->add_point_func (spline->closure, &spline->knots.d, &slope);
+ return spline->add_point_func (spline->closure,
+ &spline->knots.d, &spline->final_slope);
}
/* Note: this function is only good for computing bounds in device space. */
diff --git a/src/cairo-stroke-style.c b/src/cairo-stroke-style.c
index b9c3a0db..9b7e407c 100644
--- a/src/cairo-stroke-style.c
+++ b/src/cairo-stroke-style.c
@@ -101,6 +101,7 @@ _cairo_stroke_style_fini (cairo_stroke_style_t *style)
*/
void
_cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
+ const cairo_path_fixed_t *path,
const cairo_matrix_t *ctm,
double *dx, double *dy)
{
@@ -110,6 +111,7 @@ _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 &&
+ ! path->stroke_is_rectilinear &&
style_expansion < M_SQRT2 * style->miter_limit)
{
style_expansion = M_SQRT2 * style->miter_limit;
@@ -117,8 +119,12 @@ _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
style_expansion *= style->line_width;
- *dx = style_expansion * hypot (ctm->xx, ctm->xy);
- *dy = style_expansion * hypot (ctm->yy, ctm->yx);
+ if (_cairo_matrix_has_unity_scale (ctm)) {
+ *dx = *dy = style_expansion;
+ } else {
+ *dx = style_expansion * hypot (ctm->xx, ctm->xy);
+ *dy = style_expansion * hypot (ctm->yy, ctm->yx);
+ }
}
/*
diff --git a/src/cairo-surface-backend-private.h b/src/cairo-surface-backend-private.h
new file mode 100644
index 00000000..cdcd3f8c
--- /dev/null
+++ b/src/cairo-surface-backend-private.h
@@ -0,0 +1,196 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ */
+
+#ifndef CAIRO_SURFACE_BACKEND_PRIVATE_H
+#define CAIRO_SURFACE_BACKEND_PRIVATE_H
+
+CAIRO_BEGIN_DECLS
+
+struct _cairo_surface_backend {
+ cairo_surface_type_t type;
+
+ cairo_warn cairo_status_t
+ (*finish) (void *surface);
+
+ cairo_t *
+ (*create_context) (void *surface);
+
+ cairo_surface_t *
+ (*create_similar) (void *surface,
+ cairo_content_t content,
+ int width,
+ int height);
+ cairo_surface_t *
+ (*create_similar_image) (void *surface,
+ cairo_format_t format,
+ int width,
+ int height);
+
+ cairo_surface_t *
+ (*map_to_image) (void *surface,
+ const cairo_rectangle_int_t *extents);
+ cairo_int_status_t
+ (*unmap_image) (void *surface,
+ cairo_image_surface_t *image);
+
+ cairo_warn cairo_status_t
+ (*acquire_source_image) (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra);
+
+ cairo_warn void
+ (*release_source_image) (void *abstract_surface,
+ cairo_image_surface_t *image_out,
+ void *image_extra);
+
+ cairo_surface_t *
+ (*snapshot) (void *surface);
+
+ cairo_warn cairo_int_status_t
+ (*copy_page) (void *surface);
+
+ cairo_warn cairo_int_status_t
+ (*show_page) (void *surface);
+
+ /* 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}.
+ *
+ * If this function is not implemented, or if it returns
+ * FALSE the surface is considered to be
+ * boundless and infinite bounds are used for it.
+ */
+ cairo_bool_t
+ (*get_extents) (void *surface,
+ cairo_rectangle_int_t *extents);
+
+ void
+ (*get_font_options) (void *surface,
+ cairo_font_options_t *options);
+
+ cairo_warn cairo_status_t
+ (*flush) (void *surface);
+
+ cairo_warn cairo_status_t
+ (*mark_dirty_rectangle) (void *surface,
+ int x,
+ int y,
+ int width,
+ int height);
+
+ cairo_warn cairo_int_status_t
+ (*paint) (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const 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,
+ const cairo_clip_t *clip);
+
+ cairo_warn cairo_int_status_t
+ (*stroke) (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip);
+
+ cairo_warn cairo_int_status_t
+ (*fill) (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip);
+
+ cairo_warn cairo_int_status_t
+ (*fill_stroke) (void *surface,
+ 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,
+ const cairo_path_fixed_t*path,
+ cairo_operator_t stroke_op,
+ const cairo_pattern_t *stroke_source,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *stroke_ctm,
+ const cairo_matrix_t *stroke_ctm_inverse,
+ double stroke_tolerance,
+ cairo_antialias_t stroke_antialias,
+ const cairo_clip_t *clip);
+
+ cairo_warn cairo_int_status_t
+ (*show_glyphs) (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ const cairo_clip_t *clip);
+
+ cairo_bool_t
+ (*has_show_text_glyphs) (void *surface);
+
+ cairo_warn cairo_int_status_t
+ (*show_text_glyphs) (void *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,
+ const cairo_clip_t *clip);
+};
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_SURFACE_BACKEND_PRIVATE_H */
diff --git a/src/cairo-surface-fallback-private.h b/src/cairo-surface-fallback-private.h
index ffb6f919..ecf7b0ed 100644
--- a/src/cairo-surface-fallback-private.h
+++ b/src/cairo-surface-fallback-private.h
@@ -3,6 +3,7 @@
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -34,6 +35,8 @@
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
+ * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
+ * Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_SURFACE_FALLBACK_PRIVATE_H
@@ -41,99 +44,52 @@
#include "cairoint.h"
-cairo_private cairo_status_t
-_cairo_surface_fallback_paint (cairo_surface_t *surface,
+CAIRO_BEGIN_DECLS
+
+cairo_private cairo_int_status_t
+_cairo_surface_fallback_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip);
-cairo_private cairo_status_t
-_cairo_surface_fallback_mask (cairo_surface_t *surface,
+cairo_private cairo_int_status_t
+_cairo_surface_fallback_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip);
-cairo_private cairo_status_t
-_cairo_surface_fallback_stroke (cairo_surface_t *surface,
- cairo_operator_t op,
+cairo_private cairo_int_status_t
+_cairo_surface_fallback_stroke (void *abstract_surface,
+ cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t*style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip);
-cairo_private cairo_status_t
-_cairo_surface_fallback_fill (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip);
-
-cairo_private cairo_status_t
-_cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip);
+cairo_private cairo_int_status_t
+_cairo_surface_fallback_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip);
-cairo_private cairo_surface_t *
-_cairo_surface_fallback_snapshot (cairo_surface_t *surface);
-
-cairo_private cairo_status_t
-_cairo_surface_fallback_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,
- cairo_region_t *clip_region);
-
-cairo_private cairo_status_t
-_cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects);
-
-cairo_private cairo_status_t
-_cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- cairo_antialias_t antialias,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps,
- cairo_region_t *clip_region);
+cairo_private cairo_int_status_t
+_cairo_surface_fallback_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,
+ const cairo_clip_t *clip);
-cairo_private cairo_status_t
-_cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out);
+CAIRO_END_DECLS
-#endif
+#endif /* CAIRO_SURFACE_FALLBACK_PRIVATE_H */
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index ec6946be..a0af1596 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -3,6 +3,7 @@
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -40,1545 +41,75 @@
#include "cairoint.h"
-#include "cairo-boxes-private.h"
-#include "cairo-clip-private.h"
-#include "cairo-composite-rectangles-private.h"
-#include "cairo-error-private.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-pattern-private.h"
-#include "cairo-region-private.h"
-#include "cairo-spans-private.h"
+#include "cairo-compositor-private.h"
#include "cairo-surface-fallback-private.h"
-typedef struct {
- cairo_surface_t *dst;
- cairo_rectangle_int_t extents;
- cairo_image_surface_t *image;
- cairo_rectangle_int_t image_rect;
- void *image_extra;
-} fallback_state_t;
-
-/**
- * _fallback_init:
- *
- * Acquire destination image surface needed for an image-based
- * fallback.
- *
- * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the extents are not
- * visible, %CAIRO_STATUS_SUCCESS if some portion is visible and all
- * went well, or some error status otherwise.
- **/
-static cairo_int_status_t
-_fallback_init (fallback_state_t *state,
- cairo_surface_t *dst,
- int x,
- int y,
- int width,
- int height)
-{
- cairo_status_t status;
-
- state->extents.x = x;
- state->extents.y = y;
- state->extents.width = width;
- state->extents.height = height;
-
- state->dst = dst;
-
- status = _cairo_surface_acquire_dest_image (dst, &state->extents,
- &state->image, &state->image_rect,
- &state->image_extra);
- 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. */
- assert (state->image != NULL);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_fallback_fini (fallback_state_t *state)
-{
- _cairo_surface_release_dest_image (state->dst, &state->extents,
- state->image, &state->image_rect,
- 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,
- cairo_region_t *clip_region);
-
-static void do_unaligned_row(void (*blt)(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage),
- void *closure,
- const cairo_box_t *b,
- int tx, int y, int h,
- uint16_t coverage)
-{
- int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
- int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
- if (x2 > x1) {
- if (! _cairo_fixed_is_integer (b->p1.x)) {
- blt(closure, x1, y, 1, h,
- coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
- x1++;
- }
-
- if (x2 > x1)
- blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
-
- if (! _cairo_fixed_is_integer (b->p2.x))
- blt(closure, x2, y, 1, h,
- coverage * _cairo_fixed_fractional_part (b->p2.x));
- } else
- blt(closure, x1, y, 1, h,
- coverage * (b->p2.x - b->p1.x));
-}
-
-static void do_unaligned_box(void (*blt)(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage),
- void *closure,
- const cairo_box_t *b, int tx, int ty)
-{
- int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
- int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
- if (y2 > y1) {
- if (! _cairo_fixed_is_integer (b->p1.y)) {
- do_unaligned_row(blt, closure, b, tx, y1, 1,
- 256 - _cairo_fixed_fractional_part (b->p1.y));
- y1++;
- }
-
- if (y2 > y1)
- do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
-
- if (! _cairo_fixed_is_integer (b->p2.y))
- do_unaligned_row(blt, closure, b, tx, y2, 1,
- _cairo_fixed_fractional_part (b->p2.y));
- } else
- do_unaligned_row(blt, closure, b, tx, y1, 1,
- b->p2.y - b->p1.y);
-}
-
-static void blt_in(void *closure,
- int16_t x, int16_t y,
- int16_t w, int16_t h,
- uint16_t coverage)
-{
- cairo_color_t color;
- cairo_rectangle_int_t rect;
-
- if (coverage == 0xffff)
- return;
-
- _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff);
-
- rect.x = x;
- rect.y = y;
- rect.width = w;
- rect.height = h;
-
- _cairo_surface_fill_rectangles (closure, CAIRO_OPERATOR_IN,
- &color, &rect, 1);
-}
-
-static cairo_status_t
-_create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
- cairo_clip_t *clip,
- cairo_draw_func_t draw_func,
- void *draw_closure,
- cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_surface_t *mask;
- cairo_status_t status;
- cairo_region_t *clip_region;
- int i;
-
- /* 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;
-
- clip_region = _cairo_clip_get_region (clip);
- if (clip_region && (extents->x | extents->y))
- cairo_region_translate (clip_region, -extents->x, -extents->y);
-
- status = draw_func (draw_closure, CAIRO_OPERATOR_ADD,
- &_cairo_pattern_white.base, mask,
- extents->x, extents->y,
- extents,
- clip_region);
-
- if (clip_region && (extents->x | extents->y))
- cairo_region_translate (clip_region, extents->x, extents->y);
-
- if (unlikely (status))
- goto CLEANUP;
-
- if (clip) {
- for (i = 0; i < clip->num_boxes; i++) {
- cairo_box_t *b = &clip->boxes[i];
-
- if (! _cairo_fixed_is_integer (b->p1.x) ||
- ! _cairo_fixed_is_integer (b->p1.y) ||
- ! _cairo_fixed_is_integer (b->p2.x) ||
- ! _cairo_fixed_is_integer (b->p2.y))
- {
- do_unaligned_box(blt_in, mask, b, extents->x, extents->y);
- }
- }
-
- if (clip->path != NULL) {
- status = _cairo_clip_combine_with_surface (clip, mask,
- extents->x, extents->y);
- if (unlikely (status))
- goto CLEANUP;
- }
- }
-
- _cairo_pattern_init_for_surface (mask_pattern, mask);
-
- CLEANUP:
- cairo_surface_destroy (mask);
-
- return status;
-}
-
-/* Handles compositing with a clip surface when the operator allows
- * us to combine the clip with the mask
- */
-static cairo_status_t
-_clip_and_composite_with_mask (cairo_clip_t *clip,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_draw_func_t draw_func,
- void *draw_closure,
- cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_surface_pattern_t mask_pattern;
- cairo_status_t status;
-
- status = _create_composite_mask_pattern (&mask_pattern,
- clip,
- draw_func, draw_closure,
- dst, extents);
- 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;
-}
-
-/* Handles compositing with a clip surface when we have to do the operation
- * in two pieces and combine them together.
- */
-static cairo_status_t
-_clip_and_composite_combine (cairo_clip_t *clip,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_draw_func_t draw_func,
- void *draw_closure,
- cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_surface_t *intermediate;
- cairo_surface_pattern_t pattern;
- cairo_surface_pattern_t clip_pattern;
- cairo_surface_t *clip_surface;
- int clip_x, clip_y;
- 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. Instead
- * we ask the backend to create a similar surface of identical content,
- * in the belief that the backend will do something useful - like use
- * an identical format. For example, the xlib backend will endeavor to
- * use a compatible depth to enable core protocol routines.
- */
- intermediate =
- _cairo_surface_create_similar_scratch (dst, dst->content,
- extents->width,
- extents->height);
- if (intermediate == NULL) {
- intermediate =
- _cairo_image_surface_create_with_content (dst->content,
- extents->width,
- extents->width);
- }
- if (unlikely (intermediate->status))
- return intermediate->status;
-
- /* Initialize the intermediate surface from the destination surface */
- _cairo_pattern_init_for_surface (&pattern, dst);
- status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
- &pattern.base, NULL, intermediate,
- extents->x, extents->y,
- 0, 0,
- 0, 0,
- 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,
- NULL);
- if (unlikely (status))
- goto CLEANUP_SURFACE;
-
- clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
- if (unlikely (clip_surface->status))
- goto CLEANUP_SURFACE;
-
- _cairo_pattern_init_for_surface (&clip_pattern, clip_surface);
-
- /* Combine that with the clip */
- status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_IN,
- &clip_pattern.base, NULL, intermediate,
- extents->x - clip_x,
- extents->y - clip_y,
- 0, 0,
- 0, 0,
- extents->width, extents->height,
- NULL);
- if (unlikely (status))
- goto CLEANUP_CLIP;
-
- /* Punch the clip out of the destination */
- status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
- &clip_pattern.base, NULL, dst,
- extents->x - clip_x,
- extents->y - clip_y,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height,
- NULL);
- if (unlikely (status))
- goto CLEANUP_CLIP;
-
- /* Now add the two results together */
- _cairo_pattern_init_for_surface (&pattern, intermediate);
- status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
- &pattern.base, NULL, dst,
- 0, 0,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height,
- NULL);
- _cairo_pattern_fini (&pattern.base);
-
- CLEANUP_CLIP:
- _cairo_pattern_fini (&clip_pattern.base);
- CLEANUP_SURFACE:
- cairo_surface_destroy (intermediate);
-
- return status;
-}
-
-/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
- * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
- */
-static cairo_status_t
-_clip_and_composite_source (cairo_clip_t *clip,
- const cairo_pattern_t *src,
- cairo_draw_func_t draw_func,
- void *draw_closure,
- cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_surface_pattern_t mask_pattern;
- cairo_region_t *clip_region = _cairo_clip_get_region (clip);
- cairo_status_t status;
-
- /* Create a surface that is mask IN clip */
- status = _create_composite_mask_pattern (&mask_pattern,
- clip,
- draw_func, draw_closure,
- dst, extents);
- if (unlikely (status))
- return status;
-
- /* 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,
- clip_region);
-
- if (unlikely (status))
- goto CLEANUP_MASK_PATTERN;
-
- /* 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,
- clip_region);
-
- CLEANUP_MASK_PATTERN:
- _cairo_pattern_fini (&mask_pattern.base);
- return status;
-}
-
-/**
- * _clip_and_composite:
- * @clip: a #cairo_clip_t
- * @op: the operator to draw with
- * @src: source pattern
- * @draw_func: function that can be called to draw with the mask onto a surface.
- * @draw_closure: data to pass to @draw_func.
- * @dst: destination surface
- * @extents: rectangle holding a bounding box for the operation; this
- * rectangle will be used as the size for the temporary
- * surface.
- *
- * When there is a surface clip, we typically need to create an intermediate
- * surface. This function handles the logic of creating a temporary surface
- * drawing to it, then compositing the result onto the target surface.
- *
- * @draw_func is to called to draw the mask; it will be called no more
- * than once.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded.
- **/
-static cairo_status_t
-_clip_and_composite (cairo_clip_t *clip,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_draw_func_t draw_func,
- void *draw_closure,
- cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_status_t status;
-
- if (op == CAIRO_OPERATOR_CLEAR) {
- src = &_cairo_pattern_white.base;
- op = CAIRO_OPERATOR_DEST_OUT;
- }
-
- if (op == CAIRO_OPERATOR_SOURCE) {
- status = _clip_and_composite_source (clip,
- src,
- draw_func, draw_closure,
- dst, extents);
- } else {
- if (! _cairo_clip_is_region (clip)) {
- 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,
- _cairo_clip_get_region (clip));
- }
- }
-
- return status;
-}
-
-/* Composites a region representing a set of trapezoids.
- */
-static cairo_status_t
-_composite_trap_region (cairo_clip_t *clip,
- const cairo_pattern_t *src,
- cairo_operator_t op,
- cairo_surface_t *dst,
- cairo_region_t *trap_region,
- const cairo_rectangle_int_t *extents)
-{
- cairo_status_t status;
- 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;
- int clip_x, clip_y;
-
- clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
- if (unlikely (clip_surface->status))
- return clip_surface->status;
-
- if (op == CAIRO_OPERATOR_CLEAR) {
- src = &_cairo_pattern_white.base;
- op = CAIRO_OPERATOR_DEST_OUT;
- }
-
- _cairo_pattern_init_for_surface (&mask_pattern, clip_surface);
- mask_x = extents->x - clip_x;
- mask_y = extents->y - clip_y;
- mask = &mask_pattern.base;
- }
-
- status = _cairo_surface_composite (op, src, mask, dst,
- extents->x, extents->y,
- mask_x, mask_y,
- extents->x, extents->y,
- extents->width, extents->height,
- trap_region);
-
- if (mask != NULL)
- _cairo_pattern_fini (mask);
-
- return status;
-}
-
-typedef struct {
- cairo_traps_t *traps;
- cairo_antialias_t antialias;
-} cairo_composite_traps_info_t;
-
-static cairo_status_t
-_composite_traps_draw_func (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)
-{
- cairo_composite_traps_info_t *info = closure;
- cairo_status_t status;
- cairo_region_t *extents_region = NULL;
-
- if (dst_x != 0 || dst_y != 0)
- _cairo_traps_translate (info->traps, - dst_x, - dst_y);
-
- if (clip_region == NULL &&
- !_cairo_operator_bounded_by_source (op)) {
- extents_region = cairo_region_create_rectangle (extents);
- if (unlikely (extents_region->status))
- return extents_region->status;
- cairo_region_translate (extents_region, -dst_x, -dst_y);
- clip_region = extents_region;
- }
-
- status = _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,
- clip_region);
-
- if (extents_region)
- cairo_region_destroy (extents_region);
-
- return status;
-}
-
-enum {
- HAS_CLEAR_REGION = 0x1,
-};
-
-static cairo_status_t
-_clip_and_composite_region (const cairo_pattern_t *src,
- cairo_operator_t op,
- cairo_surface_t *dst,
- cairo_region_t *trap_region,
- cairo_clip_t *clip,
- cairo_rectangle_int_t *extents)
-{
- cairo_region_t clear_region;
- unsigned int has_region = 0;
- cairo_status_t status;
-
- if (! _cairo_operator_bounded_by_mask (op) && clip == NULL) {
- /* 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))
- return status;
-
- if (! cairo_region_is_empty (&clear_region))
- has_region |= HAS_CLEAR_REGION;
- }
-
- if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
- clip == NULL)
- {
- const cairo_color_t *color;
-
- 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 {
- /* 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 (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);
- }
-
- return status;
-}
-
-/* avoid using region code to re-validate boxes */
-static cairo_status_t
-_fill_rectangles (cairo_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_traps_t *traps,
- cairo_clip_t *clip)
-{
- const cairo_color_t *color;
- cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
- cairo_rectangle_int_t *rects = stack_rects;
- cairo_status_t status;
- int i;
-
- if (! traps->is_rectilinear || ! traps->maybe_region)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* XXX: convert clip region to geometric boxes? */
- if (clip != NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* XXX: fallback for the region_subtract() operation */
- if (! _cairo_operator_bounded_by_mask (op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! (src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (traps->has_intersections) {
- if (traps->is_rectangular) {
- status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
- } else {
- status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
- }
- if (unlikely (status))
- return status;
- }
-
- for (i = 0; i < traps->num_traps; i++) {
- if (! _cairo_fixed_is_integer (traps->traps[i].top) ||
- ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
- ! _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;
- }
- }
-
- if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
- rects = _cairo_malloc_ab (traps->num_traps,
- sizeof (cairo_rectangle_int_t));
- if (unlikely (rects == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- for (i = 0; i < traps->num_traps; i++) {
- int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
- int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
- int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
- int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
-
- rects[i].x = x1;
- rects[i].y = y1;
- rects[i].width = x2 - x1;
- rects[i].height = y2 - y1;
- }
-
- if (op == CAIRO_OPERATOR_CLEAR)
- color = CAIRO_COLOR_TRANSPARENT;
- else
- color = &((cairo_solid_pattern_t *)src)->color;
-
- status = _cairo_surface_fill_rectangles (dst, op, color, rects, i);
-
- if (rects != stack_rects)
- free (rects);
-
- return status;
-}
-
-/* fast-path for very common composite of a single rectangle */
-static cairo_status_t
-_composite_rectangle (cairo_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_traps_t *traps,
- cairo_clip_t *clip)
-{
- cairo_rectangle_int_t rect;
-
- if (clip != NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (traps->num_traps > 1 || ! traps->is_rectilinear || ! traps->maybe_region)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! _cairo_fixed_is_integer (traps->traps[0].top) ||
- ! _cairo_fixed_is_integer (traps->traps[0].bottom) ||
- ! _cairo_fixed_is_integer (traps->traps[0].left.p1.x) ||
- ! _cairo_fixed_is_integer (traps->traps[0].right.p1.x))
- {
- traps->maybe_region = FALSE;
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- rect.x = _cairo_fixed_integer_part (traps->traps[0].left.p1.x);
- rect.y = _cairo_fixed_integer_part (traps->traps[0].top);
- rect.width = _cairo_fixed_integer_part (traps->traps[0].right.p1.x) - rect.x;
- rect.height = _cairo_fixed_integer_part (traps->traps[0].bottom) - rect.y;
-
- return _cairo_surface_composite (op, src, NULL, dst,
- rect.x, rect.y,
- 0, 0,
- rect.x, rect.y,
- rect.width, rect.height,
- NULL);
-}
-
-/* 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_bool_t clip_surface = ! _cairo_clip_is_region (clip);
- cairo_int_status_t status;
-
- if (traps->num_traps == 0 && _cairo_operator_bounded_by_mask (op))
- return CAIRO_STATUS_SUCCESS;
-
- /* 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 (_cairo_operator_bounded_by_source (op)) {
- status = _fill_rectangles (dst, op, src, traps, clip);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- status = _composite_rectangle (dst, op, src, traps, clip);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
- status = _cairo_traps_extract_region (traps, antialias, &trap_region);
- if (unlikely (_cairo_int_status_is_error (status)))
- return status;
-
- if (trap_region != NULL) {
- status = cairo_region_intersect_rectangle (trap_region, extents);
- if (unlikely (status)) {
- cairo_region_destroy (trap_region);
- return status;
- }
-
- if (_cairo_operator_bounded_by_mask (op)) {
- cairo_rectangle_int_t trap_extents;
-
- cairo_region_get_extents (trap_region, &trap_extents);
- if (! _cairo_rectangle_intersect (extents, &trap_extents)) {
- cairo_region_destroy (trap_region);
- return CAIRO_INT_STATUS_SUCCESS;
- }
- }
-
- status = _clip_and_composite_region (src, op, dst,
- trap_region,
- clip_surface ? clip : NULL,
- extents);
- cairo_region_destroy (trap_region);
-
- if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
- return status;
- }
- }
-
- /* No fast path, exclude self-intersections and clip trapezoids. */
- if (traps->has_intersections) {
- if (traps->is_rectangular)
- status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
- else if (traps->is_rectilinear)
- status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
- else
- status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
- if (unlikely (status))
- return status;
- }
-
- /* Otherwise render the trapezoids to a mask and composite in the usual
- * fashion.
- */
- traps_info.traps = traps;
- traps_info.antialias = antialias;
-
- return _clip_and_composite (clip, op, src,
- _composite_traps_draw_func,
- &traps_info, dst, extents);
-}
-
-cairo_status_t
-_cairo_surface_fallback_paint (cairo_surface_t *surface,
+cairo_int_status_t
+_cairo_surface_fallback_paint (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
{
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t rect;
- cairo_boxes_t boxes;
- cairo_int_status_t status;
-
- if (!_cairo_surface_get_extents (surface, &rect))
- ASSERT_NOT_REACHED;
-
- status = _cairo_composite_rectangles_init_for_paint (&extents, &rect,
- op, source,
- clip);
- if (unlikely (status))
- return status;
-
- status = _cairo_clip_to_boxes (extents.clip, &boxes);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- cairo_traps_t traps;
-
- /* meh, surface-fallback is dying anyway... */
- status = _cairo_traps_init_boxes (&traps, &boxes);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- status = _clip_and_composite_trapezoids (source, op, surface,
- &traps, CAIRO_ANTIALIAS_DEFAULT,
- extents.clip,
- extents.is_bounded ? &extents.bounded : &extents.unbounded);
- _cairo_traps_fini (&traps);
- }
- }
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
+ return _cairo_compositor_paint (&_cairo_fallback_compositor,
+ surface, op, source, clip);
}
-static cairo_status_t
-_cairo_surface_mask_draw_func (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)
-{
- cairo_pattern_t *mask = closure;
- cairo_int_status_t status;
- cairo_region_t *extents_region = NULL;
-
- if (clip_region == NULL &&
- !_cairo_operator_bounded_by_source (op)) {
- extents_region = cairo_region_create_rectangle (extents);
- if (unlikely (extents_region->status))
- return extents_region->status;
- cairo_region_translate (extents_region, -dst_x, -dst_y);
- clip_region = extents_region;
- }
-
- if (src) {
- status = _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,
- clip_region);
- } else {
- status = _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,
- clip_region);
- }
-
- if (extents_region)
- cairo_region_destroy (extents_region);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fallback_mask (cairo_surface_t *surface,
+cairo_int_status_t
+_cairo_surface_fallback_mask (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip)
{
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t rect;
- cairo_status_t status;
-
- if (!_cairo_surface_get_extents (surface, &rect))
- ASSERT_NOT_REACHED;
-
- status = _cairo_composite_rectangles_init_for_mask (&extents, &rect,
- op, source, mask, clip);
- if (unlikely (status))
- return status;
-
- status = _clip_and_composite (extents.clip, op, source,
- _cairo_surface_mask_draw_func,
- (void *) mask,
- surface,
- extents.is_bounded ? &extents.bounded : &extents.unbounded);
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
+ return _cairo_compositor_mask (&_cairo_fallback_compositor,
+ surface, op, source, mask, clip);
}
-cairo_status_t
-_cairo_surface_fallback_stroke (cairo_surface_t *surface,
+cairo_int_status_t
+_cairo_surface_fallback_stroke (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
+ const cairo_path_fixed_t*path,
+ const cairo_stroke_style_t*style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- cairo_polygon_t polygon;
- cairo_traps_t traps;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t rect;
- cairo_int_status_t status;
-
- if (!_cairo_surface_get_extents (surface, &rect))
- ASSERT_NOT_REACHED;
-
- status = _cairo_composite_rectangles_init_for_stroke (&extents, &rect,
- op, source,
- path, stroke_style, ctm,
- clip);
- if (unlikely (status))
- return status;
-
- _cairo_polygon_init_with_clip (&polygon, extents.clip);
- _cairo_traps_init_with_clip (&traps, extents.clip);
-
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
- cairo_boxes_t boxes;
-
- /* Did I mention, that I need to rewrite surface-fallback? */
- _cairo_boxes_init_with_clip (&boxes, extents.clip);
- status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
- stroke_style,
- ctm,
- antialias,
- &boxes);
- if (status == CAIRO_INT_STATUS_SUCCESS)
- status = _cairo_traps_init_boxes (&traps, &boxes);
- _cairo_boxes_fini (&boxes);
-
- if (unlikely (_cairo_int_status_is_error (status)))
- goto CLEANUP;
- }
-
- /* Fall back to trapezoid fills. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- status = _cairo_path_fixed_stroke_to_polygon (path,
- stroke_style,
- ctm, ctm_inverse,
- tolerance,
- &polygon);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
- &polygon.extents);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
- &polygon,
- CAIRO_FILL_RULE_WINDING);
- if (unlikely (status))
- goto CLEANUP;
- }
-
- status = _clip_and_composite_trapezoids (source, op, surface,
- &traps, antialias,
- extents.clip,
- extents.is_bounded ? &extents.bounded : &extents.unbounded);
- CLEANUP:
- _cairo_traps_fini (&traps);
- _cairo_polygon_fini (&polygon);
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fallback_fill (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- cairo_polygon_t polygon;
- cairo_traps_t traps;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t rect;
- cairo_int_status_t status;
-
- if (!_cairo_surface_get_extents (surface, &rect))
- ASSERT_NOT_REACHED;
-
- status = _cairo_composite_rectangles_init_for_fill (&extents, &rect,
- op, source, path,
- clip);
- if (unlikely (status))
- return status;
-
- _cairo_traps_init_with_clip (&traps, extents.clip);
- _cairo_polygon_init_with_clip (&polygon, extents.clip);
-
- if (_cairo_path_fixed_fill_is_empty (path))
- goto DO_TRAPS;
-
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (_cairo_path_fixed_fill_is_rectilinear (path)) {
- cairo_boxes_t boxes;
-
- /* meh, surface-fallback is dying anyway... */
- _cairo_boxes_init_with_clip (&boxes, extents.clip);
- status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
- fill_rule,
- antialias,
- &boxes);
- if (unlikely (status))
- goto CLEANUP;
-
- if (status == CAIRO_INT_STATUS_SUCCESS)
- status = _cairo_traps_init_boxes (&traps, &boxes);
- _cairo_boxes_fini (&boxes);
- if (unlikely (_cairo_int_status_is_error (status)))
- goto CLEANUP;
- }
-
- /* Fall back to trapezoid fills. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_composite_rectangles_intersect_mask_extents (&extents,
- &polygon.extents);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
- &polygon,
- fill_rule);
- if (unlikely (status))
- goto CLEANUP;
- }
-
- DO_TRAPS:
- status = _clip_and_composite_trapezoids (source, op, surface,
- &traps, antialias,
- extents.clip,
- extents.is_bounded ? &extents.bounded : &extents.unbounded);
- CLEANUP:
- _cairo_traps_fini (&traps);
- _cairo_polygon_fini (&polygon);
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
-}
-
-typedef struct {
- cairo_scaled_font_t *font;
- cairo_glyph_t *glyphs;
- int num_glyphs;
-} cairo_show_glyphs_info_t;
-
-static cairo_status_t
-_cairo_surface_old_show_glyphs_draw_func (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)
+ const cairo_clip_t *clip)
{
- cairo_show_glyphs_info_t *glyph_info = closure;
- cairo_int_status_t status;
-
- /* Modifying the glyph array is fine because we know that this function
- * will be called only once, and we've already made a copy of the
- * glyphs in the wrapper.
- */
- if (dst_x != 0 || dst_y != 0) {
- int 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;
- }
- }
-
- status = _cairo_surface_old_show_glyphs (glyph_info->font, op, src,
- dst,
- extents->x, extents->y,
- extents->x - dst_x,
- extents->y - dst_y,
- extents->width,
- extents->height,
- glyph_info->glyphs,
- glyph_info->num_glyphs,
- clip_region);
-
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- status = _cairo_scaled_font_show_glyphs (glyph_info->font,
- op,
- src, dst,
- extents->x, extents->y,
- extents->x - dst_x,
- extents->y - dst_y,
- extents->width, extents->height,
- glyph_info->glyphs,
- glyph_info->num_glyphs,
- clip_region);
- }
-
- return status;
+ return _cairo_compositor_stroke (&_cairo_fallback_compositor,
+ surface, op, source, path,
+ style, ctm,ctm_inverse,
+ tolerance, antialias, clip);
}
-cairo_status_t
-_cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip)
+cairo_int_status_t
+_cairo_surface_fallback_fill (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
{
- cairo_show_glyphs_info_t glyph_info;
- cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t rect;
- cairo_int_status_t status;
-
- if (!_cairo_surface_get_extents (surface, &rect))
- ASSERT_NOT_REACHED;
-
- status = _cairo_composite_rectangles_init_for_glyphs (&extents, &rect,
- op, source,
- scaled_font,
- glyphs, num_glyphs,
- clip,
- NULL);
- if (unlikely (status))
- return status;
-
- glyph_info.font = scaled_font;
- glyph_info.glyphs = glyphs;
- glyph_info.num_glyphs = num_glyphs;
-
- status = _clip_and_composite (extents.clip, op, source,
- _cairo_surface_old_show_glyphs_draw_func,
- &glyph_info, surface,
- extents.is_bounded ? &extents.bounded : &extents.unbounded);
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
+ return _cairo_compositor_fill (&_cairo_fallback_compositor,
+ surface, op, source, path,
+ fill_rule, tolerance, antialias,
+ clip);
}
-cairo_surface_t *
-_cairo_surface_fallback_snapshot (cairo_surface_t *surface)
-{
- cairo_surface_t *snapshot;
- cairo_status_t status;
- cairo_format_t format;
- cairo_surface_pattern_t pattern;
- cairo_image_surface_t *image;
- void *image_extra;
-
- status = _cairo_surface_acquire_source_image (surface,
- &image, &image_extra);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
-
- format = image->format;
- if (format == CAIRO_FORMAT_INVALID) {
- /* Non-standard images formats can be generated when retrieving
- * images from unusual xservers, for example.
- */
- format = _cairo_format_from_content (image->base.content);
- }
- snapshot = cairo_image_surface_create (format,
- image->width,
- image->height);
- if (cairo_surface_status (snapshot)) {
- _cairo_surface_release_source_image (surface, image, image_extra);
- return snapshot;
- }
-
- _cairo_pattern_init_for_surface (&pattern, &image->base);
- 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)) {
- cairo_surface_destroy (snapshot);
- return _cairo_surface_create_in_error (status);
- }
-
- return snapshot;
-}
-
-cairo_status_t
-_cairo_surface_fallback_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,
- 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))
- return status;
-
- /* We know this will never fail with the image backend; but
- * instead of calling into it directly, we call
- * _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,
- clip_region);
- FAIL:
- if (fallback_region != NULL)
- cairo_region_destroy (fallback_region);
- _fallback_fini (&state);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects)
-{
- fallback_state_t state;
- cairo_rectangle_int_t *offset_rects = NULL;
- cairo_status_t status;
- int x1, y1, x2, y2;
- int i;
-
- assert (surface->snapshot_of == NULL);
-
- if (num_rects <= 0)
- return CAIRO_STATUS_SUCCESS;
-
- /* Compute the bounds of the rectangles, so that we know what area of the
- * destination surface to fetch
- */
- x1 = rects[0].x;
- y1 = rects[0].y;
- x2 = rects[0].x + rects[0].width;
- y2 = rects[0].y + rects[0].height;
-
- for (i = 1; i < num_rects; i++) {
- if (rects[i].x < x1)
- x1 = rects[i].x;
- if (rects[i].y < y1)
- y1 = rects[i].y;
-
- if ((int) (rects[i].x + rects[i].width) > x2)
- x2 = rects[i].x + rects[i].width;
- if ((int) (rects[i].y + rects[i].height) > y2)
- y2 = rects[i].y + rects[i].height;
- }
-
- status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
- if (unlikely (status))
- return status;
-
- /* If the fetched image isn't at 0,0, we need to offset the rectangles */
-
- if (state.image_rect.x != 0 || state.image_rect.y != 0) {
- offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t));
- if (unlikely (offset_rects == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto DONE;
- }
-
- for (i = 0; i < num_rects; i++) {
- offset_rects[i].x = rects[i].x - state.image_rect.x;
- offset_rects[i].y = rects[i].y - state.image_rect.y;
- offset_rects[i].width = rects[i].width;
- offset_rects[i].height = rects[i].height;
- }
-
- rects = offset_rects;
- }
-
- status = _cairo_surface_fill_rectangles (&state.image->base,
- op, color,
- rects, num_rects);
-
- free (offset_rects);
-
- DONE:
- _fallback_fini (&state);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- cairo_antialias_t antialias,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *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))
- return status;
-
- /* If the destination image isn't at 0,0, we need to offset the trapezoids */
-
- 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 == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- 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,
- &state.image->base,
- antialias,
- src_x, src_y,
- dst_x - state.image_rect.x,
- dst_y - state.image_rect.y,
- width, height,
- traps, num_traps,
- clip_region);
- FAIL:
- free (offset_traps);
-
- if (fallback_region != NULL)
- cairo_region_destroy (fallback_region);
-
- _fallback_fini (&state);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
-{
- cairo_surface_t *new_surface;
- cairo_surface_pattern_t pattern;
- cairo_status_t status;
-
- new_surface = _cairo_surface_create_similar_scratch (surface,
- src->content,
- width, height);
- 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 */
- new_surface->device_transform = src->device_transform;
- new_surface->device_transform_inverse = src->device_transform_inverse;
-
- _cairo_pattern_init_for_surface (&pattern, src);
- cairo_matrix_init_translate (&pattern.base.matrix, src_x, src_y);
- pattern.base.filter = CAIRO_FILTER_NEAREST;
-
- status = _cairo_surface_paint (new_surface,
- CAIRO_OPERATOR_SOURCE,
- &pattern.base,
- NULL);
- _cairo_pattern_fini (&pattern.base);
-
- if (unlikely (status)) {
- cairo_surface_destroy (new_surface);
- return status;
- }
-
- *clone_offset_x = src_x;
- *clone_offset_y = src_y;
- *clone_out = new_surface;
- return CAIRO_STATUS_SUCCESS;
+cairo_int_status_t
+_cairo_surface_fallback_glyphs (void *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ const cairo_clip_t *clip)
+{
+ return _cairo_compositor_glyphs (&_cairo_fallback_compositor,
+ surface, op, source,
+ glyphs, num_glyphs, scaled_font,
+ clip);
}
diff --git a/src/cairo-surface-observer-private.h b/src/cairo-surface-observer-private.h
index 61507b21..1b5d6d94 100644
--- a/src/cairo-surface-observer-private.h
+++ b/src/cairo-surface-observer-private.h
@@ -33,14 +33,16 @@
* Chris Wilson <chris@chris-wilson.co.uk>
*/
-#ifndef CAIRO_SURFACE_SNAPSHOT_PRIVATE_H
-#define CAIRO_SURFACE_SNAPSHOT_PRIVATE_H
+#ifndef CAIRO_SURFACE_OBSERVER_PRIVATE_H
+#define CAIRO_SURFACE_OBSERVER_PRIVATE_H
-#include "cairoint.h" /* cairo_surface_backend_t */
+#include "cairoint.h"
#include "cairo-device-private.h"
+#include "cairo-list-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-private.h"
+#include "cairo-surface-backend-private.h"
#include "cairo-time-private.h"
struct stat {
@@ -180,11 +182,27 @@ struct _cairo_device_observer {
cairo_observation_t log;
};
+struct callback_list {
+ cairo_list_t link;
+
+ cairo_surface_observer_callback_t func;
+ void *data;
+};
+
struct _cairo_surface_observer {
cairo_surface_t base;
cairo_surface_t *target;
cairo_observation_t log;
+
+ cairo_list_t paint_callbacks;
+ cairo_list_t mask_callbacks;
+ cairo_list_t fill_callbacks;
+ cairo_list_t stroke_callbacks;
+ cairo_list_t glyphs_callbacks;
+
+ cairo_list_t flush_callbacks;
+ cairo_list_t finish_callbacks;
};
static inline cairo_surface_t *
diff --git a/src/cairo-surface-observer.c b/src/cairo-surface-observer.c
index 3314b823..f2c41646 100644
--- a/src/cairo-surface-observer.c
+++ b/src/cairo-surface-observer.c
@@ -37,6 +37,7 @@
#include "cairo-surface-observer-private.h"
+#include "cairo-array-private.h"
#include "cairo-combsort-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
@@ -385,18 +386,38 @@ _cairo_surface_create_observer_internal (cairo_device_t *device,
surface->base.type = surface->target->type;
surface->base.is_clear = surface->target->is_clear;
+ cairo_list_init (&surface->paint_callbacks);
+ cairo_list_init (&surface->mask_callbacks);
+ cairo_list_init (&surface->fill_callbacks);
+ cairo_list_init (&surface->stroke_callbacks);
+ cairo_list_init (&surface->glyphs_callbacks);
+
+ cairo_list_init (&surface->flush_callbacks);
+ cairo_list_init (&surface->finish_callbacks);
+
surface->log.num_surfaces++;
to_device (surface)->log.num_surfaces++;
return &surface->base;
}
+static inline void
+do_callbacks (cairo_surface_observer_t *surface, cairo_list_t *head)
+{
+ struct callback_list *cb;
+
+ cairo_list_foreach_entry (cb, struct callback_list, head, link)
+ cb->func (&surface->base, surface->target, cb->data);
+}
+
static cairo_status_t
_cairo_surface_observer_finish (void *abstract_surface)
{
cairo_surface_observer_t *surface = abstract_surface;
+ do_callbacks (surface, &surface->finish_callbacks);
+
cairo_surface_destroy (surface->target);
log_fini (&surface->log);
@@ -630,11 +651,11 @@ add_record (cairo_observation_t *log,
static void
sync (cairo_surface_t *target, int x, int y)
{
- cairo_rectangle_t extents;
+ cairo_rectangle_int_t extents;
extents.x = x;
extents.y = y;
- extents.width = 1;
+ extents.width = 1;
extents.height = 1;
cairo_surface_unmap_image (target,
@@ -687,7 +708,6 @@ _cairo_surface_observer_paint (void *abstract_surface,
cairo_surface_observer_t *surface = abstract_surface;
cairo_device_observer_t *device = to_device (surface);
cairo_composite_rectangles_t composite;
- cairo_rectangle_int_t extents;
cairo_int_status_t status;
cairo_time_t t;
int x, y;
@@ -704,9 +724,8 @@ _cairo_surface_observer_paint (void *abstract_surface,
add_pattern (&device->log.paint.source, source, surface->target);
add_clip (&device->log.paint.clip, clip);
- _cairo_surface_get_extents (surface->target, &extents);
status = _cairo_composite_rectangles_init_for_paint (&composite,
- &extents,
+ surface->target,
op, source,
clip);
if (unlikely (status)) {
@@ -722,9 +741,9 @@ _cairo_surface_observer_paint (void *abstract_surface,
_cairo_composite_rectangles_fini (&composite);
t = _cairo_time_get ();
- status = _cairo_surface_paint (surface->target,
- op, source,
- clip);
+ status = _cairo_surface_paint (surface->target,
+ op, source,
+ clip);
if (unlikely (status))
return status;
@@ -734,6 +753,8 @@ _cairo_surface_observer_paint (void *abstract_surface,
add_record_paint (&surface->log, surface->target, op, source, clip, t);
add_record_paint (&device->log, surface->target, op, source, clip, t);
+ do_callbacks (surface, &surface->paint_callbacks);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -773,7 +794,6 @@ _cairo_surface_observer_mask (void *abstract_surface,
cairo_surface_observer_t *surface = abstract_surface;
cairo_device_observer_t *device = to_device (surface);
cairo_composite_rectangles_t composite;
- cairo_rectangle_int_t extents;
cairo_int_status_t status;
cairo_time_t t;
int x, y;
@@ -790,9 +810,8 @@ _cairo_surface_observer_mask (void *abstract_surface,
add_pattern (&device->log.mask.mask, mask, surface->target);
add_clip (&device->log.mask.clip, clip);
- _cairo_surface_get_extents (surface->target, &extents);
status = _cairo_composite_rectangles_init_for_mask (&composite,
- &extents,
+ surface->target,
op, source, mask,
clip);
if (unlikely (status)) {
@@ -824,6 +843,8 @@ _cairo_surface_observer_mask (void *abstract_surface,
surface->target, op, source, mask, clip,
t);
+ do_callbacks (surface, &surface->mask_callbacks);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -875,7 +896,6 @@ _cairo_surface_observer_fill (void *abstract_surface,
cairo_surface_observer_t *surface = abstract_surface;
cairo_device_observer_t *device = to_device (surface);
cairo_composite_rectangles_t composite;
- cairo_rectangle_int_t extents;
cairo_int_status_t status;
cairo_time_t t;
int x, y;
@@ -896,9 +916,8 @@ _cairo_surface_observer_fill (void *abstract_surface,
add_path (&device->log.fill.path, path, TRUE);
add_clip (&device->log.fill.clip, clip);
- _cairo_surface_get_extents (surface->target, &extents);
status = _cairo_composite_rectangles_init_for_fill (&composite,
- &extents,
+ surface->target,
op, source, path,
clip);
if (unlikely (status)) {
@@ -934,6 +953,8 @@ _cairo_surface_observer_fill (void *abstract_surface,
fill_rule, tolerance, antialias,
clip, t);
+ do_callbacks (surface, &surface->fill_callbacks);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -990,7 +1011,6 @@ _cairo_surface_observer_stroke (void *abstract_surface,
cairo_surface_observer_t *surface = abstract_surface;
cairo_device_observer_t *device = to_device (surface);
cairo_composite_rectangles_t composite;
- cairo_rectangle_int_t extents;
cairo_int_status_t status;
cairo_time_t t;
int x, y;
@@ -1013,9 +1033,8 @@ _cairo_surface_observer_stroke (void *abstract_surface,
add_path (&device->log.stroke.path, path, FALSE);
add_clip (&device->log.stroke.clip, clip);
- _cairo_surface_get_extents (surface->target, &extents);
status = _cairo_composite_rectangles_init_for_stroke (&composite,
- &extents,
+ surface->target,
op, source,
path, style, ctm,
clip);
@@ -1055,6 +1074,8 @@ _cairo_surface_observer_stroke (void *abstract_surface,
tolerance, antialias,
clip, t);
+ do_callbacks (surface, &surface->stroke_callbacks);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -1101,13 +1122,11 @@ _cairo_surface_observer_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs)
+ const cairo_clip_t *clip)
{
cairo_surface_observer_t *surface = abstract_surface;
cairo_device_observer_t *device = to_device (surface);
cairo_composite_rectangles_t composite;
- cairo_rectangle_int_t extents;
cairo_int_status_t status;
cairo_glyph_t *dev_glyphs;
cairo_time_t t;
@@ -1123,9 +1142,8 @@ _cairo_surface_observer_glyphs (void *abstract_surface,
add_pattern (&device->log.glyphs.source, source, surface->target);
add_clip (&device->log.glyphs.clip, clip);
- _cairo_surface_get_extents (surface->target, &extents);
status = _cairo_composite_rectangles_init_for_glyphs (&composite,
- &extents,
+ surface->target,
op, source,
scaled_font,
glyphs, num_glyphs,
@@ -1150,7 +1168,6 @@ _cairo_surface_observer_glyphs (void *abstract_surface,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (dev_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
- *remaining_glyphs = 0;
t = _cairo_time_get ();
status = _cairo_surface_show_text_glyphs (surface->target, op, source,
NULL, 0,
@@ -1175,6 +1192,8 @@ _cairo_surface_observer_glyphs (void *abstract_surface,
glyphs, num_glyphs, scaled_font,
clip, t);
+ do_callbacks (surface, &surface->glyphs_callbacks);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -1183,6 +1202,8 @@ _cairo_surface_observer_flush (void *abstract_surface)
{
cairo_surface_observer_t *surface = abstract_surface;
+ do_callbacks (surface, &surface->flush_callbacks);
+
cairo_surface_flush (surface->target);
return surface->target->status;
}
@@ -1314,33 +1335,23 @@ static const cairo_surface_backend_t _cairo_surface_observer_backend = {
_cairo_surface_observer_acquire_source_image,
_cairo_surface_observer_release_source_image,
-
- NULL, NULL, /* acquire, release dest */
- NULL, /* clone similar */
- NULL, /* composite */
- NULL, /* fill rectangles */
- NULL, /* composite trapezoids */
- NULL, /* create span renderer */
- NULL, /* check span renderer */
+ _cairo_surface_observer_snapshot,
_cairo_surface_observer_copy_page,
_cairo_surface_observer_show_page,
_cairo_surface_observer_get_extents,
- NULL, /* old_show_glyphs */
_cairo_surface_observer_get_font_options,
+
_cairo_surface_observer_flush,
_cairo_surface_observer_mark_dirty,
- NULL, /* font_fini */
- NULL, /* glyph_fini */
_cairo_surface_observer_paint,
_cairo_surface_observer_mask,
_cairo_surface_observer_stroke,
_cairo_surface_observer_fill,
+ NULL, /* fill-stroke */
_cairo_surface_observer_glyphs,
-
- _cairo_surface_observer_snapshot,
};
/**
@@ -1385,6 +1396,150 @@ cairo_surface_create_observer (cairo_surface_t *target,
return surface;
}
+static cairo_status_t
+_cairo_surface_observer_add_callback (cairo_list_t *head,
+ cairo_surface_observer_callback_t func,
+ void *data)
+{
+ struct callback_list *cb;
+
+ cb = malloc (sizeof (*cb));
+ if (unlikely (cb == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ cairo_list_add (&cb->link, head);
+ cb->func = func;
+ cb->data = data;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+cairo_surface_observer_add_paint_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data)
+{
+ cairo_surface_observer_t *surface;
+
+ if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
+ return abstract_surface->status;
+
+ if (! _cairo_surface_is_observer (abstract_surface))
+ return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+
+ surface = (cairo_surface_observer_t *)abstract_surface;
+ return _cairo_surface_observer_add_callback (&surface->paint_callbacks,
+ func, data);
+}
+
+cairo_status_t
+cairo_surface_observer_add_mask_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data)
+{
+ cairo_surface_observer_t *surface;
+
+ if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
+ return abstract_surface->status;
+
+ if (! _cairo_surface_is_observer (abstract_surface))
+ return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+
+ surface = (cairo_surface_observer_t *)abstract_surface;
+ return _cairo_surface_observer_add_callback (&surface->mask_callbacks,
+ func, data);
+}
+
+cairo_status_t
+cairo_surface_observer_add_fill_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data)
+{
+ cairo_surface_observer_t *surface;
+
+ if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
+ return abstract_surface->status;
+
+ if (! _cairo_surface_is_observer (abstract_surface))
+ return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+
+ surface = (cairo_surface_observer_t *)abstract_surface;
+ return _cairo_surface_observer_add_callback (&surface->fill_callbacks,
+ func, data);
+}
+
+cairo_status_t
+cairo_surface_observer_add_stroke_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data)
+{
+ cairo_surface_observer_t *surface;
+
+ if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
+ return abstract_surface->status;
+
+ if (! _cairo_surface_is_observer (abstract_surface))
+ return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+
+ surface = (cairo_surface_observer_t *)abstract_surface;
+ return _cairo_surface_observer_add_callback (&surface->stroke_callbacks,
+ func, data);
+}
+
+cairo_status_t
+cairo_surface_observer_add_glyphs_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data)
+{
+ cairo_surface_observer_t *surface;
+
+ if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
+ return abstract_surface->status;
+
+ if (! _cairo_surface_is_observer (abstract_surface))
+ return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+
+ surface = (cairo_surface_observer_t *)abstract_surface;
+ return _cairo_surface_observer_add_callback (&surface->glyphs_callbacks,
+ func, data);
+}
+
+cairo_status_t
+cairo_surface_observer_add_flush_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data)
+{
+ cairo_surface_observer_t *surface;
+
+ if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
+ return abstract_surface->status;
+
+ if (! _cairo_surface_is_observer (abstract_surface))
+ return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+
+ surface = (cairo_surface_observer_t *)abstract_surface;
+ return _cairo_surface_observer_add_callback (&surface->flush_callbacks,
+ func, data);
+}
+
+cairo_status_t
+cairo_surface_observer_add_finish_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data)
+{
+ cairo_surface_observer_t *surface;
+
+ if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count)))
+ return abstract_surface->status;
+
+ if (! _cairo_surface_is_observer (abstract_surface))
+ return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+
+ surface = (cairo_surface_observer_t *)abstract_surface;
+ return _cairo_surface_observer_add_callback (&surface->finish_callbacks,
+ func, data);
+}
+
static void
print_extents (cairo_output_stream_t *stream, const struct extents *e)
{
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index 31ddb8c7..0bebfde7 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -61,6 +61,7 @@ struct _cairo_surface {
cairo_reference_count_t ref_count;
cairo_status_t status;
unsigned int unique_id;
+ unsigned int serial;
unsigned finished : 1;
unsigned is_clear : 1;
diff --git a/src/cairo-surface-snapshot-private.h b/src/cairo-surface-snapshot-private.h
index 0b1c8d34..b7a4d05f 100644
--- a/src/cairo-surface-snapshot-private.h
+++ b/src/cairo-surface-snapshot-private.h
@@ -36,9 +36,8 @@
#ifndef CAIRO_SURFACE_SNAPSHOT_PRIVATE_H
#define CAIRO_SURFACE_SNAPSHOT_PRIVATE_H
-#include "cairoint.h" /* for cairo_surface_backend_t */
-
#include "cairo-surface-private.h"
+#include "cairo-surface-backend-private.h"
struct _cairo_surface_snapshot {
cairo_surface_t base;
diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index 16153e21..4bc40e7e 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -109,18 +109,14 @@ static const cairo_surface_backend_t _cairo_surface_snapshot_backend = {
_cairo_surface_snapshot_acquire_source_image,
_cairo_surface_snapshot_release_source_image,
- NULL, NULL, /* acquire, release dest */
- NULL, /* clone similar */
- NULL, /* composite */
- NULL, /* fill rectangles */
- NULL, /* composite trapezoids */
- NULL, /* create span renderer */
- NULL, /* check span renderer */
+ NULL, /* snapshot */
+
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_surface_snapshot_get_extents,
- NULL, /* old-show-glyphs */
NULL, /* get-font-options */
+
_cairo_surface_snapshot_flush,
};
@@ -141,8 +137,10 @@ _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface)
if (snapshot->target->backend->snapshot != NULL) {
clone = snapshot->target->backend->snapshot (snapshot->target);
- if (clone != NULL)
+ if (clone != NULL) {
+ assert (clone->status || ! _cairo_surface_is_snapshot (clone));
goto done;
+ }
}
/* XXX copy to a similar surface, leave acquisition till later?
@@ -160,7 +158,6 @@ _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface)
done:
status = _cairo_surface_set_error (surface, clone->status);
- assert (! _cairo_surface_is_snapshot (clone));
snapshot->target = snapshot->clone = clone;
snapshot->base.type = clone->type;
}
diff --git a/src/cairo-surface-subsurface-private.h b/src/cairo-surface-subsurface-private.h
index ada09a17..6a43c8fa 100644
--- a/src/cairo-surface-subsurface-private.h
+++ b/src/cairo-surface-subsurface-private.h
@@ -36,9 +36,8 @@
#ifndef CAIRO_SURFACE_SUBSURFACE_PRIVATE_H
#define CAIRO_SURFACE_SUBSURFACE_PRIVATE_H
-#include "cairoint.h" /* for cairo_surface_backend_t */
-
#include "cairo-surface-private.h"
+#include "cairo-surface-backend-private.h"
struct _cairo_surface_subsurface {
cairo_surface_t base;
@@ -54,6 +53,25 @@ _cairo_surface_subsurface_get_target (cairo_surface_t *surface)
return ((cairo_surface_subsurface_t *) surface)->target;
}
+static inline void
+_cairo_surface_subsurface_offset (cairo_surface_t *surface,
+ int *x, int *y)
+{
+ cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface;
+ *x += ss->extents.x;
+ *y += ss->extents.y;
+}
+
+static inline cairo_surface_t *
+_cairo_surface_subsurface_get_target_with_offset (cairo_surface_t *surface,
+ int *x, int *y)
+{
+ cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface;
+ *x += ss->extents.x;
+ *y += ss->extents.y;
+ return ss->target;
+}
+
static inline cairo_bool_t
_cairo_surface_is_subsurface (cairo_surface_t *surface)
{
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 73be5f2d..48d10fb1 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -202,8 +202,7 @@ _cairo_surface_subsurface_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs)
+ const cairo_clip_t *clip)
{
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
@@ -216,7 +215,6 @@ _cairo_surface_subsurface_glyphs (void *abstract_surface,
op, source,
scaled_font, glyphs, num_glyphs,
target_clip);
- *remaining_glyphs = 0;
_cairo_clip_destroy (target_clip);
return status;
}
@@ -489,30 +487,23 @@ static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
_cairo_surface_subsurface_acquire_source_image,
_cairo_surface_subsurface_release_source_image,
- NULL, NULL, /* acquire, release dest */
- NULL, /* clone similar */
- NULL, /* composite */
- NULL, /* fill rectangles */
- NULL, /* composite trapezoids */
- NULL, /* create span renderer */
- NULL, /* check span renderer */
+ _cairo_surface_subsurface_snapshot,
+
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_surface_subsurface_get_extents,
- NULL, /* old_show_glyphs */
_cairo_surface_subsurface_get_font_options,
+
_cairo_surface_subsurface_flush,
_cairo_surface_subsurface_mark_dirty,
- NULL, /* font_fini */
- NULL, /* glyph_fini */
_cairo_surface_subsurface_paint,
_cairo_surface_subsurface_mask,
_cairo_surface_subsurface_stroke,
_cairo_surface_subsurface_fill,
+ NULL, /* fill/stroke */
_cairo_surface_subsurface_glyphs,
-
- _cairo_surface_subsurface_snapshot,
};
/**
diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h
index fbe5d80f..6529ebc1 100644
--- a/src/cairo-surface-wrapper-private.h
+++ b/src/cairo-surface-wrapper-private.h
@@ -41,6 +41,7 @@
#include "cairoint.h"
#include "cairo-types-private.h"
+#include "cairo-surface-backend-private.h"
CAIRO_BEGIN_DECLS
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index 5e628690..d2d971de 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -446,7 +446,7 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
- if (dev_glyphs == NULL) {
+ if (unlikely (dev_glyphs == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FINISH;
}
@@ -454,7 +454,9 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
for (i = 0; i < num_glyphs; i++) {
dev_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&m, &dev_glyphs[i].x, &dev_glyphs[i].y);
+ cairo_matrix_transform_point (&m,
+ &dev_glyphs[i].x,
+ &dev_glyphs[i].y);
}
status = cairo_matrix_invert (&m);
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index d15b94b7..84883801 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -38,7 +38,7 @@
#include "cairoint.h"
-#include "cairo-surface-fallback-private.h"
+#include "cairo-array-private.h"
#include "cairo-clip-private.h"
#include "cairo-device-private.h"
#include "cairo-error-private.h"
@@ -103,6 +103,7 @@ const cairo_surface_t name = { \
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \
status, /* status */ \
0, /* unique id */ \
+ 0, /* serial */ \
FALSE, /* finished */ \
TRUE, /* is_clear */ \
FALSE, /* has_font_options */ \
@@ -182,7 +183,7 @@ _cairo_surface_set_error (cairo_surface_t *surface,
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
- _cairo_status_set_error (&surface->status, status);
+ _cairo_status_set_error (&surface->status, (cairo_status_t)status);
return _cairo_error (status);
}
@@ -367,7 +368,6 @@ _cairo_surface_has_snapshot (cairo_surface_t *surface,
cairo_list_foreach_entry (snapshot, cairo_surface_t,
&surface->snapshots, snapshot)
{
- /* XXX is_similar? */
if (snapshot->backend == backend)
return snapshot;
}
@@ -375,15 +375,6 @@ _cairo_surface_has_snapshot (cairo_surface_t *surface,
return NULL;
}
-static cairo_bool_t
-_cairo_surface_is_writable (cairo_surface_t *surface)
-{
- return ! surface->finished &&
- surface->snapshot_of == NULL &&
- ! _cairo_surface_has_snapshots (surface) &&
- ! _cairo_surface_has_mime_data (surface);
-}
-
static void
_cairo_surface_begin_modification (cairo_surface_t *surface)
{
@@ -413,6 +404,7 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->unique_id = _cairo_surface_allocate_unique_id ();
surface->finished = FALSE;
surface->is_clear = FALSE;
+ surface->serial = 0;
surface->owns_device = (device != NULL);
_cairo_user_data_array_init (&surface->user_data);
@@ -461,12 +453,15 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other,
if (unlikely (other->status))
return _cairo_surface_create_in_error (other->status);
- if (other->backend->create_similar == NULL)
- return NULL;
+ surface = NULL;
+ if (other->backend->create_similar)
+ surface = other->backend->create_similar (other, content, width, height);
+ if (surface == NULL)
+ surface = cairo_surface_create_similar_image (other,
+ _cairo_format_from_content (content),
+ width, height);
- surface = other->backend->create_similar (other,
- content, width, height);
- if (surface == NULL || surface->status)
+ if (unlikely (surface->status))
return surface;
_cairo_surface_copy_similar_properties (surface, other);
@@ -518,18 +513,16 @@ cairo_surface_create_similar (cairo_surface_t *other,
return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
if (unlikely (! CAIRO_CONTENT_VALID (content)))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT);
surface = _cairo_surface_create_similar_solid (other,
content, width, height,
- CAIRO_COLOR_TRANSPARENT,
- TRUE);
+ CAIRO_COLOR_TRANSPARENT);
assert (surface->is_clear);
return surface;
}
-
/**
* cairo_surface_create_similar_image:
* @other: an existing surface used to select the preference of the new surface
@@ -564,7 +557,7 @@ cairo_surface_create_similar_image (cairo_surface_t *other,
{
cairo_surface_t *image;
- if (other->status)
+ if (unlikely (other->status))
return _cairo_surface_create_in_error (other->status);
if (unlikely (other->finished))
return _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
@@ -572,7 +565,7 @@ cairo_surface_create_similar_image (cairo_surface_t *other,
if (unlikely (width < 0 || height < 0))
return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
if (unlikely (! CAIRO_FORMAT_VALID (format)))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT);
image = NULL;
if (other->backend->create_similar_image)
@@ -580,8 +573,12 @@ cairo_surface_create_similar_image (cairo_surface_t *other,
format, width, height);
if (image == NULL)
image = cairo_image_surface_create (format, width, height);
+
+ assert (image->is_clear);
+
return image;
}
+slim_hidden_def (cairo_surface_create_similar_image);
/**
* cairo_surface_map_to_image:
@@ -608,7 +605,7 @@ cairo_surface_create_similar_image (cairo_surface_t *other,
**/
cairo_surface_t *
cairo_surface_map_to_image (cairo_surface_t *surface,
- const cairo_rectangle_t *extents)
+ const cairo_rectangle_int_t *extents)
{
cairo_rectangle_int_t rect;
cairo_surface_t *image;
@@ -621,32 +618,35 @@ cairo_surface_map_to_image (cairo_surface_t *surface,
if (extents == NULL) {
if (unlikely (! surface->backend->get_extents (surface, &rect)))
return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+ extents = &rect;
} else {
cairo_rectangle_int_t surface_extents;
- _cairo_rectangle_int_from_double (&rect, extents);
/* If this surface is bounded, we can't map parts
* that are outside of it. */
if (likely (surface->backend->get_extents (surface, &surface_extents))) {
- if (unlikely (rect.x < surface_extents.x ||
- rect.y < surface_extents.y ||
- rect.x + rect.width > surface_extents.x + surface_extents.width ||
- rect.y + rect.height > surface_extents.y + surface_extents.height))
+ if (unlikely (extents->x < surface_extents.x ||
+ extents->y < surface_extents.y ||
+ extents->x + extents->width > surface_extents.x + surface_extents.width ||
+ extents->y + extents->height > surface_extents.y + surface_extents.height))
return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
}
}
image = NULL;
if (surface->backend->map_to_image)
- image = surface->backend->map_to_image (surface, &rect);
+ image = surface->backend->map_to_image (surface, extents);
if (image == NULL) {
cairo_surface_pattern_t pattern;
cairo_status_t status;
- image = cairo_image_surface_create (_cairo_format_from_content (surface->content),
- rect.width, rect.height);
- cairo_surface_set_device_offset (image, -rect.y, -rect.y);
+ image = cairo_surface_create_similar_image (surface,
+ _cairo_format_from_content (surface->content),
+ extents->width,
+ extents->height);
+ cairo_surface_set_device_offset (image, -extents->y, -extents->y);
_cairo_pattern_init_for_surface (&pattern, surface);
pattern.base.filter = CAIRO_FILTER_NEAREST;
@@ -711,6 +711,12 @@ cairo_surface_unmap_image (cairo_surface_t *surface,
goto error;
}
+ /* If the image is untouched just skip the update */
+ if (image->serial == 0) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto error;
+ }
+
status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->backend->unmap_image)
status = surface->backend->unmap_image (surface, (cairo_image_surface_t *) image);
@@ -731,9 +737,8 @@ cairo_surface_unmap_image (cairo_surface_t *surface,
/* And we also have to clip the operation to the image's extents */
extents.x = image->device_transform_inverse.x0;
extents.y = image->device_transform_inverse.y0;
- extents.width = img->width;
+ extents.width = img->width;
extents.height = img->height;
-
clip = _cairo_clip_intersect_rectangle (NULL, &extents);
status = _cairo_surface_paint (surface,
@@ -758,8 +763,7 @@ _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)
+ const cairo_color_t *color)
{
cairo_status_t status;
cairo_surface_t *surface;
@@ -767,10 +771,7 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
surface = _cairo_surface_create_similar_scratch (other, content,
width, height);
- if (surface == NULL && allow_fallback)
- surface = _cairo_image_surface_create_with_content (content,
- width, height);
- if (surface == NULL || surface->status)
+ if (unlikely (surface->status))
return surface;
_cairo_pattern_init_solid (&pattern, color);
@@ -786,51 +787,6 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
return surface;
}
-cairo_surface_t *
-_cairo_surface_create_solid_pattern_surface (cairo_surface_t *other,
- const cairo_solid_pattern_t *solid_pattern)
-{
- if (other->backend->create_solid_pattern_surface != NULL) {
- cairo_surface_t *surface;
-
- surface = other->backend->create_solid_pattern_surface (other,
- solid_pattern);
- if (surface)
- return surface;
- }
-
- return _cairo_surface_create_similar_solid (other,
- _cairo_color_get_content (&solid_pattern->color),
- 1, 1,
- &solid_pattern->color,
- FALSE);
-}
-
-cairo_int_status_t
-_cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other,
- cairo_surface_t *solid_surface,
- const cairo_solid_pattern_t *solid_pattern)
-{
- /* Solid pattern surface for these backends are special and not trivial
- * to repaint. Skip repainting.
- *
- * This does not work optimally with things like analysis surface that
- * are proxies. But returning UNSUPPORTED is *safe* as it only
- * disables some caching.
- */
- if (other->backend->create_solid_pattern_surface != NULL &&
- ! other->backend->can_repaint_solid_pattern_surface (solid_surface,
- solid_pattern))
- {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- return _cairo_surface_paint (solid_surface,
- CAIRO_OPERATOR_SOURCE,
- &solid_pattern->base,
- NULL);
-}
-
/**
* cairo_surface_reference:
* @surface: a #cairo_surface_t
@@ -967,7 +923,7 @@ cairo_surface_finish (cairo_surface_t *surface)
if (surface->backend->finish) {
status = surface->backend->finish (surface);
if (unlikely (status))
- status = _cairo_surface_set_error (surface, status);
+ _cairo_surface_set_error (surface, status);
}
assert (surface->snapshot_of == NULL);
@@ -1012,8 +968,7 @@ void *
cairo_surface_get_user_data (cairo_surface_t *surface,
const cairo_user_data_key_t *key)
{
- return _cairo_user_data_array_get_data (&surface->user_data,
- key);
+ return _cairo_user_data_array_get_data (&surface->user_data, key);
}
/**
@@ -1192,7 +1147,7 @@ cairo_surface_set_mime_data (cairo_surface_t *surface,
if (unlikely (surface->status))
return surface->status;
- if (surface->finished)
+ if (unlikely (surface->finished))
return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
status = _cairo_intern_string (&mime_type, -1);
@@ -1279,16 +1234,13 @@ void
_cairo_surface_set_font_options (cairo_surface_t *surface,
cairo_font_options_t *options)
{
- cairo_status_t status;
-
if (surface->status)
return;
assert (surface->snapshot_of == NULL);
if (surface->finished) {
- status = _cairo_surface_set_error (surface,
- _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
@@ -1366,7 +1318,7 @@ cairo_surface_flush (cairo_surface_t *surface)
if (surface->backend->flush) {
status = surface->backend->flush (surface);
if (unlikely (status))
- status = _cairo_surface_set_error (surface, status);
+ _cairo_surface_set_error (surface, status);
}
}
slim_hidden_def (cairo_surface_flush);
@@ -1411,13 +1363,13 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
{
cairo_status_t status;
- if (surface->status)
+ if (unlikely (surface->status))
return;
assert (surface->snapshot_of == NULL);
- if (surface->finished) {
- status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ if (unlikely (surface->finished)) {
+ _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
@@ -1428,6 +1380,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
assert (! _cairo_surface_has_mime_data (surface));
surface->is_clear = FALSE;
+ surface->serial++;
if (surface->backend->mark_dirty_rectangle != NULL) {
/* XXX: FRAGILE: We're ignoring the scaling component of
@@ -1441,7 +1394,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
width, height);
if (unlikely (status))
- status = _cairo_surface_set_error (surface, status);
+ _cairo_surface_set_error (surface, status);
}
}
slim_hidden_def (cairo_surface_mark_dirty_rectangle);
@@ -1470,13 +1423,13 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface,
{
cairo_status_t status;
- if (surface->status)
+ if (unlikely (surface->status))
return;
assert (surface->snapshot_of == NULL);
- if (surface->finished) {
- status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ if (unlikely (surface->finished)) {
+ _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
@@ -1520,13 +1473,13 @@ cairo_surface_set_device_offset (cairo_surface_t *surface,
{
cairo_status_t status;
- if (surface->status)
+ if (unlikely (surface->status))
return;
assert (surface->snapshot_of == NULL);
- if (surface->finished) {
- status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ if (unlikely (surface->finished)) {
+ _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
@@ -1605,15 +1558,13 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface,
double x_pixels_per_inch,
double y_pixels_per_inch)
{
- cairo_status_t status;
-
- if (surface->status)
+ if (unlikely (surface->status))
return;
assert (surface->snapshot_of == NULL);
- if (surface->finished) {
- status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ if (unlikely (surface->finished)) {
+ _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
@@ -1621,7 +1572,7 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface,
/* XXX Could delay raising the error until we fallback, but throwing
* the error here means that we can catch the real culprit.
*/
- status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_MATRIX);
+ _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_MATRIX);
return;
}
@@ -1685,7 +1636,7 @@ _cairo_surface_acquire_source_image (cairo_surface_t *surface,
{
cairo_status_t status;
- if (surface->status)
+ if (unlikely (surface->status))
return surface->status;
assert (!surface->finished);
@@ -1703,33 +1654,6 @@ _cairo_surface_acquire_source_image (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-cairo_status_t
-_cairo_surface_acquire_source_image_transformed (cairo_surface_t *surface,
- cairo_matrix_t *device_transform,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_status_t status;
-
- if (surface->status)
- return surface->status;
-
- assert (!surface->finished);
-
- if (surface->backend->acquire_source_image_transformed == NULL)
- return _cairo_surface_acquire_source_image (surface,
- image_out, image_extra);
-
- status = surface->backend->acquire_source_image_transformed (surface, device_transform,
- image_out, image_extra);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
-
- _cairo_debug_check_image_surface_is_defined (&(*image_out)->base);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
/**
* _cairo_surface_release_source_image:
* @surface: a #cairo_surface_t
@@ -1748,469 +1672,6 @@ _cairo_surface_release_source_image (cairo_surface_t *surface,
surface->backend->release_source_image (surface, image, image_extra);
}
-/**
- * _cairo_surface_acquire_dest_image:
- * @surface: a #cairo_surface_t
- * @interest_rect: area of @surface for which fallback drawing is being done.
- * A value of %NULL indicates that the entire surface is desired.
- * XXXX I'd like to get rid of being able to pass %NULL here (nothing seems to)
- * @image_out: location to store a pointer to an image surface that includes at least
- * the intersection of @interest_rect with the visible area of @surface.
- * This surface could be @surface itself, a surface held internal to @surface,
- * or it could be a new surface with a copy of the relevant portion of @surface.
- * If a new surface is created, it should have the same channels and depth
- * as @surface so that copying to and from it is exact.
- * @image_rect: location to store area of the original surface occupied
- * by the surface stored in @image.
- * @image_extra: location to store image specific backend data
- *
- * Retrieves a local image for a surface for implementing a fallback drawing
- * operation. After calling this function, the implementation of the fallback
- * drawing operation draws the primitive to the surface stored in @image_out
- * then calls _cairo_surface_release_dest_image(),
- * which, if a temporary surface was created, copies the bits back to the
- * main surface and frees the temporary surface.
- *
- * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY.
- * %CAIRO_INT_STATUS_UNSUPPORTED can be returned but this will mean that
- * the backend can't draw with fallbacks. It's possible for the routine
- * to store %NULL in @local_out and return %CAIRO_STATUS_SUCCESS;
- * that indicates that no part of @interest_rect is visible, so no drawing
- * is necessary. _cairo_surface_release_dest_image() should not be called in that
- * case.
- **/
-cairo_status_t
-_cairo_surface_acquire_dest_image (cairo_surface_t *surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect,
- void **image_extra)
-{
- cairo_status_t status;
-
- if (surface->status)
- return surface->status;
-
- assert (_cairo_surface_is_writable (surface));
-
- if (surface->backend->acquire_dest_image == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = surface->backend->acquire_dest_image (surface,
- interest_rect,
- image_out,
- image_rect,
- image_extra);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
-
- _cairo_debug_check_image_surface_is_defined (&(*image_out)->base);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * _cairo_surface_release_dest_image:
- * @surface: a #cairo_surface_t
- * @interest_rect: same as passed to the matching _cairo_surface_acquire_dest_image()
- * @image: same as returned from the matching _cairo_surface_acquire_dest_image()
- * @image_rect: same as returned from the matching _cairo_surface_acquire_dest_image()
- * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image()
- *
- * Finishes the operation started with _cairo_surface_acquire_dest_image(), by, if
- * necessary, copying the image from @image back to @surface and freeing any
- * resources that were allocated.
- **/
-void
-_cairo_surface_release_dest_image (cairo_surface_t *surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
-{
- assert (_cairo_surface_is_writable (surface));
-
- if (surface->backend->release_dest_image)
- surface->backend->release_dest_image (surface, interest_rect,
- image, image_rect, image_extra);
-}
-
-static cairo_status_t
-_cairo_recording_surface_clone_similar (cairo_surface_t *surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
-{
- cairo_recording_surface_t *recorder = (cairo_recording_surface_t *) src;
- cairo_surface_t *similar;
- cairo_status_t status;
-
- similar = _cairo_surface_has_snapshot (src, surface->backend);
- if (similar != NULL) {
- *clone_out = cairo_surface_reference (similar);
- *clone_offset_x = 0;
- *clone_offset_y = 0;
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (recorder->unbounded ||
- width*height*8 < recorder->extents.width*recorder->extents.height)
- {
- similar = _cairo_surface_create_similar_solid (surface,
- src->content,
- width, height,
- CAIRO_COLOR_TRANSPARENT,
- FALSE);
- 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);
-
- status = _cairo_recording_surface_replay (src, similar);
- if (unlikely (status)) {
- cairo_surface_destroy (similar);
- return status;
- }
- } else {
- similar = _cairo_surface_create_similar_scratch (surface,
- src->content,
- recorder->extents.width,
- recorder->extents.height);
- if (similar == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- if (unlikely (similar->status))
- return similar->status;
-
- status = _cairo_recording_surface_replay (src, similar);
- if (unlikely (status)) {
- cairo_surface_destroy (similar);
- return status;
- }
-
- _cairo_surface_attach_snapshot (src, similar, NULL);
-
- src_x = src_y = 0;
- }
-
- *clone_out = similar;
- *clone_offset_x = src_x;
- *clone_offset_y = src_y;
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * _cairo_surface_clone_similar:
- * @surface: a #cairo_surface_t
- * @src: the source image
- * @content: target content mask
- * @src_x: extent for the rectangle in src we actually care about
- * @src_y: extent for the rectangle in src we actually care about
- * @width: extent for the rectangle in src we actually care about
- * @height: extent for the rectangle in src we actually care about
- * @clone_out: location to store a surface compatible with @surface
- * and with contents identical to @src. The caller must call
- * cairo_surface_destroy() on the result.
- *
- * Creates a surface with contents identical to @src but that
- * can be used efficiently with @surface. If @surface and @src are
- * already compatible then it may return a new reference to @src.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if a surface was created and stored
- * in @clone_out. Otherwise %CAIRO_INT_STATUS_UNSUPPORTED or another
- * error like %CAIRO_STATUS_NO_MEMORY.
- **/
-cairo_status_t
-_cairo_surface_clone_similar (cairo_surface_t *surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
-{
- cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
- cairo_image_surface_t *image;
- void *image_extra;
-
- if (unlikely (surface->status))
- return surface->status;
-
- if (unlikely (surface->finished))
- return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
-
-#if CAIRO_HAS_TEE_SURFACE
-
- if (src->type == CAIRO_SURFACE_TYPE_TEE) {
- cairo_surface_t *match;
-
- match = _cairo_tee_surface_find_match (src,
- surface->backend,
- src->content);
- if (match != NULL)
- src = match;
- }
-
-#endif
-
- if (surface->backend->clone_similar != NULL) {
- status = surface->backend->clone_similar (surface, src,
- src_x, src_y,
- width, height,
- 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;
-
- /* First check to see if we can replay to a similar surface */
- if (_cairo_surface_is_recording (src)) {
- return _cairo_recording_surface_clone_similar (surface, src,
- src_x, src_y,
- width, height,
- clone_offset_x,
- clone_offset_y,
- clone_out);
- }
-
- /* If we failed, try again with an image surface */
- status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
- if (status == CAIRO_INT_STATUS_SUCCESS) {
- status =
- surface->backend->clone_similar (surface, &image->base,
- src_x, src_y,
- width, height,
- clone_offset_x,
- clone_offset_y,
- clone_out);
-
- _cairo_surface_release_source_image (src, image, image_extra);
- }
- }
- }
-
- /* If we're still unsupported, hit our fallback path to get a clone */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- status =
- _cairo_surface_fallback_clone_similar (surface, src,
- src_x, src_y,
- width, height,
- clone_offset_x,
- clone_offset_y,
- clone_out);
- }
-
- if (unlikely (status))
- return status;
-
- /* Update the clone's device_transform (which the underlying surface
- * backend knows nothing about) */
- if (*clone_out != src) {
- (*clone_out)->device_transform = src->device_transform;
- (*clone_out)->device_transform_inverse = src->device_transform_inverse;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * _cairo_surface_is_similar
- * @surface_a: a #cairo_surface_t
- * @surface_b: a #cairo_surface_t
- * @content: a #cairo_content_t
- *
- * Find out whether the given surfaces share the same backend,
- * and if so, whether they can be considered similar.
- *
- * The definition of "similar" depends on the backend. In
- * general, it means that the surface is equivalent to one
- * that would have been generated by a call to cairo_surface_create_similar().
- *
- * Return value: %TRUE if the surfaces are similar.
- **/
-cairo_bool_t
-_cairo_surface_is_similar (cairo_surface_t *surface_a,
- cairo_surface_t *surface_b)
-{
- if (surface_a->backend != surface_b->backend)
- return FALSE;
-
- if (surface_a->backend->is_similar != NULL)
- return surface_a->backend->is_similar (surface_a, surface_b);
-
- return TRUE;
-}
-
-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,
- cairo_region_t *clip_region)
-{
- cairo_int_status_t status;
-
- if (unlikely (dst->status))
- return dst->status;
-
- assert (_cairo_surface_is_writable (dst));
-
- if (mask) {
- /* These operators aren't interpreted the same way by the backends;
- * they are implemented in terms of other operators in cairo-gstate.c
- */
- assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR);
- }
-
- if (dst->backend->composite) {
- status = dst->backend->composite (op,
- src, mask, dst,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height,
- clip_region);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return _cairo_surface_set_error (dst, status);
- }
-
- return _cairo_surface_set_error (dst,
- _cairo_surface_fallback_composite (op,
- src, mask, dst,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height,
- clip_region));
-}
-
-/**
- * _cairo_surface_fill_region:
- * @surface: a #cairo_surface_t
- * @op: the operator to apply to the region
- * @color: the source color
- * @region: the region to modify, in backend coordinates
- *
- * Applies an operator to a set of rectangles specified as a
- * #cairo_region_t using a solid color as the source.
- * See _cairo_surface_fill_rectangles() for full details.
- *
- * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred
- **/
-cairo_status_t
-_cairo_surface_fill_region (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_region_t *region)
-{
- int num_rects;
- cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
- cairo_rectangle_int_t *rects = stack_rects;
- cairo_status_t status;
- int i;
-
- if (surface->status)
- return surface->status;
-
- assert (_cairo_surface_is_writable (surface));
-
- num_rects = cairo_region_num_rectangles (region);
- if (num_rects == 0)
- return CAIRO_STATUS_SUCCESS;
-
- /* catch a common reduction of _cairo_clip_combine_with_surface() */
- if (op == CAIRO_OPERATOR_IN &&
- surface->content == CAIRO_CONTENT_ALPHA &&
- CAIRO_COLOR_IS_OPAQUE (color))
- {
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (num_rects > ARRAY_LENGTH (stack_rects)) {
- rects = _cairo_malloc_ab (num_rects,
- sizeof (cairo_rectangle_int_t));
- if (rects == NULL) {
- return _cairo_surface_set_error (surface,
- _cairo_error (CAIRO_STATUS_NO_MEMORY));
- }
- }
-
- 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);
-
- if (rects != stack_rects)
- free (rects);
-
- return _cairo_surface_set_error (surface, status);
-}
-
-/**
- * _cairo_surface_fill_rectangles:
- * @surface: a #cairo_surface_t
- * @op: the operator to apply to the region
- * @color: the source color
- * @rects: the rectangles to modify, in backend coordinates
- * @num_rects: the number of rectangles in @rects
- *
- * Applies an operator to a set of rectangles using a solid color
- * as the source. Note that even if the operator is an unbounded operator
- * such as %CAIRO_OPERATOR_IN, only the given set of rectangles
- * is affected. This differs from _cairo_surface_composite_trapezoids()
- * where the entire destination rectangle is cleared.
- *
- * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred
- **/
-cairo_status_t
-_cairo_surface_fill_rectangles (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects)
-{
- cairo_int_status_t status;
-
- if (surface->status)
- return surface->status;
-
- assert (_cairo_surface_is_writable (surface));
-
- if (num_rects == 0)
- return CAIRO_STATUS_SUCCESS;
-
- if (surface->backend->fill_rectangles) {
- 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,
- rects, num_rects));
-}
-
static cairo_status_t
_pattern_has_error (const cairo_pattern_t *pattern)
{
@@ -2248,6 +1709,9 @@ nothing_to_do (cairo_surface_t *surface,
if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
return TRUE;
+ if (op == CAIRO_OPERATOR_ATOP && (surface->content & CAIRO_CONTENT_COLOR) ==0)
+ return TRUE;
+
return FALSE;
}
@@ -2265,26 +1729,20 @@ _cairo_surface_paint (cairo_surface_t *surface,
if (_cairo_clip_is_all_clipped (clip))
return CAIRO_STATUS_SUCCESS;
- if (nothing_to_do (surface, op, source))
- return CAIRO_STATUS_SUCCESS;
-
status = _pattern_has_error (source);
if (unlikely (status))
return status;
- _cairo_surface_begin_modification (surface);
-
- if (surface->backend->paint != NULL) {
- status = surface->backend->paint (surface, op, source, clip);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- goto FINISH;
- }
+ if (nothing_to_do (surface, op, source))
+ return CAIRO_STATUS_SUCCESS;
- status = _cairo_surface_fallback_paint (surface, op, source, clip);
+ _cairo_surface_begin_modification (surface);
- FINISH:
- if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
+ status = surface->backend->paint (surface, op, source, clip);
+ if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
surface->is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL;
+ surface->serial++;
+ }
return _cairo_surface_set_error (surface, status);
}
@@ -2304,9 +1762,6 @@ _cairo_surface_mask (cairo_surface_t *surface,
if (_cairo_clip_is_all_clipped (clip))
return CAIRO_STATUS_SUCCESS;
- if (nothing_to_do (surface, op, source))
- return CAIRO_STATUS_SUCCESS;
-
/* If the mask is blank, this is just an expensive no-op */
if (_cairo_pattern_is_clear (mask) &&
_cairo_operator_bounded_by_mask (op))
@@ -2322,19 +1777,16 @@ _cairo_surface_mask (cairo_surface_t *surface,
if (unlikely (status))
return status;
- _cairo_surface_begin_modification (surface);
-
- if (surface->backend->mask != NULL) {
- status = surface->backend->mask (surface, op, source, mask, clip);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- goto FINISH;
- }
+ if (nothing_to_do (surface, op, source))
+ return CAIRO_STATUS_SUCCESS;
- status = _cairo_surface_fallback_mask (surface, op, source, mask, clip);
+ _cairo_surface_begin_modification (surface);
- FINISH:
- if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
+ status = surface->backend->mask (surface, op, source, mask, clip);
+ if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
surface->is_clear = FALSE;
+ surface->serial++;
+ }
return _cairo_surface_set_error (surface, status);
}
@@ -2413,23 +1865,25 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
goto FINISH;
FINISH:
- if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
+ if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
surface->is_clear = FALSE;
+ surface->serial++;
+ }
return _cairo_surface_set_error (surface, status);
}
cairo_status_t
-_cairo_surface_stroke (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
+_cairo_surface_stroke (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
{
cairo_int_status_t status;
@@ -2439,48 +1893,37 @@ _cairo_surface_stroke (cairo_surface_t *surface,
if (_cairo_clip_is_all_clipped (clip))
return CAIRO_STATUS_SUCCESS;
- if (nothing_to_do (surface, op, source))
- return CAIRO_STATUS_SUCCESS;
-
status = _pattern_has_error (source);
if (unlikely (status))
return status;
- _cairo_surface_begin_modification (surface);
-
- if (surface->backend->stroke != NULL) {
- status = surface->backend->stroke (surface, op, source,
- path, stroke_style,
- ctm, ctm_inverse,
- tolerance, antialias,
- clip);
-
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- goto FINISH;
- }
+ if (nothing_to_do (surface, op, source))
+ return CAIRO_STATUS_SUCCESS;
- status = _cairo_surface_fallback_stroke (surface, op, source,
- path, stroke_style,
- ctm, ctm_inverse,
- tolerance, antialias,
- clip);
+ _cairo_surface_begin_modification (surface);
- FINISH:
- if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
+ status = surface->backend->stroke (surface, op, source,
+ path, stroke_style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
+ if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
surface->is_clear = FALSE;
+ surface->serial++;
+ }
return _cairo_surface_set_error (surface, status);
}
cairo_status_t
-_cairo_surface_fill (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
+_cairo_surface_fill (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
{
cairo_int_status_t status;
@@ -2490,129 +1933,25 @@ _cairo_surface_fill (cairo_surface_t *surface,
if (_cairo_clip_is_all_clipped (clip))
return CAIRO_STATUS_SUCCESS;
- if (nothing_to_do (surface, op, source))
- return CAIRO_STATUS_SUCCESS;
-
status = _pattern_has_error (source);
if (unlikely (status))
return status;
- _cairo_surface_begin_modification (surface);
-
- if (surface->backend->fill != NULL) {
- status = surface->backend->fill (surface, op, source,
- path, fill_rule,
- tolerance, antialias,
- clip);
-
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- goto FINISH;
- }
+ if (nothing_to_do (surface, op, source))
+ return CAIRO_STATUS_SUCCESS;
- status = _cairo_surface_fallback_fill (surface, op, source,
- path, fill_rule,
- tolerance, antialias,
- clip);
+ _cairo_surface_begin_modification (surface);
- FINISH:
- if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
+ status = surface->backend->fill (surface, op, source,
+ path, fill_rule,
+ tolerance, antialias,
+ clip);
+ if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
surface->is_clear = FALSE;
-
- return _cairo_surface_set_error (surface, status);
-}
-
-cairo_status_t
-_cairo_surface_composite_trapezoids (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- cairo_antialias_t antialias,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps,
- cairo_region_t *clip_region)
-{
- cairo_int_status_t status;
-
- if (dst->status)
- return dst->status;
-
- assert (_cairo_surface_is_writable (dst));
-
- /* These operators aren't interpreted the same way by the backends;
- * they are implemented in terms of other operators in cairo-gstate.c
- */
- assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR);
-
- if (dst->backend->composite_trapezoids) {
- status = dst->backend->composite_trapezoids (op,
- pattern, dst,
- antialias,
- src_x, src_y,
- dst_x, dst_y,
- width, height,
- traps, num_traps,
- clip_region);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return _cairo_surface_set_error (dst, status);
- }
-
- return _cairo_surface_set_error (dst,
- _cairo_surface_fallback_composite_trapezoids (op, pattern, dst,
- antialias,
- src_x, src_y,
- dst_x, dst_y,
- width, height,
- 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_t *dst,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects,
- cairo_region_t *clip_region)
-{
- assert (dst->snapshot_of == NULL);
-
- if (unlikely (dst->status))
- return _cairo_span_renderer_create_in_error (dst->status);
-
- 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, clip_region);
+ surface->serial++;
}
- 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,
- const cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- cairo_antialias_t antialias)
-{
- assert (dst->snapshot_of == NULL);
- assert (dst->status == CAIRO_STATUS_SUCCESS);
- assert (! dst->finished);
-
- /* XXX: Currently we have no mono span renderer */
- if (antialias == CAIRO_ANTIALIAS_NONE)
- return FALSE;
-
- if (dst->backend->check_span_renderer != NULL)
- return dst->backend->check_span_renderer (op, pattern, dst, antialias);
-
- return FALSE;
+ return _cairo_surface_set_error (surface, status);
}
/**
@@ -2632,16 +1971,13 @@ _cairo_surface_check_span_renderer (cairo_operator_t op,
void
cairo_surface_copy_page (cairo_surface_t *surface)
{
- cairo_status_t status_ignored;
-
- if (surface->status)
+ if (unlikely (surface->status))
return;
assert (surface->snapshot_of == NULL);
- if (surface->finished) {
- status_ignored = _cairo_surface_set_error (surface,
- CAIRO_STATUS_SURFACE_FINISHED);
+ if (unlikely (surface->finished)) {
+ _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
return;
}
@@ -2649,8 +1985,7 @@ cairo_surface_copy_page (cairo_surface_t *surface)
if (surface->backend->copy_page == NULL)
return;
- status_ignored = _cairo_surface_set_error (surface,
- surface->backend->copy_page (surface));
+ _cairo_surface_set_error (surface, surface->backend->copy_page (surface));
}
slim_hidden_def (cairo_surface_copy_page);
@@ -2669,14 +2004,11 @@ slim_hidden_def (cairo_surface_copy_page);
void
cairo_surface_show_page (cairo_surface_t *surface)
{
- cairo_status_t status_ignored;
-
- if (surface->status)
+ if (unlikely (surface->status))
return;
- if (surface->finished) {
- status_ignored = _cairo_surface_set_error (surface,
- CAIRO_STATUS_SURFACE_FINISHED);
+ if (unlikely (surface->finished)) {
+ _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
return;
}
@@ -2686,8 +2018,7 @@ cairo_surface_show_page (cairo_surface_t *surface)
if (surface->backend->show_page == NULL)
return;
- status_ignored = _cairo_surface_set_error (surface,
- surface->backend->show_page (surface));
+ _cairo_surface_set_error (surface, surface->backend->show_page (surface));
}
slim_hidden_def (cairo_surface_show_page);
@@ -2755,14 +2086,11 @@ _cairo_surface_get_extents (cairo_surface_t *surface,
cairo_bool_t
cairo_surface_has_show_text_glyphs (cairo_surface_t *surface)
{
- cairo_status_t status_ignored;
-
- if (surface->status)
+ if (unlikely (surface->status))
return FALSE;
- if (surface->finished) {
- status_ignored = _cairo_surface_set_error (surface,
- CAIRO_STATUS_SURFACE_FINISHED);
+ if (unlikely (surface->finished)) {
+ _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
return FALSE;
}
@@ -2814,13 +2142,13 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
if (_cairo_clip_is_all_clipped (clip))
return CAIRO_STATUS_SUCCESS;
- if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
- return CAIRO_STATUS_SUCCESS;
-
status = _pattern_has_error (source);
if (unlikely (status))
return status;
+ if (nothing_to_do (surface, op, source))
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_surface_begin_modification (surface);
if (_cairo_surface_has_device_transform (surface) &&
@@ -2861,32 +2189,20 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
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,
- clip,
- &remaining_glyphs);
- glyphs += num_glyphs - remaining_glyphs;
- num_glyphs = remaining_glyphs;
- if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0)
- status = CAIRO_INT_STATUS_SUCCESS;
+ clip);
}
} else {
/* A mere show_glyphs call. Try show_glyphs backend method first */
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,
- 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;
+ clip);
} 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
@@ -2906,269 +2222,15 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
}
}
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- status = _cairo_surface_fallback_show_glyphs (surface, op,
- source,
- glyphs, num_glyphs,
- dev_scaled_font,
- clip);
- }
-
if (dev_scaled_font != scaled_font)
cairo_scaled_font_destroy (dev_scaled_font);
- if (status != CAIRO_INT_STATUS_NOTHING_TO_DO)
+ if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
surface->is_clear = FALSE;
-
- return _cairo_surface_set_error (surface, status);
-}
-
-/* XXX: Previously, we had a function named _cairo_surface_show_glyphs
- * with not-so-useful semantics. We've now got a
- * _cairo_surface_show_text_glyphs with the proper semantics, and its
- * fallback still uses this old function (which still needs to be
- * cleaned up in terms of both semantics and naming). */
-cairo_status_t
-_cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- 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)
-{
- if (unlikely (dst->status))
- return dst->status;
-
- assert (_cairo_surface_is_writable (dst));
-
- if (dst->backend->old_show_glyphs == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- return _cairo_surface_set_error
- (dst, dst->backend->old_show_glyphs (scaled_font,
- op, pattern, dst,
- source_x, source_y,
- dest_x, dest_y,
- width, height,
- glyphs, num_glyphs,
- clip_region));
-}
-
-static cairo_status_t
-_cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst,
- cairo_rectangle_int_t *src_rectangle,
- cairo_rectangle_int_t *mask_rectangle,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_region_t *clip_region)
-{
- cairo_rectangle_int_t dst_rectangle;
- cairo_region_t clear_region;
- cairo_status_t status;
-
- /* The area that was drawn is the area in the destination rectangle but
- * not within the source or the mask.
- */
- dst_rectangle.x = dst_x;
- dst_rectangle.y = dst_y;
- dst_rectangle.width = width;
- dst_rectangle.height = height;
-
- _cairo_region_init_rectangle (&clear_region, &dst_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 != NULL) {
- if (! _cairo_rectangle_intersect (&dst_rectangle, mask_rectangle))
- goto EMPTY;
- }
-
- /* Now compute the area that is in dst but not drawn */
- status = cairo_region_subtract_rectangle (&clear_region, &dst_rectangle);
- if (unlikely (status) || cairo_region_is_empty (&clear_region))
- goto CLEANUP_REGIONS;
-
- EMPTY:
- status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
- CAIRO_COLOR_TRANSPARENT,
- &clear_region);
-
- CLEANUP_REGIONS:
- _cairo_region_fini (&clear_region);
-
- return _cairo_surface_set_error (dst, status);
-}
-
-/**
- * _cairo_surface_composite_fixup_unbounded:
- * @dst: the destination surface
- * @src_attr: source surface attributes (from _cairo_pattern_acquire_surface())
- * @src_width: width of source surface
- * @src_height: height of source surface
- * @mask_attr: mask surface attributes or %NULL if no mask
- * @mask_width: width of mask surface
- * @mask_height: height of mask surface
- * @src_x: @src_x from _cairo_surface_composite()
- * @src_y: @src_y from _cairo_surface_composite()
- * @mask_x: @mask_x from _cairo_surface_composite()
- * @mask_y: @mask_y from _cairo_surface_composite()
- * @dst_x: @dst_x from _cairo_surface_composite()
- * @dst_y: @dst_y from _cairo_surface_composite()
- * @width: @width from _cairo_surface_composite()
- * @height: @height_x from _cairo_surface_composite()
- *
- * Eeek! Too many parameters! This is a helper function to take care of fixing
- * up for bugs in libpixman and RENDER where, when asked to composite an
- * untransformed surface with an unbounded operator (like CLEAR or SOURCE)
- * only the region inside both the source and the mask is affected.
- * This function clears the region that should have been drawn but was wasn't.
- **/
-cairo_status_t
-_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
- cairo_surface_attributes_t *src_attr,
- int src_width,
- int src_height,
- cairo_surface_attributes_t *mask_attr,
- int mask_width,
- int mask_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_rectangle_int_t src_tmp, mask_tmp;
- cairo_rectangle_int_t *src_rectangle = NULL;
- cairo_rectangle_int_t *mask_rectangle = NULL;
-
- if (unlikely (dst->status))
- return dst->status;
-
- assert (_cairo_surface_is_writable (dst));
-
- /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
- * non-repeating sources and masks. Other sources and masks can be ignored.
- */
- if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
- src_attr->extend == CAIRO_EXTEND_NONE)
- {
- src_tmp.x = (dst_x - (src_x + src_attr->x_offset));
- src_tmp.y = (dst_y - (src_y + src_attr->y_offset));
- src_tmp.width = src_width;
- src_tmp.height = src_height;
-
- src_rectangle = &src_tmp;
- }
-
- if (mask_attr &&
- _cairo_matrix_is_integer_translation (&mask_attr->matrix, NULL, NULL) &&
- mask_attr->extend == CAIRO_EXTEND_NONE)
- {
- mask_tmp.x = (dst_x - (mask_x + mask_attr->x_offset));
- mask_tmp.y = (dst_y - (mask_y + mask_attr->y_offset));
- mask_tmp.width = mask_width;
- mask_tmp.height = mask_height;
-
- mask_rectangle = &mask_tmp;
+ surface->serial++;
}
- return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle,
- dst_x, dst_y, width, height,
- clip_region);
-}
-
-/**
- * _cairo_surface_composite_shape_fixup_unbounded:
- * @dst: the destination surface
- * @src_attr: source surface attributes (from _cairo_pattern_acquire_surface())
- * @src_width: width of source surface
- * @src_height: height of source surface
- * @mask_width: width of mask surface
- * @mask_height: height of mask surface
- * @src_x: @src_x from _cairo_surface_composite()
- * @src_y: @src_y from _cairo_surface_composite()
- * @mask_x: @mask_x from _cairo_surface_composite()
- * @mask_y: @mask_y from _cairo_surface_composite()
- * @dst_x: @dst_x from _cairo_surface_composite()
- * @dst_y: @dst_y from _cairo_surface_composite()
- * @width: @width from _cairo_surface_composite()
- * @height: @height_x from _cairo_surface_composite()
- *
- * Like _cairo_surface_composite_fixup_unbounded(), but instead of
- * handling the case where we have a source pattern and a mask
- * pattern, handle the case where we are compositing a source pattern
- * using a mask we create ourselves, as in
- * _cairo_surface_composite_glyphs() or _cairo_surface_composite_trapezoids()
- **/
-cairo_status_t
-_cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
- cairo_surface_attributes_t *src_attr,
- int src_width,
- int src_height,
- int mask_width,
- int mask_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_rectangle_int_t src_tmp, *src= NULL;
- cairo_rectangle_int_t mask;
-
- if (dst->status)
- return dst->status;
-
- assert (_cairo_surface_is_writable (dst));
-
- /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
- * non-repeating sources and masks. Other sources and masks can be ignored.
- */
- if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
- src_attr->extend == CAIRO_EXTEND_NONE)
- {
- src_tmp.x = (dst_x - (src_x + src_attr->x_offset));
- src_tmp.y = (dst_y - (src_y + src_attr->y_offset));
- src_tmp.width = src_width;
- src_tmp.height = src_height;
-
- src = &src_tmp;
- }
-
- mask.x = dst_x - mask_x;
- mask.y = dst_y - mask_y;
- mask.width = mask_width;
- mask.height = mask_height;
-
- return _cairo_surface_composite_fixup_unbounded_internal (dst, src, &mask,
- dst_x, dst_y, width, height,
- clip_region);
+ return _cairo_surface_set_error (surface, status);
}
/**
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 2cf91eab..6f607d3c 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -41,7 +41,10 @@
#define _BSD_SOURCE /* for snprintf() */
#include "cairoint.h"
+
#include "cairo-svg.h"
+
+#include "cairo-array-private.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
@@ -2474,8 +2477,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs)
+ const cairo_clip_t *clip)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_svg_document_t *document = surface->document;
@@ -2587,31 +2589,23 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = {
NULL, /* acquire_source_image */
NULL, /* release_source_image */
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* _cairo_svg_surface_composite, */
- NULL, /* _cairo_svg_surface_fill_rectangles, */
- NULL, /* _cairo_svg_surface_composite_trapezoids,*/
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ NULL, /* snapshot */
+
_cairo_svg_surface_copy_page,
_cairo_svg_surface_show_page,
+
_cairo_svg_surface_get_extents,
- NULL, /* _cairo_svg_surface_old_show_glyphs, */
_cairo_svg_surface_get_font_options,
+
NULL, /* flush */
NULL, /* mark dirty rectangle */
- NULL, /* scaled font fini */
- NULL, /* scaled glyph fini */
+
_cairo_svg_surface_paint,
_cairo_svg_surface_mask,
_cairo_svg_surface_stroke,
_cairo_svg_surface_fill,
+ _cairo_svg_surface_fill_stroke,
_cairo_svg_surface_show_glyphs,
- NULL, /* snapshot */
- NULL, /* is_similar */
- _cairo_svg_surface_fill_stroke
};
static cairo_status_t
diff --git a/src/cairo-time-private.h b/src/cairo-time-private.h
index f7c48f38..06dc912b 100644
--- a/src/cairo-time-private.h
+++ b/src/cairo-time-private.h
@@ -33,15 +33,16 @@
#include "cairo-compiler-private.h"
#include "cairo-wideint-private.h"
-typedef cairo_uint64_t cairo_time_t;
+/* Make the base type signed for easier arithmetic */
+typedef cairo_int64_t cairo_time_t;
-#define _cairo_time_add _cairo_uint64_add
-#define _cairo_time_sub _cairo_uint64_sub
-#define _cairo_time_gt _cairo_uint64_gt
-#define _cairo_time_lt _cairo_uint64_lt
+#define _cairo_time_add _cairo_int64_add
+#define _cairo_time_sub _cairo_int64_sub
+#define _cairo_time_gt _cairo_int64_gt
+#define _cairo_time_lt _cairo_int64_lt
-#define _cairo_time_to_double _cairo_uint64_to_double
-#define _cairo_time_from_double _cairo_double_to_uint64
+#define _cairo_time_to_double _cairo_int64_to_double
+#define _cairo_time_from_double _cairo_double_to_int64
cairo_private int
_cairo_time_cmp (const void *a,
@@ -75,7 +76,7 @@ _cairo_time_to_ns (cairo_time_t t)
static cairo_always_inline cairo_time_t
_cairo_time_max (cairo_time_t a, cairo_time_t b)
{
- if (_cairo_uint64_gt (a, b))
+ if (_cairo_int64_gt (a, b))
return a;
else
return b;
@@ -84,7 +85,7 @@ _cairo_time_max (cairo_time_t a, cairo_time_t b)
static cairo_always_inline cairo_time_t
_cairo_time_min (cairo_time_t a, cairo_time_t b)
{
- if (_cairo_uint64_lt (a, b))
+ if (_cairo_int64_lt (a, b))
return a;
else
return b;
diff --git a/src/cairo-time.c b/src/cairo-time.c
index 32749f5f..9a594e8e 100644
--- a/src/cairo-time.c
+++ b/src/cairo-time.c
@@ -34,7 +34,7 @@
#include "cairo-time-private.h"
-#if HAVE_CLOCKGETTIME
+#if HAVE_CLOCK_GETTIME
#if defined(CLOCK_MONOTONIC_RAW)
#define CAIRO_CLOCK CLOCK_MONOTONIC_RAW
#elif defined(CLOCK_MONOTONIC)
@@ -79,12 +79,12 @@ cairo_time_t
_cairo_time_get (void)
{
QWORD t;
- cairo_uint64_t r;
+ cairo_int64_t r;
DosTmrQueryTime (&t);
- r = _cairo_uint64_lsl (_cairo_uint32_to_uint64 (t.ulHi), 32);
- r = _cairo_uint64_add (r, _cairo_uint32_to_uint64 (t.ulLo));
+ r = _cairo_int64_lsl (_cairo_int32_to_int64 (t.ulHi), 32);
+ r = _cairo_int64_add (r, _cairo_int32_to_int64 (t.ulLo));
return r;
}
@@ -130,9 +130,9 @@ _cairo_time_get (void)
clock_gettime (CAIRO_CLOCK, &t);
- r = _cairo_double_to_uint64 (_cairo_time_1s ());
- r = _cairo_uint64_mul (r, _cairo_uint32_to_uint64 (t.tv_sec));
- r = _cairo_uint64_add (r, _cairo_uint32_to_uint64 (t.tv_nsec));
+ r = _cairo_double_to_int64 (_cairo_time_1s ());
+ r = _cairo_int64_mul (r, _cairo_int32_to_int64 (t.tv_sec));
+ r = _cairo_int64_add (r, _cairo_int32_to_int64 (t.tv_nsec));
return r;
}
@@ -154,9 +154,9 @@ _cairo_time_get (void)
gettimeofday (&t, NULL);
- r = _cairo_double_to_uint64 (_cairo_time_1s ());
- r = _cairo_uint64_mul (r, _cairo_uint32_to_uint64 (t.tv_sec));
- r = _cairo_uint64_add (r, _cairo_uint32_to_uint64 (t.tv_usec));
+ r = _cairo_double_to_int64 (_cairo_time_1s ());
+ r = _cairo_int64_mul (r, _cairo_int32_to_int64 (t.tv_sec));
+ r = _cairo_int64_add (r, _cairo_int32_to_int64 (t.tv_usec));
return r;
}
@@ -167,17 +167,8 @@ int
_cairo_time_cmp (const void *a,
const void *b)
{
- const cairo_time_t *ta, *tb;
-
- ta = a;
- tb = b;
-
- if (_cairo_time_gt (*ta, *tb))
- return 1;
- else if (_cairo_time_lt (*ta, *tb))
- return -1;
- else
- return 0;
+ const cairo_time_t *ta = a, *tb = b;
+ return _cairo_int64_cmp (*ta, *tb);
}
static double
@@ -205,11 +196,11 @@ _cairo_time_s_per_tick (void)
double
_cairo_time_to_s (cairo_time_t t)
{
- return _cairo_uint64_to_double (t) * _cairo_time_s_per_tick ();
+ return _cairo_int64_to_double (t) * _cairo_time_s_per_tick ();
}
cairo_time_t
_cairo_time_from_s (double t)
{
- return _cairo_double_to_uint64 (t * _cairo_time_ticks_per_sec ());
+ return _cairo_double_to_int64 (t * _cairo_time_ticks_per_sec ());
}
diff --git a/src/cairo-tor-scan-converter.c b/src/cairo-tor-scan-converter.c
index d571f6e6..b001bbd6 100644
--- a/src/cairo-tor-scan-converter.c
+++ b/src/cairo-tor-scan-converter.c
@@ -115,8 +115,10 @@ typedef cairo_status_t glitter_status_t;
/* The input coordinate scale and the rasterisation grid scales. */
#define GLITTER_INPUT_BITS CAIRO_FIXED_FRAC_BITS
-#define GRID_X_BITS CAIRO_FIXED_FRAC_BITS
-#define GRID_Y 15
+//#define GRID_X_BITS CAIRO_FIXED_FRAC_BITS
+//#define GRID_Y 15
+#define GRID_X_BITS 2
+#define GRID_Y_BITS 2
/* Set glitter up to use a cairo span renderer to do the coverage
* blitting. */
@@ -163,15 +165,6 @@ glitter_scan_converter_reset(
int xmin, int ymin,
int xmax, int ymax);
-/* Add a new polygon edge from pixel (x1,y1) to (x2,y2) to the scan
- * converter. The coordinates represent pixel positions scaled by
- * 2**GLITTER_PIXEL_BITS. If this function fails then the scan
- * converter should be reset or destroyed. Dir must be +1 or -1,
- * with the latter reversing the orientation of the edge. */
-I void
-glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
- const cairo_edge_t *edge);
-
/* Render the polygon in the scan converter to the given A8 format
* image raster. Only the pixels accessible as pixels[y*stride+x] for
* x,y inside the clip box are written to, where xmin <= x < xmax,
@@ -348,10 +341,7 @@ struct edge {
grid_scaled_y_t dy;
};
-/* Number of subsample rows per y-bucket. Must be GRID_Y. */
-#define EDGE_Y_BUCKET_HEIGHT GRID_Y
-
-#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/EDGE_Y_BUCKET_HEIGHT)
+#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/GRID_Y)
/* A collection of sorted and vertically clipped edges of the polygon.
* Edges are moved from the polygon to an active list while scan
@@ -707,16 +697,14 @@ cell_list_find (struct cell_list *cells, int x)
{
struct cell *tail = cells->cursor;
- assert (x >= tail->x);
-
if (tail->x == x)
return tail;
while (1) {
UNROLL3({
- if (tail->next->x > x)
- break;
- tail = tail->next;
+ if (tail->next->x > x)
+ break;
+ tail = tail->next;
});
}
@@ -738,15 +726,12 @@ cell_list_find_pair(struct cell_list *cells, int x1, int x2)
{
struct cell_pair pair;
- assert (x2 > x1);
- assert (x1 >= cells->cursor->x);
-
pair.cell1 = cells->cursor;
while (1) {
UNROLL3({
- if (pair.cell1->next->x > x1)
- break;
- pair.cell1 = pair.cell1->next;
+ if (pair.cell1->next->x > x1)
+ break;
+ pair.cell1 = pair.cell1->next;
});
}
if (pair.cell1->x != x1)
@@ -755,9 +740,9 @@ cell_list_find_pair(struct cell_list *cells, int x1, int x2)
pair.cell2 = pair.cell1;
while (1) {
UNROLL3({
- if (pair.cell2->next->x > x2)
- break;
- pair.cell2 = pair.cell2->next;
+ if (pair.cell2->next->x > x2)
+ break;
+ pair.cell2 = pair.cell2->next;
});
}
if (pair.cell2->x != x2)
@@ -954,12 +939,11 @@ polygon_reset (struct polygon *polygon,
grid_scaled_y_t ymax)
{
unsigned h = ymax - ymin;
- unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + EDGE_Y_BUCKET_HEIGHT-1,
- ymin);
+ unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + GRID_Y-1, ymin);
pool_reset(polygon->edge_pool.base);
- if (unlikely (h > 0x7FFFFFFFU - EDGE_Y_BUCKET_HEIGHT))
+ if (unlikely (h > 0x7FFFFFFFU - GRID_Y))
goto bail_no_mem; /* even if you could, you wouldn't want to. */
if (polygon->y_buckets != polygon->y_buckets_embedded)
@@ -978,16 +962,15 @@ polygon_reset (struct polygon *polygon,
polygon->ymax = ymax;
return GLITTER_STATUS_SUCCESS;
- bail_no_mem:
+bail_no_mem:
polygon->ymin = 0;
polygon->ymax = 0;
return GLITTER_STATUS_NO_MEMORY;
}
static void
-_polygon_insert_edge_into_its_y_bucket(
- struct polygon *polygon,
- struct edge *e)
+_polygon_insert_edge_into_its_y_bucket(struct polygon *polygon,
+ struct edge *e)
{
unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin);
struct edge **ptail = &polygon->y_buckets[ix];
@@ -1191,7 +1174,7 @@ sort_edges (struct edge *list,
return remaining;
}
-static struct edge *
+ static struct edge *
merge_unsorted_edges (struct edge *head, struct edge *unsorted)
{
sort_edges (unsorted, UINT_MAX, &unsorted);
@@ -1283,47 +1266,6 @@ polygon_fill_buckets (struct active_list *active,
active->min_height = min_height;
}
-/* Advance the edges on the active list by one subsample row by
- * updating their x positions. Drop edges from the list that end. */
-inline static void
-active_list_substep_edges(struct active_list *active)
-{
- grid_scaled_x_t prev_x = INT_MIN;
- struct edge *edge = active->head.next;
-
- while (edge != &active->tail) {
- struct edge *next = edge->next;
-
- if (--edge->height_left) {
- edge->x.quo += edge->dxdy.quo;
- edge->x.rem += edge->dxdy.rem;
- if (edge->x.rem >= 0) {
- ++edge->x.quo;
- edge->x.rem -= edge->dy;
- }
-
- if (edge->x.quo < prev_x) {
- struct edge *pos = edge->prev;
- pos->next = next;
- next->prev = pos;
- do {
- pos = pos->prev;
- } while (edge->x.quo < pos->x.quo);
- pos->next->prev = edge;
- edge->next = pos->next;
- edge->prev = pos;
- pos->next = edge;
- } else
- prev_x = edge->x.quo;
- } else {
- edge->prev->next = next;
- next->prev = edge->prev;
- }
-
- edge = next;
- }
-}
-
inline static void
sub_row (struct active_list *active,
struct cell_list *coverages,
@@ -1481,9 +1423,9 @@ int_to_grid_scaled(int i, int scale)
I glitter_status_t
glitter_scan_converter_reset(
- glitter_scan_converter_t *converter,
- int xmin, int ymin,
- int xmax, int ymax)
+ glitter_scan_converter_t *converter,
+ int xmin, int ymin,
+ int xmax, int ymax)
{
glitter_status_t status;
@@ -1536,11 +1478,16 @@ glitter_scan_converter_reset(
#endif
#define INPUT_TO_GRID_general(in, out, grid_scale) do { \
- long long tmp__ = (long long)(grid_scale) * (in); \
- tmp__ >>= GLITTER_INPUT_BITS; \
- (out) = tmp__; \
+ long long tmp__ = (long long)(grid_scale) * (in); \
+ tmp__ >>= GLITTER_INPUT_BITS; \
+ (out) = tmp__; \
} while (0)
+/* Add a new polygon edge from pixel (x1,y1) to (x2,y2) to the scan
+ * converter. The coordinates represent pixel positions scaled by
+ * 2**GLITTER_PIXEL_BITS. If this function fails then the scan
+ * converter should be reset or destroyed. Dir must be +1 or -1,
+ * with the latter reversing the orientation of the edge. */
I void
glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
const cairo_edge_t *edge)
@@ -1566,18 +1513,6 @@ glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
polygon_add_edge (converter->polygon, &e);
}
-#ifndef GLITTER_BLIT_COVERAGES_BEGIN
-# define GLITTER_BLIT_COVERAGES_BEGIN
-#endif
-
-#ifndef GLITTER_BLIT_COVERAGES_END
-# define GLITTER_BLIT_COVERAGES_END
-#endif
-
-#ifndef GLITTER_BLIT_COVERAGES_EMPTY
-# define GLITTER_BLIT_COVERAGES_EMPTY(y0, y1, xmin, xmax)
-#endif
-
static void
step_edges (struct active_list *active, int count)
{
@@ -1594,11 +1529,11 @@ step_edges (struct active_list *active, int count)
}
static glitter_status_t
-blit (struct cell_list *cells,
- cairo_span_renderer_t *renderer,
- cairo_half_open_span_t *spans,
- int y, int height,
- int xmin, int xmax)
+blit_a8 (struct cell_list *cells,
+ cairo_span_renderer_t *renderer,
+ cairo_half_open_span_t *spans,
+ int y, int height,
+ int xmin, int xmax)
{
struct cell *cell = cells->head.next;
int prev_x = xmin, last_x = -1;
@@ -1661,10 +1596,80 @@ blit (struct cell_list *cells,
return renderer->render_rows (renderer, y, height, spans, num_spans);
}
+#define GRID_AREA_TO_A1(A) ((GRID_AREA_TO_ALPHA (A) > 127) ? 255 : 0)
+static glitter_status_t
+blit_a1 (struct cell_list *cells,
+ cairo_span_renderer_t *renderer,
+ cairo_half_open_span_t *spans,
+ int y, int height,
+ int xmin, int xmax)
+{
+ struct cell *cell = cells->head.next;
+ int prev_x = xmin, last_x = -1;
+ int16_t cover = 0;
+ uint8_t coverage, last_cover = 0;
+ unsigned num_spans;
+
+ if (cell == &cells->tail)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* Skip cells to the left of the clip region. */
+ while (cell->x < xmin) {
+ cover += cell->covered_height;
+ cell = cell->next;
+ }
+ cover *= GRID_X*2;
+
+ /* Form the spans from the coverages and areas. */
+ num_spans = 0;
+ for (; cell->x < xmax; cell = cell->next) {
+ int x = cell->x;
+ int16_t area;
+
+ coverage = GRID_AREA_TO_A1 (cover);
+ if (x > prev_x && coverage != last_cover) {
+ last_x = spans[num_spans].x = prev_x;
+ last_cover = spans[num_spans].coverage = coverage;
+ ++num_spans;
+ }
+
+ cover += cell->covered_height*GRID_X*2;
+ area = cover - cell->uncovered_area;
+
+ coverage = GRID_AREA_TO_A1 (area);
+ if (coverage != last_cover) {
+ last_x = spans[num_spans].x = x;
+ last_cover = spans[num_spans].coverage = coverage;
+ ++num_spans;
+ }
+
+ prev_x = x+1;
+ }
+
+ coverage = GRID_AREA_TO_A1 (cover);
+ if (prev_x <= xmax && coverage != last_cover) {
+ last_x = spans[num_spans].x = prev_x;
+ last_cover = spans[num_spans].coverage = coverage;
+ ++num_spans;
+ }
+
+ if (last_x < xmax && last_cover) {
+ spans[num_spans].x = xmax;
+ spans[num_spans].coverage = 0;
+ ++num_spans;
+ }
+ if (num_spans == 1)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* Dump them into the renderer. */
+ return renderer->render_rows (renderer, y, height, spans, num_spans);
+}
+
I void
glitter_scan_converter_render(glitter_scan_converter_t *converter,
unsigned int winding_mask,
+ int antialias,
cairo_span_renderer_t *renderer)
{
int i, j;
@@ -1682,9 +1687,6 @@ glitter_scan_converter_render(glitter_scan_converter_t *converter,
if (xmin_i >= xmax_i)
return;
- /* Let the coverage blitter initialise itself. */
- GLITTER_BLIT_COVERAGES_BEGIN;
-
/* Render each pixel row. */
for (i = 0; i < h; i = j) {
int do_full_row = 0;
@@ -1693,13 +1695,12 @@ glitter_scan_converter_render(glitter_scan_converter_t *converter,
/* Determine if we can ignore this row or use the full pixel
* stepper. */
- if (GRID_Y == EDGE_Y_BUCKET_HEIGHT && ! polygon->y_buckets[i]) {
+ if (! polygon->y_buckets[i]) {
if (active->head.next == &active->tail) {
active->min_height = INT_MAX;
active->is_vertical = 1;
for (; j < h && ! polygon->y_buckets[j]; j++)
;
- GLITTER_BLIT_COVERAGES_EMPTY (i+ymin_i, j-i, xmin_i, xmax_i);
continue;
}
@@ -1740,15 +1741,16 @@ glitter_scan_converter_render(glitter_scan_converter_t *converter,
}
}
- blit (coverages, renderer, converter->spans,
- i+ymin_i, j-i, xmin_i, xmax_i);
+ if (antialias)
+ blit_a8 (coverages, renderer, converter->spans,
+ i+ymin_i, j-i, xmin_i, xmax_i);
+ else
+ blit_a1 (coverages, renderer, converter->spans,
+ i+ymin_i, j-i, xmin_i, xmax_i);
cell_list_reset (coverages);
active->min_height -= GRID_Y;
}
-
- /* Clean up the coverage blitter. */
- GLITTER_BLIT_COVERAGES_END;
}
struct _cairo_tor_scan_converter {
@@ -1756,6 +1758,7 @@ struct _cairo_tor_scan_converter {
glitter_scan_converter_t converter[1];
cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
jmp_buf jmp;
};
@@ -1773,36 +1776,21 @@ _cairo_tor_scan_converter_destroy (void *converter)
free(self);
}
-static cairo_status_t
-_cairo_tor_scan_converter_add_edge (void *converter,
- const cairo_point_t *p1,
- const cairo_point_t *p2,
- int top, int bottom,
- int dir)
-{
- cairo_tor_scan_converter_t *self = converter;
- cairo_edge_t edge;
-
- edge.line.p1 = *p1;
- edge.line.p2 = *p2;
- edge.top = top;
- edge.bottom = bottom;
- edge.dir = dir;
-
- glitter_scan_converter_add_edge (self->converter, &edge);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
+cairo_status_t
_cairo_tor_scan_converter_add_polygon (void *converter,
const cairo_polygon_t *polygon)
{
cairo_tor_scan_converter_t *self = converter;
int i;
+#if 0
+ FILE *file = fopen ("polygon.txt", "w");
+ _cairo_debug_print_polygon (file, polygon);
+ fclose (file);
+#endif
+
for (i = 0; i < polygon->num_edges; i++)
- glitter_scan_converter_add_edge (self->converter,
- &polygon->edges[i]);
+ glitter_scan_converter_add_edge (self->converter, &polygon->edges[i]);
return CAIRO_STATUS_SUCCESS;
}
@@ -1819,6 +1807,7 @@ _cairo_tor_scan_converter_generate (void *converter,
glitter_scan_converter_render (self->converter,
self->fill_rule == CAIRO_FILL_RULE_WINDING ? ~0 : 1,
+ self->antialias != CAIRO_ANTIALIAS_NONE,
renderer);
return CAIRO_STATUS_SUCCESS;
}
@@ -1828,20 +1817,19 @@ _cairo_tor_scan_converter_create (int xmin,
int ymin,
int xmax,
int ymax,
- cairo_fill_rule_t fill_rule)
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias)
{
cairo_tor_scan_converter_t *self;
cairo_status_t status;
- self = calloc (1, sizeof(struct _cairo_tor_scan_converter));
+ self = malloc (sizeof(struct _cairo_tor_scan_converter));
if (unlikely (self == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto bail_nomem;
}
self->base.destroy = _cairo_tor_scan_converter_destroy;
- self->base.add_edge = _cairo_tor_scan_converter_add_edge;
- self->base.add_polygon = _cairo_tor_scan_converter_add_polygon;
self->base.generate = _cairo_tor_scan_converter_generate;
_glitter_scan_converter_init (self->converter, &self->jmp);
@@ -1851,6 +1839,7 @@ _cairo_tor_scan_converter_create (int xmin,
goto bail;
self->fill_rule = fill_rule;
+ self->antialias = antialias;
return &self->base;
diff --git a/src/cairo-tor22-scan-converter.c b/src/cairo-tor22-scan-converter.c
new file mode 100644
index 00000000..2f930306
--- /dev/null
+++ b/src/cairo-tor22-scan-converter.c
@@ -0,0 +1,1707 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* glitter-paths - polygon scan converter
+ *
+ * Copyright (c) 2008 M Joonas Pihlaja
+ * Copyright (c) 2007 David Turner
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+/* This is the Glitter paths scan converter incorporated into cairo.
+ * The source is from commit 734c53237a867a773640bd5b64816249fa1730f8
+ * of
+ *
+ * http://gitweb.freedesktop.org/?p=users/joonas/glitter-paths
+ */
+/* Glitter-paths is a stand alone polygon rasteriser derived from
+ * David Turner's reimplementation of Tor Anderssons's 15x17
+ * supersampling rasteriser from the Apparition graphics library. The
+ * main new feature here is cheaply choosing per-scan line between
+ * doing fully analytical coverage computation for an entire row at a
+ * time vs. using a supersampling approach.
+ *
+ * David Turner's code can be found at
+ *
+ * http://david.freetype.org/rasterizer-shootout/raster-comparison-20070813.tar.bz2
+ *
+ * In particular this file incorporates large parts of ftgrays_tor10.h
+ * from raster-comparison-20070813.tar.bz2
+ */
+/* Overview
+ *
+ * A scan converter's basic purpose to take polygon edges and convert
+ * them into an RLE compressed A8 mask. This one works in two phases:
+ * gathering edges and generating spans.
+ *
+ * 1) As the user feeds the scan converter edges they are vertically
+ * clipped and bucketted into a _polygon_ data structure. The edges
+ * are also snapped from the user's coordinates to the subpixel grid
+ * coordinates used during scan conversion.
+ *
+ * user
+ * |
+ * | edges
+ * V
+ * polygon buckets
+ *
+ * 2) Generating spans works by performing a vertical sweep of pixel
+ * rows from top to bottom and maintaining an _active_list_ of edges
+ * that intersect the row. From the active list the fill rule
+ * determines which edges are the left and right edges of the start of
+ * each span, and their contribution is then accumulated into a pixel
+ * coverage list (_cell_list_) as coverage deltas. Once the coverage
+ * deltas of all edges are known we can form spans of constant pixel
+ * coverage by summing the deltas during a traversal of the cell list.
+ * At the end of a pixel row the cell list is sent to a coverage
+ * blitter for rendering to some target surface.
+ *
+ * The pixel coverages are computed by either supersampling the row
+ * and box filtering a mono rasterisation, or by computing the exact
+ * coverages of edges in the active list. The supersampling method is
+ * used whenever some edge starts or stops within the row or there are
+ * edge intersections in the row.
+ *
+ * polygon bucket for \
+ * current pixel row |
+ * | |
+ * | activate new edges | Repeat GRID_Y times if we
+ * V \ are supersampling this row,
+ * active list / or just once if we're computing
+ * | | analytical coverage.
+ * | coverage deltas |
+ * V |
+ * pixel coverage list /
+ * |
+ * V
+ * coverage blitter
+ */
+#include "cairoint.h"
+#include "cairo-spans-private.h"
+#include "cairo-error-private.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <setjmp.h>
+
+/*-------------------------------------------------------------------------
+ * cairo specific config
+ */
+#define I static
+
+/* Prefer cairo's status type. */
+#define GLITTER_HAVE_STATUS_T 1
+#define GLITTER_STATUS_SUCCESS CAIRO_STATUS_SUCCESS
+#define GLITTER_STATUS_NO_MEMORY CAIRO_STATUS_NO_MEMORY
+typedef cairo_status_t glitter_status_t;
+
+/* The input coordinate scale and the rasterisation grid scales. */
+#define GLITTER_INPUT_BITS CAIRO_FIXED_FRAC_BITS
+//#define GRID_X_BITS CAIRO_FIXED_FRAC_BITS
+//#define GRID_Y 15
+#define GRID_X_BITS 2
+#define GRID_Y_BITS 2
+
+/* Set glitter up to use a cairo span renderer to do the coverage
+ * blitting. */
+struct pool;
+struct cell_list;
+
+/*-------------------------------------------------------------------------
+ * glitter-paths.h
+ */
+
+/* "Input scaled" numbers are fixed precision reals with multiplier
+ * 2**GLITTER_INPUT_BITS. Input coordinates are given to glitter as
+ * pixel scaled numbers. These get converted to the internal grid
+ * scaled numbers as soon as possible. Internal overflow is possible
+ * if GRID_X/Y inside glitter-paths.c is larger than
+ * 1<<GLITTER_INPUT_BITS. */
+#ifndef GLITTER_INPUT_BITS
+# define GLITTER_INPUT_BITS 8
+#endif
+#define GLITTER_INPUT_SCALE (1<<GLITTER_INPUT_BITS)
+typedef int glitter_input_scaled_t;
+
+#if !GLITTER_HAVE_STATUS_T
+typedef enum {
+ GLITTER_STATUS_SUCCESS = 0,
+ GLITTER_STATUS_NO_MEMORY
+} glitter_status_t;
+#endif
+
+#ifndef I
+# define I /*static*/
+#endif
+
+/* Opaque type for scan converting. */
+typedef struct glitter_scan_converter glitter_scan_converter_t;
+
+/* Reset a scan converter to accept polygon edges and set the clip box
+ * in pixels. Allocates O(ymax-ymin) bytes of memory. The clip box
+ * is set to integer pixel coordinates xmin <= x < xmax, ymin <= y <
+ * ymax. */
+I glitter_status_t
+glitter_scan_converter_reset(
+ glitter_scan_converter_t *converter,
+ int xmin, int ymin,
+ int xmax, int ymax);
+
+/* Render the polygon in the scan converter to the given A8 format
+ * image raster. Only the pixels accessible as pixels[y*stride+x] for
+ * x,y inside the clip box are written to, where xmin <= x < xmax,
+ * ymin <= y < ymax. The image is assumed to be clear on input.
+ *
+ * If nonzero_fill is true then the interior of the polygon is
+ * computed with the non-zero fill rule. Otherwise the even-odd fill
+ * rule is used.
+ *
+ * The scan converter must be reset or destroyed after this call. */
+
+/*-------------------------------------------------------------------------
+ * glitter-paths.c: Implementation internal types
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+/* All polygon coordinates are snapped onto a subsample grid. "Grid
+ * scaled" numbers are fixed precision reals with multiplier GRID_X or
+ * GRID_Y. */
+typedef int grid_scaled_t;
+typedef int grid_scaled_x_t;
+typedef int grid_scaled_y_t;
+
+/* Default x/y scale factors.
+ * You can either define GRID_X/Y_BITS to get a power-of-two scale
+ * or define GRID_X/Y separately. */
+#if !defined(GRID_X) && !defined(GRID_X_BITS)
+# define GRID_X_BITS 8
+#endif
+#if !defined(GRID_Y) && !defined(GRID_Y_BITS)
+# define GRID_Y 15
+#endif
+
+/* Use GRID_X/Y_BITS to define GRID_X/Y if they're available. */
+#ifdef GRID_X_BITS
+# define GRID_X (1 << GRID_X_BITS)
+#endif
+#ifdef GRID_Y_BITS
+# define GRID_Y (1 << GRID_Y_BITS)
+#endif
+
+/* The GRID_X_TO_INT_FRAC macro splits a grid scaled coordinate into
+ * integer and fractional parts. The integer part is floored. */
+#if defined(GRID_X_TO_INT_FRAC)
+ /* do nothing */
+#elif defined(GRID_X_BITS)
+# define GRID_X_TO_INT_FRAC(x, i, f) \
+ _GRID_TO_INT_FRAC_shift(x, i, f, GRID_X_BITS)
+#else
+# define GRID_X_TO_INT_FRAC(x, i, f) \
+ _GRID_TO_INT_FRAC_general(x, i, f, GRID_X)
+#endif
+
+#define _GRID_TO_INT_FRAC_general(t, i, f, m) do { \
+ (i) = (t) / (m); \
+ (f) = (t) % (m); \
+ if ((f) < 0) { \
+ --(i); \
+ (f) += (m); \
+ } \
+} while (0)
+
+#define _GRID_TO_INT_FRAC_shift(t, i, f, b) do { \
+ (f) = (t) & ((1 << (b)) - 1); \
+ (i) = (t) >> (b); \
+} while (0)
+
+/* A grid area is a real in [0,1] scaled by 2*GRID_X*GRID_Y. We want
+ * to be able to represent exactly areas of subpixel trapezoids whose
+ * vertices are given in grid scaled coordinates. The scale factor
+ * comes from needing to accurately represent the area 0.5*dx*dy of a
+ * triangle with base dx and height dy in grid scaled numbers. */
+#define GRID_XY (2*GRID_X*GRID_Y) /* Unit area on the grid. */
+
+/* GRID_AREA_TO_ALPHA(area): map [0,GRID_XY] to [0,255]. */
+#if GRID_XY == 510
+# define GRID_AREA_TO_ALPHA(c) (((c)+1) >> 1)
+#elif GRID_XY == 255
+# define GRID_AREA_TO_ALPHA(c) (c)
+#elif GRID_XY == 64
+# define GRID_AREA_TO_ALPHA(c) (((c) << 2) | -(((c) & 0x40) >> 6))
+#elif GRID_XY == 128
+# define GRID_AREA_TO_ALPHA(c) ((((c) << 1) | -((c) >> 7)) & 255)
+#elif GRID_XY == 256
+# define GRID_AREA_TO_ALPHA(c) (((c) | -((c) >> 8)) & 255)
+#elif GRID_XY == 15
+# define GRID_AREA_TO_ALPHA(c) (((c) << 4) + (c))
+#elif GRID_XY == 2*256*15
+# define GRID_AREA_TO_ALPHA(c) (((c) + ((c)<<4) + 256) >> 9)
+#else
+# define GRID_AREA_TO_ALPHA(c) (((c)*255 + GRID_XY/2) / GRID_XY)
+#endif
+
+#define UNROLL3(x) x x x
+
+struct quorem {
+ int32_t quo;
+ int32_t rem;
+};
+
+/* Header for a chunk of memory in a memory pool. */
+struct _pool_chunk {
+ /* # bytes used in this chunk. */
+ size_t size;
+
+ /* # bytes total in this chunk */
+ size_t capacity;
+
+ /* Pointer to the previous chunk or %NULL if this is the sentinel
+ * chunk in the pool header. */
+ struct _pool_chunk *prev_chunk;
+
+ /* Actual data starts here. Well aligned for pointers. */
+};
+
+/* A memory pool. This is supposed to be embedded on the stack or
+ * within some other structure. It may optionally be followed by an
+ * embedded array from which requests are fulfilled until
+ * malloc needs to be called to allocate a first real chunk. */
+struct pool {
+ /* Chunk we're allocating from. */
+ struct _pool_chunk *current;
+
+ jmp_buf *jmp;
+
+ /* Free list of previously allocated chunks. All have >= default
+ * capacity. */
+ struct _pool_chunk *first_free;
+
+ /* The default capacity of a chunk. */
+ size_t default_capacity;
+
+ /* Header for the sentinel chunk. Directly following the pool
+ * struct should be some space for embedded elements from which
+ * the sentinel chunk allocates from. */
+ struct _pool_chunk sentinel[1];
+};
+
+/* A polygon edge. */
+struct edge {
+ /* Next in y-bucket or active list. */
+ struct edge *next, *prev;
+
+ /* Number of subsample rows remaining to scan convert of this
+ * edge. */
+ grid_scaled_y_t height_left;
+
+ /* Original sign of the edge: +1 for downwards, -1 for upwards
+ * edges. */
+ int dir;
+ int vertical;
+
+ /* Current x coordinate while the edge is on the active
+ * list. Initialised to the x coordinate of the top of the
+ * edge. The quotient is in grid_scaled_x_t units and the
+ * remainder is mod dy in grid_scaled_y_t units.*/
+ struct quorem x;
+
+ /* Advance of the current x when moving down a subsample line. */
+ struct quorem dxdy;
+
+ /* The clipped y of the top of the edge. */
+ grid_scaled_y_t ytop;
+
+ /* y2-y1 after orienting the edge downwards. */
+ grid_scaled_y_t dy;
+};
+
+#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/GRID_Y)
+
+/* A collection of sorted and vertically clipped edges of the polygon.
+ * Edges are moved from the polygon to an active list while scan
+ * converting. */
+struct polygon {
+ /* The vertical clip extents. */
+ grid_scaled_y_t ymin, ymax;
+
+ /* Array of edges all starting in the same bucket. An edge is put
+ * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when
+ * it is added to the polygon. */
+ struct edge **y_buckets;
+ struct edge *y_buckets_embedded[64];
+
+ struct {
+ struct pool base[1];
+ struct edge embedded[32];
+ } edge_pool;
+};
+
+/* A cell records the effect on pixel coverage of polygon edges
+ * passing through a pixel. It contains two accumulators of pixel
+ * coverage.
+ *
+ * Consider the effects of a polygon edge on the coverage of a pixel
+ * it intersects and that of the following one. The coverage of the
+ * following pixel is the height of the edge multiplied by the width
+ * of the pixel, and the coverage of the pixel itself is the area of
+ * the trapezoid formed by the edge and the right side of the pixel.
+ *
+ * +-----------------------+-----------------------+
+ * | | |
+ * | | |
+ * |_______________________|_______________________|
+ * | \...................|.......................|\
+ * | \..................|.......................| |
+ * | \.................|.......................| |
+ * | \....covered.....|.......................| |
+ * | \....area.......|.......................| } covered height
+ * | \..............|.......................| |
+ * |uncovered\.............|.......................| |
+ * | area \............|.......................| |
+ * |___________\...........|.......................|/
+ * | | |
+ * | | |
+ * | | |
+ * +-----------------------+-----------------------+
+ *
+ * Since the coverage of the following pixel will always be a multiple
+ * of the width of the pixel, we can store the height of the covered
+ * area instead. The coverage of the pixel itself is the total
+ * coverage minus the area of the uncovered area to the left of the
+ * edge. As it's faster to compute the uncovered area we only store
+ * that and subtract it from the total coverage later when forming
+ * spans to blit.
+ *
+ * The heights and areas are signed, with left edges of the polygon
+ * having positive sign and right edges having negative sign. When
+ * two edges intersect they swap their left/rightness so their
+ * contribution above and below the intersection point must be
+ * computed separately. */
+struct cell {
+ struct cell *next;
+ int x;
+ int16_t uncovered_area;
+ int16_t covered_height;
+};
+
+/* A cell list represents the scan line sparsely as cells ordered by
+ * ascending x. It is geared towards scanning the cells in order
+ * using an internal cursor. */
+struct cell_list {
+ /* Sentinel nodes */
+ struct cell head, tail;
+
+ /* Cursor state for iterating through the cell list. */
+ struct cell *cursor, *rewind;
+
+ /* Cells in the cell list are owned by the cell list and are
+ * allocated from this pool. */
+ struct {
+ struct pool base[1];
+ struct cell embedded[32];
+ } cell_pool;
+};
+
+struct cell_pair {
+ struct cell *cell1;
+ struct cell *cell2;
+};
+
+/* The active list contains edges in the current scan line ordered by
+ * the x-coordinate of the intercept of the edge and the scan line. */
+struct active_list {
+ /* Leftmost edge on the current scan line. */
+ struct edge head, tail;
+
+ /* A lower bound on the height of the active edges is used to
+ * estimate how soon some active edge ends. We can't advance the
+ * scan conversion by a full pixel row if an edge ends somewhere
+ * within it. */
+ grid_scaled_y_t min_height;
+ int is_vertical;
+};
+
+struct glitter_scan_converter {
+ struct polygon polygon[1];
+ struct active_list active[1];
+ struct cell_list coverages[1];
+
+ cairo_half_open_span_t *spans;
+ cairo_half_open_span_t spans_embedded[64];
+
+ /* Clip box. */
+ grid_scaled_x_t xmin, xmax;
+ grid_scaled_y_t ymin, ymax;
+};
+
+/* Compute the floored division a/b. Assumes / and % perform symmetric
+ * division. */
+inline static struct quorem
+floored_divrem(int a, int b)
+{
+ struct quorem qr;
+ qr.quo = a/b;
+ qr.rem = a%b;
+ if ((a^b)<0 && qr.rem) {
+ qr.quo -= 1;
+ qr.rem += b;
+ }
+ return qr;
+}
+
+/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric
+ * division. */
+static struct quorem
+floored_muldivrem(int x, int a, int b)
+{
+ struct quorem qr;
+ long long xa = (long long)x*a;
+ qr.quo = xa/b;
+ qr.rem = xa%b;
+ if ((xa>=0) != (b>=0) && qr.rem) {
+ qr.quo -= 1;
+ qr.rem += b;
+ }
+ return qr;
+}
+
+static struct _pool_chunk *
+_pool_chunk_init(
+ struct _pool_chunk *p,
+ struct _pool_chunk *prev_chunk,
+ size_t capacity)
+{
+ p->prev_chunk = prev_chunk;
+ p->size = 0;
+ p->capacity = capacity;
+ return p;
+}
+
+static struct _pool_chunk *
+_pool_chunk_create(struct pool *pool, size_t size)
+{
+ struct _pool_chunk *p;
+
+ p = malloc(size + sizeof(struct _pool_chunk));
+ if (unlikely (NULL == p))
+ longjmp (*pool->jmp, _cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ return _pool_chunk_init(p, pool->current, size);
+}
+
+static void
+pool_init(struct pool *pool,
+ jmp_buf *jmp,
+ size_t default_capacity,
+ size_t embedded_capacity)
+{
+ pool->jmp = jmp;
+ pool->current = pool->sentinel;
+ pool->first_free = NULL;
+ pool->default_capacity = default_capacity;
+ _pool_chunk_init(pool->sentinel, NULL, embedded_capacity);
+}
+
+static void
+pool_fini(struct pool *pool)
+{
+ struct _pool_chunk *p = pool->current;
+ do {
+ while (NULL != p) {
+ struct _pool_chunk *prev = p->prev_chunk;
+ if (p != pool->sentinel)
+ free(p);
+ p = prev;
+ }
+ p = pool->first_free;
+ pool->first_free = NULL;
+ } while (NULL != p);
+}
+
+/* Satisfy an allocation by first allocating a new large enough chunk
+ * and adding it to the head of the pool's chunk list. This function
+ * is called as a fallback if pool_alloc() couldn't do a quick
+ * allocation from the current chunk in the pool. */
+static void *
+_pool_alloc_from_new_chunk(
+ struct pool *pool,
+ size_t size)
+{
+ struct _pool_chunk *chunk;
+ void *obj;
+ size_t capacity;
+
+ /* If the allocation is smaller than the default chunk size then
+ * try getting a chunk off the free list. Force alloc of a new
+ * chunk for large requests. */
+ capacity = size;
+ chunk = NULL;
+ if (size < pool->default_capacity) {
+ capacity = pool->default_capacity;
+ chunk = pool->first_free;
+ if (chunk) {
+ pool->first_free = chunk->prev_chunk;
+ _pool_chunk_init(chunk, pool->current, chunk->capacity);
+ }
+ }
+
+ if (NULL == chunk)
+ chunk = _pool_chunk_create (pool, capacity);
+ pool->current = chunk;
+
+ obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size);
+ chunk->size += size;
+ return obj;
+}
+
+/* Allocate size bytes from the pool. The first allocated address
+ * returned from a pool is aligned to sizeof(void*). Subsequent
+ * addresses will maintain alignment as long as multiples of void* are
+ * allocated. Returns the address of a new memory area or %NULL on
+ * allocation failures. The pool retains ownership of the returned
+ * memory. */
+inline static void *
+pool_alloc (struct pool *pool, size_t size)
+{
+ struct _pool_chunk *chunk = pool->current;
+
+ if (size <= chunk->capacity - chunk->size) {
+ void *obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size);
+ chunk->size += size;
+ return obj;
+ } else {
+ return _pool_alloc_from_new_chunk(pool, size);
+ }
+}
+
+/* Relinquish all pool_alloced memory back to the pool. */
+static void
+pool_reset (struct pool *pool)
+{
+ /* Transfer all used chunks to the chunk free list. */
+ struct _pool_chunk *chunk = pool->current;
+ if (chunk != pool->sentinel) {
+ while (chunk->prev_chunk != pool->sentinel) {
+ chunk = chunk->prev_chunk;
+ }
+ chunk->prev_chunk = pool->first_free;
+ pool->first_free = pool->current;
+ }
+ /* Reset the sentinel as the current chunk. */
+ pool->current = pool->sentinel;
+ pool->sentinel->size = 0;
+}
+
+/* Rewinds the cell list's cursor to the beginning. After rewinding
+ * we're good to cell_list_find() the cell any x coordinate. */
+inline static void
+cell_list_rewind (struct cell_list *cells)
+{
+ cells->cursor = &cells->head;
+}
+
+inline static void
+cell_list_maybe_rewind (struct cell_list *cells, int x)
+{
+ if (x < cells->cursor->x) {
+ cells->cursor = cells->rewind;
+ if (x < cells->cursor->x)
+ cells->cursor = &cells->head;
+ }
+}
+
+inline static void
+cell_list_set_rewind (struct cell_list *cells)
+{
+ cells->rewind = cells->cursor;
+}
+
+static void
+cell_list_init(struct cell_list *cells, jmp_buf *jmp)
+{
+ pool_init(cells->cell_pool.base, jmp,
+ 256*sizeof(struct cell),
+ sizeof(cells->cell_pool.embedded));
+ cells->tail.next = NULL;
+ cells->tail.x = INT_MAX;
+ cells->head.x = INT_MIN;
+ cells->head.next = &cells->tail;
+ cell_list_rewind (cells);
+}
+
+static void
+cell_list_fini(struct cell_list *cells)
+{
+ pool_fini (cells->cell_pool.base);
+}
+
+/* Empty the cell list. This is called at the start of every pixel
+ * row. */
+inline static void
+cell_list_reset (struct cell_list *cells)
+{
+ cell_list_rewind (cells);
+ cells->head.next = &cells->tail;
+ pool_reset (cells->cell_pool.base);
+}
+
+inline static struct cell *
+cell_list_alloc (struct cell_list *cells,
+ struct cell *tail,
+ int x)
+{
+ struct cell *cell;
+
+ cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell));
+ cell->next = tail->next;
+ tail->next = cell;
+ cell->x = x;
+ *(uint32_t *)&cell->uncovered_area = 0;
+
+ return cell;
+}
+
+/* Find a cell at the given x-coordinate. Returns %NULL if a new cell
+ * needed to be allocated but couldn't be. Cells must be found with
+ * non-decreasing x-coordinate until the cell list is rewound using
+ * cell_list_rewind(). Ownership of the returned cell is retained by
+ * the cell list. */
+inline static struct cell *
+cell_list_find (struct cell_list *cells, int x)
+{
+ struct cell *tail = cells->cursor;
+
+ if (tail->x == x)
+ return tail;
+
+ while (1) {
+ UNROLL3({
+ if (tail->next->x > x)
+ break;
+ tail = tail->next;
+ });
+ }
+
+ if (tail->x != x)
+ tail = cell_list_alloc (cells, tail, x);
+ return cells->cursor = tail;
+
+}
+
+/* Find two cells at x1 and x2. This is exactly equivalent
+ * to
+ *
+ * pair.cell1 = cell_list_find(cells, x1);
+ * pair.cell2 = cell_list_find(cells, x2);
+ *
+ * except with less function call overhead. */
+inline static struct cell_pair
+cell_list_find_pair(struct cell_list *cells, int x1, int x2)
+{
+ struct cell_pair pair;
+
+ pair.cell1 = cells->cursor;
+ while (1) {
+ UNROLL3({
+ if (pair.cell1->next->x > x1)
+ break;
+ pair.cell1 = pair.cell1->next;
+ });
+ }
+ if (pair.cell1->x != x1)
+ pair.cell1 = cell_list_alloc (cells, pair.cell1, x1);
+
+ pair.cell2 = pair.cell1;
+ while (1) {
+ UNROLL3({
+ if (pair.cell2->next->x > x2)
+ break;
+ pair.cell2 = pair.cell2->next;
+ });
+ }
+ if (pair.cell2->x != x2)
+ pair.cell2 = cell_list_alloc (cells, pair.cell2, x2);
+
+ cells->cursor = pair.cell2;
+ return pair;
+}
+
+/* Add a subpixel span covering [x1, x2) to the coverage cells. */
+inline static void
+cell_list_add_subspan(struct cell_list *cells,
+ grid_scaled_x_t x1,
+ grid_scaled_x_t x2)
+{
+ int ix1, fx1;
+ int ix2, fx2;
+
+ if (x1 == x2)
+ return;
+
+ GRID_X_TO_INT_FRAC(x1, ix1, fx1);
+ GRID_X_TO_INT_FRAC(x2, ix2, fx2);
+
+ if (ix1 != ix2) {
+ struct cell_pair p;
+ p = cell_list_find_pair(cells, ix1, ix2);
+ p.cell1->uncovered_area += 2*fx1;
+ ++p.cell1->covered_height;
+ p.cell2->uncovered_area -= 2*fx2;
+ --p.cell2->covered_height;
+ } else {
+ struct cell *cell = cell_list_find(cells, ix1);
+ cell->uncovered_area += 2*(fx1-fx2);
+ }
+}
+
+/* Adds the analytical coverage of an edge crossing the current pixel
+ * row to the coverage cells and advances the edge's x position to the
+ * following row.
+ *
+ * This function is only called when we know that during this pixel row:
+ *
+ * 1) The relative order of all edges on the active list doesn't
+ * change. In particular, no edges intersect within this row to pixel
+ * precision.
+ *
+ * 2) No new edges start in this row.
+ *
+ * 3) No existing edges end mid-row.
+ *
+ * This function depends on being called with all edges from the
+ * active list in the order they appear on the list (i.e. with
+ * non-decreasing x-coordinate.) */
+static void
+cell_list_render_edge(struct cell_list *cells,
+ struct edge *edge,
+ int sign)
+{
+ grid_scaled_x_t fx;
+ struct cell *cell;
+ int ix;
+
+ GRID_X_TO_INT_FRAC(edge->x.quo, ix, fx);
+
+ /* We always know that ix1 is >= the cell list cursor in this
+ * case due to the no-intersections precondition. */
+ cell = cell_list_find(cells, ix);
+ cell->covered_height += sign*GRID_Y;
+ cell->uncovered_area += sign*2*fx*GRID_Y;
+}
+
+static void
+polygon_init (struct polygon *polygon, jmp_buf *jmp)
+{
+ polygon->ymin = polygon->ymax = 0;
+ polygon->y_buckets = polygon->y_buckets_embedded;
+ pool_init (polygon->edge_pool.base, jmp,
+ 8192 - sizeof (struct _pool_chunk),
+ sizeof (polygon->edge_pool.embedded));
+}
+
+static void
+polygon_fini (struct polygon *polygon)
+{
+ if (polygon->y_buckets != polygon->y_buckets_embedded)
+ free (polygon->y_buckets);
+
+ pool_fini (polygon->edge_pool.base);
+}
+
+/* Empties the polygon of all edges. The polygon is then prepared to
+ * receive new edges and clip them to the vertical range
+ * [ymin,ymax). */
+static glitter_status_t
+polygon_reset (struct polygon *polygon,
+ grid_scaled_y_t ymin,
+ grid_scaled_y_t ymax)
+{
+ unsigned h = ymax - ymin;
+ unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + GRID_Y-1, ymin);
+
+ pool_reset(polygon->edge_pool.base);
+
+ if (unlikely (h > 0x7FFFFFFFU - GRID_Y))
+ goto bail_no_mem; /* even if you could, you wouldn't want to. */
+
+ if (polygon->y_buckets != polygon->y_buckets_embedded)
+ free (polygon->y_buckets);
+
+ polygon->y_buckets = polygon->y_buckets_embedded;
+ if (num_buckets > ARRAY_LENGTH (polygon->y_buckets_embedded)) {
+ polygon->y_buckets = _cairo_malloc_ab (num_buckets,
+ sizeof (struct edge *));
+ if (unlikely (NULL == polygon->y_buckets))
+ goto bail_no_mem;
+ }
+ memset (polygon->y_buckets, 0, num_buckets * sizeof (struct edge *));
+
+ polygon->ymin = ymin;
+ polygon->ymax = ymax;
+ return GLITTER_STATUS_SUCCESS;
+
+bail_no_mem:
+ polygon->ymin = 0;
+ polygon->ymax = 0;
+ return GLITTER_STATUS_NO_MEMORY;
+}
+
+static void
+_polygon_insert_edge_into_its_y_bucket(struct polygon *polygon,
+ struct edge *e)
+{
+ unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin);
+ struct edge **ptail = &polygon->y_buckets[ix];
+ e->next = *ptail;
+ *ptail = e;
+}
+
+inline static void
+polygon_add_edge (struct polygon *polygon,
+ const cairo_edge_t *edge)
+{
+ struct edge *e;
+ grid_scaled_x_t dx;
+ grid_scaled_y_t dy;
+ grid_scaled_y_t ytop, ybot;
+ grid_scaled_y_t ymin = polygon->ymin;
+ grid_scaled_y_t ymax = polygon->ymax;
+
+ if (unlikely (edge->top >= ymax || edge->bottom <= ymin))
+ return;
+
+ e = pool_alloc (polygon->edge_pool.base, sizeof (struct edge));
+
+ dx = edge->line.p2.x - edge->line.p1.x;
+ dy = edge->line.p2.y - edge->line.p1.y;
+ e->dy = dy;
+ e->dir = edge->dir;
+
+ ytop = edge->top >= ymin ? edge->top : ymin;
+ ybot = edge->bottom <= ymax ? edge->bottom : ymax;
+ e->ytop = ytop;
+ e->height_left = ybot - ytop;
+
+ if (dx == 0) {
+ e->vertical = TRUE;
+ e->x.quo = edge->line.p1.x;
+ e->x.rem = 0;
+ e->dxdy.quo = 0;
+ e->dxdy.rem = 0;
+ } else {
+ e->vertical = FALSE;
+ e->dxdy = floored_divrem (dx, dy);
+ if (ytop == edge->line.p1.y) {
+ e->x.quo = edge->line.p1.x;
+ e->x.rem = 0;
+ } else {
+ e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy);
+ e->x.quo += edge->line.p1.x;
+ }
+ }
+
+ _polygon_insert_edge_into_its_y_bucket (polygon, e);
+
+ e->x.rem -= dy; /* Bias the remainder for faster
+ * edge advancement. */
+}
+
+static void
+active_list_reset (struct active_list *active)
+{
+ active->head.vertical = 1;
+ active->head.height_left = INT_MAX;
+ active->head.x.quo = INT_MIN;
+ active->head.prev = NULL;
+ active->head.next = &active->tail;
+ active->tail.prev = &active->head;
+ active->tail.next = NULL;
+ active->tail.x.quo = INT_MAX;
+ active->tail.height_left = INT_MAX;
+ active->tail.vertical = 1;
+ active->min_height = 0;
+ active->is_vertical = 1;
+}
+
+static void
+active_list_init(struct active_list *active)
+{
+ active_list_reset(active);
+}
+
+/*
+ * Merge two sorted edge lists.
+ * Input:
+ * - head_a: The head of the first list.
+ * - head_b: The head of the second list; head_b cannot be NULL.
+ * Output:
+ * Returns the head of the merged list.
+ *
+ * Implementation notes:
+ * To make it fast (in particular, to reduce to an insertion sort whenever
+ * one of the two input lists only has a single element) we iterate through
+ * a list until its head becomes greater than the head of the other list,
+ * then we switch their roles. As soon as one of the two lists is empty, we
+ * just attach the other one to the current list and exit.
+ * Writes to memory are only needed to "switch" lists (as it also requires
+ * attaching to the output list the list which we will be iterating next) and
+ * to attach the last non-empty list.
+ */
+static struct edge *
+merge_sorted_edges (struct edge *head_a, struct edge *head_b)
+{
+ struct edge *head, **next, *prev;
+ int32_t x;
+
+ prev = head_a->prev;
+ next = &head;
+ if (head_a->x.quo <= head_b->x.quo) {
+ head = head_a;
+ } else {
+ head = head_b;
+ head_b->prev = prev;
+ goto start_with_b;
+ }
+
+ do {
+ x = head_b->x.quo;
+ while (head_a != NULL && head_a->x.quo <= x) {
+ prev = head_a;
+ next = &head_a->next;
+ head_a = head_a->next;
+ }
+
+ head_b->prev = prev;
+ *next = head_b;
+ if (head_a == NULL)
+ return head;
+
+start_with_b:
+ x = head_a->x.quo;
+ while (head_b != NULL && head_b->x.quo <= x) {
+ prev = head_b;
+ next = &head_b->next;
+ head_b = head_b->next;
+ }
+
+ head_a->prev = prev;
+ *next = head_a;
+ if (head_b == NULL)
+ return head;
+ } while (1);
+}
+
+/*
+ * Sort (part of) a list.
+ * Input:
+ * - list: The list to be sorted; list cannot be NULL.
+ * - limit: Recursion limit.
+ * Output:
+ * - head_out: The head of the sorted list containing the first 2^(level+1) elements of the
+ * input list; if the input list has fewer elements, head_out be a sorted list
+ * containing all the elements of the input list.
+ * Returns the head of the list of unprocessed elements (NULL if the sorted list contains
+ * all the elements of the input list).
+ *
+ * Implementation notes:
+ * Special case single element list, unroll/inline the sorting of the first two elements.
+ * Some tail recursion is used since we iterate on the bottom-up solution of the problem
+ * (we start with a small sorted list and keep merging other lists of the same size to it).
+ */
+static struct edge *
+sort_edges (struct edge *list,
+ unsigned int level,
+ struct edge **head_out)
+{
+ struct edge *head_other, *remaining;
+ unsigned int i;
+
+ head_other = list->next;
+
+ if (head_other == NULL) {
+ *head_out = list;
+ return NULL;
+ }
+
+ remaining = head_other->next;
+ if (list->x.quo <= head_other->x.quo) {
+ *head_out = list;
+ head_other->next = NULL;
+ } else {
+ *head_out = head_other;
+ head_other->prev = list->prev;
+ head_other->next = list;
+ list->prev = head_other;
+ list->next = NULL;
+ }
+
+ for (i = 0; i < level && remaining; i++) {
+ remaining = sort_edges (remaining, i, &head_other);
+ *head_out = merge_sorted_edges (*head_out, head_other);
+ }
+
+ return remaining;
+}
+
+static struct edge *
+merge_unsorted_edges (struct edge *head, struct edge *unsorted)
+{
+ sort_edges (unsorted, UINT_MAX, &unsorted);
+ return merge_sorted_edges (head, unsorted);
+}
+
+/* Test if the edges on the active list can be safely advanced by a
+ * full row without intersections or any edges ending. */
+inline static int
+can_do_full_row (struct active_list *active)
+{
+ const struct edge *e;
+
+ /* Recomputes the minimum height of all edges on the active
+ * list if we have been dropping edges. */
+ if (active->min_height <= 0) {
+ int min_height = INT_MAX;
+ int is_vertical = 1;
+
+ e = active->head.next;
+ while (NULL != e) {
+ if (e->height_left < min_height)
+ min_height = e->height_left;
+ is_vertical &= e->vertical;
+ e = e->next;
+ }
+
+ active->is_vertical = is_vertical;
+ active->min_height = min_height;
+ }
+
+ if (active->min_height < GRID_Y)
+ return 0;
+
+ return active->is_vertical;
+}
+
+/* Merges edges on the given subpixel row from the polygon to the
+ * active_list. */
+inline static void
+active_list_merge_edges_from_bucket(struct active_list *active,
+ struct edge *edges)
+{
+ active->head.next = merge_unsorted_edges (active->head.next, edges);
+}
+
+inline static void
+polygon_fill_buckets (struct active_list *active,
+ struct edge *edge,
+ int y,
+ struct edge **buckets)
+{
+ grid_scaled_y_t min_height = active->min_height;
+ int is_vertical = active->is_vertical;
+
+ while (edge) {
+ struct edge *next = edge->next;
+ int suby = edge->ytop - y;
+ if (buckets[suby])
+ buckets[suby]->prev = edge;
+ edge->next = buckets[suby];
+ edge->prev = NULL;
+ buckets[suby] = edge;
+ if (edge->height_left < min_height)
+ min_height = edge->height_left;
+ is_vertical &= edge->vertical;
+ edge = next;
+ }
+
+ active->is_vertical = is_vertical;
+ active->min_height = min_height;
+}
+
+inline static void
+sub_row (struct active_list *active,
+ struct cell_list *coverages,
+ unsigned int mask)
+{
+ struct edge *edge = active->head.next;
+ int xstart = INT_MIN, prev_x = INT_MIN;
+ int winding = 0;
+
+ cell_list_rewind (coverages);
+
+ while (&active->tail != edge) {
+ struct edge *next = edge->next;
+ int xend = edge->x.quo;
+
+ if (--edge->height_left) {
+ edge->x.quo += edge->dxdy.quo;
+ edge->x.rem += edge->dxdy.rem;
+ if (edge->x.rem >= 0) {
+ ++edge->x.quo;
+ edge->x.rem -= edge->dy;
+ }
+
+ if (edge->x.quo < prev_x) {
+ struct edge *pos = edge->prev;
+ pos->next = next;
+ next->prev = pos;
+ do {
+ pos = pos->prev;
+ } while (edge->x.quo < pos->x.quo);
+ pos->next->prev = edge;
+ edge->next = pos->next;
+ edge->prev = pos;
+ pos->next = edge;
+ } else
+ prev_x = edge->x.quo;
+ } else {
+ edge->prev->next = next;
+ next->prev = edge->prev;
+ }
+
+ winding += edge->dir;
+ if ((winding & mask) == 0) {
+ if (next->x.quo != xend) {
+ cell_list_add_subspan (coverages, xstart, xend);
+ xstart = INT_MIN;
+ }
+ } else if (xstart == INT_MIN)
+ xstart = xend;
+
+ edge = next;
+ }
+}
+
+inline static void dec (struct edge *e, int h)
+{
+ e->height_left -= h;
+ if (e->height_left == 0) {
+ e->prev->next = e->next;
+ e->next->prev = e->prev;
+ }
+}
+
+static void
+full_row (struct active_list *active,
+ struct cell_list *coverages,
+ unsigned int mask)
+{
+ struct edge *left = active->head.next;
+
+ while (&active->tail != left) {
+ struct edge *right;
+ int winding;
+
+ dec (left, GRID_Y);
+
+ winding = left->dir;
+ right = left->next;
+ do {
+ dec (right, GRID_Y);
+
+ winding += right->dir;
+ if ((winding & mask) == 0 && right->next->x.quo != right->x.quo)
+ break;
+
+ right = right->next;
+ } while (1);
+
+ cell_list_set_rewind (coverages);
+ cell_list_render_edge (coverages, left, +1);
+ cell_list_render_edge (coverages, right, -1);
+
+ left = right->next;
+ }
+}
+
+static void
+_glitter_scan_converter_init(glitter_scan_converter_t *converter, jmp_buf *jmp)
+{
+ polygon_init(converter->polygon, jmp);
+ active_list_init(converter->active);
+ cell_list_init(converter->coverages, jmp);
+ converter->xmin=0;
+ converter->ymin=0;
+ converter->xmax=0;
+ converter->ymax=0;
+}
+
+static void
+_glitter_scan_converter_fini(glitter_scan_converter_t *self)
+{
+ if (self->spans != self->spans_embedded)
+ free (self->spans);
+
+ polygon_fini(self->polygon);
+ cell_list_fini(self->coverages);
+
+ self->xmin=0;
+ self->ymin=0;
+ self->xmax=0;
+ self->ymax=0;
+}
+
+static grid_scaled_t
+int_to_grid_scaled(int i, int scale)
+{
+ /* Clamp to max/min representable scaled number. */
+ if (i >= 0) {
+ if (i >= INT_MAX/scale)
+ i = INT_MAX/scale;
+ }
+ else {
+ if (i <= INT_MIN/scale)
+ i = INT_MIN/scale;
+ }
+ return i*scale;
+}
+
+#define int_to_grid_scaled_x(x) int_to_grid_scaled((x), GRID_X)
+#define int_to_grid_scaled_y(x) int_to_grid_scaled((x), GRID_Y)
+
+I glitter_status_t
+glitter_scan_converter_reset(
+ glitter_scan_converter_t *converter,
+ int xmin, int ymin,
+ int xmax, int ymax)
+{
+ glitter_status_t status;
+
+ converter->xmin = 0; converter->xmax = 0;
+ converter->ymin = 0; converter->ymax = 0;
+
+ if (xmax - xmin > ARRAY_LENGTH(converter->spans_embedded)) {
+ converter->spans = _cairo_malloc_ab (xmax - xmin,
+ sizeof (cairo_half_open_span_t));
+ if (unlikely (converter->spans == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ } else
+ converter->spans = converter->spans_embedded;
+
+ xmin = int_to_grid_scaled_x(xmin);
+ ymin = int_to_grid_scaled_y(ymin);
+ xmax = int_to_grid_scaled_x(xmax);
+ ymax = int_to_grid_scaled_y(ymax);
+
+ active_list_reset(converter->active);
+ cell_list_reset(converter->coverages);
+ status = polygon_reset(converter->polygon, ymin, ymax);
+ if (status)
+ return status;
+
+ converter->xmin = xmin;
+ converter->xmax = xmax;
+ converter->ymin = ymin;
+ converter->ymax = ymax;
+ return GLITTER_STATUS_SUCCESS;
+}
+
+/* INPUT_TO_GRID_X/Y (in_coord, out_grid_scaled, grid_scale)
+ * These macros convert an input coordinate in the client's
+ * device space to the rasterisation grid.
+ */
+/* Gah.. this bit of ugly defines INPUT_TO_GRID_X/Y so as to use
+ * shifts if possible, and something saneish if not.
+ */
+#if !defined(INPUT_TO_GRID_Y) && defined(GRID_Y_BITS) && GRID_Y_BITS <= GLITTER_INPUT_BITS
+# define INPUT_TO_GRID_Y(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_Y_BITS)
+#else
+# define INPUT_TO_GRID_Y(in, out) INPUT_TO_GRID_general(in, out, GRID_Y)
+#endif
+
+#if !defined(INPUT_TO_GRID_X) && defined(GRID_X_BITS) && GRID_X_BITS <= GLITTER_INPUT_BITS
+# define INPUT_TO_GRID_X(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_X_BITS)
+#else
+# define INPUT_TO_GRID_X(in, out) INPUT_TO_GRID_general(in, out, GRID_X)
+#endif
+
+#define INPUT_TO_GRID_general(in, out, grid_scale) do { \
+ long long tmp__ = (long long)(grid_scale) * (in); \
+ tmp__ >>= GLITTER_INPUT_BITS; \
+ (out) = tmp__; \
+} while (0)
+
+/* Add a new polygon edge from pixel (x1,y1) to (x2,y2) to the scan
+ * converter. The coordinates represent pixel positions scaled by
+ * 2**GLITTER_PIXEL_BITS. If this function fails then the scan
+ * converter should be reset or destroyed. Dir must be +1 or -1,
+ * with the latter reversing the orientation of the edge. */
+I void
+glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
+ const cairo_edge_t *edge)
+{
+ cairo_edge_t e;
+
+ INPUT_TO_GRID_Y (edge->top, e.top);
+ INPUT_TO_GRID_Y (edge->bottom, e.bottom);
+ if (e.top >= e.bottom)
+ return;
+
+ /* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */
+ INPUT_TO_GRID_Y (edge->line.p1.y, e.line.p1.y);
+ INPUT_TO_GRID_Y (edge->line.p2.y, e.line.p2.y);
+ if (e.line.p1.y == e.line.p2.y)
+ return;
+
+ INPUT_TO_GRID_X (edge->line.p1.x, e.line.p1.x);
+ INPUT_TO_GRID_X (edge->line.p2.x, e.line.p2.x);
+
+ e.dir = edge->dir;
+
+ polygon_add_edge (converter->polygon, &e);
+}
+
+static void
+step_edges (struct active_list *active, int count)
+{
+ struct edge *edge;
+
+ count *= GRID_Y;
+ for (edge = active->head.next; edge != &active->tail; edge = edge->next) {
+ edge->height_left -= count;
+ if (! edge->height_left) {
+ edge->prev->next = edge->next;
+ edge->next->prev = edge->prev;
+ }
+ }
+}
+
+static glitter_status_t
+blit_a8 (struct cell_list *cells,
+ cairo_span_renderer_t *renderer,
+ cairo_half_open_span_t *spans,
+ int y, int height,
+ int xmin, int xmax)
+{
+ struct cell *cell = cells->head.next;
+ int prev_x = xmin, last_x = -1;
+ int16_t cover = 0, last_cover = 0;
+ unsigned num_spans;
+
+ if (cell == &cells->tail)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* Skip cells to the left of the clip region. */
+ while (cell->x < xmin) {
+ cover += cell->covered_height;
+ cell = cell->next;
+ }
+ cover *= GRID_X*2;
+
+ /* Form the spans from the coverages and areas. */
+ num_spans = 0;
+ for (; cell->x < xmax; cell = cell->next) {
+ int x = cell->x;
+ int16_t area;
+
+ if (x > prev_x && cover != last_cover) {
+ spans[num_spans].x = prev_x;
+ spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover);
+ last_cover = cover;
+ last_x = prev_x;
+ ++num_spans;
+ }
+
+ cover += cell->covered_height*GRID_X*2;
+ area = cover - cell->uncovered_area;
+
+ if (area != last_cover) {
+ spans[num_spans].x = x;
+ spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area);
+ last_cover = area;
+ last_x = x;
+ ++num_spans;
+ }
+
+ prev_x = x+1;
+ }
+
+ if (prev_x <= xmax && cover != last_cover) {
+ spans[num_spans].x = prev_x;
+ spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover);
+ last_cover = cover;
+ last_x = prev_x;
+ ++num_spans;
+ }
+
+ if (last_x < xmax && last_cover) {
+ spans[num_spans].x = xmax;
+ spans[num_spans].coverage = 0;
+ ++num_spans;
+ }
+
+ /* Dump them into the renderer. */
+ return renderer->render_rows (renderer, y, height, spans, num_spans);
+}
+
+#define GRID_AREA_TO_A1(A) ((GRID_AREA_TO_ALPHA (A) > 127) ? 255 : 0)
+static glitter_status_t
+blit_a1 (struct cell_list *cells,
+ cairo_span_renderer_t *renderer,
+ cairo_half_open_span_t *spans,
+ int y, int height,
+ int xmin, int xmax)
+{
+ struct cell *cell = cells->head.next;
+ int prev_x = xmin, last_x = -1;
+ int16_t cover = 0;
+ uint8_t coverage, last_cover = 0;
+ unsigned num_spans;
+
+ if (cell == &cells->tail)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* Skip cells to the left of the clip region. */
+ while (cell->x < xmin) {
+ cover += cell->covered_height;
+ cell = cell->next;
+ }
+ cover *= GRID_X*2;
+
+ /* Form the spans from the coverages and areas. */
+ num_spans = 0;
+ for (; cell->x < xmax; cell = cell->next) {
+ int x = cell->x;
+ int16_t area;
+
+ coverage = GRID_AREA_TO_A1 (cover);
+ if (x > prev_x && coverage != last_cover) {
+ last_x = spans[num_spans].x = prev_x;
+ last_cover = spans[num_spans].coverage = coverage;
+ ++num_spans;
+ }
+
+ cover += cell->covered_height*GRID_X*2;
+ area = cover - cell->uncovered_area;
+
+ coverage = GRID_AREA_TO_A1 (area);
+ if (coverage != last_cover) {
+ last_x = spans[num_spans].x = x;
+ last_cover = spans[num_spans].coverage = coverage;
+ ++num_spans;
+ }
+
+ prev_x = x+1;
+ }
+
+ coverage = GRID_AREA_TO_A1 (cover);
+ if (prev_x <= xmax && coverage != last_cover) {
+ last_x = spans[num_spans].x = prev_x;
+ last_cover = spans[num_spans].coverage = coverage;
+ ++num_spans;
+ }
+
+ if (last_x < xmax && last_cover) {
+ spans[num_spans].x = xmax;
+ spans[num_spans].coverage = 0;
+ ++num_spans;
+ }
+ if (num_spans == 1)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* Dump them into the renderer. */
+ return renderer->render_rows (renderer, y, height, spans, num_spans);
+}
+
+
+I void
+glitter_scan_converter_render(glitter_scan_converter_t *converter,
+ unsigned int winding_mask,
+ int antialias,
+ cairo_span_renderer_t *renderer)
+{
+ int i, j;
+ int ymax_i = converter->ymax / GRID_Y;
+ int ymin_i = converter->ymin / GRID_Y;
+ int xmin_i, xmax_i;
+ int h = ymax_i - ymin_i;
+ struct polygon *polygon = converter->polygon;
+ struct cell_list *coverages = converter->coverages;
+ struct active_list *active = converter->active;
+ struct edge *buckets[GRID_Y] = { 0 };
+
+ xmin_i = converter->xmin / GRID_X;
+ xmax_i = converter->xmax / GRID_X;
+ if (xmin_i >= xmax_i)
+ return;
+
+ /* Render each pixel row. */
+ for (i = 0; i < h; i = j) {
+ int do_full_row = 0;
+
+ j = i + 1;
+
+ /* Determine if we can ignore this row or use the full pixel
+ * stepper. */
+ if (! polygon->y_buckets[i]) {
+ if (active->head.next == &active->tail) {
+ active->min_height = INT_MAX;
+ active->is_vertical = 1;
+ for (; j < h && ! polygon->y_buckets[j]; j++)
+ ;
+ continue;
+ }
+
+ do_full_row = can_do_full_row (active);
+ }
+
+ if (do_full_row) {
+ /* Step by a full pixel row's worth. */
+ full_row (active, coverages, winding_mask);
+
+ if (active->is_vertical) {
+ while (j < h &&
+ polygon->y_buckets[j] == NULL &&
+ active->min_height >= 2*GRID_Y)
+ {
+ active->min_height -= GRID_Y;
+ j++;
+ }
+ if (j != i + 1)
+ step_edges (active, j - (i + 1));
+ }
+ } else {
+ int sub;
+
+ polygon_fill_buckets (active,
+ polygon->y_buckets[i],
+ (i+ymin_i)*GRID_Y,
+ buckets);
+
+ /* Subsample this row. */
+ for (sub = 0; sub < GRID_Y; sub++) {
+ if (buckets[sub]) {
+ active_list_merge_edges_from_bucket (active, buckets[sub]);
+ buckets[sub] = NULL;
+ }
+
+ sub_row (active, coverages, winding_mask);
+ }
+ }
+
+ if (antialias)
+ blit_a8 (coverages, renderer, converter->spans,
+ i+ymin_i, j-i, xmin_i, xmax_i);
+ else
+ blit_a1 (coverages, renderer, converter->spans,
+ i+ymin_i, j-i, xmin_i, xmax_i);
+ cell_list_reset (coverages);
+
+ active->min_height -= GRID_Y;
+ }
+}
+
+struct _cairo_tor22_scan_converter {
+ cairo_scan_converter_t base;
+
+ glitter_scan_converter_t converter[1];
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+
+ jmp_buf jmp;
+};
+
+typedef struct _cairo_tor22_scan_converter cairo_tor22_scan_converter_t;
+
+static void
+_cairo_tor22_scan_converter_destroy (void *converter)
+{
+ cairo_tor22_scan_converter_t *self = converter;
+ if (self == NULL) {
+ return;
+ }
+ _glitter_scan_converter_fini (self->converter);
+ free(self);
+}
+
+cairo_status_t
+_cairo_tor22_scan_converter_add_polygon (void *converter,
+ const cairo_polygon_t *polygon)
+{
+ cairo_tor22_scan_converter_t *self = converter;
+ int i;
+
+#if 0
+ FILE *file = fopen ("polygon.txt", "w");
+ _cairo_debug_print_polygon (file, polygon);
+ fclose (file);
+#endif
+
+ for (i = 0; i < polygon->num_edges; i++)
+ glitter_scan_converter_add_edge (self->converter, &polygon->edges[i]);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_tor22_scan_converter_generate (void *converter,
+ cairo_span_renderer_t *renderer)
+{
+ cairo_tor22_scan_converter_t *self = converter;
+ cairo_status_t status;
+
+ if ((status = setjmp (self->jmp)))
+ return _cairo_scan_converter_set_error (self, _cairo_error (status));
+
+ glitter_scan_converter_render (self->converter,
+ self->fill_rule == CAIRO_FILL_RULE_WINDING ? ~0 : 1,
+ self->antialias != CAIRO_ANTIALIAS_NONE,
+ renderer);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_scan_converter_t *
+_cairo_tor22_scan_converter_create (int xmin,
+ int ymin,
+ int xmax,
+ int ymax,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias)
+{
+ cairo_tor22_scan_converter_t *self;
+ cairo_status_t status;
+
+ self = malloc (sizeof(struct _cairo_tor22_scan_converter));
+ if (unlikely (self == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto bail_nomem;
+ }
+
+ self->base.destroy = _cairo_tor22_scan_converter_destroy;
+ self->base.generate = _cairo_tor22_scan_converter_generate;
+
+ _glitter_scan_converter_init (self->converter, &self->jmp);
+ status = glitter_scan_converter_reset (self->converter,
+ xmin, ymin, xmax, ymax);
+ if (unlikely (status))
+ goto bail;
+
+ self->fill_rule = fill_rule;
+ self->antialias = antialias;
+
+ return &self->base;
+
+ bail:
+ self->base.destroy(&self->base);
+ bail_nomem:
+ return _cairo_scan_converter_create_in_error (status);
+}
diff --git a/src/cairo-traps-compositor.c b/src/cairo-traps-compositor.c
new file mode 100644
index 00000000..92c8665a
--- /dev/null
+++ b/src/cairo-traps-compositor.c
@@ -0,0 +1,2032 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-box-private.h"
+#include "cairo-boxes-private.h"
+#include "cairo-clip-private.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
+#include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-paginated-private.h"
+#include "cairo-recording-surface-private.h"
+#include "cairo-surface-subsurface-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-observer-private.h"
+#include "cairo-region-private.h"
+#include "cairo-spans-private.h"
+#include "cairo-traps-private.h"
+#include "cairo-tristrip-private.h"
+
+typedef cairo_int_status_t
+(*draw_func_t) (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip);
+
+static void do_unaligned_row(void (*blt)(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage),
+ void *closure,
+ const cairo_box_t *b,
+ int tx, int y, int h,
+ uint16_t coverage)
+{
+ int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
+ int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
+ if (x2 > x1) {
+ if (! _cairo_fixed_is_integer (b->p1.x)) {
+ blt(closure, x1, y, 1, h,
+ coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
+ x1++;
+ }
+
+ if (x2 > x1)
+ blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
+
+ if (! _cairo_fixed_is_integer (b->p2.x))
+ blt(closure, x2, y, 1, h,
+ coverage * _cairo_fixed_fractional_part (b->p2.x));
+ } else
+ blt(closure, x1, y, 1, h,
+ coverage * (b->p2.x - b->p1.x));
+}
+
+static void do_unaligned_box(void (*blt)(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage),
+ void *closure,
+ const cairo_box_t *b, int tx, int ty)
+{
+ int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
+ int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
+ if (y2 > y1) {
+ if (! _cairo_fixed_is_integer (b->p1.y)) {
+ do_unaligned_row(blt, closure, b, tx, y1, 1,
+ 256 - _cairo_fixed_fractional_part (b->p1.y));
+ y1++;
+ }
+
+ if (y2 > y1)
+ do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
+
+ if (! _cairo_fixed_is_integer (b->p2.y))
+ do_unaligned_row(blt, closure, b, tx, y2, 1,
+ _cairo_fixed_fractional_part (b->p2.y));
+ } else
+ do_unaligned_row(blt, closure, b, tx, y1, 1,
+ b->p2.y - b->p1.y);
+}
+
+struct blt_in {
+ const cairo_traps_compositor_t *compositor;
+ cairo_surface_t *dst;
+ cairo_boxes_t boxes;
+};
+
+static void blt_in(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage)
+{
+ struct blt_in *info = closure;
+ cairo_color_t color;
+
+ if (CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage))
+ return;
+
+ _cairo_box_from_integers (&info->boxes.chunks.base[0], x, y, w, h);
+
+ _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff);
+ info->compositor->fill_boxes (info->dst,
+ CAIRO_OPERATOR_IN, &color,
+ &info->boxes);
+}
+
+static cairo_int_status_t
+combine_clip_as_traps (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *mask,
+ const cairo_clip_t *clip,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_polygon_t polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+ cairo_traps_t traps;
+ cairo_surface_t *src;
+ int src_x, src_y;
+ cairo_int_status_t status;
+
+ status = _cairo_clip_get_polygon (clip, &polygon,
+ &fill_rule, &antialias);
+ if (status)
+ return status;
+
+ _cairo_traps_init (&traps);
+ status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
+ &polygon,
+ fill_rule);
+ _cairo_polygon_fini (&polygon);
+ if (unlikely (status))
+ return status;
+
+ src = compositor->pattern_to_surface (mask, NULL, FALSE,
+ extents, NULL,
+ &src_x, &src_y);
+ if (unlikely (src->status)) {
+ _cairo_traps_fini (&traps);
+ return src->status;
+ }
+
+ status = compositor->composite_traps (mask, CAIRO_OPERATOR_IN, src,
+ src_x, src_y,
+ extents->x, extents->y,
+ extents,
+ antialias, &traps);
+
+ cairo_surface_destroy (src);
+ _cairo_traps_fini (&traps);
+
+ return status;
+}
+
+static cairo_surface_t *
+traps_get_clip_surface (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *target,
+ const cairo_clip_t *clip,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_surface_t *surface;
+ cairo_int_status_t status;
+
+ surface = _cairo_surface_create_similar_solid (target,
+ CAIRO_CONTENT_ALPHA,
+ extents->width,
+ extents->height,
+ CAIRO_COLOR_WHITE);
+ if (unlikely (surface->status))
+ return surface;
+
+ status = compositor->acquire (surface);
+ if (unlikely (status)) {
+ cairo_surface_destroy (surface);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ status = combine_clip_as_traps (compositor, surface, clip, extents);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ status = _cairo_clip_combine_with_surface (clip, surface,
+ extents->x, extents->y);
+ }
+ compositor->release (surface);
+
+ return surface;
+}
+
+static cairo_surface_t *
+create_composite_mask (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *draw_closure,
+ draw_func_t draw_func,
+ draw_func_t mask_func,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *surface, *src;
+ cairo_int_status_t status;
+ struct blt_in info;
+ int src_x, src_y;
+ int i;
+
+ surface = _cairo_surface_create_similar_solid (dst,
+ CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height,
+ CAIRO_COLOR_TRANSPARENT);
+ if (unlikely (surface->status))
+ return surface;
+
+ src = compositor->pattern_to_surface (surface,
+ &_cairo_pattern_white.base,
+ FALSE,
+ &extents->bounded,
+ &extents->bounded,
+ &src_x, &src_y);
+ if (unlikely (src->status))
+ return src;
+
+ status = compositor->acquire (surface);
+ if (unlikely (status)) {
+ cairo_surface_destroy (src);
+ cairo_surface_destroy (surface);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ if (mask_func) {
+ status = mask_func (compositor, surface, draw_closure,
+ CAIRO_OPERATOR_SOURCE, src, src_x, src_y,
+ extents->bounded.x, extents->bounded.y,
+ &extents->bounded, extents->clip);
+ if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED)) {
+ cairo_surface_destroy (src);
+ goto out;
+ }
+ }
+
+ /* Is it worth setting the clip region here? */
+ status = draw_func (compositor, surface, draw_closure,
+ CAIRO_OPERATOR_ADD, src, src_x, src_y,
+ extents->bounded.x, extents->bounded.y,
+ &extents->bounded, NULL);
+ cairo_surface_destroy (src);
+ if (unlikely (status))
+ goto error;
+
+ info.compositor = compositor;
+ info.dst = surface;
+ _cairo_boxes_init (&info.boxes);
+ info.boxes.num_boxes = 1;
+ for (i = 0; i < extents->clip->num_boxes; i++) {
+ cairo_box_t *b = &extents->clip->boxes[i];
+
+ if (! _cairo_fixed_is_integer (b->p1.x) ||
+ ! _cairo_fixed_is_integer (b->p1.y) ||
+ ! _cairo_fixed_is_integer (b->p2.x) ||
+ ! _cairo_fixed_is_integer (b->p2.y))
+ {
+ do_unaligned_box(blt_in, &info, b,
+ extents->bounded.x,
+ extents->bounded.y);
+ }
+ }
+
+ if (extents->clip->path != NULL) {
+ status = combine_clip_as_traps (compositor, surface,
+ extents->clip, &extents->bounded);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ status = _cairo_clip_combine_with_surface (extents->clip, surface,
+ extents->bounded.x,
+ extents->bounded.y);
+ }
+ if (unlikely (status))
+ goto error;
+ }
+
+out:
+ compositor->release (surface);
+ surface->is_clear = FALSE;
+ return surface;
+
+error:
+ cairo_surface_destroy (surface);
+ surface = _cairo_surface_create_in_error (status);
+ compositor->release (surface);
+ return surface;
+}
+
+/* Handles compositing with a clip surface when the operator allows
+ * us to combine the clip with the mask
+ */
+static cairo_status_t
+clip_and_composite_with_mask (const cairo_traps_compositor_t *compositor,
+ const cairo_composite_rectangles_t*extents,
+ draw_func_t draw_func,
+ draw_func_t mask_func,
+ void *draw_closure,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x, int src_y)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_surface_t *mask;
+
+ mask = create_composite_mask (compositor, dst, draw_closure,
+ draw_func, mask_func,
+ extents);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ if (src != NULL || dst->content != CAIRO_CONTENT_ALPHA) {
+ compositor->composite (dst, op, src, mask,
+ extents->bounded.x + src_x,
+ extents->bounded.y + src_y,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ } else {
+ compositor->composite (dst, op, mask, NULL,
+ 0, 0,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ }
+ cairo_surface_destroy (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Handles compositing with a clip surface when we have to do the operation
+ * in two pieces and combine them together.
+ */
+static cairo_status_t
+clip_and_composite_combine (const cairo_traps_compositor_t *compositor,
+ const cairo_composite_rectangles_t*extents,
+ draw_func_t draw_func,
+ void *draw_closure,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x, int src_y)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_surface_t *tmp, *clip;
+ cairo_status_t status;
+
+ tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (tmp->status))
+ return tmp->status;
+
+ status = compositor->acquire (tmp);
+ if (unlikely (status)) {
+ cairo_surface_destroy (tmp);
+ return status;
+ }
+
+ compositor->composite (tmp,
+ dst->is_clear ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
+ dst, NULL,
+ extents->bounded.x, extents->bounded.y,
+ 0, 0,
+ 0, 0,
+ extents->bounded.width, extents->bounded.height);
+
+ status = draw_func (compositor, tmp, draw_closure, op,
+ src, src_x, src_y,
+ extents->bounded.x, extents->bounded.y,
+ &extents->bounded, NULL);
+
+ if (unlikely (status))
+ goto cleanup;
+
+ clip = traps_get_clip_surface (compositor, dst, extents->clip,
+ &extents->bounded);
+ if (unlikely ((status = clip->status)))
+ goto cleanup;
+
+ if (dst->is_clear) {
+ compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
+ 0, 0,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ } else {
+ compositor->lerp (dst, tmp, clip,
+ 0, 0,
+ 0,0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ }
+ cairo_surface_destroy (clip);
+
+cleanup:
+ compositor->release (tmp);
+ cairo_surface_destroy (tmp);
+
+ return status;
+}
+
+/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
+ * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
+ */
+static cairo_status_t
+clip_and_composite_source (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *dst,
+ draw_func_t draw_func,
+ draw_func_t mask_func,
+ void *draw_closure,
+ cairo_surface_t *src,
+ int src_x,
+ int src_y,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *mask;
+
+ /* Create a surface that is mask IN clip */
+ mask = create_composite_mask (compositor, dst, draw_closure,
+ draw_func, mask_func,
+ extents);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ if (dst->is_clear) {
+ compositor->composite (dst, CAIRO_OPERATOR_SOURCE, src, mask,
+ extents->bounded.x + src_x, extents->bounded.y + src_y,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ } else {
+ compositor->lerp (dst, src, mask,
+ extents->bounded.x + src_x, extents->bounded.y + src_y,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ }
+
+ cairo_surface_destroy (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+can_reduce_alpha_op (cairo_operator_t op)
+{
+ int iop = op;
+ switch (iop) {
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_SOURCE:
+ case CAIRO_OPERATOR_ADD:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static cairo_bool_t
+reduce_alpha_op (cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_operator_t op = extents->op;
+ const cairo_pattern_t *pattern = &extents->source_pattern.base;
+ return dst->is_clear &&
+ dst->content == CAIRO_CONTENT_ALPHA &&
+ _cairo_pattern_is_opaque_solid (pattern) &&
+ can_reduce_alpha_op (op);
+}
+
+static cairo_status_t
+fixup_unbounded_with_mask (const cairo_traps_compositor_t *compositor,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_clip_t *clip = extents->clip;
+ cairo_surface_t *mask;
+
+ /* XXX can we avoid querying the clip surface again? */
+ mask = traps_get_clip_surface (compositor, dst, clip, &extents->unbounded);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ /* top */
+ if (extents->bounded.y != extents->unbounded.y) {
+ int x = extents->unbounded.x;
+ int y = extents->unbounded.y;
+ int width = extents->unbounded.width;
+ int height = extents->bounded.y - y;
+
+ compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+ 0, 0,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* left */
+ if (extents->bounded.x != extents->unbounded.x) {
+ int x = extents->unbounded.x;
+ int y = extents->bounded.y;
+ int width = extents->bounded.x - x;
+ int height = extents->bounded.height;
+
+ compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+ 0, y - extents->unbounded.y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* right */
+ if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
+ int x = extents->bounded.x + extents->bounded.width;
+ int y = extents->bounded.y;
+ int width = extents->unbounded.x + extents->unbounded.width - x;
+ int height = extents->bounded.height;
+
+ compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+ x - extents->unbounded.x, y - extents->unbounded.y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* bottom */
+ if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
+ int x = extents->unbounded.x;
+ int y = extents->bounded.y + extents->bounded.height;
+ int width = extents->unbounded.width;
+ int height = extents->unbounded.y + extents->unbounded.height - y;
+
+ compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
+ 0, y - extents->unbounded.y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ cairo_surface_destroy (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+add_rect (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2)
+{
+ cairo_box_t box;
+ cairo_int_status_t status;
+
+ box.p1.x = _cairo_fixed_from_int (x1);
+ box.p1.y = _cairo_fixed_from_int (y1);
+ box.p2.x = _cairo_fixed_from_int (x2);
+ box.p2.y = _cairo_fixed_from_int (y2);
+
+ status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box);
+ assert (status == CAIRO_INT_STATUS_SUCCESS);
+}
+
+static cairo_status_t
+fixup_unbounded (const cairo_traps_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_boxes_t clear, tmp;
+ cairo_box_t box;
+ cairo_int_status_t status;
+
+ if (extents->bounded.width == extents->unbounded.width &&
+ extents->bounded.height == extents->unbounded.height)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ assert (extents->clip->path == NULL);
+
+ /* subtract the drawn boxes from the unbounded area */
+ _cairo_boxes_init (&clear);
+
+ box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+ box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+ box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+ box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+ if (boxes == NULL) {
+ if (extents->bounded.width == 0 || extents->bounded.height == 0) {
+ goto empty;
+ } else {
+ /* top */
+ if (extents->bounded.y != extents->unbounded.y) {
+ add_rect (&clear,
+ extents->unbounded.x, extents->unbounded.y,
+ extents->unbounded.x + extents->unbounded.width,
+ extents->bounded.y);
+ }
+ /* left */
+ if (extents->bounded.x != extents->unbounded.x) {
+ add_rect (&clear,
+ extents->unbounded.x, extents->bounded.y,
+ extents->bounded.x,
+ extents->bounded.y + extents->bounded.height);
+ }
+ /* right */
+ if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
+ add_rect (&clear,
+ extents->bounded.x + extents->bounded.width,
+ extents->bounded.y,
+ extents->unbounded.x + extents->unbounded.width,
+ extents->bounded.y + extents->bounded.height);
+ }
+ /* bottom */
+ if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
+ add_rect (&clear,
+ extents->unbounded.x,
+ extents->bounded.y + extents->bounded.height,
+ extents->unbounded.x + extents->unbounded.width,
+ extents->unbounded.y + extents->unbounded.height);
+ }
+ }
+ } else if (boxes->num_boxes) {
+ _cairo_boxes_init (&tmp);
+
+ assert (boxes->is_pixel_aligned);
+
+ status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
+ assert (status == CAIRO_INT_STATUS_SUCCESS);
+
+ tmp.chunks.next = &boxes->chunks;
+ tmp.num_boxes += boxes->num_boxes;
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+ tmp.chunks.next = NULL;
+ if (unlikely (status))
+ goto error;
+ } else {
+empty:
+ box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
+ box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+
+ status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
+ assert (status == CAIRO_INT_STATUS_SUCCESS);
+ }
+
+ /* Now intersect with the clip boxes */
+ if (extents->clip->num_boxes) {
+ _cairo_boxes_init_for_array (&tmp,
+ extents->clip->boxes,
+ extents->clip->num_boxes);
+ status = _cairo_boxes_intersect (&clear, &tmp, &clear);
+ if (unlikely (status))
+ goto error;
+ }
+
+ status = compositor->fill_boxes (dst,
+ CAIRO_OPERATOR_CLEAR,
+ CAIRO_COLOR_TRANSPARENT,
+ &clear);
+
+error:
+ _cairo_boxes_fini (&clear);
+ return status;
+}
+
+enum {
+ NEED_CLIP_REGION = 0x1,
+ NEED_CLIP_SURFACE = 0x2,
+ FORCE_CLIP_REGION = 0x4,
+};
+
+static cairo_bool_t
+need_bounded_clip (cairo_composite_rectangles_t *extents)
+{
+ unsigned int flags = 0;
+
+ if (extents->unbounded.width < extents->destination.width ||
+ extents->unbounded.height < extents->destination.height)
+ {
+ flags |= NEED_CLIP_REGION;
+ }
+
+ if (! _cairo_clip_is_region (extents->clip))
+ flags |= NEED_CLIP_SURFACE;
+
+ return flags;
+}
+
+static cairo_bool_t
+need_unbounded_clip (cairo_composite_rectangles_t *extents)
+{
+ unsigned int flags = 0;
+ if (! extents->is_bounded) {
+ flags |= NEED_CLIP_REGION;
+ if (! _cairo_clip_is_region (extents->clip))
+ flags |= NEED_CLIP_SURFACE;
+ }
+ if (extents->clip->path != NULL)
+ flags |= NEED_CLIP_SURFACE;
+ return flags;
+}
+
+static cairo_status_t
+clip_and_composite (const cairo_traps_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ draw_func_t draw_func,
+ draw_func_t mask_func,
+ void *draw_closure,
+ unsigned int need_clip)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_operator_t op = extents->op;
+ cairo_pattern_t *source = &extents->source_pattern.base;
+ cairo_surface_t *src;
+ int src_x, src_y;
+ cairo_region_t *clip_region = NULL;
+ cairo_status_t status;
+
+ if (reduce_alpha_op (extents)) {
+ op = CAIRO_OPERATOR_ADD;
+ source = NULL;
+ }
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ op = CAIRO_OPERATOR_DEST_OUT;
+ source = NULL;
+ }
+
+ src = compositor->pattern_to_surface (dst, source, FALSE,
+ &extents->bounded,
+ &extents->source_sample_area,
+ &src_x, &src_y);
+ if (unlikely (src->status))
+ return src->status;
+
+ compositor->acquire (dst);
+
+ if (need_clip & NEED_CLIP_REGION) {
+ const cairo_rectangle_int_t *limit;
+
+ if ((need_clip & FORCE_CLIP_REGION) == 0)
+ limit = &extents->unbounded;
+ else
+ limit = &extents->destination;
+
+ clip_region = _cairo_clip_get_region (extents->clip);
+ if (clip_region != NULL &&
+ cairo_region_contains_rectangle (clip_region,
+ limit) == CAIRO_REGION_OVERLAP_IN)
+ clip_region = NULL;
+
+ if (clip_region != NULL) {
+ status = compositor->set_clip_region (dst, clip_region);
+ if (unlikely (status)) {
+ compositor->release (dst);
+ return status;
+ }
+ }
+ }
+
+ if (op == CAIRO_OPERATOR_SOURCE) {
+ status = clip_and_composite_source (compositor, dst,
+ draw_func, mask_func, draw_closure,
+ src, src_x, src_y,
+ extents);
+ } else {
+ if (need_clip & NEED_CLIP_SURFACE) {
+ if (extents->is_bounded) {
+ status = clip_and_composite_with_mask (compositor, extents,
+ draw_func, mask_func,
+ draw_closure,
+ op, src, src_x, src_y);
+ } else {
+ status = clip_and_composite_combine (compositor, extents,
+ draw_func, draw_closure,
+ op, src, src_x, src_y);
+ }
+ } else {
+ status = draw_func (compositor,
+ dst, draw_closure,
+ op, src, src_x, src_y,
+ 0, 0,
+ &extents->bounded,
+ extents->clip);
+ }
+ }
+
+ if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
+ if (need_clip & NEED_CLIP_SURFACE)
+ status = fixup_unbounded_with_mask (compositor, extents);
+ else
+ status = fixup_unbounded (compositor, extents, NULL);
+ }
+
+ if (clip_region)
+ compositor->set_clip_region (dst, NULL);
+
+ cairo_surface_destroy (src);
+ compositor->release (dst);
+
+ return status;
+}
+
+/* meta-ops */
+
+typedef struct {
+ cairo_traps_t traps;
+ cairo_antialias_t antialias;
+} composite_traps_info_t;
+
+static cairo_int_status_t
+composite_traps (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x, int src_y,
+ int dst_x, int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ composite_traps_info_t *info = closure;
+
+ return compositor->composite_traps (dst, op, src,
+ src_x - dst_x, src_y - dst_y,
+ dst_x, dst_y,
+ extents,
+ info->antialias, &info->traps);
+}
+
+typedef struct {
+ cairo_tristrip_t strip;
+ cairo_antialias_t antialias;
+} composite_tristrip_info_t;
+
+static cairo_int_status_t
+composite_tristrip (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x, int src_y,
+ int dst_x, int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ composite_tristrip_info_t *info = closure;
+
+ return compositor->composite_tristrip (dst, op, src,
+ src_x - dst_x, src_y - dst_y,
+ dst_x, dst_y,
+ extents,
+ info->antialias, &info->strip);
+}
+
+static cairo_bool_t
+is_recording_pattern (const cairo_pattern_t *pattern)
+{
+ cairo_surface_t *surface;
+
+ if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
+ return FALSE;
+
+ surface = ((const cairo_surface_pattern_t *) pattern)->surface;
+ if (_cairo_surface_is_paginated (surface))
+ surface = _cairo_paginated_surface_get_recording (surface);
+ if (_cairo_surface_is_snapshot (surface))
+ surface = _cairo_surface_snapshot_get_target (surface);
+ return _cairo_surface_is_recording (surface);
+}
+
+static cairo_surface_t *
+recording_pattern_get_surface (const cairo_pattern_t *pattern)
+{
+ cairo_surface_t *surface;
+
+ surface = ((const cairo_surface_pattern_t *) pattern)->surface;
+ if (_cairo_surface_is_paginated (surface))
+ surface = _cairo_paginated_surface_get_recording (surface);
+ if (_cairo_surface_is_snapshot (surface))
+ surface = _cairo_surface_snapshot_get_target (surface);
+ return surface;
+}
+
+static cairo_bool_t
+recording_pattern_contains_sample (const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *sample)
+{
+ cairo_recording_surface_t *surface;
+
+ if (! is_recording_pattern (pattern))
+ return FALSE;
+
+ if (pattern->extend == CAIRO_EXTEND_NONE)
+ return TRUE;
+
+ surface = (cairo_recording_surface_t *) recording_pattern_get_surface (pattern);
+ if (surface->unbounded)
+ return TRUE;
+
+ if (sample->x >= surface->extents.x &&
+ sample->y >= surface->extents.y &&
+ sample->x + sample->width <= surface->extents.x + surface->extents.width &&
+ sample->y + sample->height <= surface->extents.y + surface->extents.height)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static cairo_bool_t
+op_reduces_to_source (cairo_composite_rectangles_t *extents)
+{
+ if (extents->op == CAIRO_OPERATOR_SOURCE)
+ return TRUE;
+
+ if (extents->surface->is_clear)
+ return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
+
+ return FALSE;
+}
+
+static cairo_status_t
+composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_surface_t *dst = extents->surface;
+ cairo_operator_t op = extents->op;
+ cairo_bool_t need_clip_mask = extents->clip->path != NULL;
+ cairo_bool_t op_is_source;
+ cairo_status_t status;
+
+ if (need_clip_mask &&
+ (! extents->is_bounded || extents->op == CAIRO_OPERATOR_SOURCE))
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ op_is_source = op_reduces_to_source (extents);
+
+ /* Are we just copying a recording surface? */
+ if (! need_clip_mask && op_is_source &&
+ recording_pattern_contains_sample (&extents->source_pattern.base,
+ &extents->source_sample_area))
+ {
+ cairo_clip_t *recording_clip;
+ cairo_pattern_t *source = &extents->source_pattern.base;
+
+ /* XXX could also do tiling repeat modes... */
+
+ /* first clear the area about to be overwritten */
+ if (! dst->is_clear) {
+ status = compositor->acquire (dst);
+ if (unlikely (status))
+ return status;
+
+ status = compositor->fill_boxes (dst,
+ CAIRO_OPERATOR_CLEAR,
+ CAIRO_COLOR_TRANSPARENT,
+ boxes);
+ compositor->release (dst);
+ if (unlikely (status))
+ return status;
+ }
+
+ recording_clip = _cairo_clip_from_boxes (boxes);
+ status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source),
+ &source->matrix,
+ dst, recording_clip);
+ _cairo_clip_destroy (recording_clip);
+
+ return status;
+ }
+
+ status = compositor->acquire (dst);
+ if (unlikely (status))
+ return status;
+
+ if (! need_clip_mask &&
+ (op == CAIRO_OPERATOR_CLEAR ||
+ extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID))
+ {
+ const cairo_color_t *color;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ color = CAIRO_COLOR_TRANSPARENT;
+ } else {
+ color = &((cairo_solid_pattern_t *) &extents->source_pattern)->color;
+ if (op_is_source)
+ op = CAIRO_OPERATOR_SOURCE;
+ }
+
+ status = compositor->fill_boxes (dst, op, color, boxes);
+ }
+ else
+ {
+ cairo_surface_t *src, *mask = NULL;
+ cairo_pattern_t *source = &extents->source_pattern.base;
+ int src_x, src_y;
+ int mask_x = 0, mask_y = 0;
+
+ if (need_clip_mask) {
+ mask = _cairo_clip_get_surface (extents->clip, dst,
+ &mask_x, &mask_y);
+ if (unlikely (mask->status))
+ return mask->status;
+
+ mask_x = -mask_x;
+ mask_y = -mask_y;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ source = NULL;
+ op = CAIRO_OPERATOR_DEST_OUT;
+ }
+ } else if (op_is_source)
+ op = CAIRO_OPERATOR_SOURCE;
+
+ src = compositor->pattern_to_surface (dst, source, FALSE,
+ &extents->bounded,
+ &extents->source_sample_area,
+ &src_x, &src_y);
+ if (likely (src->status == CAIRO_STATUS_SUCCESS)) {
+ status = compositor->composite_boxes (dst, op, src, mask,
+ src_x, src_y,
+ mask_x, mask_y,
+ 0, 0,
+ boxes, &extents->bounded);
+ cairo_surface_destroy (src);
+ } else
+ status = src->status;
+
+ cairo_surface_destroy (mask);
+ }
+
+ if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
+ status = fixup_unbounded (compositor, extents, boxes);
+
+ compositor->release (dst);
+
+ return status;
+}
+
+static cairo_status_t
+upload_boxes (const cairo_traps_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_surface_t *dst = extents->surface;
+ const cairo_pattern_t *source = &extents->source_pattern.base;
+ const cairo_surface_pattern_t *pattern;
+ cairo_surface_t *src;
+ cairo_rectangle_int_t limit;
+ cairo_int_status_t status;
+ int tx, ty;
+
+ pattern = (const cairo_surface_pattern_t *) source;
+ src = pattern->surface;
+ if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (_cairo_surface_is_snapshot (src))
+ src = _cairo_surface_snapshot_get_target (src);
+ if (_cairo_surface_is_observer (src))
+ src = _cairo_surface_observer_get_target (src);
+ if (_cairo_surface_is_subsurface (src)) {
+ _cairo_surface_subsurface_offset (src, &tx, &ty);
+ src = _cairo_surface_subsurface_get_target (src);
+ }
+
+ /* Check that the data is entirely within the image */
+ if (extents->bounded.x + tx < 0 || extents->bounded.y + ty < 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_surface_get_extents (pattern->surface, &limit);
+ if (extents->bounded.x + extents->bounded.width + tx > limit.width ||
+ extents->bounded.y + extents->bounded.height + ty > limit.height)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE)
+ status = compositor->draw_image_boxes (dst,
+ (cairo_image_surface_t *)src,
+ boxes, tx, ty);
+ else
+ status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
+ tx, ty);
+
+ return status;
+}
+
+static cairo_int_status_t
+trim_extents_to_traps (cairo_composite_rectangles_t *extents,
+ cairo_traps_t *traps)
+{
+ cairo_box_t box;
+
+ _cairo_traps_extents (traps, &box);
+ return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
+}
+
+static cairo_int_status_t
+trim_extents_to_tristrip (cairo_composite_rectangles_t *extents,
+ cairo_tristrip_t *strip)
+{
+ cairo_box_t box;
+
+ _cairo_tristrip_extents (strip, &box);
+ return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
+}
+
+static cairo_int_status_t
+trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_box_t box;
+
+ _cairo_boxes_extents (boxes, &box);
+ return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
+}
+
+static cairo_int_status_t
+boxes_for_traps (cairo_boxes_t *boxes,
+ cairo_traps_t *traps,
+ cairo_antialias_t antialias)
+{
+ int i;
+
+ /* first check that the traps are rectilinear */
+ if (antialias == CAIRO_ANTIALIAS_NONE) {
+ for (i = 0; i < traps->num_traps; i++) {
+ const cairo_trapezoid_t *t = &traps->traps[i];
+ if (_cairo_fixed_integer_round_down (t->left.p1.x) !=
+ _cairo_fixed_integer_round_down (t->left.p2.x) ||
+ _cairo_fixed_integer_round_down (t->right.p1.x) !=
+ _cairo_fixed_integer_round_down (t->right.p2.x))
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ }
+ } else {
+ for (i = 0; i < traps->num_traps; i++) {
+ const cairo_trapezoid_t *t = &traps->traps[i];
+ if (t->left.p1.x != t->left.p2.x || t->right.p1.x != t->right.p2.x)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ }
+
+ _cairo_boxes_init (boxes);
+
+ boxes->num_boxes = traps->num_traps;
+ boxes->chunks.base = (cairo_box_t *) traps->traps;
+ boxes->chunks.count = traps->num_traps;
+ boxes->chunks.size = traps->num_traps;
+
+ if (antialias != CAIRO_ANTIALIAS_NONE) {
+ for (i = 0; i < traps->num_traps; i++) {
+ /* Note the traps and boxes alias so we need to take the local copies first. */
+ cairo_fixed_t x1 = traps->traps[i].left.p1.x;
+ cairo_fixed_t x2 = traps->traps[i].right.p1.x;
+ cairo_fixed_t y1 = traps->traps[i].top;
+ cairo_fixed_t y2 = traps->traps[i].bottom;
+
+ boxes->chunks.base[i].p1.x = x1;
+ boxes->chunks.base[i].p1.y = y1;
+ boxes->chunks.base[i].p2.x = x2;
+ boxes->chunks.base[i].p2.y = y2;
+
+ if (boxes->is_pixel_aligned) {
+ boxes->is_pixel_aligned =
+ _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
+ _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
+ }
+ }
+ } else {
+ boxes->is_pixel_aligned = TRUE;
+
+ for (i = 0; i < traps->num_traps; i++) {
+ /* Note the traps and boxes alias so we need to take the local copies first. */
+ cairo_fixed_t x1 = traps->traps[i].left.p1.x;
+ cairo_fixed_t x2 = traps->traps[i].right.p1.x;
+ cairo_fixed_t y1 = traps->traps[i].top;
+ cairo_fixed_t y2 = traps->traps[i].bottom;
+
+ /* round down here to match Pixman's behavior when using traps. */
+ boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
+ boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
+ boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
+ boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
+ }
+ }
+
+ return CAIRO_INT_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+clip_and_composite_boxes (const cairo_traps_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes);
+
+static cairo_status_t
+clip_and_composite_polygon (const cairo_traps_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_polygon_t *polygon,
+ cairo_antialias_t antialias,
+ cairo_fill_rule_t fill_rule)
+{
+ composite_traps_info_t traps;
+ cairo_surface_t *dst = extents->surface;
+ cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip);
+ cairo_int_status_t status;
+
+ if (polygon->num_edges == 0) {
+ status = CAIRO_INT_STATUS_SUCCESS;
+
+ if (! extents->is_bounded) {
+ cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
+
+ if (clip_region &&
+ cairo_region_contains_rectangle (clip_region,
+ &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
+ clip_region = NULL;
+
+ if (clip_region != NULL) {
+ status = compositor->set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ return status;
+ }
+
+ if (clip_surface)
+ status = fixup_unbounded_with_mask (compositor, extents);
+ else
+ status = fixup_unbounded (compositor, extents, NULL);
+
+ if (clip_region != NULL)
+ compositor->set_clip_region (dst, NULL);
+ }
+
+ return status;
+ }
+
+ if (extents->clip->path != NULL && extents->is_bounded) {
+ cairo_polygon_t clipper;
+ cairo_fill_rule_t clipper_fill_rule;
+ cairo_antialias_t clipper_antialias;
+
+ status = _cairo_clip_get_polygon (extents->clip,
+ &clipper,
+ &clipper_fill_rule,
+ &clipper_antialias);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ if (clipper_antialias == antialias) {
+ status = _cairo_polygon_intersect (polygon, fill_rule,
+ &clipper, clipper_fill_rule);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip);
+ _cairo_clip_destroy (extents->clip);
+ extents->clip = clip;
+
+ fill_rule = CAIRO_FILL_RULE_WINDING;
+ }
+ _cairo_polygon_fini (&clipper);
+ }
+ }
+ }
+
+ _cairo_traps_init (&traps.traps);
+
+ status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
+ if (unlikely (status))
+ goto CLEANUP_TRAPS;
+
+ status = trim_extents_to_traps (extents, &traps.traps);
+ if (unlikely (status))
+ goto CLEANUP_TRAPS;
+
+ /* Use a fast path if the trapezoids consist of a set of boxes. */
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (1) {
+ cairo_boxes_t boxes;
+
+ status = boxes_for_traps (&boxes, &traps.traps, antialias);
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
+ status = clip_and_composite_boxes (compositor, extents, &boxes);
+ /* XXX need to reconstruct the traps! */
+ assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
+ }
+ }
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ /* Otherwise render the trapezoids to a mask and composite in the usual
+ * fashion.
+ */
+ unsigned int flags = 0;
+
+ /* For unbounded operations, the X11 server will estimate the
+ * affected rectangle and apply the operation to that. However,
+ * there are cases where this is an overestimate (e.g. the
+ * clip-fill-{eo,nz}-unbounded test).
+ *
+ * The clip will trim that overestimate to our expectations.
+ */
+ if (! extents->is_bounded)
+ flags |= FORCE_CLIP_REGION;
+
+ traps.antialias = antialias;
+ status = clip_and_composite (compositor, extents,
+ composite_traps, NULL, &traps,
+ need_unbounded_clip (extents) | flags);
+ }
+
+CLEANUP_TRAPS:
+ _cairo_traps_fini (&traps.traps);
+
+ return status;
+}
+
+struct composite_opacity_info {
+ const cairo_traps_compositor_t *compositor;
+ uint8_t op;
+ cairo_surface_t *dst;
+ cairo_surface_t *src;
+ int src_x, src_y;
+ double opacity;
+};
+
+static void composite_opacity(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage)
+{
+ struct composite_opacity_info *info = closure;
+ const cairo_traps_compositor_t *compositor = info->compositor;
+ cairo_surface_t *mask;
+ int mask_x, mask_y;
+ cairo_color_t color;
+ cairo_solid_pattern_t solid;
+
+ _cairo_color_init_rgba (&color, 0, 0, 0, info->opacity * coverage);
+ _cairo_pattern_init_solid (&solid, &color);
+ mask = compositor->pattern_to_surface (info->dst, &solid.base, TRUE,
+ &_cairo_unbounded_rectangle,
+ &_cairo_unbounded_rectangle,
+ &mask_x, &mask_y);
+ if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
+ if (info->src) {
+ compositor->composite (info->dst, info->op, info->src, mask,
+ x + info->src_x, y + info->src_y,
+ mask_x, mask_y,
+ x, y,
+ w, h);
+ } else {
+ compositor->composite (info->dst, info->op, mask, NULL,
+ mask_x, mask_y,
+ 0, 0,
+ x, y,
+ w, h);
+ }
+ }
+
+ cairo_surface_destroy (mask);
+}
+
+
+static cairo_int_status_t
+composite_opacity_boxes (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ const cairo_solid_pattern_t *mask = closure;
+ struct composite_opacity_info info;
+ int i;
+
+ info.compositor = compositor;
+ info.op = op;
+ info.dst = dst;
+
+ info.src = src;
+ info.src_x = src_x;
+ info.src_y = src_y;
+
+ info.opacity = mask->color.alpha / (double) 0xffff;
+
+ /* XXX for lots of boxes create a clip region for the fully opaque areas */
+ for (i = 0; i < clip->num_boxes; i++)
+ do_unaligned_box(composite_opacity, &info,
+ &clip->boxes[i], dst_x, dst_y);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_boxes (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ const cairo_boxes_t *boxes = closure;
+ const struct _cairo_boxes_chunk *chunk;
+ struct composite_opacity_info info;
+ int i;
+
+ info.compositor = compositor;
+ info.op = op;
+ info.dst = dst;
+
+ info.src = src;
+ info.src_x = src_x;
+ info.src_y = src_y;
+
+ info.opacity = 1. / (double) 0xffff;
+
+ /* XXX for lots of boxes create a clip region for the fully opaque areas */
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++)
+ do_unaligned_box(composite_opacity, &info,
+ &chunk->base[i], dst_x, dst_y);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+clip_and_composite_boxes (const cairo_traps_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_int_status_t status;
+
+ if (boxes->num_boxes == 0 && extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = trim_extents_to_boxes (extents, boxes);
+ if (unlikely (status))
+ return status;
+
+ if (boxes->is_pixel_aligned && extents->clip->path == NULL &&
+ extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
+ (op_reduces_to_source (extents) ||
+ (extents->op == CAIRO_OPERATOR_OVER &&
+ (extents->source_pattern.surface.surface->content & CAIRO_CONTENT_ALPHA) == 0)))
+ {
+ status = upload_boxes (compositor, extents, boxes);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+ /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
+ if (extents->clip->path != NULL && extents->is_bounded) {
+ cairo_polygon_t polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+ cairo_clip_t *clip;
+
+ clip = _cairo_clip_copy (extents->clip);
+ clip = _cairo_clip_intersect_boxes (clip, boxes);
+ status = _cairo_clip_get_polygon (clip, &polygon,
+ &fill_rule, &antialias);
+ _cairo_clip_path_destroy (clip->path);
+ clip->path = NULL;
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ cairo_clip_t *saved_clip = extents->clip;
+ extents->clip = clip;
+
+ status = clip_and_composite_polygon (compositor, extents, &polygon,
+ antialias, fill_rule);
+
+ clip = extents->clip;
+ extents->clip = saved_clip;
+
+ _cairo_polygon_fini (&polygon);
+ }
+ _cairo_clip_destroy (clip);
+
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+ /* Use a fast path if the boxes are pixel aligned (or nearly aligned!) */
+ if (boxes->is_pixel_aligned) {
+ status = composite_aligned_boxes (compositor, extents, boxes);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+ return clip_and_composite (compositor, extents,
+ composite_boxes, composite_boxes, boxes,
+ need_unbounded_clip (extents));
+}
+
+static cairo_int_status_t
+composite_traps_as_boxes (const cairo_traps_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ composite_traps_info_t *info)
+{
+ cairo_boxes_t boxes;
+
+ if (! _cairo_traps_to_boxes (&info->traps, info->antialias, &boxes))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return clip_and_composite_boxes (compositor, extents, &boxes);
+}
+
+static cairo_int_status_t
+clip_and_composite_traps (const cairo_traps_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ composite_traps_info_t *info)
+{
+ cairo_int_status_t status;
+
+ status = trim_extents_to_traps (extents, &info->traps);
+ if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
+ return status;
+
+ status = composite_traps_as_boxes (compositor, extents, info);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ unsigned int flags = 0;
+
+ /* For unbounded operations, the X11 server will estimate the
+ * affected rectangle and apply the operation to that. However,
+ * there are cases where this is an overestimate (e.g. the
+ * clip-fill-{eo,nz}-unbounded test).
+ *
+ * The clip will trim that overestimate to our expectations.
+ */
+ if (! extents->is_bounded)
+ flags |= FORCE_CLIP_REGION;
+
+ status = clip_and_composite (compositor, extents,
+ composite_traps, NULL, info,
+ need_unbounded_clip (extents) | flags);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+clip_and_composite_tristrip (const cairo_traps_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ composite_tristrip_info_t *info)
+{
+ cairo_int_status_t status;
+ unsigned int flags = 0;
+
+ status = trim_extents_to_tristrip (extents, &info->strip);
+ if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
+ return status;
+
+ if (! extents->is_bounded)
+ flags |= FORCE_CLIP_REGION;
+
+ status = clip_and_composite (compositor, extents,
+ composite_tristrip, NULL, info,
+ need_unbounded_clip (extents) | flags);
+
+ return status;
+}
+
+struct composite_mask {
+ cairo_surface_t *mask;
+ int mask_x, mask_y;
+};
+
+static cairo_int_status_t
+composite_mask (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ struct composite_mask *data = closure;
+
+ if (src != NULL) {
+ compositor->composite (dst, op, src, data->mask,
+ extents->x + src_x, extents->y + src_y,
+ extents->x + data->mask_x, extents->y + data->mask_y,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+ } else {
+ compositor->composite (dst, op, data->mask, NULL,
+ extents->x + data->mask_x, extents->y + data->mask_y,
+ 0, 0,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+struct composite_box_info {
+ const cairo_traps_compositor_t *compositor;
+ cairo_surface_t *dst;
+ cairo_surface_t *src;
+ int src_x, src_y;
+ uint8_t op;
+};
+
+static void composite_box(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage)
+{
+ struct composite_box_info *info = closure;
+ const cairo_traps_compositor_t *compositor = info->compositor;
+
+ if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) {
+ cairo_surface_t *mask;
+ cairo_color_t color;
+ cairo_solid_pattern_t solid;
+ int mask_x, mask_y;
+
+ _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double)0xffff);
+ _cairo_pattern_init_solid (&solid, &color);
+
+ mask = compositor->pattern_to_surface (info->dst, &solid.base, FALSE,
+ &_cairo_unbounded_rectangle,
+ &_cairo_unbounded_rectangle,
+ &mask_x, &mask_y);
+
+ if (likely (mask->status == CAIRO_STATUS_SUCCESS)) {
+ compositor->composite (info->dst, info->op, info->src, mask,
+ x + info->src_x, y + info->src_y,
+ mask_x, mask_y,
+ x, y,
+ w, h);
+ }
+
+ cairo_surface_destroy (mask);
+ } else {
+ compositor->composite (info->dst, info->op, info->src, NULL,
+ x + info->src_x, y + info->src_y,
+ 0, 0,
+ x, y,
+ w, h);
+ }
+}
+
+static cairo_int_status_t
+composite_mask_clip_boxes (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ struct composite_mask *data = closure;
+ struct composite_box_info info;
+ int i;
+
+ info.compositor = compositor;
+ info.op = CAIRO_OPERATOR_SOURCE;
+ info.dst = dst;
+ info.src = data->mask;
+ info.src_x = data->mask_x;
+ info.src_y = data->mask_y;
+
+ info.src_x += dst_x;
+ info.src_y += dst_y;
+
+ for (i = 0; i < clip->num_boxes; i++)
+ do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_mask_clip (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ struct composite_mask *data = closure;
+ cairo_polygon_t polygon;
+ cairo_fill_rule_t fill_rule;
+ composite_traps_info_t info;
+ cairo_status_t status;
+
+ status = _cairo_clip_get_polygon (clip, &polygon,
+ &fill_rule, &info.antialias);
+ if (unlikely (status))
+ return status;
+
+ _cairo_traps_init (&info.traps);
+ status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps,
+ &polygon,
+ fill_rule);
+ _cairo_polygon_fini (&polygon);
+ if (unlikely (status))
+ return status;
+
+ status = composite_traps (compositor, dst, &info,
+ CAIRO_OPERATOR_SOURCE,
+ data->mask,
+ data->mask_x + dst_x, data->mask_y + dst_y,
+ dst_x, dst_y,
+ extents, NULL);
+ _cairo_traps_fini (&info.traps);
+
+ return status;
+}
+
+/* high-level compositor interface */
+
+static cairo_int_status_t
+_cairo_traps_compositor_paint (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor;
+ cairo_boxes_t boxes;
+ cairo_int_status_t status;
+
+ _cairo_clip_steal_boxes (extents->clip, &boxes);
+ status = clip_and_composite_boxes (compositor, extents, &boxes);
+ _cairo_clip_unsteal_boxes (extents->clip, &boxes);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_traps_compositor_mask (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor;
+ cairo_int_status_t status;
+
+ if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
+ extents->clip->path == NULL) {
+ status = clip_and_composite (compositor, extents,
+ composite_opacity_boxes,
+ composite_opacity_boxes,
+ &extents->mask_pattern,
+ need_unbounded_clip (extents));
+ } else {
+ struct composite_mask data;
+
+ data.mask = compositor->pattern_to_surface (extents->surface,
+ &extents->mask_pattern.base,
+ TRUE,
+ &extents->bounded,
+ &extents->mask_sample_area,
+ &data.mask_x,
+ &data.mask_y);
+
+ status = clip_and_composite (compositor, extents,
+ composite_mask,
+ extents->clip->path ? composite_mask_clip : composite_mask_clip_boxes,
+ &data, need_bounded_clip (extents));
+
+ cairo_surface_destroy (data.mask);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_traps_compositor_stroke (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init_with_clip (&boxes, extents->clip);
+ status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+ style,
+ ctm,
+ antialias,
+ &boxes);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = clip_and_composite_boxes (compositor, extents, &boxes);
+ _cairo_boxes_fini (&boxes);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED && 0 &&
+ _cairo_clip_is_region (extents->clip)) /* XXX */
+ {
+ composite_tristrip_info_t info;
+
+ info.antialias = antialias;
+ _cairo_tristrip_init_with_clip (&info.strip, extents->clip);
+ status = _cairo_path_fixed_stroke_to_tristrip (path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ &info.strip);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = clip_and_composite_tristrip (compositor, extents, &info);
+ _cairo_tristrip_fini (&info.strip);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ composite_traps_info_t info;
+
+ info.antialias = antialias;
+ _cairo_traps_init_with_clip (&info.traps, extents->clip);
+ status = _cairo_path_fixed_stroke_to_traps (path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ &info.traps);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = clip_and_composite_traps (compositor, extents, &info);
+ _cairo_traps_fini (&info.traps);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_traps_compositor_fill (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_fill_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init_with_clip (&boxes, extents->clip);
+ status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+ fill_rule,
+ antialias,
+ &boxes);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = clip_and_composite_boxes (compositor, extents, &boxes);
+ _cairo_boxes_fini (&boxes);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ cairo_polygon_t polygon;
+
+#if 0
+ if (extents->mask.width > extents->unbounded.width ||
+ extents->mask.height > extents->unbounded.height)
+ {
+ cairo_box_t limits;
+ _cairo_box_from_rectangle (&limits, &extents->unbounded);
+ _cairo_polygon_init (&polygon, &limits, 1);
+ }
+ else
+ {
+ _cairo_polygon_init (&polygon, NULL, 0);
+ }
+
+ status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
+ extents->clip->boxes,
+ extents->clip->num_boxes);
+ }
+#else
+ _cairo_polygon_init_with_clip (&polygon, extents->clip);
+ status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
+#endif
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ status = clip_and_composite_polygon (compositor, extents, &polygon,
+ antialias, fill_rule);
+ }
+ _cairo_polygon_fini (&polygon);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+composite_glyphs (const cairo_traps_compositor_t *compositor,
+ cairo_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ cairo_surface_t *src,
+ int src_x, int src_y,
+ int dst_x, int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ cairo_composite_glyphs_info_t *info = closure;
+
+ if (op == CAIRO_OPERATOR_ADD && (dst->content & CAIRO_CONTENT_COLOR) == 0)
+ info->use_mask = 0;
+
+ return compositor->composite_glyphs (dst, op, src,
+ src_x, src_y,
+ dst_x, dst_y,
+ info);
+}
+
+static cairo_int_status_t
+_cairo_traps_compositor_glyphs (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_bool_t overlap)
+{
+ const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor;
+ cairo_int_status_t status;
+
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ status = compositor->check_composite_glyphs (extents,
+ scaled_font, glyphs,
+ &num_glyphs);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ cairo_composite_glyphs_info_t info;
+ unsigned flags = 0;
+
+ info.font = scaled_font;
+ info.glyphs = glyphs;
+ info.num_glyphs = num_glyphs;
+ info.use_mask = overlap || ! extents->is_bounded;
+ info.extents = extents->bounded;
+
+ if (extents->mask.width > extents->bounded.width ||
+ extents->mask.height > extents->bounded.height)
+ {
+ flags |= FORCE_CLIP_REGION;
+ }
+
+ status = clip_and_composite (compositor, extents,
+ composite_glyphs, NULL, &info,
+ need_bounded_clip (extents) |
+ flags);
+ }
+ _cairo_scaled_font_thaw_cache (scaled_font);
+
+ return status;
+}
+
+void
+_cairo_traps_compositor_init (cairo_traps_compositor_t *compositor,
+ const cairo_compositor_t *delegate)
+{
+ compositor->base.delegate = delegate;
+
+ compositor->base.paint = _cairo_traps_compositor_paint;
+ compositor->base.mask = _cairo_traps_compositor_mask;
+ compositor->base.fill = _cairo_traps_compositor_fill;
+ compositor->base.stroke = _cairo_traps_compositor_stroke;
+ compositor->base.glyphs = _cairo_traps_compositor_glyphs;
+}
diff --git a/src/cairo-traps-private.h b/src/cairo-traps-private.h
new file mode 100644
index 00000000..5b17719f
--- /dev/null
+++ b/src/cairo-traps-private.h
@@ -0,0 +1,126 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ */
+
+#ifndef CAIRO_TRAPS_PRIVATE_H
+#define CAIRO_TRAPS_PRIVATE_H
+
+#include "cairo-compiler-private.h"
+#include "cairo-error-private.h"
+#include "cairo-types-private.h"
+
+CAIRO_BEGIN_DECLS
+
+struct _cairo_traps {
+ cairo_status_t status;
+
+ const cairo_box_t *limits;
+ int num_limits;
+
+ unsigned int maybe_region : 1; /* hint: 0 implies that it cannot be */
+ unsigned int has_intersections : 1;
+ unsigned int is_rectilinear : 1;
+ unsigned int is_rectangular : 1;
+
+ int num_traps;
+ int traps_size;
+ cairo_trapezoid_t *traps;
+ cairo_trapezoid_t traps_embedded[16];
+};
+
+/* cairo-traps.c */
+cairo_private void
+_cairo_traps_init (cairo_traps_t *traps);
+
+cairo_private void
+_cairo_traps_init_with_clip (cairo_traps_t *traps,
+ const cairo_clip_t *clip);
+
+cairo_private void
+_cairo_traps_limit (cairo_traps_t *traps,
+ const cairo_box_t *boxes,
+ int num_boxes);
+
+cairo_private cairo_status_t
+_cairo_traps_init_boxes (cairo_traps_t *traps,
+ const cairo_boxes_t *boxes);
+
+cairo_private void
+_cairo_traps_clear (cairo_traps_t *traps);
+
+cairo_private void
+_cairo_traps_fini (cairo_traps_t *traps);
+
+#define _cairo_traps_status(T) (T)->status
+
+cairo_private void
+_cairo_traps_translate (cairo_traps_t *traps, int x, int y);
+
+cairo_private cairo_status_t
+_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
+ const cairo_point_t *top_left,
+ const cairo_point_t *bottom_right);
+
+cairo_private void
+_cairo_traps_add_trap (cairo_traps_t *traps,
+ cairo_fixed_t top, cairo_fixed_t bottom,
+ cairo_line_t *left, cairo_line_t *right);
+
+cairo_private int
+_cairo_traps_contain (const cairo_traps_t *traps,
+ double x, double y);
+
+cairo_private void
+_cairo_traps_extents (const cairo_traps_t *traps,
+ cairo_box_t *extents);
+
+cairo_private cairo_int_status_t
+_cairo_traps_extract_region (cairo_traps_t *traps,
+ cairo_antialias_t antialias,
+ cairo_region_t **region);
+
+cairo_private cairo_bool_t
+_cairo_traps_to_boxes (cairo_traps_t *traps,
+ cairo_antialias_t antialias,
+ cairo_boxes_t *boxes);
+
+cairo_private cairo_status_t
+_cairo_traps_path (const cairo_traps_t *traps,
+ cairo_path_fixed_t *path);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_TRAPS_PRIVATE_H */
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 42e2eb55..a6e7f94e 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -43,6 +43,7 @@
#include "cairo-error-private.h"
#include "cairo-region-private.h"
#include "cairo-slope-private.h"
+#include "cairo-traps-private.h"
/* private functions */
@@ -608,6 +609,66 @@ _cairo_traps_extract_region (cairo_traps_t *traps,
return status;
}
+cairo_bool_t
+_cairo_traps_to_boxes (cairo_traps_t *traps,
+ cairo_antialias_t antialias,
+ cairo_boxes_t *boxes)
+{
+ int i;
+
+ 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)
+ return FALSE;
+ }
+
+ _cairo_boxes_init (boxes);
+
+ boxes->num_boxes = traps->num_traps;
+ boxes->chunks.base = (cairo_box_t *) traps->traps;
+ boxes->chunks.count = traps->num_traps;
+ boxes->chunks.size = traps->num_traps;
+
+ if (antialias != CAIRO_ANTIALIAS_NONE) {
+ for (i = 0; i < traps->num_traps; i++) {
+ /* Note the traps and boxes alias so we need to take the local copies first. */
+ cairo_fixed_t x1 = traps->traps[i].left.p1.x;
+ cairo_fixed_t x2 = traps->traps[i].right.p1.x;
+ cairo_fixed_t y1 = traps->traps[i].top;
+ cairo_fixed_t y2 = traps->traps[i].bottom;
+
+ boxes->chunks.base[i].p1.x = x1;
+ boxes->chunks.base[i].p1.y = y1;
+ boxes->chunks.base[i].p2.x = x2;
+ boxes->chunks.base[i].p2.y = y2;
+
+ if (boxes->is_pixel_aligned) {
+ boxes->is_pixel_aligned =
+ _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
+ _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
+ }
+ }
+ } else {
+ boxes->is_pixel_aligned = TRUE;
+
+ for (i = 0; i < traps->num_traps; i++) {
+ /* Note the traps and boxes alias so we need to take the local copies first. */
+ cairo_fixed_t x1 = traps->traps[i].left.p1.x;
+ cairo_fixed_t x2 = traps->traps[i].right.p1.x;
+ cairo_fixed_t y1 = traps->traps[i].top;
+ cairo_fixed_t y2 = traps->traps[i].bottom;
+
+ /* round down here to match Pixman's behavior when using traps. */
+ boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1);
+ boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1);
+ boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2);
+ boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2);
+ }
+ }
+
+ return TRUE;
+}
+
/* moves trap points such that they become the actual corners of the trapezoid */
static void
_sanitize_trap (cairo_trapezoid_t *t)
diff --git a/src/cairo-tristrip-private.h b/src/cairo-tristrip-private.h
new file mode 100644
index 00000000..ccd28799
--- /dev/null
+++ b/src/cairo-tristrip-private.h
@@ -0,0 +1,94 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * 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.uk>
+ */
+
+#ifndef CAIRO_TRISTRIP_PRIVATE_H
+#define CAIRO_TRISTRIP_PRIVATE_H
+
+#include "cairo-compiler-private.h"
+#include "cairo-error-private.h"
+#include "cairo-types-private.h"
+
+CAIRO_BEGIN_DECLS
+
+struct _cairo_tristrip {
+ cairo_status_t status;
+
+ /* XXX clipping */
+
+ const cairo_box_t *limits;
+ int num_limits;
+
+ int num_points;
+ int size_points;
+ cairo_point_t *points;
+ cairo_point_t points_embedded[64];
+};
+
+cairo_private void
+_cairo_tristrip_init (cairo_tristrip_t *strip);
+
+cairo_private void
+_cairo_tristrip_limit (cairo_tristrip_t *strip,
+ const cairo_box_t *limits,
+ int num_limits);
+
+cairo_private void
+_cairo_tristrip_init_with_clip (cairo_tristrip_t *strip,
+ const cairo_clip_t *clip);
+
+cairo_private void
+_cairo_tristrip_translate (cairo_tristrip_t *strip, int x, int y);
+
+cairo_private void
+_cairo_tristrip_move_to (cairo_tristrip_t *strip,
+ const cairo_point_t *point);
+
+cairo_private void
+_cairo_tristrip_add_point (cairo_tristrip_t *strip,
+ const cairo_point_t *point);
+
+cairo_private void
+_cairo_tristrip_extents (const cairo_tristrip_t *strip,
+ cairo_box_t *extents);
+
+cairo_private void
+_cairo_tristrip_fini (cairo_tristrip_t *strip);
+
+#define _cairo_tristrip_status(T) ((T)->status)
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_TRISTRIP_PRIVATE_H */
diff --git a/src/cairo-tristrip.c b/src/cairo-tristrip.c
new file mode 100644
index 00000000..bb4972f5
--- /dev/null
+++ b/src/cairo-tristrip.c
@@ -0,0 +1,185 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilsonc.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-error-private.h"
+#include "cairo-tristrip-private.h"
+
+void
+_cairo_tristrip_init (cairo_tristrip_t *strip)
+{
+ VG (VALGRIND_MAKE_MEM_UNDEFINED (strip, sizeof (cairo_tristrip_t)));
+
+ strip->status = CAIRO_STATUS_SUCCESS;
+
+ strip->num_limits = 0;
+ strip->num_points = 0;
+
+ strip->size_points = ARRAY_LENGTH (strip->points_embedded);
+ strip->points = strip->points_embedded;
+}
+
+void
+_cairo_tristrip_fini (cairo_tristrip_t *strip)
+{
+ if (strip->points != strip->points_embedded)
+ free (strip->points);
+
+ VG (VALGRIND_MAKE_MEM_NOACCESS (strip, sizeof (cairo_tristrip_t)));
+}
+
+
+void
+_cairo_tristrip_limit (cairo_tristrip_t *strip,
+ const cairo_box_t *limits,
+ int num_limits)
+{
+ strip->limits = limits;
+ strip->num_limits = num_limits;
+}
+
+void
+_cairo_tristrip_init_with_clip (cairo_tristrip_t *strip,
+ const cairo_clip_t *clip)
+{
+ _cairo_tristrip_init (strip);
+ if (clip)
+ _cairo_tristrip_limit (strip, clip->boxes, clip->num_boxes);
+}
+
+/* make room for at least one more trap */
+static cairo_bool_t
+_cairo_tristrip_grow (cairo_tristrip_t *strip)
+{
+ cairo_point_t *points;
+ int new_size = 4 * strip->size_points;
+
+ if (CAIRO_INJECT_FAULT ()) {
+ strip->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return FALSE;
+ }
+
+ if (strip->points == strip->points_embedded) {
+ points = _cairo_malloc_ab (new_size, sizeof (cairo_point_t));
+ if (points != NULL)
+ memcpy (points, strip->points, sizeof (strip->points_embedded));
+ } else {
+ points = _cairo_realloc_ab (strip->points,
+ new_size, sizeof (cairo_trapezoid_t));
+ }
+
+ if (unlikely (points == NULL)) {
+ strip->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return FALSE;
+ }
+
+ strip->points = points;
+ strip->size_points = new_size;
+ return TRUE;
+}
+
+void
+_cairo_tristrip_add_point (cairo_tristrip_t *strip,
+ const cairo_point_t *p)
+{
+ if (unlikely (strip->num_points == strip->size_points)) {
+ if (unlikely (! _cairo_tristrip_grow (strip)))
+ return;
+ }
+
+ strip->points[strip->num_points++] = *p;
+}
+
+/* Insert degenerate triangles to advance to the given point. The
+ * next point inserted must also be @p. */
+void
+_cairo_tristrip_move_to (cairo_tristrip_t *strip,
+ const cairo_point_t *p)
+{
+ if (strip->num_points == 0)
+ return;
+
+ _cairo_tristrip_add_point (strip, &strip->points[strip->num_points-1]);
+ _cairo_tristrip_add_point (strip, p);
+#if 0
+ /* and one more for luck! (to preserve cw/ccw ordering) */
+ _cairo_tristrip_add_point (strip, p);
+#endif
+}
+
+void
+_cairo_tristrip_translate (cairo_tristrip_t *strip, int x, int y)
+{
+ cairo_fixed_t xoff, yoff;
+ cairo_point_t *p;
+ int i;
+
+ xoff = _cairo_fixed_from_int (x);
+ yoff = _cairo_fixed_from_int (y);
+
+ for (i = 0, p = strip->points; i < strip->num_points; i++, p++) {
+ p->x += xoff;
+ p->y += yoff;
+ }
+}
+
+void
+_cairo_tristrip_extents (const cairo_tristrip_t *strip,
+ cairo_box_t *extents)
+{
+ int i;
+
+ if (strip->num_points == 0) {
+ extents->p1.x = extents->p1.y = 0;
+ extents->p2.x = extents->p2.y = 0;
+ return;
+ }
+
+ extents->p2 = extents->p1 = strip->points[0];
+ for (i = 1; i < strip->num_points; i++) {
+ const cairo_point_t *p = &strip->points[i];
+
+ if (p->x < extents->p1.x)
+ extents->p1.x = p->x;
+ else if (p->x > extents->p2.x)
+ extents->p2.x = p->x;
+
+ if (p->y < extents->p1.y)
+ extents->p1.y = p->y;
+ else if (p->y > extents->p2.y)
+ extents->p2.y = p->y;
+ }
+}
diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c
index 88c4ee36..d0d6ab7f 100644
--- a/src/cairo-truetype-subset.c
+++ b/src/cairo-truetype-subset.c
@@ -42,6 +42,8 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
+
+#include "cairo-array-private.h"
#include "cairo-error-private.h"
#if CAIRO_HAS_FONT_SUBSET
diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c
index 5284cfed..4a657413 100644
--- a/src/cairo-type1-fallback.c
+++ b/src/cairo-type1-fallback.c
@@ -35,6 +35,8 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
+
+#include "cairo-array-private.h"
#include "cairo-error-private.h"
#if CAIRO_HAS_FONT_SUBSET
diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c
index a637e24f..efe3028a 100644
--- a/src/cairo-type1-subset.c
+++ b/src/cairo-type1-subset.c
@@ -41,6 +41,8 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
+
+#include "cairo-array-private.h"
#include "cairo-error-private.h"
#if CAIRO_HAS_FONT_SUBSET
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index 07554154..ee2d0e34 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -287,8 +287,7 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs)
+ const cairo_clip_t *clip)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@@ -325,38 +324,32 @@ static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH,
_cairo_type3_glyph_surface_finish,
- _cairo_default_context_create,
+ _cairo_default_context_create, /* XXX usable through a context? */
- NULL, /* _cairo_type3_glyph_surface_create_similar */
- NULL, /* _cairo_type3_glyph_surface_create_similar_image */
- NULL, /* _cairo_type3_glyph_surface_create_map_to_image */
- NULL, /* _cairo_type3_glyph_surface_create_unmap_image */
+ NULL, /* create similar */
+ NULL, /* create similar image */
+ NULL, /* map to image */
+ NULL, /* unmap image */
NULL, /* acquire_source_image */
NULL, /* release_source_image */
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
- NULL, /* cairo_type3_glyph_surface_copy_page */
- NULL, /* _cairo_type3_glyph_surface_show_page */
+ NULL, /* snapshot */
+
+ NULL, /* copy page */
+ NULL, /* show page */
+
NULL, /* _cairo_type3_glyph_surface_get_extents */
- NULL, /* old_show_glyphs */
NULL, /* _cairo_type3_glyph_surface_get_font_options */
+
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
- NULL, /* scaled_font_fini */
- NULL, /* scaled_glyph_fini */
+
_cairo_type3_glyph_surface_paint,
_cairo_type3_glyph_surface_mask,
_cairo_type3_glyph_surface_stroke,
_cairo_type3_glyph_surface_fill,
+ NULL, /* fill-stroke */
_cairo_type3_glyph_surface_show_glyphs,
- NULL, /* snapshot */
};
static void
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index f18a20ea..2fdd0a19 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -80,7 +80,6 @@ typedef struct _cairo_output_stream cairo_output_stream_t;
typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_t;
typedef struct _cairo_path_fixed cairo_path_fixed_t;
typedef struct _cairo_rectangle_int16 cairo_glyph_size_t;
-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_attributes cairo_surface_attributes_t;
@@ -89,11 +88,24 @@ typedef struct _cairo_surface_observer cairo_surface_observer_t;
typedef struct _cairo_surface_snapshot cairo_surface_snapshot_t;
typedef struct _cairo_surface_subsurface cairo_surface_subsurface_t;
typedef struct _cairo_surface_wrapper cairo_surface_wrapper_t;
+typedef struct _cairo_traps cairo_traps_t;
+typedef struct _cairo_tristrip cairo_tristrip_t;
typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t;
typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t;
typedef cairo_array_t cairo_user_data_array_t;
+typedef struct _cairo_scaled_font_private cairo_scaled_font_private_t;
+typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t;
+typedef struct _cairo_scaled_glyph cairo_scaled_glyph_t;
+typedef struct _cairo_scaled_glyph_private cairo_scaled_glyph_private_t;
+
+typedef struct cairo_compositor cairo_compositor_t;
+typedef struct cairo_fallback_compositor cairo_fallback_compositor_t;
+typedef struct cairo_mask_compositor cairo_mask_compositor_t;
+typedef struct cairo_traps_compositor cairo_traps_compositor_t;
+typedef struct cairo_spans_compositor cairo_spans_compositor_t;
+
struct _cairo_observer {
cairo_list_t link;
void (*callback) (cairo_observer_t *self, void *arg);
@@ -248,8 +260,6 @@ typedef enum _cairo_internal_device_type {
} cairo_device_surface_type_t;
#define CAIRO_HAS_TEST_PAGINATED_SURFACE 1
-#define CAIRO_HAS_TEST_NULL_SURFACE 1
-#define CAIRO_HAS_TEST_WRAPPING_SURFACE 1
typedef struct _cairo_slope {
cairo_fixed_t dx;
@@ -413,24 +423,6 @@ typedef struct _cairo_unscaled_font {
cairo_reference_count_t ref_count;
const cairo_unscaled_font_backend_t *backend;
} cairo_unscaled_font_t;
-
-typedef struct _cairo_scaled_glyph {
- cairo_hash_entry_t hash_entry;
-
- cairo_text_extents_t metrics; /* user-space metrics */
- cairo_text_extents_t fs_metrics; /* font-space metrics */
- cairo_box_t bbox; /* device-space bounds */
- int16_t x_advance; /* device-space rounded X advance */
- int16_t y_advance; /* device-space rounded Y advance */
-
- unsigned int has_info;
- cairo_image_surface_t *surface; /* device-space image */
- cairo_path_fixed_t *path; /* device-space outline */
- cairo_surface_t *recording_surface; /* device-space recording-surface */
-
- void *surface_private; /* for the surface backend */
-} cairo_scaled_glyph_t;
-
CAIRO_END_DECLS
#endif /* CAIRO_TYPES_PRIVATE_H */
diff --git a/src/cairo-wideint-private.h b/src/cairo-wideint-private.h
index f6ae5bcf..24c506a7 100644
--- a/src/cairo-wideint-private.h
+++ b/src/cairo-wideint-private.h
@@ -56,6 +56,9 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den);
cairo_uint64_t I _cairo_double_to_uint64 (double i);
double I _cairo_uint64_to_double (uint64_t i);
+cairo_int64_t I _cairo_double_to_int64 (double i);
+double I _cairo_int64_to_double (uint64_t i);
+
cairo_uint64_t I _cairo_uint32_to_uint64 (uint32_t i);
#define _cairo_uint64_to_uint32(a) ((a).lo)
cairo_uint64_t I _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b);
@@ -115,6 +118,9 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
static cairo_always_inline cairo_const cairo_uint64_t _cairo_double_to_uint64 (double i) { return i; }
static cairo_always_inline cairo_const double _cairo_uint64_to_double (cairo_uint64_t i) { return i; }
+static cairo_always_inline cairo_int64_t I _cairo_double_to_int64 (double i) { return i; }
+static cairo_always_inline double I _cairo_int64_to_double (cairo_int64_t i) { return i; }
+
#define _cairo_uint32_to_uint64(i) ((uint64_t) (i))
#define _cairo_uint64_to_uint32(i) ((uint32_t) (i))
#define _cairo_uint64_add(a,b) ((a) + (b))
diff --git a/src/cairo-wideint.c b/src/cairo-wideint.c
index b6e22808..59af2c8c 100644
--- a/src/cairo-wideint.c
+++ b/src/cairo-wideint.c
@@ -99,6 +99,22 @@ _cairo_uint64_to_double (cairo_uint64_t i)
return i.hi * 4294967296. + i.lo;
}
+cairo_int64_t
+_cairo_double_to_int64 (double i)
+{
+ cairo_uint64_t q;
+
+ q.hi = i * (1. / INT32_MAX);
+ q.lo = i - q.hi * (double)INT32_MAX;
+ return q;
+}
+
+double
+_cairo_int64_to_double (cairo_int64_t i)
+{
+ return i.hi * INT32_MAX + i.lo;
+}
+
cairo_uint64_t
_cairo_uint32_to_uint64 (uint32_t i)
{
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 99aca4a9..f6ce2028 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -56,6 +56,7 @@
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-image-info-private.h"
#include "cairo-image-surface-private.h"
+#include "cairo-surface-backend-private.h"
#include "cairo-surface-clipper-private.h"
#include <windows.h>
@@ -1873,21 +1874,17 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
NULL, /* acquire_source_image */
NULL, /* release_source_image */
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ NULL, /* snapshot */
+
NULL, /* copy_page */
_cairo_win32_printing_surface_show_page,
+
_cairo_win32_surface_get_extents,
- NULL, /* old_show_glyphs */
_cairo_win32_printing_surface_get_font_options,
+
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
+
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
@@ -1895,10 +1892,8 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
NULL, /* mask */
_cairo_win32_printing_surface_stroke,
_cairo_win32_printing_surface_fill,
+ NULL, /* fill/stroke */
_cairo_win32_printing_surface_show_glyphs,
- NULL, /* snapshot */
- NULL, /* is_similar */
- NULL, /* fill_stroke */
};
static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend = {
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index b1d1c616..274df3ff 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -2213,7 +2213,7 @@ _cairo_win32_save_initial_clip (HDC hdc, cairo_win32_surface_t *surface)
* set. GetClipBox returns values in logical (transformed) coordinates;
* it's unclear what GetClipRgn returns, because the region is empty in the
* case of a SIMPLEREGION clip, but I assume device (untransformed) coordinates.
- * Similarily, IntersectClipRect works in logical units, whereas SelectClipRgn
+ * Similarly, IntersectClipRect works in logical units, whereas SelectClipRgn
* works in device units.
*
* So, avoid the whole mess and get rid of the world transform
diff --git a/src/cairo-xcb-connection.c b/src/cairo-xcb-connection.c
index b2526484..2808395e 100644
--- a/src/cairo-xcb-connection.c
+++ b/src/cairo-xcb-connection.c
@@ -527,7 +527,7 @@ _device_finish (void *device)
font = cairo_list_first_entry (&connection->fonts,
cairo_xcb_font_t,
link);
- _cairo_xcb_font_finish (font);
+ _cairo_xcb_font_close (font);
}
while (! cairo_list_is_empty (&connection->screens)) {
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index e87f0e88..9223d670 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -48,6 +48,7 @@
#include "cairo-mutex-private.h"
#include "cairo-pattern-private.h"
#include "cairo-reference-count-private.h"
+#include "cairo-scaled-font-private.h"
#include "cairo-spans-private.h"
#include "cairo-surface-private.h"
@@ -167,6 +168,7 @@ typedef struct _cairo_xcb_font_glyphset_info {
} cairo_xcb_font_glyphset_info_t;
struct _cairo_xcb_font {
+ cairo_scaled_font_private_t base;
cairo_scaled_font_t *scaled_font;
cairo_xcb_connection_t *connection;
cairo_xcb_font_glyphset_info_t glyphset_info[NUM_GLYPHSETS];
@@ -321,7 +323,7 @@ cairo_private void
_cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t *connection);
cairo_private void
-_cairo_xcb_font_finish (cairo_xcb_font_t *font);
+_cairo_xcb_font_close (cairo_xcb_font_t *font);
cairo_private cairo_xcb_screen_t *
_cairo_xcb_screen_get (xcb_connection_t *connection,
diff --git a/src/cairo-xcb-surface-core.c b/src/cairo-xcb-surface-core.c
index c2885750..447529d5 100644
--- a/src/cairo-xcb-surface-core.c
+++ b/src/cairo-xcb-surface-core.c
@@ -34,6 +34,7 @@
#include "cairo-boxes-private.h"
#include "cairo-xcb-private.h"
#include "cairo-image-surface-private.h"
+#include "cairo-surface-backend-private.h"
/* XXX dithering */
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index aa9100fc..f9d33c71 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -31,6 +31,8 @@
#include "cairoint.h"
+#include "cairo-xcb-private.h"
+
#include "cairo-boxes-private.h"
#include "cairo-clip-private.h"
#include "cairo-composite-rectangles-private.h"
@@ -39,7 +41,7 @@
#include "cairo-surface-offset-private.h"
#include "cairo-surface-snapshot-private.h"
#include "cairo-surface-subsurface-private.h"
-#include "cairo-xcb-private.h"
+#include "cairo-traps-private.h"
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
@@ -2501,10 +2503,10 @@ _composite_boxes (cairo_xcb_surface_t *dst,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- if (cairo_region_contains_rectangle (clip_region, &extents->bounded) == CAIRO_REGION_OVERLAP_IN) {
- clip = NULL;
+ if (clip_region != NULL &&
+ cairo_region_contains_rectangle (clip_region,
+ &extents->bounded) == CAIRO_REGION_OVERLAP_IN)
clip_region = NULL;
- }
status = _cairo_xcb_connection_acquire (dst->connection);
if (unlikely (status))
@@ -3396,7 +3398,6 @@ _cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_boxes_t boxes;
cairo_status_t status;
@@ -3427,18 +3428,16 @@ _cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
- _cairo_xcb_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_paint (&extents,
+ &surface->base,
op, source,
clip);
if (unlikely (status))
return status;
- status = _cairo_clip_to_boxes(extents.clip, &boxes);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _clip_and_composite_boxes (surface, op, source,
- &boxes, &extents);
- }
+ _cairo_clip_steal_boxes(extents.clip, &boxes);
+ status = _clip_and_composite_boxes (surface, op, source, &boxes, &extents);
+ _cairo_clip_unsteal_boxes (extents.clip, &boxes);
_cairo_composite_rectangles_fini (&extents);
@@ -3453,7 +3452,6 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_status_t status;
if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
@@ -3462,8 +3460,7 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface,
if ((surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
- _cairo_xcb_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_mask (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_mask (&extents, &surface->base,
op, source, mask, clip);
if (unlikely (status))
return status;
@@ -3599,7 +3596,6 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_int_status_t status;
if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
@@ -3611,8 +3607,8 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- _cairo_xcb_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ &surface->base,
op, source,
path, style, ctm,
clip);
@@ -3750,7 +3746,6 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_int_status_t status;
if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
@@ -3762,8 +3757,7 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- _cairo_xcb_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_fill (&extents, &surface->base,
op, source, path,
clip);
if (unlikely (status))
@@ -3916,7 +3910,7 @@ _can_composite_glyphs (cairo_xcb_surface_t *dst,
valid_glyphs = glyphs;
for (glyphs_end = glyphs + *num_glyphs; glyphs != glyphs_end; glyphs++) {
double x1, y1, x2, y2;
- cairo_scaled_glyph_t *scaled_glyph;
+ cairo_scaled_glyph_t *glyph;
cairo_box_t *bbox;
int width, height, len;
int g;
@@ -3926,12 +3920,12 @@ _can_composite_glyphs (cairo_xcb_surface_t *dst,
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs->index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
- &scaled_glyph);
+ &glyph);
if (unlikely (status))
break;
glyph_cache[g] = glyphs->index;
- bbox_cache[g] = scaled_glyph->bbox;
+ bbox_cache[g] = glyph->bbox;
}
bbox = &bbox_cache[g];
@@ -4013,170 +4007,115 @@ typedef struct {
} x_glyph_elt_t;
#define _cairo_sz_x_glyph_elt_t (sizeof (x_glyph_elt_t) + 4)
-static cairo_xcb_font_glyphset_info_t *
-_cairo_xcb_scaled_glyph_get_glyphset_info (cairo_scaled_glyph_t *scaled_glyph)
-{
- return scaled_glyph->surface_private;
-}
-
-static void
-_cairo_xcb_scaled_glyph_set_glyphset_info (cairo_scaled_glyph_t *scaled_glyph,
- cairo_xcb_font_glyphset_info_t *glyphset_info)
-{
- scaled_glyph->surface_private = glyphset_info;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_font_init (cairo_xcb_connection_t *connection,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_font_t *font_private;
- int i;
-
- font_private = malloc (sizeof (cairo_xcb_font_t));
- if (unlikely (font_private == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- font_private->scaled_font = scaled_font;
- font_private->connection = _cairo_xcb_connection_reference (connection);
- for (i = 0; i < NUM_GLYPHSETS; i++) {
- cairo_xcb_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
- switch (i) {
- case GLYPHSET_INDEX_ARGB32: glyphset_info->format = CAIRO_FORMAT_ARGB32; break;
- case GLYPHSET_INDEX_A8: glyphset_info->format = CAIRO_FORMAT_A8; break;
- case GLYPHSET_INDEX_A1: glyphset_info->format = CAIRO_FORMAT_A1; break;
- default: ASSERT_NOT_REACHED; break;
- }
- glyphset_info->xrender_format = 0;
- glyphset_info->glyphset = XCB_NONE;
- glyphset_info->pending_free_glyphs = NULL;
- }
-
- scaled_font->surface_private = font_private;
- scaled_font->surface_backend = &_cairo_xcb_surface_backend;
-
- cairo_list_add (&font_private->link, &connection->fonts);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static void
_cairo_xcb_font_destroy (cairo_xcb_font_t *font)
{
int i;
for (i = 0; i < NUM_GLYPHSETS; i++) {
- cairo_xcb_font_glyphset_info_t *glyphset_info;
+ cairo_xcb_font_glyphset_info_t *info;
- glyphset_info = &font->glyphset_info[i];
-
- free (glyphset_info->pending_free_glyphs);
+ info = &font->glyphset_info[i];
+ free (info->pending_free_glyphs);
}
+ cairo_list_del (&font->base.link);
cairo_list_del (&font->link);
+
_cairo_xcb_connection_destroy (font->connection);
free (font);
}
-void
-_cairo_xcb_font_finish (cairo_xcb_font_t *font)
-{
- cairo_scaled_font_t *scaled_font;
-
- scaled_font = font->scaled_font;
-
- CAIRO_MUTEX_LOCK (scaled_font->mutex);
- scaled_font->surface_private = NULL;
- _cairo_scaled_font_reset_cache (scaled_font);
- CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
-
- _cairo_xcb_font_destroy (font);
-}
-
-void
-_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+static void
+_cairo_xcb_font_fini (cairo_scaled_font_private_t *abstract_private,
+ cairo_scaled_font_t *scaled_font)
{
- cairo_xcb_font_t *font_private;
+ cairo_xcb_font_t *font_private = (cairo_xcb_font_t *)abstract_private;
cairo_xcb_connection_t *connection;
cairo_bool_t have_connection;
cairo_status_t status;
int i;
- font_private = scaled_font->surface_private;
- if (font_private == NULL)
- return;
-
connection = font_private->connection;
status = _cairo_xcb_connection_acquire (connection);
have_connection = status == CAIRO_STATUS_SUCCESS;
for (i = 0; i < NUM_GLYPHSETS; i++) {
- cairo_xcb_font_glyphset_info_t *glyphset_info;
+ cairo_xcb_font_glyphset_info_t *info;
- glyphset_info = &font_private->glyphset_info[i];
- if (glyphset_info->glyphset && status == CAIRO_STATUS_SUCCESS) {
+ info = &font_private->glyphset_info[i];
+ if (info->glyphset && status == CAIRO_STATUS_SUCCESS) {
_cairo_xcb_connection_render_free_glyph_set (connection,
- glyphset_info->glyphset);
+ info->glyphset);
}
}
if (have_connection)
_cairo_xcb_connection_release (connection);
-
_cairo_xcb_font_destroy (font_private);
}
-static void
-_cairo_xcb_render_free_glyphs (cairo_xcb_connection_t *connection,
- cairo_xcb_font_glyphset_free_glyphs_t *to_free)
-{
- _cairo_xcb_connection_render_free_glyphs (connection,
- to_free->glyphset,
- to_free->glyph_count,
- to_free->glyph_indices);
-}
-void
-_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font)
+static cairo_xcb_font_t *
+_cairo_xcb_font_create (cairo_xcb_connection_t *connection,
+ cairo_scaled_font_t *font)
{
- cairo_xcb_font_t *font_private;
- cairo_xcb_font_glyphset_info_t *glyphset_info;
+ cairo_xcb_font_t *priv;
+ int i;
- if (scaled_font->finished)
- return;
+ priv = malloc (sizeof (cairo_xcb_font_t));
+ if (unlikely (priv == NULL))
+ return NULL;
- font_private = scaled_font->surface_private;
- glyphset_info = _cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph);
- if (font_private != NULL && glyphset_info != NULL) {
- cairo_xcb_font_glyphset_free_glyphs_t *to_free;
+ _cairo_scaled_font_attach_private (font, &priv->base, connection,
+ _cairo_xcb_font_fini);
- to_free = glyphset_info->pending_free_glyphs;
- if (to_free != NULL &&
- to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
- {
- _cairo_xcb_render_free_glyphs (font_private->connection, to_free);
- to_free = glyphset_info->pending_free_glyphs = NULL;
+ priv->scaled_font = font;
+ priv->connection = _cairo_xcb_connection_reference (connection);
+ cairo_list_add (&priv->link, &connection->fonts);
+
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xcb_font_glyphset_info_t *info = &priv->glyphset_info[i];
+ switch (i) {
+ case GLYPHSET_INDEX_ARGB32: info->format = CAIRO_FORMAT_ARGB32; break;
+ case GLYPHSET_INDEX_A8: info->format = CAIRO_FORMAT_A8; break;
+ case GLYPHSET_INDEX_A1: info->format = CAIRO_FORMAT_A1; break;
+ default: ASSERT_NOT_REACHED; break;
}
+ info->xrender_format = 0;
+ info->glyphset = XCB_NONE;
+ info->pending_free_glyphs = NULL;
+ }
- if (to_free == NULL) {
- to_free = malloc (sizeof (cairo_xcb_font_glyphset_free_glyphs_t));
- if (unlikely (to_free == NULL)) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return; /* XXX cannot propagate failure */
- }
+ return priv;
+}
- to_free->glyphset = glyphset_info->glyphset;
- to_free->glyph_count = 0;
- glyphset_info->pending_free_glyphs = to_free;
- }
+void
+_cairo_xcb_font_close (cairo_xcb_font_t *font)
+{
+ cairo_scaled_font_t *scaled_font;
- to_free->glyph_indices[to_free->glyph_count++] =
- _cairo_scaled_glyph_index (scaled_glyph);
- }
+ scaled_font = font->scaled_font;
+
+ CAIRO_MUTEX_LOCK (scaled_font->mutex);
+ //scaled_font->surface_private = NULL;
+ _cairo_scaled_font_reset_cache (scaled_font);
+ CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
+
+ _cairo_xcb_font_destroy (font);
+}
+
+static void
+_cairo_xcb_render_free_glyphs (cairo_xcb_connection_t *connection,
+ cairo_xcb_font_glyphset_free_glyphs_t *to_free)
+{
+ _cairo_xcb_connection_render_free_glyphs (connection,
+ to_free->glyphset,
+ to_free->glyph_count,
+ to_free->glyph_indices);
}
static int
@@ -4191,42 +4130,57 @@ _cairo_xcb_get_glyphset_index_for_format (cairo_format_t format)
return GLYPHSET_INDEX_ARGB32;
}
+
+
+static inline cairo_xcb_font_t *
+_cairo_xcb_font_get (const cairo_xcb_connection_t *c,
+ cairo_scaled_font_t *font)
+{
+ return (cairo_xcb_font_t *)_cairo_scaled_font_find_private (font, c);
+}
+
+
static cairo_xcb_font_glyphset_info_t *
-_cairo_xcb_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scaled_font,
+_cairo_xcb_scaled_font_get_glyphset_info_for_format (cairo_xcb_connection_t *c,
+ cairo_scaled_font_t *font,
cairo_format_t format)
{
- cairo_xcb_font_t *font_private;
- cairo_xcb_font_glyphset_info_t *glyphset_info;
+ cairo_xcb_font_t *priv;
+ cairo_xcb_font_glyphset_info_t *info;
int glyphset_index;
glyphset_index = _cairo_xcb_get_glyphset_index_for_format (format);
- font_private = scaled_font->surface_private;
- glyphset_info = &font_private->glyphset_info[glyphset_index];
- if (glyphset_info->glyphset == XCB_NONE) {
- cairo_xcb_connection_t *connection = font_private->connection;
- glyphset_info->glyphset = _cairo_xcb_connection_get_xid (font_private->connection);
- glyphset_info->xrender_format =
- connection->standard_formats[glyphset_info->format];
+ priv = _cairo_xcb_font_get (c, font);
+ if (priv == NULL) {
+ priv = _cairo_xcb_font_create (c, font);
+ if (priv == NULL)
+ return NULL;
+ }
+
+ info = &priv->glyphset_info[glyphset_index];
+ if (info->glyphset == XCB_NONE) {
+ info->glyphset = _cairo_xcb_connection_get_xid (c);
+ info->xrender_format = c->standard_formats[info->format];
- _cairo_xcb_connection_render_create_glyph_set (font_private->connection,
- glyphset_info->glyphset,
- glyphset_info->xrender_format);
+ _cairo_xcb_connection_render_create_glyph_set (c,
+ info->glyphset,
+ info->xrender_format);
}
- return glyphset_info;
+ return info;
}
static cairo_bool_t
_cairo_xcb_glyphset_info_has_pending_free_glyph (
- cairo_xcb_font_glyphset_info_t *glyphset_info,
+ cairo_xcb_font_glyphset_info_t *info,
unsigned long glyph_index)
{
- if (glyphset_info->pending_free_glyphs != NULL) {
+ if (info->pending_free_glyphs != NULL) {
cairo_xcb_font_glyphset_free_glyphs_t *to_free;
int i;
- to_free = glyphset_info->pending_free_glyphs;
+ to_free = info->pending_free_glyphs;
for (i = 0; i < to_free->glyph_count; i++) {
if (to_free->glyph_indices[i] == glyph_index) {
to_free->glyph_count--;
@@ -4241,44 +4195,115 @@ _cairo_xcb_glyphset_info_has_pending_free_glyph (
return FALSE;
}
+typedef struct {
+ cairo_scaled_glyph_private_t base;
+
+ cairo_xcb_font_glyphset_info_t *glyphset;
+} cairo_xcb_glyph_private_t;
+
static cairo_xcb_font_glyphset_info_t *
-_cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (
- cairo_scaled_font_t *scaled_font,
+_cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (cairo_xcb_connection_t *c,
+ cairo_scaled_font_t *font,
unsigned long glyph_index,
cairo_image_surface_t *surface)
{
- cairo_xcb_font_t *font_private;
+ cairo_xcb_font_t *priv;
int i;
- font_private = scaled_font->surface_private;
- if (font_private == NULL)
+ priv = _cairo_xcb_font_get (c, font);
+ if (priv == NULL)
return NULL;
if (surface != NULL) {
i = _cairo_xcb_get_glyphset_index_for_format (surface->format);
if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
- &font_private->glyphset_info[i],
+ &priv->glyphset_info[i],
glyph_index))
{
- return &font_private->glyphset_info[i];
+ return &priv->glyphset_info[i];
}
} else {
for (i = 0; i < NUM_GLYPHSETS; i++) {
if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
- &font_private->glyphset_info[i],
+ &priv->glyphset_info[i],
glyph_index))
{
- return &font_private->glyphset_info[i];
+ return &priv->glyphset_info[i];
}
}
}
return NULL;
}
+
+static void
+_cairo_xcb_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
+ cairo_scaled_glyph_t *glyph,
+ cairo_scaled_font_t *font)
+{
+ cairo_xcb_glyph_private_t *priv = (cairo_xcb_glyph_private_t *)glyph_private;
+
+ if (! font->finished) {
+ cairo_xcb_font_glyphset_info_t *info = priv->glyphset;
+ cairo_xcb_font_glyphset_free_glyphs_t *to_free;
+ cairo_xcb_font_t *font_private;
+
+ font_private = _cairo_xcb_font_get (glyph_private->key, font);
+ assert (font_private);
+
+ to_free = info->pending_free_glyphs;
+ if (to_free != NULL &&
+ to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
+ {
+ _cairo_xcb_render_free_glyphs (font_private->connection, to_free);
+ to_free = info->pending_free_glyphs = NULL;
+ }
+
+ if (to_free == NULL) {
+ to_free = malloc (sizeof (cairo_xcb_font_glyphset_free_glyphs_t));
+ if (unlikely (to_free == NULL)) {
+ _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ return; /* XXX cannot propagate failure */
+ }
+
+ to_free->glyphset = info->glyphset;
+ to_free->glyph_count = 0;
+ info->pending_free_glyphs = to_free;
+ }
+
+ to_free->glyph_indices[to_free->glyph_count++] =
+ _cairo_scaled_glyph_index (glyph);
+ }
+
+ cairo_list_del (&glyph_private->link);
+ free (glyph_private);
+}
+
+
+static cairo_status_t
+_cairo_xcb_glyph_attach (cairo_xcb_connection_t *c,
+ cairo_scaled_glyph_t *glyph,
+ cairo_xcb_font_glyphset_info_t *info)
+{
+ cairo_xcb_glyph_private_t *priv;
+
+ priv = malloc (sizeof (*priv));
+ if (unlikely (priv == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ _cairo_scaled_glyph_attach_private (glyph, &priv->base, c,
+ _cairo_xcb_glyph_fini);
+ priv->glyphset = info;
+
+ glyph->dev_private = info;
+ glyph->dev_private_key = c;
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_status_t
_cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
- cairo_scaled_font_t *scaled_font,
+ cairo_scaled_font_t *font,
cairo_scaled_glyph_t **scaled_glyph_out)
{
xcb_render_glyphinfo_t glyph_info;
@@ -4288,19 +4313,17 @@ _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
cairo_scaled_glyph_t *scaled_glyph = *scaled_glyph_out;
cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
cairo_bool_t already_had_glyph_surface;
- cairo_xcb_font_glyphset_info_t *glyphset_info;
+ cairo_xcb_font_glyphset_info_t *info;
glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
/* check to see if we have a pending XRenderFreeGlyph for this glyph */
- glyphset_info = _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (scaled_font, glyph_index, glyph_surface);
- if (glyphset_info != NULL) {
- _cairo_xcb_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
- return CAIRO_STATUS_SUCCESS;
- }
+ info = _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (connection, font, glyph_index, glyph_surface);
+ if (info != NULL)
+ return _cairo_xcb_glyph_attach (connection, scaled_glyph, info);
if (glyph_surface == NULL) {
- status = _cairo_scaled_glyph_lookup (scaled_font,
+ status = _cairo_scaled_glyph_lookup (font,
glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS |
CAIRO_SCALED_GLYPH_INFO_SURFACE,
@@ -4315,22 +4338,22 @@ _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
already_had_glyph_surface = TRUE;
}
- if (scaled_font->surface_private == NULL) {
- status = _cairo_xcb_surface_font_init (connection, scaled_font);
- if (unlikely (status))
- return status;
+ info = _cairo_xcb_scaled_font_get_glyphset_info_for_format (connection,
+ font,
+ glyph_surface->format);
+ if (unlikely (info == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
}
- glyphset_info = _cairo_xcb_scaled_font_get_glyphset_info_for_format (scaled_font,
- glyph_surface->format);
-
+#if 0
/* If the glyph surface has zero height or width, we create
* a clear 1x1 surface, to avoid various X server bugs.
*/
if (glyph_surface->width == 0 || glyph_surface->height == 0) {
cairo_surface_t *tmp_surface;
- tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
+ tmp_surface = cairo_image_surface_create (info->format, 1, 1);
status = tmp_surface->status;
if (unlikely (status))
goto BAIL;
@@ -4340,14 +4363,15 @@ _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
glyph_surface = (cairo_image_surface_t *) tmp_surface;
}
+#endif
/* If the glyph format does not match the font format, then we
* create a temporary surface for the glyph image with the font's
* format.
*/
- if (glyph_surface->format != glyphset_info->format) {
+ if (glyph_surface->format != info->format) {
glyph_surface = _cairo_image_surface_coerce_to_format (glyph_surface,
- glyphset_info->format);
+ info->format);
status = glyph_surface->base.status;
if (unlikely (status))
goto BAIL;
@@ -4423,7 +4447,7 @@ _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
/* XXX assume X server wants pixman padding. Xft assumes this as well */
_cairo_xcb_connection_render_add_glyphs (connection,
- glyphset_info->glyphset,
+ info->glyphset,
1, &glyph_index, &glyph_info,
glyph_surface->stride * glyph_surface->height,
data);
@@ -4431,7 +4455,7 @@ _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
if (data != glyph_surface->data)
free (data);
- _cairo_xcb_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
+ status = _cairo_xcb_glyph_attach (connection, scaled_glyph, info);
BAIL:
if (glyph_surface != scaled_glyph->surface)
@@ -4444,7 +4468,7 @@ _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
* the cache
*/
if (! already_had_glyph_surface)
- _cairo_scaled_glyph_set_surface (scaled_glyph, scaled_font, NULL);
+ _cairo_scaled_glyph_set_surface (scaled_glyph, font, NULL);
return status;
}
@@ -4471,7 +4495,7 @@ _emit_glyphs_chunk (cairo_xcb_surface_t *dst,
int num_glyphs,
int width,
int estimated_req_size,
- cairo_xcb_font_glyphset_info_t *glyphset_info,
+ cairo_xcb_font_glyphset_info_t *info,
xcb_render_pictformat_t mask_format)
{
cairo_xcb_render_composite_text_func_t composite_text_func;
@@ -4529,7 +4553,7 @@ _emit_glyphs_chunk (cairo_xcb_surface_t *dst,
src->picture,
dst->picture,
mask_format,
- glyphset_info->glyphset,
+ info->glyphset,
src->x + glyphs[0].i.x,
src->y + glyphs[0].i.y,
len, buf);
@@ -4577,43 +4601,43 @@ _composite_glyphs (void *closure,
memset (glyph_cache, 0, sizeof (glyph_cache));
for (i = 0; i < info->num_glyphs; i++) {
- cairo_scaled_glyph_t *scaled_glyph;
+ cairo_scaled_glyph_t *glyph;
unsigned long glyph_index = info->glyphs[i].index;
int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
int old_width = width;
int this_x, this_y;
- scaled_glyph = glyph_cache[cache_index];
- if (scaled_glyph == NULL ||
- _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
+ glyph = glyph_cache[cache_index];
+ if (glyph == NULL ||
+ _cairo_scaled_glyph_index (glyph) != glyph_index)
{
status = _cairo_scaled_glyph_lookup (info->font,
glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
- &scaled_glyph);
+ &glyph);
if (unlikely (status)) {
cairo_surface_destroy (&src->base);
return status;
}
/* Send unseen glyphs to the server */
- if (_cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph) == NULL) {
+ if (glyph->dev_private_key != dst->connection) {
status = _cairo_xcb_surface_add_glyph (dst->connection,
info->font,
- &scaled_glyph);
+ &glyph);
if (unlikely (status)) {
cairo_surface_destroy (&src->base);
return status;
}
}
- glyph_cache[cache_index] = scaled_glyph;
+ glyph_cache[cache_index] = glyph;
}
this_x = _cairo_lround (info->glyphs[i].d.x) - dst_x;
this_y = _cairo_lround (info->glyphs[i].d.y) - dst_y;
- this_glyphset_info = _cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph);
+ this_glyphset_info = glyph->dev_private;
if (glyphset_info == NULL)
glyphset_info = this_glyphset_info;
@@ -4689,8 +4713,8 @@ _composite_glyphs (void *closure,
request_size += _cairo_sz_x_glyph_elt_t;
/* adjust current-position */
- x = this_x + scaled_glyph->x_advance;
- y = this_y + scaled_glyph->y_advance;
+ x = this_x + glyph->x_advance;
+ y = this_y + glyph->y_advance;
request_size += width;
}
@@ -4708,23 +4732,6 @@ _composite_glyphs (void *closure,
return status;
}
-static cairo_bool_t
-_surface_owns_font (cairo_xcb_surface_t *dst,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_font_t *font_private;
-
- font_private = scaled_font->surface_private;
- if ((scaled_font->surface_backend != NULL &&
- scaled_font->surface_backend != dst->base.backend) ||
- (font_private != NULL && font_private->connection != dst->connection))
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
cairo_int_status_t
_cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface,
cairo_operator_t op,
@@ -4735,7 +4742,6 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface,
const cairo_clip_t *clip)
{
cairo_composite_rectangles_t extents;
- cairo_rectangle_int_t unbounded;
cairo_int_status_t status;
cairo_bool_t overlap;
@@ -4745,8 +4751,7 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface,
if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
- _cairo_xcb_surface_get_extents (surface, &unbounded);
- status = _cairo_composite_rectangles_init_for_glyphs (&extents, &unbounded,
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents, &surface->base,
op, source,
scaled_font,
glyphs, num_glyphs,
@@ -4755,40 +4760,38 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface,
return status;
status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS) {
+ if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS && 0) {
_cairo_scaled_font_freeze_cache (scaled_font);
- if (_surface_owns_font (surface, scaled_font)) {
- status = _can_composite_glyphs (surface, &extents.bounded,
- scaled_font, glyphs, &num_glyphs);
- if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
- composite_glyphs_info_t info;
- unsigned flags = 0;
-
- info.font = scaled_font;
- info.glyphs = (cairo_xcb_glyph_t *) glyphs;
- info.num_glyphs = num_glyphs;
- info.use_mask =
- overlap ||
- ! extents.is_bounded ||
- ! _cairo_clip_is_region(extents.clip);
-
- if (extents.mask.width > extents.unbounded.width ||
- extents.mask.height > extents.unbounded.height)
- {
- /* Glyphs are tricky since we do not directly control the
- * geometry and their inked extents depend on the
- * individual glyph-surface size. We must set a clip region
- * so that the X server can trim the glyphs appropriately.
- */
- flags |= FORCE_CLIP_REGION;
- }
- status = _clip_and_composite (surface, op, source,
- _composite_glyphs, NULL,
- &info, &extents,
- need_bounded_clip (&extents) |
- flags);
+ status = _can_composite_glyphs (surface, &extents.bounded,
+ scaled_font, glyphs, &num_glyphs);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ composite_glyphs_info_t info;
+ unsigned flags = 0;
+
+ info.font = scaled_font;
+ info.glyphs = (cairo_xcb_glyph_t *) glyphs;
+ info.num_glyphs = num_glyphs;
+ info.use_mask =
+ overlap ||
+ ! extents.is_bounded ||
+ ! _cairo_clip_is_region(extents.clip);
+
+ if (extents.mask.width > extents.unbounded.width ||
+ extents.mask.height > extents.unbounded.height)
+ {
+ /* Glyphs are tricky since we do not directly control the
+ * geometry and their inked extents depend on the
+ * individual glyph-surface size. We must set a clip region
+ * so that the X server can trim the glyphs appropriately.
+ */
+ flags |= FORCE_CLIP_REGION;
}
+ status = _clip_and_composite (surface, op, source,
+ _composite_glyphs, NULL,
+ &info, &extents,
+ need_bounded_clip (&extents) |
+ flags);
}
_cairo_scaled_font_thaw_cache (scaled_font);
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 9639f916..fe4d6286 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -45,6 +45,7 @@
#include "cairo-default-context-private.h"
#include "cairo-image-surface-private.h"
+#include "cairo-surface-backend-private.h"
#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
slim_hidden_proto (cairo_xcb_surface_create);
@@ -822,14 +823,11 @@ _cairo_xcb_surface_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *num_remaining)
+ const cairo_clip_t *clip)
{
cairo_xcb_surface_t *surface = abstract_surface;
cairo_int_status_t status;
- *num_remaining = 0;
-
if (surface->fallback == NULL) {
status = _cairo_xcb_surface_cairo_glyphs (surface,
op, source,
@@ -864,36 +862,28 @@ const cairo_surface_backend_t _cairo_xcb_surface_backend = {
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_create_similar_image,
-
_cairo_xcb_surface_map_to_image,
_cairo_xcb_surface_unmap,
_cairo_xcb_surface_acquire_source_image,
_cairo_xcb_surface_release_source_image,
+ NULL, /* snapshot */
- NULL, NULL, NULL, /* dest acquire/release/clone */
-
- NULL, /* composite */
- NULL, /* fill */
- NULL, /* trapezoids */
- NULL, /* span */
- NULL, /* check-span */
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_xcb_surface_get_extents,
- NULL, /* old-glyphs */
_cairo_xcb_surface_get_font_options,
_cairo_xcb_surface_flush,
NULL,
- _cairo_xcb_surface_scaled_font_fini,
- _cairo_xcb_surface_scaled_glyph_fini,
_cairo_xcb_surface_paint,
_cairo_xcb_surface_mask,
_cairo_xcb_surface_stroke,
_cairo_xcb_surface_fill,
+ NULL, /* fill-stroke */
_cairo_xcb_surface_glyphs,
};
@@ -1231,26 +1221,25 @@ cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface,
int height)
{
cairo_xcb_surface_t *surface;
- cairo_status_t status_ignored;
if (unlikely (abstract_surface->status))
return;
if (unlikely (abstract_surface->finished)) {
- status_ignored = _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ _cairo_surface_set_error (abstract_surface,
+ _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) {
- status_ignored = _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+ _cairo_surface_set_error (abstract_surface,
+ _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
return;
}
if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) {
- status_ignored = _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_INVALID_SIZE));
+ _cairo_surface_set_error (abstract_surface,
+ _cairo_error (CAIRO_STATUS_INVALID_SIZE));
return;
}
diff --git a/src/cairo-xlib-core-compositor.c b/src/cairo-xlib-core-compositor.c
new file mode 100644
index 00000000..4d59c1f1
--- /dev/null
+++ b/src/cairo-xlib-core-compositor.c
@@ -0,0 +1,524 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Behdad Esfahbod <behdad@behdad.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
+ */
+
+/* The original X drawing API was very restrictive in what it could handle,
+ * pixel-aligned fill/blits are all that map into Cairo's drawing model.
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xlib-private.h"
+#include "cairo-xlib-surface-private.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-compositor-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-region-private.h"
+#include "cairo-surface-offset-private.h"
+
+/* the low-level interface */
+
+static cairo_int_status_t
+acquire (void *abstract_dst)
+{
+ cairo_xlib_surface_t *dst = abstract_dst;
+ return _cairo_xlib_display_acquire (dst->base.device, &dst->display);
+}
+
+static cairo_int_status_t
+release (void *abstract_dst)
+{
+ cairo_xlib_surface_t *dst = abstract_dst;
+
+ cairo_device_release (&dst->display->base);
+ dst->display = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+struct _fill_box {
+ Display *dpy;
+ Drawable drawable;
+ GC gc;
+};
+
+static cairo_bool_t fill_box (cairo_box_t *box, void *closure)
+{
+ struct _fill_box *data = closure;
+ int x = _cairo_fixed_integer_part (box->p1.x);
+ int y = _cairo_fixed_integer_part (box->p1.y);
+ int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
+ int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
+
+ XFillRectangle (data->dpy, data->drawable, data->gc, x, y, width, height);
+ return TRUE;
+}
+
+static cairo_int_status_t
+fill_boxes (cairo_xlib_surface_t *dst,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ cairo_surface_t *dither = NULL;
+ cairo_status_t status;
+ struct _fill_box fb;
+
+ status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb.gc);
+ if (unlikely (status))
+ return status;
+
+ fb.dpy = dst->display->display;
+ fb.drawable = dst->drawable;
+
+ if (dst->visual && dst->visual->class != TrueColor) {
+ cairo_solid_pattern_t solid;
+ cairo_surface_attributes_t attrs;
+
+ _cairo_pattern_init_solid (&solid, color);
+#if 0
+ status = _cairo_pattern_acquire_surface (&solid.base, &dst->base,
+ 0, 0,
+ ARRAY_LENGTH (dither_pattern[0]),
+ ARRAY_LENGTH (dither_pattern),
+ CAIRO_PATTERN_ACQUIRE_NONE,
+ &dither,
+ &attrs);
+ if (unlikely (status)) {
+ _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
+ return status;
+ }
+#endif
+
+ XSetTSOrigin (fb.dpy, fb.gc,
+ - (dst->base.device_transform.x0 + attrs.x_offset),
+ - (dst->base.device_transform.y0 + attrs.y_offset));
+ XSetTile (fb.dpy, fb.gc, ((cairo_xlib_surface_t *) dither)->drawable);
+ } else {
+ //XChangeGC (fb.dpy, fb.gc, GCForeground, color_to_pixel (&color));
+ }
+
+ _cairo_boxes_for_each_box (boxes, fill_box, &fb);
+ _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
+
+ cairo_surface_destroy (dither);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+struct _fallback_box {
+ cairo_xlib_surface_t *dst;
+ cairo_format_t format;
+ const cairo_pattern_t *pattern;
+};
+
+static cairo_bool_t fallback_box (cairo_box_t *box, void *closure)
+{
+ struct _fallback_box *data = closure;
+ int x = _cairo_fixed_integer_part (box->p1.x);
+ int y = _cairo_fixed_integer_part (box->p1.y);
+ int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
+ int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
+ cairo_surface_t *image;
+ cairo_status_t status;
+
+ /* XXX for EXTEND_NONE and if the box is wholly outside we can just fill */
+
+ image = cairo_surface_create_similar_image (&data->dst->base, data->format,
+ width, height);
+ status = _cairo_surface_offset_paint (image, x, y,
+ CAIRO_OPERATOR_SOURCE,
+ data->pattern, NULL);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ status = _cairo_xlib_surface_draw_image (data->dst,
+ (cairo_image_surface_t *)image,
+ 0, 0,
+ width, height,
+ x, y);
+ }
+ cairo_surface_destroy (image);
+
+ return status == CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+fallback_boxes (cairo_xlib_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_boxes_t *boxes)
+{
+ struct _fallback_box fb;
+
+ /* XXX create_similar_image using pixman_format? */
+ switch (dst->depth) {
+ case 8: fb.format = CAIRO_FORMAT_A8; break;
+ case 16: fb.format = CAIRO_FORMAT_RGB16_565; break;
+ case 24: fb.format = CAIRO_FORMAT_RGB24; break;
+ case 30: fb.format = CAIRO_FORMAT_RGB30; break;
+ case 32: fb.format = CAIRO_FORMAT_ARGB32; break;
+ default: return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ fb.dst = dst;
+ fb.pattern = pattern;
+
+ if (! _cairo_boxes_for_each_box (boxes, fallback_box, &fb))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+render_boxes (cairo_xlib_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_boxes_t *boxes)
+{
+ double pad;
+
+ if (_cairo_pattern_analyze_filter (pattern, &pad) != CAIRO_FILTER_NEAREST)
+ return fallback_boxes (dst, pattern, boxes);
+
+ switch (pattern->extend) {
+ default:
+ case CAIRO_EXTEND_NONE:
+ case CAIRO_EXTEND_REFLECT:
+ case CAIRO_EXTEND_PAD:
+ return fallback_boxes (dst, pattern, boxes);
+
+ case CAIRO_EXTEND_REPEAT: /* XXX Use tiling */
+ return fallback_boxes (dst, pattern, boxes);
+ }
+}
+
+/* the mid-level: converts boxes into drawing operations */
+
+struct _box_data {
+ Display *dpy;
+ cairo_xlib_surface_t *dst;
+ cairo_surface_t *src;
+ GC gc;
+ int tx, ty;
+ int width, height;
+};
+
+static cairo_bool_t source_contains_box (cairo_box_t *box, void *closure)
+{
+ struct _box_data *data = closure;
+
+ /* The box is pixel-aligned so the truncation is safe. */
+ return
+ _cairo_fixed_integer_part (box->p1.x) + data->tx >= 0 &&
+ _cairo_fixed_integer_part (box->p1.y) + data->ty >= 0 &&
+ _cairo_fixed_integer_part (box->p2.x) + data->tx <= data->width &&
+ _cairo_fixed_integer_part (box->p2.y) + data->ty <= data->height;
+}
+
+static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure)
+{
+ const struct _box_data *iub = closure;
+ int x = _cairo_fixed_integer_part (box->p1.x);
+ int y = _cairo_fixed_integer_part (box->p1.y);
+ int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
+ int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
+
+ return _cairo_xlib_surface_draw_image (iub->dst,
+ (cairo_image_surface_t *)iub->src,
+ x + iub->tx, y + iub->ty,
+ width, height,
+ x, y) == CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+upload_image_inplace (cairo_xlib_surface_t *dst,
+ const cairo_pattern_t *source,
+ cairo_boxes_t *boxes)
+{
+ const cairo_surface_pattern_t *pattern;
+ struct _box_data iub;
+ cairo_image_surface_t *image;
+
+ if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ pattern = (const cairo_surface_pattern_t *) source;
+ if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ image = (cairo_image_surface_t *) pattern->surface;
+ if (image->format == CAIRO_FORMAT_INVALID)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (image->depth != dst->depth)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* XXX subsurface */
+
+ if (! _cairo_matrix_is_integer_translation (&source->matrix,
+ &iub.tx, &iub.ty))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ iub.dst = dst;
+ iub.src = &image->base;
+ iub.width = image->width;
+ iub.height = image->height;
+
+ /* First check that the data is entirely within the image */
+ if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &iub))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (! _cairo_boxes_for_each_box (boxes, image_upload_box, &iub))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t copy_box (cairo_box_t *box, void *closure)
+{
+ const struct _box_data *cb = closure;
+ int x = _cairo_fixed_integer_part (box->p1.x);
+ int y = _cairo_fixed_integer_part (box->p1.y);
+ int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
+ int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
+
+ XCopyArea (cb->dpy,
+ ((cairo_xlib_surface_t *)cb->src)->drawable,
+ cb->dst->drawable,
+ cb->gc,
+ x + cb->tx, y + cb->ty,
+ width, height,
+ x, y);
+ return TRUE;
+}
+
+static cairo_status_t
+copy_boxes (cairo_xlib_surface_t *dst,
+ const cairo_pattern_t *source,
+ cairo_boxes_t *boxes)
+{
+ const cairo_surface_pattern_t *pattern;
+ struct _box_data cb;
+ cairo_xlib_surface_t *src;
+ cairo_status_t status;
+
+ if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ pattern = (const cairo_surface_pattern_t *) source;
+ if (pattern->surface->type != CAIRO_SURFACE_TYPE_XLIB)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ src = (cairo_xlib_surface_t *) pattern->surface;
+ if (src->depth != dst->depth)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (! _cairo_xlib_surface_same_screen (dst, src))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* XXX subsurface */
+
+ if (! _cairo_matrix_is_integer_translation (&source->matrix,
+ &cb.tx, &cb.ty))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ cb.dpy = dst->display->display;
+ cb.dst = dst;
+ cb.src = &src->base;
+ cb.width = src->width;
+ cb.height = src->height;
+
+ /* First check that the data is entirely within the image */
+ if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_xlib_surface_get_gc (dst->display, dst, &cb.gc);
+ if (unlikely (status))
+ return status;
+
+ if (! _cairo_boxes_for_each_box (boxes, copy_box, &cb))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_xlib_surface_put_gc (dst->display, dst, cb.gc);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+draw_boxes (cairo_composite_rectangles_t *extents,
+ cairo_boxes_t *boxes)
+{
+ cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)extents->surface;
+ cairo_operator_t op = extents->op;
+ const cairo_pattern_t *src = &extents->source_pattern.base;
+ cairo_int_status_t status;
+
+ if (boxes->num_boxes == 0 && extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (! boxes->is_pixel_aligned)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (op == CAIRO_OPERATOR_CLEAR)
+ op = CAIRO_OPERATOR_SOURCE;
+
+ if (_cairo_pattern_is_opaque (src, &extents->bounded))
+ op = CAIRO_OPERATOR_SOURCE;
+
+ if (dst->base.is_clear && op == CAIRO_OPERATOR_OVER)
+ op = CAIRO_OPERATOR_SOURCE;
+
+ if (op != CAIRO_OPERATOR_SOURCE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = acquire (dst);
+ if (unlikely (status))
+ return status;
+
+ if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
+ status = fill_boxes (dst,
+ &((cairo_solid_pattern_t *) src)->color,
+ boxes);
+ } else {
+ status = upload_image_inplace (dst, src, boxes);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ status = copy_boxes (dst, src, boxes);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ status = render_boxes (dst, src, boxes);
+ }
+
+ release (dst);
+
+ return status;
+}
+
+/* high-level compositor interface */
+
+static cairo_int_status_t
+_cairo_xlib_core_compositor_paint (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_clip_is_region (extents->clip)) {
+ cairo_boxes_t boxes;
+
+ _cairo_clip_steal_boxes (extents->clip, &boxes);
+ status = draw_boxes (extents, &boxes);
+ _cairo_clip_unsteal_boxes (extents->clip, &boxes);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_xlib_core_compositor_stroke (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init_with_clip (&boxes, extents->clip);
+ status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+ style,
+ ctm,
+ antialias,
+ &boxes);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = draw_boxes (extents, &boxes);
+ _cairo_boxes_fini (&boxes);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_xlib_core_compositor_fill (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_fill_is_rectilinear (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init_with_clip (&boxes, extents->clip);
+ status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+ fill_rule,
+ antialias,
+ &boxes);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = draw_boxes (extents, &boxes);
+ _cairo_boxes_fini (&boxes);
+ }
+
+ return status;
+}
+
+const cairo_compositor_t *
+_cairo_xlib_core_compositor_get (void)
+{
+ static cairo_compositor_t compositor;
+
+ if (compositor.delegate == NULL) {
+ compositor.delegate = _cairo_xlib_fallback_compositor_get ();
+
+ compositor.paint = _cairo_xlib_core_compositor_paint;
+ compositor.mask = NULL;
+ compositor.fill = _cairo_xlib_core_compositor_fill;
+ compositor.stroke = _cairo_xlib_core_compositor_stroke;
+ compositor.glyphs = NULL; /* XXX PolyGlyph? */
+ }
+
+ return &compositor;
+}
diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index 3acc8937..fd7253cc 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -47,52 +47,8 @@
typedef int (*cairo_xlib_error_func_t) (Display *display,
XErrorEvent *event);
-struct _cairo_xlib_job {
- cairo_xlib_job_t *next;
- enum {
- RESOURCE,
- WORK
- } type;
- union {
- struct {
- cairo_xlib_notify_resource_func notify;
- XID xid;
- } resource;
- struct {
- cairo_xlib_notify_func notify;
- void *data;
- void (*destroy) (void *);
- } work;
- } func;
-};
-
static cairo_xlib_display_t *_cairo_xlib_display_list;
-static void
-_cairo_xlib_remove_close_display_hook_internal (cairo_xlib_display_t *display,
- cairo_xlib_hook_t *hook);
-
-static void
-_cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display)
-{
- cairo_xlib_screen_t *screen;
- cairo_xlib_hook_t *hook;
-
- cairo_list_foreach_entry (screen, cairo_xlib_screen_t, &display->screens, link)
- _cairo_xlib_screen_close_display (display, screen);
-
- while (TRUE) {
- hook = display->close_display_hooks;
- if (hook == NULL)
- break;
-
- _cairo_xlib_remove_close_display_hook_internal (display, hook);
-
- hook->func (display, hook);
- }
- display->closed = TRUE;
-}
-
static int
_noop_error_handler (Display *display,
XErrorEvent *event)
@@ -101,59 +57,6 @@ _noop_error_handler (Display *display,
}
static void
-_cairo_xlib_display_notify (cairo_xlib_display_t *display)
-{
- cairo_xlib_job_t *jobs, *job, *freelist;
- Display *dpy = display->display;
-
- /* Optimistic atomic pointer read -- don't care if it is wrong due to
- * contention as we will check again very shortly.
- */
- if (display->workqueue == NULL)
- return;
-
- jobs = display->workqueue;
- while (jobs != NULL) {
- display->workqueue = NULL;
-
- /* reverse the list to obtain FIFO order */
- job = NULL;
- do {
- cairo_xlib_job_t *next = jobs->next;
- jobs->next = job;
- job = jobs;
- jobs = next;
- } while (jobs != NULL);
- freelist = jobs = job;
-
- do {
- job = jobs;
- jobs = job->next;
-
- switch (job->type){
- case WORK:
- job->func.work.notify (dpy, job->func.work.data);
- if (job->func.work.destroy != NULL)
- job->func.work.destroy (job->func.work.data);
- break;
-
- case RESOURCE:
- job->func.resource.notify (dpy, job->func.resource.xid);
- break;
- }
- } while (jobs != NULL);
-
- do {
- job = freelist;
- freelist = job->next;
- _cairo_freelist_free (&display->wq_freelist, job);
- } while (freelist != NULL);
-
- jobs = display->workqueue;
- }
-}
-
-static void
_cairo_xlib_display_finish (void *abstract_display)
{
cairo_xlib_display_t *display = abstract_display;
@@ -166,11 +69,18 @@ _cairo_xlib_display_finish (void *abstract_display)
XSync (dpy, False);
old_handler = XSetErrorHandler (_noop_error_handler);
- _cairo_xlib_display_notify (display);
- _cairo_xlib_call_close_display_hooks (display);
+ while (! cairo_list_is_empty (&display->fonts)) {
+ _cairo_xlib_font_close (cairo_list_first_entry (&display->fonts,
+ cairo_xlib_font_t,
+ link));
+ }
- /* catch any that arrived before marking the display as closed */
- _cairo_xlib_display_notify (display);
+ while (! cairo_list_is_empty (&display->screens)) {
+ _cairo_xlib_screen_destroy (display,
+ cairo_list_first_entry (&display->screens,
+ cairo_xlib_screen_t,
+ link));
+ }
XSync (dpy, False);
XSetErrorHandler (old_handler);
@@ -184,24 +94,6 @@ _cairo_xlib_display_destroy (void *abstract_display)
{
cairo_xlib_display_t *display = abstract_display;
- /* destroy all outstanding notifies */
- while (display->workqueue != NULL) {
- cairo_xlib_job_t *job = display->workqueue;
- display->workqueue = job->next;
-
- if (job->type == WORK && job->func.work.destroy != NULL)
- job->func.work.destroy (job->func.work.data);
-
- _cairo_freelist_free (&display->wq_freelist, job);
- }
- _cairo_freelist_fini (&display->wq_freelist);
-
- while (! cairo_list_is_empty (&display->screens)) {
- _cairo_xlib_screen_destroy (cairo_list_first_entry (&display->screens,
- cairo_xlib_screen_t,
- link));
- }
-
free (display);
}
@@ -340,15 +232,18 @@ _cairo_xlib_device_create (Display *dpy)
XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
- _cairo_freelist_init (&display->wq_freelist, sizeof (cairo_xlib_job_t));
-
cairo_device_reference (&display->base); /* add one for the CloseDisplay */
display->display = dpy;
cairo_list_init (&display->screens);
- display->workqueue = NULL;
- display->close_display_hooks = NULL;
+ cairo_list_init (&display->fonts);
display->closed = FALSE;
+ display->white = NULL;
+ memset (display->alpha, 0, sizeof (display->alpha));
+ memset (display->solid, 0, sizeof (display->solid));
+ memset (display->solid_cache, 0, sizeof (display->solid_cache));
+ memset (display->last_solid_cache, 0, sizeof (display->last_solid_cache));
+
memset (display->cached_xrender_formats, 0,
sizeof (display->cached_xrender_formats));
@@ -436,6 +331,13 @@ _cairo_xlib_device_create (Display *dpy)
display->buggy_pad_reflect = TRUE;
}
+ if (display->render_major > 0 || display->render_minor >= 4)
+ display->compositor = _cairo_xlib_traps_compositor_get ();
+ else if (display->render_major > 0 || display->render_minor >= 0)
+ display->compositor = _cairo_xlib_mask_compositor_get ();
+ else
+ display->compositor = _cairo_xlib_core_compositor_get ();
+
display->next = _cairo_xlib_display_list;
_cairo_xlib_display_list = display;
@@ -446,92 +348,6 @@ UNLOCK:
return device;
}
-void
-_cairo_xlib_add_close_display_hook (cairo_xlib_display_t *display,
- cairo_xlib_hook_t *hook)
-{
- hook->prev = NULL;
- hook->next = display->close_display_hooks;
- if (hook->next != NULL)
- hook->next->prev = hook;
- display->close_display_hooks = hook;
-}
-
-static void
-_cairo_xlib_remove_close_display_hook_internal (cairo_xlib_display_t *display,
- cairo_xlib_hook_t *hook)
-{
- if (display->close_display_hooks == hook)
- display->close_display_hooks = hook->next;
- else if (hook->prev != NULL)
- hook->prev->next = hook->next;
-
- if (hook->next != NULL)
- hook->next->prev = hook->prev;
-
- hook->prev = NULL;
- hook->next = NULL;
-}
-
-void
-_cairo_xlib_remove_close_display_hook (cairo_xlib_display_t *display,
- cairo_xlib_hook_t *hook)
-{
- _cairo_xlib_remove_close_display_hook_internal (display, hook);
-}
-
-cairo_status_t
-_cairo_xlib_display_queue_resource (cairo_xlib_display_t *display,
- cairo_xlib_notify_resource_func notify,
- XID xid)
-{
- cairo_xlib_job_t *job;
- cairo_status_t status = CAIRO_STATUS_NO_MEMORY;
-
- if (display->closed == FALSE) {
- job = _cairo_freelist_alloc (&display->wq_freelist);
- if (job != NULL) {
- job->type = RESOURCE;
- job->func.resource.xid = xid;
- job->func.resource.notify = notify;
-
- job->next = display->workqueue;
- display->workqueue = job;
-
- status = CAIRO_STATUS_SUCCESS;
- }
- }
-
- return status;
-}
-
-cairo_status_t
-_cairo_xlib_display_queue_work (cairo_xlib_display_t *display,
- cairo_xlib_notify_func notify,
- void *data,
- void (*destroy) (void *))
-{
- cairo_xlib_job_t *job;
- cairo_status_t status = CAIRO_STATUS_NO_MEMORY;
-
- if (display->closed == FALSE) {
- job = _cairo_freelist_alloc (&display->wq_freelist);
- if (job != NULL) {
- job->type = WORK;
- job->func.work.data = data;
- job->func.work.notify = notify;
- job->func.work.destroy = destroy;
-
- job->next = display->workqueue;
- display->workqueue = job;
-
- status = CAIRO_STATUS_SUCCESS;
- }
- }
-
- return status;
-}
-
cairo_status_t
_cairo_xlib_display_acquire (cairo_device_t *device, cairo_xlib_display_t **display)
{
@@ -542,7 +358,6 @@ _cairo_xlib_display_acquire (cairo_device_t *device, cairo_xlib_display_t **disp
return status;
*display = (cairo_xlib_display_t *) device;
- _cairo_xlib_display_notify (*display);
return status;
}
@@ -719,14 +534,6 @@ _cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
return NULL;
}
-void
-_cairo_xlib_display_get_xrender_version (cairo_xlib_display_t *display,
- int *major, int *minor)
-{
- *major = display->render_major;
- *minor = display->render_minor;
-}
-
cairo_bool_t
_cairo_xlib_display_has_repeat (cairo_device_t *device)
{
diff --git a/src/test-null-surface.h b/src/cairo-xlib-fallback-compositor.c
index 3c05190f..53919268 100644
--- a/src/test-null-surface.h
+++ b/src/cairo-xlib-fallback-compositor.c
@@ -1,6 +1,9 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2009 Chris Wilson
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -27,20 +30,25 @@
*
* The Original Code is the cairo graphics library.
*
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
* Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Behdad Esfahbod <behdad@behdad.org>
* Chris Wilson <chris@chris-wilson.co.uk>
+ * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
*/
-#ifndef TEST_NULL_SURFACE_H
-#define TEST_NULL_SURFACE_H
-
-#include "cairo.h"
-
-CAIRO_BEGIN_DECLS
+#include "cairoint.h"
-cairo_public cairo_surface_t *
-_cairo_test_null_surface_create (cairo_content_t content);
+#include "cairo-xlib-private.h"
-CAIRO_END_DECLS
+#include "cairo-compositor-private.h"
-#endif /* TEST_NULL_SURFACE_H */
+const cairo_compositor_t *
+_cairo_xlib_fallback_compositor_get (void)
+{
+ /* XXX Do something interesting here to mitigate fallbacks ala xcb */
+ return &_cairo_fallback_compositor;
+}
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index 3a32eff2..45228323 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -46,21 +46,15 @@
#include "cairo-list-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-types-private.h"
+#include "cairo-scaled-font-private.h"
+#include "cairo-surface-private.h"
#include <pixman.h>
typedef struct _cairo_xlib_display cairo_xlib_display_t;
typedef struct _cairo_xlib_screen cairo_xlib_screen_t;
-
-typedef struct _cairo_xlib_hook cairo_xlib_hook_t;
-typedef struct _cairo_xlib_job cairo_xlib_job_t;
-typedef void (*cairo_xlib_notify_func) (Display *, void *);
-typedef void (*cairo_xlib_notify_resource_func) (Display *, XID);
-
-struct _cairo_xlib_hook {
- cairo_xlib_hook_t *prev, *next; /* private */
- void (*func) (cairo_xlib_display_t *display, void *data);
-};
+typedef struct _cairo_xlib_source cairo_xlib_source_t;
+typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
/* size of color cube */
#define CUBE_SIZE 6
@@ -76,20 +70,43 @@ struct _cairo_xlib_display {
Display *display;
cairo_list_t screens;
+ cairo_list_t fonts;
+
+ const cairo_compositor_t *compositor;
int render_major;
int render_minor;
XRenderPictFormat *cached_xrender_formats[CAIRO_FORMAT_RGB16_565 + 1];
- cairo_xlib_job_t *workqueue;
- cairo_freelist_t wq_freelist;
-
int force_precision;
- cairo_xlib_hook_t *close_display_hooks;
- unsigned int buggy_gradients :1;
- unsigned int buggy_pad_reflect :1;
- unsigned int buggy_repeat :1;
+ cairo_surface_t *white;
+ cairo_surface_t *alpha[256];
+ cairo_surface_t *solid[32];
+ uint32_t solid_cache[32]; /* low 16 are opaque, high 16 transparent */
+ struct {
+ uint32_t color;
+ int index;
+ } last_solid_cache[2];
+
+ /* TRUE if the server has a bug with repeating pictures
+ *
+ * https://bugs.freedesktop.org/show_bug.cgi?id=3566
+ *
+ * We can't test for this because it depends on whether the
+ * picture is in video memory or not.
+ *
+ * We also use this variable as a guard against a second
+ * independent bug with transformed repeating pictures:
+ *
+ * http://lists.freedesktop.org/archives/cairo/2004-September/001839.html
+ *
+ * Both are fixed in xorg >= 6.9 and hopefully in > 6.8.2, so
+ * we can reuse the test for now.
+ */
+ unsigned int buggy_gradients : 1;
+ unsigned int buggy_pad_reflect : 1;
+ unsigned int buggy_repeat : 1;
unsigned int closed :1;
};
@@ -120,6 +137,79 @@ struct _cairo_xlib_screen {
cairo_list_t visuals;
};
+enum {
+ GLYPHSET_INDEX_ARGB32,
+ GLYPHSET_INDEX_A8,
+ GLYPHSET_INDEX_A1,
+ NUM_GLYPHSETS
+};
+
+typedef struct _cairo_xlib_font_glyphset {
+ GlyphSet glyphset;
+ cairo_format_t format;
+ XRenderPictFormat *xrender_format;
+ struct _cairo_xlib_font_glyphset_free_glyphs {
+ int count;
+ unsigned long indices[128];
+ } to_free;
+} cairo_xlib_font_glyphset_t;
+
+typedef struct _cairo_xlib_font {
+ cairo_scaled_font_private_t base;
+ cairo_scaled_font_t *font;
+ cairo_device_t *device;
+ cairo_list_t link;
+ cairo_xlib_font_glyphset_t glyphset[NUM_GLYPHSETS];
+} cairo_xlib_font_t;
+
+struct _cairo_xlib_surface {
+ cairo_surface_t base;
+
+ Picture picture;
+
+ const cairo_compositor_t *compositor;
+
+ cairo_xlib_display_t *display;
+ cairo_xlib_screen_t *screen;
+ cairo_list_t link;
+
+ Display *dpy; /* only valid between acquire/release */
+ Drawable drawable;
+ cairo_bool_t owns_pixmap;
+ Visual *visual;
+
+ int use_pixmap;
+
+ int width;
+ int height;
+ int depth;
+
+ int precision;
+ XRenderPictFormat *xrender_format;
+ /* XXX pixman_format instead of masks? */
+ uint32_t a_mask;
+ uint32_t r_mask;
+ uint32_t g_mask;
+ uint32_t b_mask;
+
+ struct _cairo_xlib_source {
+ cairo_surface_t base;
+
+ Picture picture;
+ Display *dpy;
+
+ unsigned int filter:3;
+ unsigned int extend:3;
+ unsigned int has_matrix:1;
+ unsigned int has_component_alpha:1;
+ } embedded_source;
+};
+
+cairo_private cairo_status_t
+_cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
+ cairo_xlib_surface_t *surface,
+ GC *gc);
+
cairo_private cairo_device_t *
_cairo_xlib_device_create (Display *display);
@@ -127,29 +217,10 @@ cairo_private cairo_xlib_screen_t *
_cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
Screen *screen);
-cairo_private void
-_cairo_xlib_add_close_display_hook (cairo_xlib_display_t *display, cairo_xlib_hook_t *hook);
-
-cairo_private void
-_cairo_xlib_remove_close_display_hook (cairo_xlib_display_t *display, cairo_xlib_hook_t *hook);
-
-cairo_private cairo_status_t
-_cairo_xlib_display_queue_work (cairo_xlib_display_t *display,
- cairo_xlib_notify_func notify,
- void *data,
- void (*destroy)(void *));
-cairo_private cairo_status_t
-_cairo_xlib_display_queue_resource (cairo_xlib_display_t *display,
- cairo_xlib_notify_resource_func notify,
- XID resource);
cairo_private cairo_status_t
_cairo_xlib_display_acquire (cairo_device_t *device,
cairo_xlib_display_t **display);
-cairo_private void
-_cairo_xlib_display_get_xrender_version (cairo_xlib_display_t *display,
- int *major, int *minor);
-
cairo_private cairo_bool_t
_cairo_xlib_display_has_repeat (cairo_device_t *device);
@@ -177,21 +248,17 @@ _cairo_xlib_screen_get (Display *dpy,
cairo_xlib_screen_t **out);
cairo_private void
-_cairo_xlib_screen_destroy (cairo_xlib_screen_t *info);
-
-cairo_private void
-_cairo_xlib_screen_close_display (cairo_xlib_display_t *display,
- cairo_xlib_screen_t *info);
+_cairo_xlib_screen_destroy (cairo_xlib_display_t *display,
+ cairo_xlib_screen_t *info);
cairo_private GC
_cairo_xlib_screen_get_gc (cairo_xlib_display_t *display,
cairo_xlib_screen_t *info,
int depth,
Drawable drawable);
-
cairo_private void
_cairo_xlib_screen_put_gc (cairo_xlib_display_t *display,
- cairo_xlib_screen_t *info,
+ cairo_xlib_screen_t *info,
int depth,
GC gc);
@@ -213,4 +280,105 @@ _cairo_xlib_visual_info_create (Display *dpy,
cairo_private void
_cairo_xlib_visual_info_destroy (cairo_xlib_visual_info_t *info);
+cairo_private const cairo_compositor_t *
+_cairo_xlib_core_compositor_get (void);
+
+cairo_private const cairo_compositor_t *
+_cairo_xlib_fallback_compositor_get (void);
+
+cairo_private const cairo_compositor_t *
+_cairo_xlib_mask_compositor_get (void);
+
+cairo_private const cairo_compositor_t *
+_cairo_xlib_traps_compositor_get (void);
+
+cairo_private void
+_cairo_xlib_surface_ensure_picture (cairo_xlib_surface_t *surface);
+
+cairo_private void
+_cairo_xlib_surface_set_precision (cairo_xlib_surface_t *surface,
+ cairo_antialias_t antialias);
+
+cairo_private cairo_int_status_t
+_cairo_xlib_surface_set_attributes (cairo_xlib_display_t *display,
+ cairo_xlib_surface_t *surface,
+ cairo_surface_attributes_t *attributes,
+ double xc,
+ double yc);
+
+cairo_private cairo_status_t
+_cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
+ cairo_image_surface_t *image,
+ int src_x,
+ int src_y,
+ int width,
+ int height,
+ int dst_x,
+ int dst_y);
+
+cairo_private cairo_surface_t *
+_cairo_xlib_source_create_for_pattern (cairo_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y);
+
+cairo_private void
+_cairo_xlib_font_close (cairo_xlib_font_t *font);
+
+#define CAIRO_RENDER_AT_LEAST(surface, major, minor) \
+ (((surface)->render_major > major) || \
+ (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
+
+#define CAIRO_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 0)
+#define CAIRO_RENDER_HAS_COMPOSITE(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 0)
+#define CAIRO_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 0)
+
+#define CAIRO_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 1)
+
+#define CAIRO_RENDER_HAS_DISJOINT(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 2)
+#define CAIRO_RENDER_HAS_CONJOINT(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 2)
+
+#define CAIRO_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 4)
+#define CAIRO_RENDER_HAS_TRIANGLES(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 4)
+#define CAIRO_RENDER_HAS_TRISTRIP(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 4)
+#define CAIRO_RENDER_HAS_TRIFAN(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 4)
+
+#define CAIRO_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 6)
+#define CAIRO_RENDER_HAS_FILTERS(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 6)
+
+#define CAIRO_RENDER_HAS_EXTENDED_REPEAT(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 10)
+#define CAIRO_RENDER_HAS_GRADIENTS(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 10)
+
+#define CAIRO_RENDER_HAS_PDF_OPERATORS(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 11)
+
+#define CAIRO_RENDER_SUPPORTS_OPERATOR(surface, op) \
+ ((op) <= CAIRO_OPERATOR_SATURATE || \
+ (CAIRO_RENDER_HAS_PDF_OPERATORS(surface) && \
+ (op) <= CAIRO_OPERATOR_HSL_LUMINOSITY))
+
+/*
+ * Return whether two xlib surfaces share the same
+ * screen. Both core and Render drawing require this
+ * when using multiple drawables in an operation.
+ */
+static inline cairo_bool_t
+_cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
+ cairo_xlib_surface_t *src)
+{
+ return dst->screen == src->screen;
+}
+
+static inline void
+_cairo_xlib_surface_put_gc (cairo_xlib_display_t *display,
+ cairo_xlib_surface_t *surface,
+ GC gc)
+{
+ _cairo_xlib_screen_put_gc (display,
+ surface->screen,
+ surface->depth,
+ gc);
+}
+
#endif /* CAIRO_XLIB_PRIVATE_H */
diff --git a/src/cairo-xlib-render-compositor.c b/src/cairo-xlib-render-compositor.c
new file mode 100644
index 00000000..6e53f133
--- /dev/null
+++ b/src/cairo-xlib-render-compositor.c
@@ -0,0 +1,1685 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Behdad Esfahbod <behdad@behdad.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xlib-private.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-traps-private.h"
+#include "cairo-tristrip-private.h"
+
+static cairo_int_status_t
+acquire (void *abstract_dst)
+{
+ cairo_xlib_surface_t *dst = abstract_dst;
+ cairo_int_status_t status;
+
+ status = _cairo_xlib_display_acquire (dst->base.device, &dst->display);
+ if (unlikely (status))
+ return status;
+
+ dst->dpy = dst->display->display;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+release (void *abstract_dst)
+{
+ cairo_xlib_surface_t *dst = abstract_dst;
+
+ cairo_device_release (&dst->display->base);
+ dst->dpy = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+set_clip_region (void *_surface,
+ cairo_region_t *region)
+{
+ cairo_xlib_surface_t *surface = _surface;
+
+ _cairo_xlib_surface_ensure_picture (surface);
+
+ if (region != NULL) {
+ XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
+ XRectangle *rects = stack_rects;
+ int n_rects, i;
+
+ n_rects = cairo_region_num_rectangles (region);
+ if (n_rects > ARRAY_LENGTH (stack_rects)) {
+ rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
+ if (unlikely (rects == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ 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;
+ }
+ XRenderSetPictureClipRectangles (surface->dpy,
+ surface->picture,
+ 0, 0,
+ rects, n_rects);
+ if (rects != stack_rects)
+ free (rects);
+ } else {
+ XRenderPictureAttributes pa;
+ pa.clip_mask = None;
+ XRenderChangePicture (surface->dpy,
+ surface->picture,
+ CPClipMask, &pa);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+draw_image_boxes (void *_dst,
+ cairo_image_surface_t *image,
+ cairo_boxes_t *boxes,
+ int dx, int dy)
+{
+ struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ cairo_box_t *b = &chunk->base[i];
+ int x1 = _cairo_fixed_integer_part (b->p1.x);
+ int y1 = _cairo_fixed_integer_part (b->p1.y);
+ int x2 = _cairo_fixed_integer_part (b->p2.x);
+ int y2 = _cairo_fixed_integer_part (b->p2.y);
+ if ( _cairo_xlib_surface_draw_image (_dst, image,
+ x1 + dx, y1 + dy,
+ x2 - x1, y2 - y1,
+ x1, y1))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+copy_boxes (void *_dst,
+ cairo_surface_t *_src,
+ cairo_boxes_t *boxes,
+ const cairo_rectangle_int_t *extents,
+ int dx, int dy)
+{
+ cairo_xlib_surface_t *dst = _dst;
+ cairo_xlib_surface_t *src = (cairo_xlib_surface_t *)_src;
+ struct _cairo_boxes_chunk *chunk;
+ cairo_int_status_t status;
+ GC gc;
+ int i, j;
+
+ if (! _cairo_xlib_surface_same_screen (dst, src))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (dst->depth != src->depth)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = acquire (dst);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
+ if (unlikely (status)) {
+ release (dst);
+ return status;
+ }
+
+ if (boxes->num_boxes == 1) {
+ int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
+ int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
+ int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
+ int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
+
+ XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
+ x1 + dx, y1 + dy,
+ x2 - x1, y2 - y1,
+ x1, y1);
+ } else {
+ XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
+ XRectangle *rects = stack_rects;
+
+ if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
+ rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
+ if (unlikely (rects == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ j = 0;
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+ rects[j].x = x1;
+ rects[j].y = y1;
+ rects[j].width = x2 - x1;
+ rects[j].height = y2 - y1;
+ j++;
+ }
+ }
+ assert (j == boxes->num_boxes);
+
+ XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, YSorted);
+
+ XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
+ extents->x + dx, extents->y + dy,
+ extents->width, extents->height,
+ extents->x, extents->y);
+
+ XSetClipMask (dst->dpy, gc, None);
+
+ if (rects != stack_rects)
+ free (rects);
+ }
+
+ _cairo_xlib_surface_put_gc (dst->display, dst, gc);
+ release (dst);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static int
+_render_operator (cairo_operator_t op)
+{
+ switch (op) {
+ case CAIRO_OPERATOR_CLEAR:
+ return PictOpClear;
+
+ case CAIRO_OPERATOR_SOURCE:
+ return PictOpSrc;
+ case CAIRO_OPERATOR_OVER:
+ return PictOpOver;
+ case CAIRO_OPERATOR_IN:
+ return PictOpIn;
+ case CAIRO_OPERATOR_OUT:
+ return PictOpOut;
+ case CAIRO_OPERATOR_ATOP:
+ return PictOpAtop;
+
+ case CAIRO_OPERATOR_DEST:
+ return PictOpDst;
+ case CAIRO_OPERATOR_DEST_OVER:
+ return PictOpOverReverse;
+ case CAIRO_OPERATOR_DEST_IN:
+ return PictOpInReverse;
+ case CAIRO_OPERATOR_DEST_OUT:
+ return PictOpOutReverse;
+ case CAIRO_OPERATOR_DEST_ATOP:
+ return PictOpAtopReverse;
+
+ case CAIRO_OPERATOR_XOR:
+ return PictOpXor;
+ case CAIRO_OPERATOR_ADD:
+ return PictOpAdd;
+ case CAIRO_OPERATOR_SATURATE:
+ return PictOpSaturate;
+
+ case CAIRO_OPERATOR_MULTIPLY:
+ return PictOpMultiply;
+ case CAIRO_OPERATOR_SCREEN:
+ return PictOpScreen;
+ case CAIRO_OPERATOR_OVERLAY:
+ return PictOpOverlay;
+ case CAIRO_OPERATOR_DARKEN:
+ return PictOpDarken;
+ case CAIRO_OPERATOR_LIGHTEN:
+ return PictOpLighten;
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ return PictOpColorDodge;
+ case CAIRO_OPERATOR_COLOR_BURN:
+ return PictOpColorBurn;
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ return PictOpHardLight;
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ return PictOpSoftLight;
+ case CAIRO_OPERATOR_DIFFERENCE:
+ return PictOpDifference;
+ case CAIRO_OPERATOR_EXCLUSION:
+ return PictOpExclusion;
+ case CAIRO_OPERATOR_HSL_HUE:
+ return PictOpHSLHue;
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ return PictOpHSLSaturation;
+ case CAIRO_OPERATOR_HSL_COLOR:
+ return PictOpHSLColor;
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
+ return PictOpHSLLuminosity;
+
+ default:
+ ASSERT_NOT_REACHED;
+ return PictOpOver;
+ }
+}
+
+static cairo_bool_t
+fill_reduces_to_source (cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_xlib_surface_t *dst)
+{
+ if (dst->base.is_clear || CAIRO_COLOR_IS_OPAQUE (color))
+ return op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD;
+
+ return FALSE;
+}
+
+static cairo_int_status_t
+fill_rectangles (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_rectangle_int_t *rects,
+ int num_rects)
+{
+ cairo_xlib_surface_t *dst = abstract_surface;
+ XRenderColor render_color;
+ int i;
+
+ //X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
+
+ render_color.red = color->red_short;
+ render_color.green = color->green_short;
+ render_color.blue = color->blue_short;
+ render_color.alpha = color->alpha_short;
+
+ if (fill_reduces_to_source (op, color, dst))
+ op = CAIRO_OPERATOR_SOURCE;
+
+ _cairo_xlib_surface_ensure_picture (dst);
+ if (num_rects == 1) {
+ /* Take advantage of the protocol compaction that libXrender performs
+ * to amalgamate sequences of XRenderFillRectangle().
+ */
+ XRenderFillRectangle (dst->dpy,
+ _render_operator (op),
+ dst->picture,
+ &render_color,
+ rects->x, rects->y,
+ rects->width, rects->height);
+ } else {
+ XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
+ XRectangle *xrects = stack_xrects;
+
+ if (num_rects > ARRAY_LENGTH (stack_xrects)) {
+ xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
+ if (unlikely (xrects == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ for (i = 0; i < num_rects; i++) {
+ xrects[i].x = rects[i].x;
+ xrects[i].y = rects[i].y;
+ xrects[i].width = rects[i].width;
+ xrects[i].height = rects[i].height;
+ }
+
+ XRenderFillRectangles (dst->dpy,
+ _render_operator (op),
+ dst->picture,
+ &render_color, xrects, num_rects);
+
+ if (xrects != stack_xrects)
+ free (xrects);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+fill_boxes (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ cairo_xlib_surface_t *dst = abstract_surface;
+ XRenderColor render_color;
+
+ render_color.red = color->red_short;
+ render_color.green = color->green_short;
+ render_color.blue = color->blue_short;
+ render_color.alpha = color->alpha_short;
+
+ if (fill_reduces_to_source (op, color, dst))
+ op = CAIRO_OPERATOR_SOURCE;
+
+ _cairo_xlib_surface_ensure_picture (dst);
+ if (boxes->num_boxes == 1) {
+ int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
+ int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
+ int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
+ int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
+
+ /* Take advantage of the protocol compaction that libXrender performs
+ * to amalgamate sequences of XRenderFillRectangle().
+ */
+ XRenderFillRectangle (dst->dpy,
+ _render_operator (op),
+ dst->picture,
+ &render_color,
+ x1, y1,
+ x2 - x1, y2 - y1);
+ } else {
+ XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
+ XRectangle *xrects = stack_xrects;
+ struct _cairo_boxes_chunk *chunk;
+ int i, j;
+
+ if (boxes->num_boxes > ARRAY_LENGTH (stack_xrects)) {
+ xrects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
+ if (unlikely (xrects == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ j = 0;
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+ xrects[j].x = x1;
+ xrects[j].y = y1;
+ xrects[j].width = x2 - x1;
+ xrects[j].height = y2 - y1;
+ j++;
+ }
+ }
+
+ XRenderFillRectangles (dst->dpy,
+ _render_operator (op),
+ dst->picture,
+ &render_color, xrects, j);
+
+ if (xrects != stack_xrects)
+ free (xrects);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#if 0
+check_composite ()
+ operation = _categorize_composite_operation (dst, op, src_pattern,
+ mask_pattern != NULL);
+ if (operation == DO_UNSUPPORTED)
+ return UNSUPPORTED ("unsupported operation");
+
+ //X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable));
+
+ operation = _recategorize_composite_operation (dst, op, src, &src_attr,
+ mask_pattern != NULL);
+ if (operation == DO_UNSUPPORTED) {
+ status = UNSUPPORTED ("unsupported operation");
+ goto BAIL;
+ }
+#endif
+
+static cairo_int_status_t
+composite (void *abstract_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ 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_xlib_surface_t *dst = abstract_dst;
+ cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
+
+ op = _render_operator (op);
+
+ _cairo_xlib_surface_ensure_picture (dst);
+ if (abstract_mask) {
+ cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask;
+
+ XRenderComposite (dst->dpy, op,
+ src->picture, mask->picture, dst->picture,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+ } else {
+ XRenderComposite (dst->dpy, op,
+ src->picture, 0, dst->picture,
+ src_x, src_y,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+lerp (void *abstract_dst,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ 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_xlib_surface_t *dst = abstract_dst;
+ cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
+ cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask;
+
+ _cairo_xlib_surface_ensure_picture (dst);
+ XRenderComposite (dst->dpy, PictOpOutReverse,
+ mask->picture, None, dst->picture,
+ mask_x, mask_y,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ XRenderComposite (dst->dpy, PictOpAdd,
+ src->picture, mask->picture, dst->picture,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_boxes (void *abstract_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ cairo_boxes_t *boxes,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_xlib_surface_t *dst = abstract_dst;
+ Picture src = ((cairo_xlib_source_t *)abstract_src)->picture;
+ Picture mask = abstract_mask ? ((cairo_xlib_source_t *)abstract_mask)->picture : 0;
+ XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
+ XRectangle *rects = stack_rects;
+ struct _cairo_boxes_chunk *chunk;
+ int i, j;
+
+ op = _render_operator (op);
+ _cairo_xlib_surface_ensure_picture (dst);
+ if (boxes->num_boxes == 1) {
+ int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
+ int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
+ int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
+ int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
+
+ XRenderComposite (dst->dpy, op,
+ src, mask, dst->picture,
+ x1 + src_x, y1 + src_y,
+ x1 + mask_x, y1 + mask_y,
+ x1 - dst_x, y1 - dst_y,
+ x2 - x1, y2 - y1);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
+ rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
+ if (unlikely (rects == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ j = 0;
+ for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+ rects[j].x = x1 - dst_x;
+ rects[j].y = y1 - dst_y;
+ rects[j].width = x2 - x1;
+ rects[j].height = y2 - y1;
+ j++;
+ }
+ }
+ assert (j == boxes->num_boxes);
+
+ XRenderSetPictureClipRectangles (dst->dpy,
+ dst->picture,
+ 0, 0,
+ rects, j);
+ if (rects != stack_rects)
+ free (rects);
+
+ XRenderComposite (dst->dpy, op,
+ src, mask, dst->picture,
+ extents->x + src_x, extents->y + src_y,
+ extents->x + mask_x, extents->y + mask_y,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+
+ set_clip_region (dst, NULL);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* font rendering */
+
+void
+_cairo_xlib_font_close (cairo_xlib_font_t *priv)
+{
+ cairo_xlib_display_t *display = (cairo_xlib_display_t *)priv->base.key;
+ int i;
+
+ /* XXX All I really want is to do is zap my glyphs... */
+ _cairo_scaled_font_reset_cache (priv->font);
+
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xlib_font_glyphset_t *info;
+
+ info = &priv->glyphset[i];
+ if (info->glyphset)
+ XRenderFreeGlyphSet (display->display, info->glyphset);
+ }
+
+ /* XXX locking */
+ cairo_list_del (&priv->link);
+ cairo_list_del (&priv->base.link);
+ free (priv);
+}
+
+static void
+_cairo_xlib_font_fini (cairo_scaled_font_private_t *abstract_private,
+ cairo_scaled_font_t *font)
+{
+ cairo_xlib_font_t *priv = (cairo_xlib_font_t *) abstract_private;
+ cairo_status_t status;
+ cairo_xlib_display_t *display;
+ int i;
+
+ cairo_list_del (&priv->base.link);
+ cairo_list_del (&priv->link);
+
+ status = _cairo_xlib_display_acquire (priv->device, &display);
+ if (status)
+ goto BAIL;
+
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xlib_font_glyphset_t *info;
+
+ info = &priv->glyphset[i];
+ if (info->glyphset)
+ XRenderFreeGlyphSet (display->display, info->glyphset);
+ }
+
+ cairo_device_release (&display->base);
+BAIL:
+ cairo_device_destroy (&display->base);
+ free (priv);
+}
+
+static cairo_xlib_font_t *
+_cairo_xlib_font_create (cairo_xlib_display_t *display,
+ cairo_scaled_font_t *font)
+{
+ cairo_xlib_font_t *priv;
+ int i;
+
+ priv = malloc (sizeof (cairo_xlib_font_t));
+ if (unlikely (priv == NULL))
+ return NULL;
+
+ _cairo_scaled_font_attach_private (font, &priv->base, display,
+ _cairo_xlib_font_fini);
+
+ priv->device = cairo_device_reference (&display->base);
+ priv->font = font;
+ cairo_list_add (&priv->link, &display->fonts);
+
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xlib_font_glyphset_t *info = &priv->glyphset[i];
+ switch (i) {
+ case GLYPHSET_INDEX_ARGB32: info->format = CAIRO_FORMAT_ARGB32; break;
+ case GLYPHSET_INDEX_A8: info->format = CAIRO_FORMAT_A8; break;
+ case GLYPHSET_INDEX_A1: info->format = CAIRO_FORMAT_A1; break;
+ default: ASSERT_NOT_REACHED; break;
+ }
+ info->xrender_format = NULL;
+ info->glyphset = None;
+ info->to_free.count = 0;
+ }
+
+ return priv;
+}
+
+static int
+_cairo_xlib_get_glyphset_index_for_format (cairo_format_t format)
+{
+ if (format == CAIRO_FORMAT_A8)
+ return GLYPHSET_INDEX_A8;
+ if (format == CAIRO_FORMAT_A1)
+ return GLYPHSET_INDEX_A1;
+
+ assert (format == CAIRO_FORMAT_ARGB32);
+ return GLYPHSET_INDEX_ARGB32;
+}
+
+static inline cairo_xlib_font_t *
+_cairo_xlib_font_get (const cairo_xlib_display_t *display,
+ cairo_scaled_font_t *font)
+{
+ return (cairo_xlib_font_t *)_cairo_scaled_font_find_private (font, display);
+}
+
+typedef struct {
+ cairo_scaled_glyph_private_t base;
+
+
+ cairo_xlib_font_glyphset_t *glyphset;
+} cairo_xlib_glyph_private_t;
+
+static void
+_cairo_xlib_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
+ cairo_scaled_glyph_t *glyph,
+ cairo_scaled_font_t *font)
+{
+ cairo_xlib_glyph_private_t *priv = (cairo_xlib_glyph_private_t *)glyph_private;
+
+ if (! font->finished) {
+ cairo_xlib_font_t *font_private;
+ struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
+ cairo_xlib_font_glyphset_t *info;
+
+ font_private = _cairo_xlib_font_get (glyph_private->key, font);
+ assert (font_private);
+
+ info = priv->glyphset;
+ to_free = &info->to_free;
+ if (to_free->count == ARRAY_LENGTH (to_free->indices)) {
+ cairo_xlib_display_t *display;
+
+ if (_cairo_xlib_display_acquire (font_private->device,
+ &display) == CAIRO_STATUS_SUCCESS) {
+ XRenderFreeGlyphs (display->display,
+ info->glyphset,
+ to_free->indices,
+ to_free->count);
+ cairo_device_release (&display->base);
+ }
+
+ to_free->count = 0;
+ }
+
+ to_free->indices[to_free->count++] =
+ _cairo_scaled_glyph_index (glyph);
+ }
+
+ cairo_list_del (&glyph_private->link);
+ free (glyph_private);
+}
+
+static cairo_status_t
+_cairo_xlib_glyph_attach (cairo_xlib_display_t *display,
+ cairo_scaled_glyph_t *glyph,
+ cairo_xlib_font_glyphset_t *info)
+{
+ cairo_xlib_glyph_private_t *priv;
+
+ priv = malloc (sizeof (*priv));
+ if (unlikely (priv == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ _cairo_scaled_glyph_attach_private (glyph, &priv->base, display,
+ _cairo_xlib_glyph_fini);
+ priv->glyphset = info;
+
+ glyph->dev_private = info;
+ glyph->dev_private_key = display;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xlib_font_glyphset_t *
+_cairo_xlib_font_get_glyphset_info_for_format (cairo_xlib_display_t *display,
+ cairo_scaled_font_t *font,
+ cairo_format_t format)
+{
+ cairo_xlib_font_t *priv;
+ cairo_xlib_font_glyphset_t *info;
+ int glyphset_index;
+
+ glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format);
+
+ priv = _cairo_xlib_font_get (display, font);
+ if (priv == NULL) {
+ priv = _cairo_xlib_font_create (display, font);
+ if (priv == NULL)
+ return NULL;
+ }
+
+ info = &priv->glyphset[glyphset_index];
+ if (info->glyphset == None) {
+ info->xrender_format =
+ _cairo_xlib_display_get_xrender_format (display, info->format);
+ info->glyphset = XRenderCreateGlyphSet (display->display,
+ info->xrender_format);
+ }
+
+ return info;
+}
+
+static cairo_bool_t
+has_pending_free_glyph (cairo_xlib_font_glyphset_t *info,
+ unsigned long glyph_index)
+{
+ struct _cairo_xlib_font_glyphset_free_glyphs *to_free;
+ int i;
+
+ to_free = &info->to_free;
+ for (i = 0; i < to_free->count; i++) {
+ if (to_free->indices[i] == glyph_index) {
+ to_free->count--;
+ memmove (&to_free->indices[i],
+ &to_free->indices[i+1],
+ (to_free->count - i) * sizeof (to_free->indices[0]));
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static cairo_xlib_font_glyphset_t *
+find_pending_free_glyph (cairo_xlib_display_t *display,
+ cairo_scaled_font_t *font,
+ unsigned long glyph_index,
+ cairo_image_surface_t *surface)
+{
+ cairo_xlib_font_t *priv;
+ int i;
+
+ priv = _cairo_xlib_font_get (display, font);
+ if (priv == NULL)
+ return NULL;
+
+ if (surface != NULL) {
+ i = _cairo_xlib_get_glyphset_index_for_format (surface->format);
+ if (has_pending_free_glyph (&priv->glyphset[i], glyph_index))
+ return &priv->glyphset[i];
+ } else {
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ if (has_pending_free_glyph (&priv->glyphset[i], glyph_index))
+ return &priv->glyphset[i];
+ }
+ }
+
+ return NULL;
+}
+
+static cairo_status_t
+_cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
+ cairo_scaled_font_t *font,
+ cairo_scaled_glyph_t **pscaled_glyph)
+{
+ XGlyphInfo glyph_info;
+ unsigned long glyph_index;
+ unsigned char *data;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_scaled_glyph_t *glyph = *pscaled_glyph;
+ cairo_image_surface_t *glyph_surface = glyph->surface;
+ cairo_bool_t already_had_glyph_surface;
+ cairo_xlib_font_glyphset_t *info;
+
+ glyph_index = _cairo_scaled_glyph_index (glyph);
+
+ /* check to see if we have a pending XRenderFreeGlyph for this glyph */
+ info = find_pending_free_glyph (display, font, glyph_index, glyph_surface);
+ if (info != NULL)
+ return _cairo_xlib_glyph_attach (display, glyph, info);
+
+ if (glyph_surface == NULL) {
+ status = _cairo_scaled_glyph_lookup (font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS |
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ pscaled_glyph);
+ if (unlikely (status))
+ return status;
+
+ glyph = *pscaled_glyph;
+ glyph_surface = glyph->surface;
+ already_had_glyph_surface = FALSE;
+ } else {
+ already_had_glyph_surface = TRUE;
+ }
+
+ info = _cairo_xlib_font_get_glyphset_info_for_format (display, font,
+ glyph_surface->format);
+
+#if 0
+ /* If the glyph surface has zero height or width, we create
+ * a clear 1x1 surface, to avoid various X server bugs.
+ */
+ if (glyph_surface->width == 0 || glyph_surface->height == 0) {
+ cairo_surface_t *tmp_surface;
+
+ tmp_surface = cairo_image_surface_create (info->format, 1, 1);
+ status = tmp_surface->status;
+ if (unlikely (status))
+ goto BAIL;
+
+ tmp_surface->device_transform = glyph_surface->base.device_transform;
+ tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
+
+ glyph_surface = (cairo_image_surface_t *) tmp_surface;
+ }
+#endif
+
+ /* If the glyph format does not match the font format, then we
+ * create a temporary surface for the glyph image with the font's
+ * format.
+ */
+ if (glyph_surface->format != info->format) {
+ cairo_surface_pattern_t pattern;
+ cairo_surface_t *tmp_surface;
+
+ tmp_surface = cairo_image_surface_create (info->format,
+ glyph_surface->width,
+ glyph_surface->height);
+ status = tmp_surface->status;
+ if (unlikely (status))
+ goto BAIL;
+
+ tmp_surface->device_transform = glyph_surface->base.device_transform;
+ tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
+
+ _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
+ status = _cairo_surface_paint (tmp_surface,
+ CAIRO_OPERATOR_SOURCE, &pattern.base,
+ NULL);
+ _cairo_pattern_fini (&pattern.base);
+
+ glyph_surface = (cairo_image_surface_t *) tmp_surface;
+
+ if (unlikely (status))
+ goto BAIL;
+ }
+
+ /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
+ glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
+ glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
+ glyph_info.width = glyph_surface->width;
+ glyph_info.height = glyph_surface->height;
+ glyph_info.xOff = glyph->x_advance;
+ glyph_info.yOff = glyph->y_advance;
+
+ data = glyph_surface->data;
+
+ /* flip formats around */
+ switch (_cairo_xlib_get_glyphset_index_for_format (glyph->surface->format)) {
+ case GLYPHSET_INDEX_A1:
+ /* local bitmaps are always stored with bit == byte */
+ if (_cairo_is_little_endian() != (BitmapBitOrder (display->display) == LSBFirst)) {
+ int c = glyph_surface->stride * glyph_surface->height;
+ unsigned char *d;
+ unsigned char *new, *n;
+
+ new = malloc (c);
+ if (!new) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
+ }
+ n = new;
+ d = data;
+ do {
+ char b = *d++;
+ b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
+ b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
+ b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
+ *n++ = b;
+ } while (--c);
+ data = new;
+ }
+ break;
+ case GLYPHSET_INDEX_A8:
+ break;
+ case GLYPHSET_INDEX_ARGB32:
+ if (_cairo_is_little_endian() != (ImageByteOrder (display->display) == LSBFirst)) {
+ unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
+ const uint32_t *d;
+ uint32_t *new, *n;
+
+ new = malloc (4 * c);
+ if (unlikely (new == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
+ }
+ n = new;
+ d = (uint32_t *) data;
+ do {
+ *n++ = bswap_32 (*d);
+ d++;
+ } while (--c);
+ data = (uint8_t *) new;
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ break;
+ }
+ /* XXX assume X server wants pixman padding. Xft assumes this as well */
+
+ XRenderAddGlyphs (display->display, info->glyphset,
+ &glyph_index, &glyph_info, 1,
+ (char *) data,
+ glyph_surface->stride * glyph_surface->height);
+
+ if (data != glyph_surface->data)
+ free (data);
+
+ status = _cairo_xlib_glyph_attach (display, glyph, info);
+
+ BAIL:
+ if (glyph_surface != glyph->surface)
+ cairo_surface_destroy (&glyph_surface->base);
+
+ /* if the scaled glyph didn't already have a surface attached
+ * to it, release the created surface now that we have it
+ * uploaded to the X server. If the surface has already been
+ * there (eg. because image backend requested it), leave it in
+ * the cache
+ */
+ if (!already_had_glyph_surface)
+ _cairo_scaled_glyph_set_surface (glyph, font, NULL);
+
+ return status;
+}
+
+typedef void (*cairo_xrender_composite_text_func_t)
+ (Display *dpy,
+ int op,
+ Picture src,
+ Picture dst,
+ _Xconst XRenderPictFormat *maskFormat,
+ int xSrc,
+ int ySrc,
+ int xDst,
+ int yDst,
+ _Xconst XGlyphElt8 *elts,
+ int nelt);
+
+/* Build a struct of the same size of #cairo_glyph_t that can be used both as
+ * an input glyph with double coordinates, and as "working" glyph with
+ * integer from-current-point offsets. */
+typedef union {
+ cairo_glyph_t d;
+ unsigned long index;
+ struct {
+ unsigned long index;
+ int x;
+ int y;
+ } i;
+} cairo_xlib_glyph_t;
+
+/* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
+COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t));
+
+/* Start a new element for the first glyph,
+ * or for any glyph that has unexpected position,
+ * or if current element has too many glyphs
+ * (Xrender limits each element to 252 glyphs, we limit them to 128)
+ *
+ * These same conditions need to be mirrored between
+ * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
+ */
+#define _start_new_glyph_elt(count, glyph) \
+ (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
+
+static cairo_status_t
+_emit_glyphs_chunk (cairo_xlib_display_t *display,
+ cairo_xlib_surface_t *dst,
+ int dst_x, int dst_y,
+ cairo_xlib_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *font,
+ cairo_bool_t use_mask,
+ cairo_operator_t op,
+ cairo_xlib_source_t *src,
+ int src_x, int src_y,
+ /* info for this chunk */
+ int num_elts,
+ int width,
+ cairo_xlib_font_glyphset_t *info)
+{
+ /* Which XRenderCompositeText function to use */
+ cairo_xrender_composite_text_func_t composite_text_func;
+ int size;
+
+ /* Element buffer stuff */
+ XGlyphElt8 *elts;
+ XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
+
+ /* Reuse the input glyph array for output char generation */
+ char *char8 = (char *) glyphs;
+ unsigned short *char16 = (unsigned short *) glyphs;
+ unsigned int *char32 = (unsigned int *) glyphs;
+
+ int i;
+ int nelt; /* Element index */
+ int n; /* Num output glyphs in current element */
+ int j; /* Num output glyphs so far */
+
+ switch (width) {
+ case 1:
+ /* don't cast the 8-variant, to catch possible mismatches */
+ composite_text_func = XRenderCompositeText8;
+ size = sizeof (char);
+ break;
+ case 2:
+ composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
+ size = sizeof (unsigned short);
+ break;
+ default:
+ case 4:
+ composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
+ size = sizeof (unsigned int);
+ }
+
+ /* Allocate element array */
+ if (num_elts <= ARRAY_LENGTH (stack_elts)) {
+ elts = stack_elts;
+ } else {
+ elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
+ if (unlikely (elts == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ /* Fill them in */
+ nelt = 0;
+ n = 0;
+ j = 0;
+ for (i = 0; i < num_glyphs; i++) {
+ /* Start a new element for first output glyph,
+ * or for any glyph that has unexpected position,
+ * or if current element has too many glyphs.
+ *
+ * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
+ */
+ if (_start_new_glyph_elt (j, &glyphs[i])) {
+ if (j) {
+ elts[nelt].nchars = n;
+ nelt++;
+ n = 0;
+ }
+ elts[nelt].chars = char8 + size * j;
+ elts[nelt].glyphset = info->glyphset;
+ elts[nelt].xOff = glyphs[i].i.x;
+ elts[nelt].yOff = glyphs[i].i.y;
+ }
+
+ switch (width) {
+ case 1: char8 [j] = (char) glyphs[i].index; break;
+ case 2: char16[j] = (unsigned short) glyphs[i].index; break;
+ default:
+ case 4: char32[j] = (unsigned int) glyphs[i].index; break;
+ }
+
+ n++;
+ j++;
+ }
+
+ if (n) {
+ elts[nelt].nchars = n;
+ nelt++;
+ }
+
+ /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
+ * expected number of xGlyphElts. */
+ assert (nelt == num_elts);
+
+ composite_text_func (display->display, op,
+ src->picture,
+ dst->picture,
+ use_mask ? info->xrender_format : NULL,
+ src_x + elts[0].xOff,
+ src_y + elts[0].yOff,
+ elts[0].xOff - dst_x, elts[0].yOff - dst_y,
+ (XGlyphElt8 *) elts, nelt);
+
+ if (elts != stack_elts)
+ free (elts);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+check_composite_glyphs (const cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *font,
+ cairo_glyph_t *glyphs,
+ int *num_glyphs)
+{
+ cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)extents->surface;
+ cairo_xlib_display_t *display = dst->display;
+ int max_request_size, size;
+
+ if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* The glyph coordinates must be representable in an int16_t.
+ * When possible, they will be expressed as an offset from the
+ * previous glyph, otherwise they will be an offset from the
+ * surface origin. If we can't guarantee this to be possible,
+ * fallback.
+ */
+ if (extents->bounded.x + extents->bounded.width > INT16_MAX ||
+ extents->bounded.y + extents->bounded.height> INT16_MAX ||
+ extents->bounded.x < INT16_MIN ||
+ extents->bounded.y < INT16_MIN)
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ /* Approximate the size of the largest glyph and fallback if we can not
+ * upload it to the xserver.
+ */
+ size = ceil (font->max_scale);
+ size = 4 * size * size;
+ max_request_size = (XExtendedMaxRequestSize (display->display) ? XExtendedMaxRequestSize (display->display)
+ : XMaxRequestSize (display->display)) * 4 -
+ sz_xRenderAddGlyphsReq -
+ sz_xGlyphInfo -
+ 8;
+ if (size >= max_request_size)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
+ * enough room for padding */
+#define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
+
+static cairo_int_status_t
+composite_glyphs (void *surface,
+ cairo_operator_t op,
+ cairo_surface_t *_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info)
+{
+ cairo_xlib_surface_t *dst = surface;
+ cairo_xlib_glyph_t *glyphs = (cairo_xlib_glyph_t *)info->glyphs;
+ cairo_xlib_source_t *src = (cairo_xlib_source_t *)_src;
+ cairo_xlib_display_t *display = dst->display;
+ cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
+ cairo_scaled_glyph_t *glyph;
+ cairo_fixed_t x = 0, y = 0;
+ cairo_xlib_font_glyphset_t *glyphset = NULL, *this_glyphset_info;
+
+ unsigned long max_index = 0;
+ int width = 1;
+ int num_elts = 0;
+ int num_out_glyphs = 0;
+ int num_glyphs = info->num_glyphs;
+
+ int max_request_size = XMaxRequestSize (display->display) * 4
+ - MAX (sz_xRenderCompositeGlyphs8Req,
+ MAX(sz_xRenderCompositeGlyphs16Req,
+ sz_xRenderCompositeGlyphs32Req));
+ int request_size = 0;
+ int i;
+
+ op = _render_operator (op),
+ _cairo_xlib_surface_ensure_picture (dst);
+ for (i = 0; i < num_glyphs; i++) {
+ int this_x, this_y;
+ int old_width;
+
+ status = _cairo_scaled_glyph_lookup (info->font,
+ glyphs[i].index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS,
+ &glyph);
+ if (unlikely (status))
+ return status;
+
+ this_x = _cairo_lround (glyphs[i].d.x);
+ this_y = _cairo_lround (glyphs[i].d.y);
+
+ /* Send unsent glyphs to the server */
+ if (glyph->dev_private_key != display) {
+ status = _cairo_xlib_surface_add_glyph (display, info->font, &glyph);
+ if (unlikely (status))
+ return status;
+ }
+
+ this_glyphset_info = glyph->dev_private;
+ if (!glyphset)
+ glyphset = this_glyphset_info;
+
+ /* The invariant here is that we can always flush the glyphs
+ * accumulated before this one, using old_width, and they
+ * would fit in the request.
+ */
+ old_width = width;
+
+ /* Update max glyph index */
+ if (glyphs[i].index > max_index) {
+ max_index = glyphs[i].index;
+ if (max_index >= 65536)
+ width = 4;
+ else if (max_index >= 256)
+ width = 2;
+ if (width != old_width)
+ request_size += (width - old_width) * num_out_glyphs;
+ }
+
+ /* If we will pass the max request size by adding this glyph,
+ * flush current glyphs. Note that we account for a
+ * possible element being added below.
+ *
+ * Also flush if changing glyphsets, as Xrender limits one mask
+ * format per request, so we can either break up, or use a
+ * wide-enough mask format. We do the former. One reason to
+ * prefer the latter is the fact that Xserver ADDs all glyphs
+ * to the mask first, and then composes that to final surface,
+ * though it's not a big deal.
+ *
+ * If the glyph has a coordinate which cannot be represented
+ * as a 16-bit offset from the previous glyph, flush the
+ * current chunk. The current glyph will be the first one in
+ * the next chunk, thus its coordinates will be an offset from
+ * the destination origin. This offset is guaranteed to be
+ * representable as 16-bit offset (otherwise we would have
+ * fallen back).
+ */
+ if (request_size + width > max_request_size - _cairo_sz_xGlyphElt ||
+ this_x - x > INT16_MAX || this_x - x < INT16_MIN ||
+ this_y - y > INT16_MAX || this_y - y < INT16_MIN ||
+ (this_glyphset_info != glyphset)) {
+ status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
+ glyphs, i, info->font, info->use_mask,
+ op, src, src_x, src_y,
+ num_elts, old_width, glyphset);
+ if (unlikely (status))
+ return status;
+
+ glyphs += i;
+ num_glyphs -= i;
+ i = 0;
+ max_index = glyphs[i].index;
+ width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
+ request_size = 0;
+ num_elts = 0;
+ num_out_glyphs = 0;
+ x = y = 0;
+ glyphset = this_glyphset_info;
+ }
+
+ /* Convert absolute glyph position to relative-to-current-point
+ * position */
+ glyphs[i].i.x = this_x - x;
+ glyphs[i].i.y = this_y - y;
+
+ /* Start a new element for the first glyph,
+ * or for any glyph that has unexpected position,
+ * or if current element has too many glyphs.
+ *
+ * These same conditions are mirrored in _emit_glyphs_chunk().
+ */
+ if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
+ num_elts++;
+ request_size += _cairo_sz_xGlyphElt;
+ }
+
+ /* adjust current-position */
+ x = this_x + glyph->x_advance;
+ y = this_y + glyph->y_advance;
+
+ num_out_glyphs++;
+ request_size += width;
+ }
+
+ if (num_elts) {
+ status = _emit_glyphs_chunk (display, dst, dst_x, dst_y,
+ glyphs, i, info->font, info->use_mask,
+ op, src, src_x, src_y,
+ num_elts, width, glyphset);
+ }
+
+ return status;
+}
+
+const cairo_compositor_t *
+_cairo_xlib_mask_compositor_get (void)
+{
+ static cairo_mask_compositor_t compositor;
+
+ if (compositor.base.delegate == NULL) {
+ _cairo_mask_compositor_init (&compositor,
+ _cairo_xlib_fallback_compositor_get ());
+
+ compositor.acquire = acquire;
+ compositor.release = release;
+ compositor.set_clip_region = set_clip_region;
+ compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
+ compositor.draw_image_boxes = draw_image_boxes;
+ compositor.fill_rectangles = fill_rectangles;
+ compositor.fill_boxes = fill_boxes;
+ //compositor.check_composite = check_composite;
+ compositor.composite = composite;
+ //compositor.check_composite_boxes = check_composite_boxes;
+ compositor.composite_boxes = composite_boxes;
+ compositor.check_composite_glyphs = check_composite_glyphs;
+ compositor.composite_glyphs = composite_glyphs;
+ }
+
+ return &compositor.base;
+}
+
+#define CAIRO_FIXED_16_16_MIN -32768
+#define CAIRO_FIXED_16_16_MAX 32767
+
+static cairo_bool_t
+line_exceeds_16_16 (const cairo_line_t *line)
+{
+ return
+ line->p1.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
+ line->p1.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
+ line->p2.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
+ line->p2.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
+ line->p1.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
+ line->p1.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
+ line->p2.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
+ line->p2.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX);
+}
+
+static void
+project_line_x_onto_16_16 (const cairo_line_t *line,
+ cairo_fixed_t top,
+ cairo_fixed_t bottom,
+ XLineFixed *out)
+{
+ cairo_point_double_t p1, p2;
+ double m;
+
+ p1.x = _cairo_fixed_to_double (line->p1.x);
+ p1.y = _cairo_fixed_to_double (line->p1.y);
+
+ p2.x = _cairo_fixed_to_double (line->p2.x);
+ p2.y = _cairo_fixed_to_double (line->p2.y);
+
+ m = (p2.x - p1.x) / (p2.y - p1.y);
+ out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
+ out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
+}
+#if 0
+static cairo_int_status_T
+check_composite_trapezoids ()
+{
+ operation = _categorize_composite_operation (dst, op, pattern, TRUE);
+ if (operation == DO_UNSUPPORTED)
+ return UNSUPPORTED ("unsupported operation");
+
+ operation = _recategorize_composite_operation (dst, op, src,
+ &attributes, TRUE);
+ if (operation == DO_UNSUPPORTED) {
+ status = UNSUPPORTED ("unsupported operation");
+ goto BAIL;
+ }
+
+}
+#endif
+
+static cairo_int_status_t
+composite_traps (void *abstract_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_antialias_t antialias,
+ cairo_traps_t *traps)
+{
+ cairo_xlib_surface_t *dst = abstract_dst;
+ cairo_xlib_display_t *display = dst->display;
+ cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
+ XRenderPictFormat *pict_format;
+ XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
+ XTrapezoid *xtraps = xtraps_stack;
+ int dx, dy;
+ int i;
+
+ //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
+
+ pict_format =
+ _cairo_xlib_display_get_xrender_format (display,
+ antialias == CAIRO_ANTIALIAS_NONE ? CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
+
+ if (traps->num_traps > ARRAY_LENGTH (xtraps_stack)) {
+ xtraps = _cairo_malloc_ab (traps->num_traps, sizeof (XTrapezoid));
+ if (unlikely (xtraps == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ dx = -dst_x << 16;
+ dy = -dst_y << 16;
+ for (i = 0; i < traps->num_traps; i++) {
+ cairo_trapezoid_t *t = &traps->traps[i];
+
+ /* top/bottom will be clamped to surface bounds */
+ xtraps[i].top = _cairo_fixed_to_16_16(t->top) + dy;
+ xtraps[i].bottom = _cairo_fixed_to_16_16(t->bottom) + dy;
+
+ /* However, all the other coordinates will have been left untouched so
+ * as not to introduce numerical error. Recompute them if they
+ * exceed the 16.16 limits.
+ */
+ if (unlikely (line_exceeds_16_16 (&t->left))) {
+ project_line_x_onto_16_16 (&t->left, t->top, t->bottom,
+ &xtraps[i].left);
+ xtraps[i].left.p1.x += dx;
+ xtraps[i].left.p2.x += dx;
+ xtraps[i].left.p1.y = xtraps[i].top;
+ xtraps[i].left.p2.y = xtraps[i].bottom;
+ } else {
+ xtraps[i].left.p1.x = _cairo_fixed_to_16_16(t->left.p1.x) + dx;
+ xtraps[i].left.p1.y = _cairo_fixed_to_16_16(t->left.p1.y) + dy;
+ xtraps[i].left.p2.x = _cairo_fixed_to_16_16(t->left.p2.x) + dx;
+ xtraps[i].left.p2.y = _cairo_fixed_to_16_16(t->left.p2.y) + dy;
+ }
+
+ if (unlikely (line_exceeds_16_16 (&t->right))) {
+ project_line_x_onto_16_16 (&t->right, t->top, t->bottom,
+ &xtraps[i].right);
+ xtraps[i].right.p1.x += dx;
+ xtraps[i].right.p2.x += dx;
+ xtraps[i].right.p1.y = xtraps[i].top;
+ xtraps[i].right.p2.y = xtraps[i].bottom;
+ } else {
+ xtraps[i].right.p1.x = _cairo_fixed_to_16_16(t->right.p1.x) + dx;
+ xtraps[i].right.p1.y = _cairo_fixed_to_16_16(t->right.p1.y) + dy;
+ xtraps[i].right.p2.x = _cairo_fixed_to_16_16(t->right.p2.x) + dx;
+ xtraps[i].right.p2.y = _cairo_fixed_to_16_16(t->right.p2.y) + dy;
+ }
+ }
+
+ if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
+ src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p1.x);
+ src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p1.y);
+ } else {
+ src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p2.x);
+ src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p2.y);
+ }
+ src_x += dst_x;
+ src_y += dst_y;
+
+ _cairo_xlib_surface_ensure_picture (dst);
+ _cairo_xlib_surface_set_precision (dst, antialias);
+ XRenderCompositeTrapezoids (dst->dpy,
+ _render_operator (op),
+ src->picture, dst->picture,
+ pict_format,
+ src_x, src_y,
+ xtraps, traps->num_traps);
+
+ if (xtraps != xtraps_stack)
+ free (xtraps);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_tristrip (void *abstract_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_antialias_t antialias,
+ cairo_tristrip_t *strip)
+{
+ cairo_xlib_surface_t *dst = abstract_dst;
+ cairo_xlib_display_t *display = dst->display;
+ cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src;
+ XRenderPictFormat *pict_format;
+ XPointFixed points_stack[CAIRO_STACK_ARRAY_LENGTH (XPointFixed)];
+ XPointFixed *points = points_stack;
+ int dx, dy;
+ int i;
+
+ //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
+
+ pict_format =
+ _cairo_xlib_display_get_xrender_format (display,
+ antialias == CAIRO_ANTIALIAS_NONE ? CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
+
+ if (strip->num_points > ARRAY_LENGTH (points_stack)) {
+ points = _cairo_malloc_ab (strip->num_points, sizeof (XPointFixed));
+ if (unlikely (points == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ dx = -dst_x << 16;
+ dy = -dst_y << 16;
+ for (i = 0; i < strip->num_points; i++) {
+ cairo_point_t *p = &strip->points[i];
+
+ points[i].x = _cairo_fixed_to_16_16(p->x) + dx;
+ points[i].y = _cairo_fixed_to_16_16(p->y) + dy;
+ }
+
+ src_x += _cairo_fixed_16_16_floor (points[0].x) + dst_x;
+ src_y += _cairo_fixed_16_16_floor (points[0].y) + dst_y;
+
+ _cairo_xlib_surface_ensure_picture (dst);
+ _cairo_xlib_surface_set_precision (dst, antialias);
+ XRenderCompositeTriStrip (dst->dpy,
+ _render_operator (op),
+ src->picture, dst->picture,
+ pict_format,
+ src_x, src_y,
+ points, strip->num_points);
+
+ if (points != points_stack)
+ free (points);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+const cairo_compositor_t *
+_cairo_xlib_traps_compositor_get (void)
+{
+ static cairo_traps_compositor_t compositor;
+
+ if (compositor.base.delegate == NULL) {
+ _cairo_traps_compositor_init (&compositor,
+ _cairo_xlib_mask_compositor_get ());
+
+ compositor.acquire = acquire;
+ compositor.release = release;
+ compositor.set_clip_region = set_clip_region;
+ compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern;
+ compositor.draw_image_boxes = draw_image_boxes;
+ compositor.copy_boxes = copy_boxes;
+ compositor.fill_boxes = fill_boxes;
+ //compositor.check_composite = check_composite;
+ compositor.composite = composite;
+ compositor.lerp = lerp;
+ //compositor.check_composite_boxes = check_composite_boxes;
+ compositor.composite_boxes = composite_boxes;
+ //compositor.check_composite_traps = check_composite_traps;
+ compositor.composite_traps = composite_traps;
+ //compositor.check_composite_tristrip = check_composite_tristrip;
+ compositor.composite_tristrip = composite_tristrip;
+ compositor.check_composite_glyphs = check_composite_glyphs;
+ compositor.composite_glyphs = composite_glyphs;
+ }
+
+ return &compositor.base;
+}
diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c
index 356131fa..7bfdf158 100644
--- a/src/cairo-xlib-screen.c
+++ b/src/cairo-xlib-screen.c
@@ -269,8 +269,8 @@ _cairo_xlib_init_screen_font_options (Display *dpy,
}
void
-_cairo_xlib_screen_close_display (cairo_xlib_display_t *display,
- cairo_xlib_screen_t *info)
+_cairo_xlib_screen_destroy (cairo_xlib_display_t *display,
+ cairo_xlib_screen_t *info)
{
Display *dpy;
int i;
@@ -292,11 +292,7 @@ _cairo_xlib_screen_close_display (cairo_xlib_display_t *display,
info->gc_depths[i] = 0;
}
}
-}
-void
-_cairo_xlib_screen_destroy (cairo_xlib_screen_t *info)
-{
while (! cairo_list_is_empty (&info->visuals)) {
_cairo_xlib_visual_info_destroy (cairo_list_first_entry (&info->visuals,
cairo_xlib_visual_info_t,
@@ -403,19 +399,9 @@ _cairo_xlib_screen_put_gc (cairo_xlib_display_t *display,
}
if (i == ARRAY_LENGTH (info->gc)) {
- cairo_status_t status;
-
/* perform random substitution to ensure fair caching over depths */
i = rand () % ARRAY_LENGTH (info->gc);
- status =
- _cairo_xlib_display_queue_work (display,
- (cairo_xlib_notify_func) XFreeGC,
- info->gc[i],
- NULL);
- if (unlikely (status)) {
- /* leak the server side resource... */
- XFree ((char *) info->gc[i]);
- }
+ XFreeGC(display->display, info->gc[i]);
}
info->gc[i] = gc;
diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
new file mode 100644
index 00000000..dc5aa7a0
--- /dev/null
+++ b/src/cairo-xlib-source.c
@@ -0,0 +1,938 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Behdad Esfahbod <behdad@behdad.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
+ */
+#include "cairoint.h"
+
+#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
+
+#include "cairo-xlib-private.h"
+#include "cairo-xlib-surface-private.h"
+
+#include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-paginated-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-recording-surface-private.h"
+#include "cairo-surface-backend-private.h"
+#include "cairo-surface-offset-private.h"
+#include "cairo-surface-observer-private.h"
+#include "cairo-surface-snapshot-private.h"
+
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+
+static cairo_surface_t *
+unwrap_surface (cairo_surface_t *surface, int *tx, int *ty)
+{
+ *tx = *ty = 0;
+
+ if (_cairo_surface_is_paginated (surface))
+ surface = _cairo_paginated_surface_get_recording (surface);
+ if (_cairo_surface_is_snapshot (surface))
+ surface = _cairo_surface_snapshot_get_target (surface);
+ if (_cairo_surface_is_observer (surface))
+ surface = _cairo_surface_observer_get_target (surface);
+ return surface;
+}
+
+static cairo_status_t
+_cairo_xlib_source_finish (void *abstract_surface)
+{
+ cairo_xlib_source_t *source = abstract_surface;
+
+ XRenderFreePicture (source->dpy, source->picture);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_xlib_source_backend = {
+ CAIRO_SURFACE_TYPE_IMAGE,
+ _cairo_xlib_source_finish,
+ NULL, /* read-only wrapper */
+};
+
+static cairo_surface_t *
+source (cairo_xlib_surface_t *dst, Picture picture)
+{
+ cairo_xlib_source_t *source;
+
+ if (picture == None)
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ source = malloc (sizeof (cairo_image_surface_t));
+ if (unlikely (source == NULL)) {
+ XRenderFreePicture (dst->display->display, picture);
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ _cairo_surface_init (&source->base,
+ &cairo_xlib_source_backend,
+ NULL, /* device */
+ CAIRO_CONTENT_COLOR_ALPHA);
+
+ /* The source exists only within an operation */
+ source->picture = picture;
+ source->dpy = dst->display->display;
+
+ return &source->base;
+}
+
+static uint32_t
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+ static uint32_t x;
+ return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static const XTransform identity = {
+ {
+ { 1 << 16, 0x00000, 0x00000 },
+ { 0x00000, 1 << 16, 0x00000 },
+ { 0x00000, 0x00000, 1 << 16 },
+ }
+};
+
+static cairo_bool_t
+picture_set_matrix (cairo_xlib_display_t *display,
+ Picture picture,
+ const cairo_matrix_t *matrix,
+ cairo_filter_t filter,
+ double xc,
+ double yc,
+ int *x_offset,
+ int *y_offset)
+{
+ XTransform xtransform;
+ pixman_transform_t *pixman_transform;
+ cairo_int_status_t status;
+
+ /* Casting between pixman_transform_t and XTransform is safe because
+ * they happen to be the exact same type.
+ */
+ pixman_transform = (pixman_transform_t *) &xtransform;
+ status = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
+ pixman_transform,
+ x_offset, y_offset);
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return TRUE;
+ if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
+ return FALSE;
+
+ if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0)
+ return TRUE;
+
+ /* a late check in case we perturb the matrix too far */
+ if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display))
+ return FALSE;
+
+ XRenderSetPictureTransform (display->display, picture, &xtransform);
+ return TRUE;
+}
+
+static cairo_status_t
+picture_set_filter (Display *dpy,
+ Picture picture,
+ cairo_filter_t filter)
+{
+ const char *render_filter;
+
+ switch (filter) {
+ case CAIRO_FILTER_FAST:
+ render_filter = FilterFast;
+ break;
+ case CAIRO_FILTER_GOOD:
+ render_filter = FilterGood;
+ break;
+ case CAIRO_FILTER_BEST:
+ render_filter = FilterBest;
+ break;
+ case CAIRO_FILTER_NEAREST:
+ render_filter = FilterNearest;
+ break;
+ case CAIRO_FILTER_BILINEAR:
+ render_filter = FilterBilinear;
+ break;
+ case CAIRO_FILTER_GAUSSIAN:
+ /* XXX: The GAUSSIAN value has no implementation in cairo
+ * whatsoever, so it was really a mistake to have it in the
+ * API. We could fix this by officially deprecating it, or
+ * else inventing semantics and providing an actual
+ * implementation for it. */
+ default:
+ render_filter = FilterBest;
+ break;
+ }
+
+ XRenderSetPictureFilter (dpy, picture, (char *) render_filter, NULL, 0);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static int
+extend_to_repeat (cairo_extend_t extend)
+{
+ switch (extend) {
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_EXTEND_NONE:
+ return RepeatNone;
+ case CAIRO_EXTEND_REPEAT:
+ return RepeatNormal;
+ case CAIRO_EXTEND_REFLECT:
+ return RepeatReflect;
+ case CAIRO_EXTEND_PAD:
+ return RepeatPad;
+ }
+}
+
+static cairo_bool_t
+picture_set_properties (cairo_xlib_display_t *display,
+ Picture picture,
+ const cairo_pattern_t *pattern,
+ const cairo_matrix_t *matrix,
+ const cairo_rectangle_int_t *extents,
+ int *x_off, int *y_off)
+{
+ XRenderPictureAttributes pa;
+ int mask = 0;
+
+ if (! picture_set_matrix (display, picture, matrix, pattern->filter,
+ extents->x + extents->width / 2,
+ extents->y + extents->height / 2,
+ x_off, y_off))
+ return FALSE;
+
+ picture_set_filter (display->display, picture, pattern->filter);
+
+ if (pattern->has_component_alpha) {
+ pa.component_alpha = 1;
+ mask |= CPComponentAlpha;
+ }
+
+ if (pattern->extend != CAIRO_EXTEND_NONE) {
+ pa.repeat = extend_to_repeat (pattern->extend);
+ mask |= CPRepeat;
+ }
+
+ if (mask)
+ XRenderChangePicture (display->display, picture, mask, &pa);
+
+ return TRUE;
+}
+
+static cairo_surface_t *
+render_pattern (cairo_xlib_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ int *src_x, int *src_y)
+{
+ Display *dpy = dst->display->display;
+ cairo_xlib_surface_t *src;
+ cairo_surface_t *image;
+ cairo_status_t status;
+
+ src = (cairo_xlib_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA,
+ extents->width,
+ extents->height);
+ if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ cairo_surface_destroy (&src->base);
+ return None;
+ }
+
+ image = cairo_surface_map_to_image (&src->base, NULL);
+ status = _cairo_surface_offset_paint (image, extents->x, extents->y,
+ CAIRO_OPERATOR_SOURCE, pattern,
+ NULL);
+ cairo_surface_unmap_image (&src->base, image);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&src->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ src->picture = XRenderCreatePicture (dpy,
+ src->drawable, src->xrender_format,
+ 0, NULL);
+
+ *src_x = -extents->x;
+ *src_y = -extents->y;
+ return &src->base;
+}
+
+
+static cairo_surface_t *
+gradient_source (cairo_xlib_surface_t *dst,
+ const cairo_gradient_pattern_t *gradient,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ int *src_x, int *src_y)
+{
+ cairo_xlib_display_t *display = dst->display;
+ cairo_matrix_t matrix = gradient->base.matrix;
+ char buf[CAIRO_STACK_BUFFER_SIZE];
+ cairo_circle_double_t extremes[2];
+ XFixed *stops;
+ XRenderColor *colors;
+ Picture picture;
+ unsigned int i, n_stops;
+
+ /* The RENDER specification says that the inner circle has
+ * to be completely contained inside the outer one. */
+ if (gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL &&
+ ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) gradient))
+ return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
+
+ assert (gradient->n_stops > 0);
+ n_stops = MAX (gradient->n_stops, 2);
+
+ if (n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
+ {
+ stops = (XFixed *) buf;
+ }
+ else
+ {
+ stops =
+ _cairo_malloc_ab (n_stops,
+ sizeof (XFixed) + sizeof (XRenderColor));
+ if (unlikely (stops == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ colors = (XRenderColor *) (stops + n_stops);
+ for (i = 0; i < gradient->n_stops; i++) {
+ stops[i] =
+ _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
+
+ colors[i].red = gradient->stops[i].color.red_short;
+ colors[i].green = gradient->stops[i].color.green_short;
+ colors[i].blue = gradient->stops[i].color.blue_short;
+ colors[i].alpha = gradient->stops[i].color.alpha_short;
+ }
+
+ /* RENDER does not support gradients with less than 2
+ * stops. If a gradient has only a single stop, duplicate
+ * it to make RENDER happy. */
+ if (gradient->n_stops == 1) {
+ stops[1] =
+ _cairo_fixed_16_16_from_double (gradient->stops[0].offset);
+
+ colors[1].red = gradient->stops[0].color.red_short;
+ colors[1].green = gradient->stops[0].color.green_short;
+ colors[1].blue = gradient->stops[0].color.blue_short;
+ colors[1].alpha = gradient->stops[0].color.alpha_short;
+ }
+
+#if 0
+ /* For some weird reason the X server is sometimes getting
+ * CreateGradient requests with bad length. So far I've only seen
+ * XRenderCreateLinearGradient request with 4 stops sometime end up
+ * with length field matching 0 stops at the server side. I've
+ * looked at the libXrender code and I can't see anything that
+ * could cause this behavior. However, for some reason having a
+ * XSync call here seems to avoid the issue so I'll keep it here
+ * until it's solved.
+ */
+ XSync (display->display, False);
+#endif
+
+ _cairo_gradient_pattern_fit_to_range (gradient, PIXMAN_MAX_INT >> 1, &matrix, extremes);
+
+ if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
+ XLinearGradient grad;
+
+ grad.p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
+ grad.p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
+ grad.p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
+ grad.p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
+
+ picture = XRenderCreateLinearGradient (display->display, &grad,
+ stops, colors,
+ n_stops);
+ } else {
+ XRadialGradient grad;
+
+ grad.inner.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
+ grad.inner.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
+ grad.inner.radius = _cairo_fixed_16_16_from_double (extremes[0].radius);
+ grad.outer.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
+ grad.outer.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
+ grad.outer.radius = _cairo_fixed_16_16_from_double (extremes[1].radius);
+
+ picture = XRenderCreateRadialGradient (display->display, &grad,
+ stops, colors,
+ n_stops);
+ }
+
+ if (stops != (XFixed *) buf)
+ free (stops);
+
+ *src_x = *src_y = 0;
+ if (! picture_set_properties (display, picture,
+ &gradient->base, &gradient->base.matrix,
+ extents,
+ src_x, src_y)) {
+ XRenderFreePicture (display->display, picture);
+ return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
+ }
+
+ return source (dst, picture);
+}
+
+static cairo_surface_t *
+color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
+{
+ XRenderColor xrender_color;
+
+ xrender_color.red = color->red_short;
+ xrender_color.green = color->green_short;
+ xrender_color.blue = color->blue_short;
+ xrender_color.alpha = color->alpha_short;
+
+ return source (dst,
+ XRenderCreateSolidFill (dst->display->display,
+ &xrender_color));
+}
+
+static cairo_surface_t *
+alpha_source (cairo_xlib_surface_t *dst, uint8_t alpha)
+{
+ cairo_xlib_display_t *display = dst->display;
+
+ if (display->alpha[alpha] == NULL) {
+ cairo_color_t color;
+
+ color.red_short = color.green_short = color.blue_short = 0;
+ color.alpha_short = alpha << 8 | alpha;
+
+ display->alpha[alpha] = color_source (dst, &color);
+ }
+
+ return cairo_surface_reference (display->alpha[alpha]);
+}
+
+static cairo_surface_t *
+white_source (cairo_xlib_surface_t *dst)
+{
+ cairo_xlib_display_t *display = dst->display;
+
+ if (display->white == NULL)
+ display->white = color_source (dst, CAIRO_COLOR_WHITE);
+
+ return cairo_surface_reference (display->white);
+}
+
+static cairo_surface_t *
+opaque_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
+{
+ cairo_xlib_display_t *display = dst->display;
+ uint32_t pixel =
+ 0xff000000 |
+ color->red_short >> 8 << 16 |
+ color->green_short >> 8 << 8 |
+ color->blue_short >> 8 << 0;
+ int i;
+
+ if (display->last_solid_cache[0].color == pixel)
+ return cairo_surface_reference (display->solid[display->last_solid_cache[0].index]);
+
+ for (i = 0; i < 16; i++) {
+ if (display->solid_cache[i] == pixel)
+ goto done;
+ }
+
+ i = hars_petruska_f54_1_random () % 16;
+ cairo_surface_destroy (display->solid[i]);
+
+ display->solid[i] = color_source (dst, color);
+ display->solid_cache[i] = pixel;
+
+done:
+ display->last_solid_cache[0].color = pixel;
+ display->last_solid_cache[0].index = i;
+ return cairo_surface_reference (display->solid[i]);
+}
+
+static cairo_surface_t *
+transparent_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
+{
+ cairo_xlib_display_t *display = dst->display;
+ uint32_t pixel =
+ color->alpha_short >> 8 << 24 |
+ color->red_short >> 8 << 16 |
+ color->green_short >> 8 << 8 |
+ color->blue_short >> 8 << 0;
+ int i;
+
+ if (display->last_solid_cache[1].color == pixel) {
+ assert (display->solid[display->last_solid_cache[1].index]);
+ return cairo_surface_reference (display->solid[display->last_solid_cache[1].index]);
+ }
+
+ for (i = 16; i < 32; i++) {
+ if (display->solid_cache[i] == pixel)
+ goto done;
+ }
+
+ i = 16 + (hars_petruska_f54_1_random () % 16);
+ cairo_surface_destroy (display->solid[i]);
+
+ display->solid[i] = color_source (dst, color);
+ display->solid_cache[i] = pixel;
+
+done:
+ display->last_solid_cache[1].color = pixel;
+ display->last_solid_cache[1].index = i;
+ assert (display->solid[i]);
+ return cairo_surface_reference (display->solid[i]);
+}
+
+static cairo_surface_t *
+solid_source (cairo_xlib_surface_t *dst,
+ const cairo_color_t *color)
+{
+ if ((color->red_short | color->green_short | color->blue_short) <= 0xff)
+ return alpha_source (dst, color->alpha_short >> 8);
+
+ if (CAIRO_ALPHA_SHORT_IS_OPAQUE (color->alpha_short)) {
+ if (color->red_short >= 0xff00 && color->green_short >= 0xff00 && color->blue_short >= 0xff00)
+ return white_source (dst);
+
+ return opaque_source (dst, color);
+ } else
+ return transparent_source (dst, color);
+}
+
+static cairo_surface_t *
+native_source (cairo_xlib_surface_t *dst,
+ const cairo_surface_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y)
+{
+ cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) pattern->surface;
+ cairo_xlib_source_t *source;
+ Display *dpy = dst->display->display;
+ cairo_bool_t is_contained = FALSE;
+ cairo_int_status_t status;
+ XTransform xtransform;
+ XRenderPictureAttributes pa;
+ int mask = 0;
+
+ src = (cairo_xlib_surface_t *)
+ unwrap_surface (pattern->surface, src_x, src_y);
+
+ if (sample->x >= 0 && sample->y >= 0 &&
+ sample->x + sample->width <= src->width &&
+ sample->y + sample->height <= src->height)
+ {
+ is_contained = TRUE;
+ }
+
+ if (pattern->base.filter == CAIRO_FILTER_NEAREST && is_contained) {
+ *src_x += pattern->base.matrix.x0;
+ *src_y += pattern->base.matrix.y0;
+ _cairo_xlib_surface_ensure_picture (src);
+ return cairo_surface_reference (&src->base);
+ }
+
+ /* As these are frequent and meant to be fast we track pictures for
+ * enative surface and minimse update requests.
+ */
+ source = &src->embedded_source;
+ if (source->picture == None) {
+ Picture picture;
+ XRenderPictureAttributes pa;
+ int mask = 0;
+
+ pa.subwindow_mode = IncludeInferiors;
+ mask |= CPSubwindowMode;
+
+ picture = XRenderCreatePicture (dpy,
+ src->drawable,
+ src->xrender_format,
+ mask, &pa);
+
+ _cairo_surface_init (&source->base,
+ &cairo_xlib_source_backend,
+ NULL, /* device */
+ CAIRO_CONTENT_COLOR_ALPHA);
+ source->picture = picture;
+
+ source->has_component_alpha = 0;
+ source->has_matrix = 0;
+ source->filter = CAIRO_FILTER_NEAREST;
+ source->extend = CAIRO_EXTEND_NONE;
+ }
+
+ status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
+ pattern->base.filter,
+ extents->x + extents->width / 2,
+ extents->y + extents->height / 2,
+ (pixman_transform_t *)&xtransform,
+ src_x, src_y);
+
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
+ if (source->has_matrix) {
+ source->has_matrix = 0;
+ memcpy (&xtransform, &identity, sizeof (identity));
+ status = CAIRO_INT_STATUS_SUCCESS;
+ }
+ } else
+ source->has_matrix = 1;
+ if (status == CAIRO_INT_STATUS_SUCCESS)
+ XRenderSetPictureTransform (dpy, source->picture, &xtransform);
+
+ if (source->filter != pattern->base.filter) {
+ picture_set_filter (dpy, source->picture, pattern->base.filter);
+ source->filter = pattern->base.filter;
+ }
+
+ if (source->has_component_alpha != pattern->base.has_component_alpha) {
+ pa.component_alpha = pattern->base.has_component_alpha;
+ mask |= CPComponentAlpha;
+ source->has_component_alpha = pattern->base.has_component_alpha;
+ }
+
+ if (source->extend != pattern->base.extend) {
+ pa.repeat = extend_to_repeat (pattern->base.extend);
+ mask |= CPRepeat;
+ source->extend = pattern->base.extend;
+ }
+
+ if (mask)
+ XRenderChangePicture (dpy, source->picture, mask, &pa);
+
+ return cairo_surface_reference (&source->base);
+}
+
+#if 0
+/* It is general quicker if we let the application choose which images
+ * to cache for itself and only upload the fragments required for this
+ * operation.
+ */
+static cairo_surface_t *
+image_source (cairo_xlib_surface_t *dst,
+ const cairo_surface_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ int *src_x, int *src_y)
+{
+ cairo_image_surface_t *src = (cairo_image_surface_t *) pattern->surface;
+ cairo_xlib_surface_t *snapshot;
+ cairo_surface_pattern_t local_pattern;
+ cairo_status_t status;
+
+ snapshot = (cairo_xlib_surface_t *)
+ _cairo_surface_has_snapshot (&src->base, dst->base.backend);
+ if (snapshot == NULL || snapshot->screen != dst->screen) {
+ if (snapshot)
+ _cairo_surface_detach_snapshot (&snapshot->base);
+
+ snapshot = (cairo_xlib_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ src->base.content,
+ src->width,
+ src->height);
+ if (snapshot->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ cairo_surface_destroy (&snapshot->base);
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ status = _cairo_xlib_surface_draw_image (snapshot, src,
+ 0, 0,
+ src->width, src->height,
+ 0, 0);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&snapshot->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ _cairo_surface_attach_snapshot (&src->base,
+ &snapshot->base,
+ cairo_surface_finish);
+
+ /* reference remains held by the snapshot from image */
+ cairo_surface_destroy (&snapshot->base);
+ }
+
+ local_pattern = *pattern;
+ local_pattern.surface = &snapshot->base;
+
+ return native_source (dst, &local_pattern, extents, src_x, src_y);
+}
+#endif
+
+static cairo_surface_t *
+recording_pattern_get_surface (const cairo_pattern_t *pattern)
+{
+ cairo_surface_t *surface;
+
+ surface = ((const cairo_surface_pattern_t *) pattern)->surface;
+ if (_cairo_surface_is_paginated (surface))
+ surface = _cairo_paginated_surface_get_recording (surface);
+ if (_cairo_surface_is_snapshot (surface))
+ surface = _cairo_surface_snapshot_get_target (surface);
+ return surface;
+}
+
+static cairo_surface_t *
+record_source (cairo_xlib_surface_t *dst,
+ const cairo_surface_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y)
+{
+ cairo_xlib_surface_t *src;
+ cairo_matrix_t matrix, m;
+ cairo_status_t status;
+ cairo_rectangle_int_t upload, limit;
+
+ upload = *sample;
+ if (_cairo_surface_get_extents (pattern->surface, &limit) &&
+ ! _cairo_rectangle_intersect (&upload, &limit))
+ {
+ if (pattern->base.extend == CAIRO_EXTEND_NONE)
+ return alpha_source (dst, 0);
+
+ upload = limit;
+ }
+
+ src = (cairo_xlib_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ pattern->surface->content,
+ upload.width,
+ upload.height);
+ if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ cairo_surface_destroy (&src->base);
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ cairo_matrix_init_translate (&matrix, upload.x, upload.y);
+ status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (&pattern->base),
+ &matrix, &src->base,
+ NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&src->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ matrix = pattern->base.matrix;
+ if (upload.x | upload.y) {
+ cairo_matrix_init_translate (&m, -upload.x, -upload.y);
+ cairo_matrix_multiply (&matrix, &matrix, &m);
+ }
+
+ _cairo_xlib_surface_ensure_picture (src);
+ if (! picture_set_properties (src->display, src->picture,
+ &pattern->base, &matrix, extents,
+ src_x, src_y))
+ {
+ cairo_surface_destroy (&src->base);
+ return render_pattern (dst, &pattern->base, is_mask,
+ extents, src_x, src_y);
+ }
+
+ return &src->base;
+}
+
+static cairo_surface_t *
+surface_source (cairo_xlib_surface_t *dst,
+ const cairo_surface_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y)
+{
+ cairo_xlib_surface_t *src;
+ cairo_surface_t *image;
+ cairo_surface_pattern_t local_pattern;
+ cairo_status_t status;
+ cairo_rectangle_int_t upload, limit;
+ cairo_matrix_t m;
+
+ upload = *sample;
+ if (_cairo_surface_get_extents (pattern->surface, &limit) &&
+ ! _cairo_rectangle_intersect (&upload, &limit))
+ {
+ if (pattern->base.extend == CAIRO_EXTEND_NONE)
+ return alpha_source (dst, 0);
+
+ upload = limit;
+ }
+
+ src = (cairo_xlib_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ pattern->surface->content,
+ upload.width,
+ upload.height);
+ if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ cairo_surface_destroy (&src->base);
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
+ cairo_matrix_init_translate (&local_pattern.base.matrix,
+ upload.x, upload.y);
+
+ image = cairo_surface_map_to_image (&src->base, NULL);
+ status = _cairo_surface_paint (image,
+ CAIRO_OPERATOR_SOURCE,
+ &local_pattern.base,
+ NULL);
+ cairo_surface_unmap_image (&src->base, image);
+ _cairo_pattern_fini (&local_pattern.base);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (&src->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ local_pattern.base.matrix = pattern->base.matrix;
+ if (upload.x | upload.y) {
+ cairo_matrix_init_translate (&m, -upload.x, -upload.y);
+ cairo_matrix_multiply (&local_pattern.base.matrix,
+ &local_pattern.base.matrix,
+ &m);
+ }
+
+ *src_x = *src_y = 0;
+ _cairo_xlib_surface_ensure_picture (src);
+ if (! picture_set_properties (src->display,
+ src->picture,
+ &pattern->base,
+ &local_pattern.base.matrix,
+ extents,
+ src_x, src_y))
+ {
+ cairo_surface_destroy (&src->base);
+ return render_pattern (dst, &pattern->base,
+ is_mask, extents,
+ src_x, src_y);
+ }
+
+ return &src->base;
+}
+
+static cairo_bool_t
+pattern_is_supported (cairo_xlib_display_t *display,
+ const cairo_pattern_t *pattern)
+{
+ if (pattern->type == CAIRO_PATTERN_TYPE_MESH)
+ return FALSE;
+
+ if (display->buggy_pad_reflect) {
+ if (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_PAD)
+ return FALSE;
+ }
+
+ if (display->buggy_gradients) {
+ if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
+ return FALSE;
+ }
+
+ if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display)) {
+ if (!_cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
+ return FALSE;
+ }
+
+ if (! CAIRO_RENDER_HAS_FILTERS (display)) {
+ /* No filters implies no transforms, so we optimise away BILINEAR */
+ }
+
+ return TRUE;
+}
+cairo_surface_t *
+_cairo_xlib_source_create_for_pattern (cairo_surface_t *_dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y)
+{
+ cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)_dst;
+ int tx, ty;
+
+ if (pattern == NULL || pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
+ *src_x = *src_y = 0;
+
+ if (pattern == NULL)
+ pattern = &_cairo_pattern_white.base;
+
+ return solid_source (dst, &((cairo_solid_pattern_t *)pattern)->color);
+ }
+
+ if (pattern_is_supported (dst->display, pattern)) {
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t *)pattern;
+ if (spattern->surface->type == CAIRO_SURFACE_TYPE_XLIB &&
+ _cairo_xlib_surface_same_screen (dst,
+ (cairo_xlib_surface_t *)unwrap_surface (spattern->surface, &tx, &ty)))
+ return native_source (dst, spattern, is_mask,
+ extents, sample,
+ src_x, src_y);
+
+ if (spattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
+ return record_source (dst, spattern, is_mask,
+ extents, sample,
+ src_x, src_y);
+#if 0
+ if (spattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE)
+ return image_source (dst, spattern, extents, src_x, src_y);
+#endif
+
+ return surface_source (dst, spattern, is_mask,
+ extents, sample,
+ src_x, src_y);
+ }
+
+ if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
+ pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
+ {
+ cairo_gradient_pattern_t *gpattern = (cairo_gradient_pattern_t *)pattern;
+ return gradient_source (dst, gpattern, is_mask, extents, src_x, src_y);
+ }
+ }
+
+ return render_pattern (dst, pattern, is_mask, extents, src_x, src_y);
+}
+
+#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */
diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h
index b56b245c..87db6962 100644
--- a/src/cairo-xlib-surface-private.h
+++ b/src/cairo-xlib-surface-private.h
@@ -38,76 +38,7 @@
#include "cairo-xlib-xrender-private.h"
#include "cairo-surface-private.h"
+#include "cairo-surface-backend-private.h"
-typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
-
-struct _cairo_xlib_surface {
- cairo_surface_t base;
-
- cairo_xlib_screen_t *screen;
- cairo_xlib_hook_t close_display_hook;
- cairo_list_t link;
-
- Drawable drawable;
- cairo_bool_t owns_pixmap;
- Visual *visual;
-
- int use_pixmap;
-
- int render_major;
- int render_minor;
-
- /* TRUE if the server has a bug with repeating pictures
- *
- * https://bugs.freedesktop.org/show_bug.cgi?id=3566
- *
- * We can't test for this because it depends on whether the
- * picture is in video memory or not.
- *
- * We also use this variable as a guard against a second
- * independent bug with transformed repeating pictures:
- *
- * http://lists.freedesktop.org/archives/cairo/2004-September/001839.html
- *
- * Both are fixed in xorg >= 6.9 and hopefully in > 6.8.2, so
- * we can reuse the test for now.
- */
- unsigned int buggy_gradients : 1;
- unsigned int buggy_pad_reflect : 1;
- unsigned int buggy_repeat : 1;
-#define CAIRO_XLIB_SURFACE_HAS_BUGGY_GRADIENTS 1
-#define CAIRO_XLIB_SURFACE_HAS_BUGGY_PAD_REFLECT 1
-#define CAIRO_XLIB_SURFACE_HAS_BUGGY_REPEAT 1
-
- int width;
- int height;
- int depth;
-
- Picture dst_picture, src_picture;
-
- unsigned int clip_dirty;
- XRectangle embedded_clip_rects[8];
- XRectangle *clip_rects;
- int num_clip_rects;
- cairo_region_t *clip_region;
-
- XRenderPictFormat *xrender_format;
- cairo_filter_t filter;
- cairo_extend_t extend;
- cairo_bool_t has_component_alpha;
- int precision;
- XTransform xtransform;
-
- uint32_t a_mask;
- uint32_t r_mask;
- uint32_t g_mask;
- uint32_t b_mask;
-};
-
-enum {
- CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC = 0x01,
- CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE = 0x02,
- CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL = 0x03
-};
#endif /* CAIRO_XLIB_SURFACE_PRIVATE_H */
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index e82de650..1806e64b 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -51,6 +51,8 @@
#include "cairo-xlib-private.h"
#include "cairo-xlib-surface-private.h"
+
+#include "cairo-compositor-private.h"
#include "cairo-clip-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
@@ -64,7 +66,6 @@
#include <X11/Xutil.h> /* for XDestroyImage */
#define XLIB_COORD_MAX 32767
-#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
#define DEBUG 0
@@ -169,16 +170,6 @@ _cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen,
static cairo_bool_t
_cairo_surface_is_xlib (cairo_surface_t *surface);
-static cairo_int_status_t
-_cairo_xlib_surface_show_glyphs (void *abstract_dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs);
-
/*
* Instead of taking two round trips for each blending request,
* assume that if a particular drawable fails GetImage that it will
@@ -193,37 +184,6 @@ static const XTransform identity = { {
{ 0x00000, 0x00000, 1 << 16 },
} };
-#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
- (((surface)->render_major > major) || \
- (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
-
-#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-
-#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-
-#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-
-#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-
-#define CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
-#define CAIRO_SURFACE_RENDER_HAS_GRADIENTS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
-
-#define CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 11)
-
-#define CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR(surface, op) \
- ((op) <= CAIRO_OPERATOR_SATURATE || \
- (CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS(surface) && \
- (op) <= CAIRO_OPERATOR_HSL_LUMINOSITY))
-
static Visual *
_visual_for_xrender_format(Screen *screen,
XRenderPictFormat *xrender_format)
@@ -274,62 +234,6 @@ _visual_for_xrender_format(Screen *screen,
return NULL;
}
-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_content_t
_xrender_format_to_content (XRenderPictFormat *xrender_format)
{
@@ -373,9 +277,6 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
if (width == 0 || height == 0)
return NULL;
- if (! CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (src))
- return NULL;
-
if (_cairo_xlib_display_acquire (src->base.device, &display))
return NULL;
@@ -384,21 +285,25 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
* constructing a cairo_format_t instead, (which will fairly
* arbitrarily pick a visual/depth for the similar surface.
*/
- xrender_format = src->xrender_format;
- if ((xrender_format != NULL &&
- _xrender_format_to_content (xrender_format) == content) ||
- (xrender_format =
- _cairo_xlib_display_get_xrender_format (display,
- _cairo_format_from_content (content))))
+ xrender_format = NULL;
+ if (src->xrender_format &&
+ _xrender_format_to_content (src->xrender_format) == content)
{
+ xrender_format = src->xrender_format;
+ }
+ if (xrender_format == NULL) {
+ xrender_format =
+ _cairo_xlib_display_get_xrender_format (display,
+ _cairo_format_from_content (content));
+ }
+ if (xrender_format) {
Visual *visual;
/* We've got a compatible XRenderFormat now, which means the
* similar surface will match the existing surface as closely in
* visual/depth etc. as possible. */
pix = XCreatePixmap (display->display, src->drawable,
- width <= 0 ? 1 : width, height <= 0 ? 1 : height,
- xrender_format->depth);
+ width, height, xrender_format->depth);
if (xrender_format == src->xrender_format)
visual = src->visual;
@@ -407,15 +312,13 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
xrender_format);
surface = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_internal (src->screen, pix,
- visual,
+ _cairo_xlib_surface_create_internal (src->screen, pix, visual,
xrender_format,
width, height,
xrender_format->depth);
}
else
{
-#ifdef DEBUG_FORCE_FALLBACKS
Screen *screen = src->screen->screen;
int depth;
@@ -437,20 +340,12 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
DefaultVisualOfScreen (screen),
NULL,
width, height, depth);
-#else
- /* No compatabile XRenderFormat, just say no. */
- cairo_device_release (&display->base);
- return NULL;
-#endif
}
- if (unlikely (surface->base.status)) {
+ if (likely (surface->base.status == CAIRO_STATUS_SUCCESS))
+ surface->owns_pixmap = TRUE;
+ else
XFreePixmap (display->display, pix);
- cairo_device_release (&display->base);
- return &surface->base;
- }
-
- surface->owns_pixmap = TRUE;
cairo_device_release (&display->base);
@@ -472,53 +367,19 @@ _cairo_xlib_surface_finish (void *abstract_surface)
if (unlikely (status))
return status;
- if (surface->owns_pixmap) {
- cairo_status_t status2;
-
- if (surface->dst_picture != None) {
- status2 = _cairo_xlib_display_queue_resource (display,
- XRenderFreePicture,
- surface->dst_picture);
- if (status == CAIRO_STATUS_SUCCESS)
- status = status2;
- }
-
- if (surface->src_picture != None) {
- status2 = _cairo_xlib_display_queue_resource (display,
- XRenderFreePicture,
- surface->src_picture);
- if (status == CAIRO_STATUS_SUCCESS)
- status = status2;
- }
-
- status2 = _cairo_xlib_display_queue_resource (display,
- (cairo_xlib_notify_resource_func) XFreePixmap,
- surface->drawable);
- if (status == CAIRO_STATUS_SUCCESS)
- status = status2;
- } else {
- if (surface->dst_picture != None)
- XRenderFreePicture (display->display, surface->dst_picture);
-
- if (surface->src_picture != None)
- XRenderFreePicture (display->display, surface->src_picture);
- }
-
- if (surface->clip_rects != surface->embedded_clip_rects)
- free (surface->clip_rects);
-
- if (display->display != NULL)
- _cairo_xlib_remove_close_display_hook (display,
- &surface->close_display_hook);
+ if (surface->embedded_source.picture)
+ XRenderFreePicture (display->display, surface->embedded_source.picture);
+ if (surface->picture)
+ XRenderFreePicture (display->display, surface->picture);
+ if (surface->owns_pixmap)
+ XFreePixmap (display->display, surface->drawable);
cairo_device_release (&display->base);
- cairo_region_destroy (surface->clip_region);
-
return status;
}
-static cairo_status_t
+cairo_status_t
_cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
cairo_xlib_surface_t *surface,
GC *gc)
@@ -533,17 +394,6 @@ _cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
return CAIRO_STATUS_SUCCESS;
}
-static void
-_cairo_xlib_surface_put_gc (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *surface,
- GC gc)
-{
- _cairo_xlib_screen_put_gc (display,
- surface->screen,
- surface->depth,
- gc);
-}
-
static int
_noop_error_handler (Display *display,
XErrorEvent *event)
@@ -714,7 +564,6 @@ _characterize_field (uint32_t mask, int *width, int *shift)
*shift = _cairo_popcount ((mask - 1) & ~mask) & 31;
}
-
/* Convert a field of 'width' bits to 'new_width' bits with correct
* rounding. */
static inline uint32_t
@@ -806,7 +655,6 @@ _pseudocolor_to_rgb888 (cairo_xlib_visual_info_t *visual_info,
(b );
}
-
/* should range from -128 to 127 */
#define X 16
static const int8_t dither_pattern[4][4] = {
@@ -817,7 +665,6 @@ static const int8_t dither_pattern[4][4] = {
};
#undef X
-
static cairo_surface_t *
_get_image_surface (cairo_xlib_surface_t *surface,
const cairo_rectangle_int_t *extents)
@@ -834,6 +681,20 @@ _get_image_surface (cairo_xlib_surface_t *surface,
assert (extents->x + extents->width <= surface->width);
assert (extents->y + extents->height <= surface->height);
+ if (surface->base.serial == 0) {
+ xlib_masks.bpp = (surface->depth + 7) & ~7;
+ xlib_masks.alpha_mask = surface->a_mask;
+ xlib_masks.red_mask = surface->r_mask;
+ xlib_masks.green_mask = surface->g_mask;
+ xlib_masks.blue_mask = surface->b_mask;
+ _pixman_format_from_masks (&xlib_masks, &pixman_format);
+ return _cairo_image_surface_create_with_pixman_format (NULL,
+ pixman_format,
+ extents->width,
+ extents->height,
+ 0);
+ }
+
status = _cairo_xlib_display_acquire (surface->base.device, &display);
if (status)
return _cairo_surface_create_in_error (status);
@@ -1046,48 +907,11 @@ _get_image_surface (cairo_xlib_surface_t *surface,
return &image->base;
}
-static void
-_cairo_xlib_surface_ensure_src_picture (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *surface)
-{
- if (!surface->src_picture) {
- XRenderPictureAttributes pa;
- int mask = 0;
-
- pa.subwindow_mode = IncludeInferiors;
- mask |= CPSubwindowMode;
-
- surface->src_picture = XRenderCreatePicture (display->display,
- surface->drawable,
- surface->xrender_format,
- mask, &pa);
- }
-}
-
-static void
-_cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *surface)
-{
- if (surface->clip_region != NULL) {
- XRenderSetPictureClipRectangles (display->display, surface->dst_picture,
- 0, 0,
- surface->clip_rects,
- surface->num_clip_rects);
- } else {
- XRenderPictureAttributes pa;
- pa.clip_mask = None;
- XRenderChangePicture (display->display, surface->dst_picture,
- CPClipMask, &pa);
- }
-
- surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE;
-}
-
-static void
-_cairo_xlib_surface_set_precision (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *surface,
+void
+_cairo_xlib_surface_set_precision (cairo_xlib_surface_t *surface,
cairo_antialias_t antialias)
{
+ cairo_xlib_display_t *display = surface->display;
int precision;
if (display->force_precision != -1)
@@ -1111,37 +935,46 @@ _cairo_xlib_surface_set_precision (cairo_xlib_display_t *display,
XRenderPictureAttributes pa;
pa.poly_mode = precision;
- XRenderChangePicture (display->display, surface->dst_picture,
+ XRenderChangePicture (display->display, surface->picture,
CPPolyMode, &pa);
surface->precision = precision;
}
}
-static void
-_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *surface)
+void
+_cairo_xlib_surface_ensure_picture (cairo_xlib_surface_t *surface)
{
- if (!surface->dst_picture) {
- surface->dst_picture = XRenderCreatePicture (display->display,
- surface->drawable,
- surface->xrender_format,
- 0, NULL);
- }
+ cairo_xlib_display_t *display = surface->display;
+ XRenderPictureAttributes pa;
+ int mask = 0;
- if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE)
- _cairo_xlib_surface_set_picture_clip_rects (display, surface);
-}
+ if (surface->picture)
+ return;
-static cairo_status_t
-_draw_image_surface (cairo_xlib_surface_t *surface,
- cairo_image_surface_t *image,
- int src_x,
- int src_y,
- int width,
- int height,
- int dst_x,
- int dst_y)
+ if (display->force_precision != -1)
+ pa.poly_mode = display->force_precision;
+ else
+ pa.poly_mode = PolyModeImprecise;
+ if (pa.poly_mode)
+ mask |= CPPolyMode;
+
+ surface->precision = pa.poly_mode;
+ surface->picture = XRenderCreatePicture (display->display,
+ surface->drawable,
+ surface->xrender_format,
+ mask, &pa);
+}
+
+cairo_status_t
+_cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
+ cairo_image_surface_t *image,
+ int src_x,
+ int src_y,
+ int width,
+ int height,
+ int dst_x,
+ int dst_y)
{
cairo_xlib_display_t *display;
XImage ximage;
@@ -1400,7 +1233,7 @@ _cairo_xlib_surface_snapshot (void *abstract_surface)
extents.width = surface->width;
extents.height = surface->height;
- /* XXX notice the duplication */
+ /* XXX notice the duplication with acquire source */
return _get_image_surface (surface, &extents);
}
@@ -1428,1703 +1261,114 @@ static cairo_int_status_t
_cairo_xlib_surface_unmap_image (void *abstract_surface,
cairo_image_surface_t *image)
{
- return _draw_image_surface (abstract_surface, image,
- 0, 0,
- image->width, image->height,
- image->base.device_transform_inverse.x0,
- image->base.device_transform_inverse.y0);
-}
-
-static cairo_status_t
-_cairo_xlib_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect_out,
- void **image_extra)
-{
- if (image_rect_out)
- *image_rect_out = *interest_rect;
- *image_extra = NULL;
- *image_out = (cairo_image_surface_t *)
- _get_image_surface (abstract_surface, interest_rect);
- return (*image_out)->base.status;
-}
-
-static void
-_cairo_xlib_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
- status = _draw_image_surface (surface, image,
- 0, 0, image->width, image->height,
- image_rect->x, image_rect->y);
- status = _cairo_surface_set_error (&surface->base, status);
-
- cairo_surface_destroy (&image->base);
-}
-
-/*
- * Return whether two xlib surfaces share the same
- * screen. Both core and Render drawing require this
- * when using multiple drawables in an operation.
- */
-static inline cairo_bool_t
-_cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
- cairo_xlib_surface_t *src)
-{
- return dst->screen == src->screen;
-}
-
-static cairo_xlib_surface_t *
-_cairo_xlib_surface_create_similar_for_image(cairo_xlib_surface_t *other,
- cairo_image_surface_t *image,
- int width, int height)
-{
- XRenderPictFormat *xrender_format;
- cairo_xlib_display_t *display;
- cairo_xlib_surface_t *surface;
- cairo_status_t status;
- Visual *visual;
- Pixmap pix;
-
- /* Try to create a surface using an xrender format that exactly matches
- * the image data so that we can upload the pixels and perform any
- * conversion on the GPU.
- */
-
- if (!CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (other)) {
-fallback:
- return (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_similar (other,
- image->base.content,
- width, height);
- }
-
- status = _cairo_xlib_display_acquire (other->base.device, &display);
- if (unlikely (status))
- return (cairo_xlib_surface_t *) _cairo_surface_create_in_error(status);
-
- if (image->format != CAIRO_FORMAT_INVALID)
- xrender_format =
- _cairo_xlib_display_get_xrender_format (display, image->format);
- else
- xrender_format =
- _cairo_xlib_display_get_xrender_format_for_pixman (display,
- image->pixman_format);
- if (xrender_format == NULL) {
- cairo_device_release (&display->base);
- goto fallback;
- }
-
- pix = XCreatePixmap (display->display, other->drawable,
- width, height, xrender_format->depth);
-
- if (xrender_format == other->xrender_format)
- visual = other->visual;
- else
- visual = _visual_for_xrender_format(other->screen->screen,
- xrender_format);
-
- surface = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_internal (other->screen, pix, visual,
- xrender_format,
- width, height,
- xrender_format->depth);
-
- if (unlikely (surface->base.status)) {
- XFreePixmap (display->display, pix);
- cairo_device_release (&display->base);
- return surface;
- }
-
- surface->owns_pixmap = TRUE;
- cairo_device_release (&display->base);
- return surface;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_xlib_surface_t *clone;
- cairo_status_t status;
-
- if (src->backend == surface->base.backend ) {
- cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src;
-
- if (_cairo_xlib_surface_same_screen (surface, xlib_src)) {
- *clone_offset_x = 0;
- *clone_offset_y = 0;
- *clone_out = cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
- } else if (_cairo_surface_is_image (src)) {
- cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
-
- if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
- return UNSUPPORTED ("roi too large for xlib");
-
- clone = _cairo_xlib_surface_create_similar_for_image(surface,
- image_src,
- width, height);
- if (clone == NULL)
- return UNSUPPORTED ("unhandled image format, no similar surface");
-
- if (unlikely (clone->base.status))
- return clone->base.status;
-
- status = _draw_image_surface (clone, image_src,
- src_x, src_y,
- width, height,
- 0, 0);
- if (unlikely (status)) {
- cairo_surface_destroy (&clone->base);
- return status;
- }
-
- *clone_offset_x = src_x;
- *clone_offset_y = src_y;
- *clone_out = &clone->base;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_surface_t *
-_cairo_xlib_surface_create_solid_pattern_surface (void *abstract_surface,
- const cairo_solid_pattern_t *solid_pattern)
-{
- /* This function's only responsibility is to create a proper surface
- * for when XRender is not available. The proper surface is a xlib
- * surface (as opposed to image surface which is what create_similar
- * returns in those cases) and the size of the dithering pattern, not
- * 1x1. This surface can then be used in
- * _cairo_xlib_surface_solid_fill_rectangles() to do dithered "solid"
- * fills using core protocol */
-
- cairo_xlib_surface_t *other = abstract_surface;
- cairo_image_surface_t *image;
- cairo_xlib_surface_t *surface = NULL;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_xlib_display_t *display;
-
- int width = ARRAY_LENGTH (dither_pattern[0]);
- int height = ARRAY_LENGTH (dither_pattern);
-
- Pixmap pixmap = None;
-
- if (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other))
- return NULL;
-
- image = (cairo_image_surface_t *)
- _cairo_image_surface_create_with_content (_cairo_color_get_content (&solid_pattern->color),
- width, height);
- status = image->base.status;
- if (unlikely (status))
- goto BAIL;
-
- status = _cairo_xlib_display_acquire (other->base.device, &display);
- if (unlikely (status))
- goto BAIL;
-
- pixmap = XCreatePixmap (display->display,
- other->drawable,
- width, height,
- other->depth);
- cairo_device_release (&display->base);
-
- surface = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_internal (other->screen,
- pixmap,
- other->visual,
- other->xrender_format,
- width, height,
- other->depth);
- status = surface->base.status;
- if (unlikely (status))
- goto BAIL;
-
- status = _cairo_surface_paint (&image->base,
- CAIRO_OPERATOR_SOURCE,
- &solid_pattern->base,
- NULL);
- if (unlikely (status))
- goto BAIL;
-
- status = _draw_image_surface (surface, image,
- 0, 0,
- width, height,
- 0, 0);
- if (unlikely (status))
- goto BAIL;
-
- BAIL:
- cairo_surface_destroy (&image->base);
-
- if (status) {
- if (pixmap != None) {
- if (!_cairo_xlib_display_acquire (other->base.device, &display)) {
- XFreePixmap (display->display, pixmap);
- cairo_device_release (&display->base);
- }
- }
- cairo_surface_destroy (&surface->base);
-
- return _cairo_surface_create_in_error (status);
- }
-
- surface->owns_pixmap = TRUE;
- return &surface->base;
-}
-
-static cairo_bool_t
-_cairo_xlib_surface_can_repaint_solid_pattern_surface (void *abstract_surface,
- const cairo_solid_pattern_t *solid_pattern)
-{
- cairo_xlib_surface_t *other = abstract_surface;
- return CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other);
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_set_matrix (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *surface,
- const cairo_matrix_t *matrix,
- cairo_filter_t filter,
- double xc,
- double yc,
- int *x_offset,
- int *y_offset)
-{
- XTransform xtransform;
- pixman_transform_t *pixman_transform;
- cairo_int_status_t status;
-
- /* Casting between pixman_transform_t and XTransform is safe because
- * they happen to be the exact same type.
- */
- pixman_transform = (pixman_transform_t *) &xtransform;
-
- status = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
- pixman_transform,
- x_offset, y_offset);
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- status = CAIRO_INT_STATUS_SUCCESS;
- if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
- return status;
-
- if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0)
- return CAIRO_STATUS_SUCCESS;
-
- if (! CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
- return UNSUPPORTED ("XRender does not support picture transforms");
-
- XRenderSetPictureTransform (display->display, surface->src_picture, &xtransform);
- surface->xtransform = xtransform;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_set_filter (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *surface,
- cairo_filter_t filter)
-{
- const char *render_filter;
-
- if (surface->filter == filter)
- return CAIRO_STATUS_SUCCESS;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) {
- if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
- return CAIRO_STATUS_SUCCESS;
-
- return UNSUPPORTED ("XRender does not support filter");
- }
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- render_filter = FilterFast;
- break;
- case CAIRO_FILTER_GOOD:
- render_filter = FilterGood;
- break;
- case CAIRO_FILTER_BEST:
- render_filter = FilterBest;
- break;
- case CAIRO_FILTER_NEAREST:
- render_filter = FilterNearest;
- break;
- case CAIRO_FILTER_BILINEAR:
- render_filter = FilterBilinear;
- break;
- case CAIRO_FILTER_GAUSSIAN:
- /* XXX: The GAUSSIAN value has no implementation in cairo
- * whatsoever, so it was really a mistake to have it in the
- * API. We could fix this by officially deprecating it, or
- * else inventing semantics and providing an actual
- * implementation for it. */
- default:
- render_filter = FilterBest;
- break;
- }
-
- XRenderSetPictureFilter (display->display, surface->src_picture,
- (char *) render_filter, NULL, 0);
- surface->filter = filter;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface,
- cairo_extend_t extend,
- unsigned long *mask,
- XRenderPictureAttributes *pa)
-{
- int repeat;
-
- if (surface->extend == extend)
- return CAIRO_STATUS_SUCCESS;
-
- switch (extend) {
- case CAIRO_EXTEND_NONE:
- repeat = RepeatNone;
- break;
- case CAIRO_EXTEND_REPEAT:
- repeat = RepeatNormal;
- break;
- case CAIRO_EXTEND_REFLECT:
- if (surface->buggy_pad_reflect)
- return UNSUPPORTED ("buggy reflect");
-
- repeat = RepeatReflect;
- break;
- case CAIRO_EXTEND_PAD:
- if (surface->buggy_pad_reflect)
- return UNSUPPORTED ("buggy pad");
-
- repeat = RepeatPad;
- break;
- default:
- ASSERT_NOT_REACHED;
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- *mask |= CPRepeat;
- pa->repeat = repeat;
-
- surface->extend = extend;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_set_component_alpha (cairo_xlib_surface_t *surface,
- cairo_bool_t ca,
- unsigned long *mask,
- XRenderPictureAttributes *pa)
-{
- if (surface->has_component_alpha == ca)
- return CAIRO_STATUS_SUCCESS;
-
- *mask |= CPComponentAlpha;
- pa->component_alpha = ca;
-
- surface->has_component_alpha = ca;
- return CAIRO_STATUS_SUCCESS;
+ return _cairo_xlib_surface_draw_image (abstract_surface, image,
+ 0, 0,
+ image->width, image->height,
+ image->base.device_transform_inverse.x0,
+ image->base.device_transform_inverse.y0);
}
-static cairo_int_status_t
-_cairo_xlib_surface_set_attributes (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *surface,
- cairo_surface_attributes_t *attributes,
- double xc,
- double yc)
-{
- cairo_int_status_t status;
- XRenderPictureAttributes pa;
- unsigned long mask = 0;
-
- _cairo_xlib_surface_ensure_src_picture (display, surface);
-
- status = _cairo_xlib_surface_set_matrix (display, surface,
- &attributes->matrix,
- attributes->filter,
- xc, yc,
- &attributes->x_offset,
- &attributes->y_offset);
- if (unlikely (status))
- return status;
-
- status = _cairo_xlib_surface_set_repeat (surface, attributes->extend,
- &mask, &pa);
- if (unlikely (status))
- return status;
-
- status = _cairo_xlib_surface_set_component_alpha (surface,
- attributes->has_component_alpha,
- &mask, &pa);
- if (unlikely (status))
- return status;
-
- status = _cairo_xlib_surface_set_filter (display, surface, attributes->filter);
- if (unlikely (status))
- return status;
-
- if (mask)
- XRenderChangePicture (display->display, surface->src_picture, mask, &pa);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Checks whether we can can directly draw from src to dst with
- * the core protocol: either with CopyArea or using src as a
- * a tile in a GC.
- */
static cairo_bool_t
-_surfaces_compatible (cairo_xlib_surface_t *dst,
- cairo_xlib_surface_t *src)
+_cairo_xlib_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *rectangle)
{
- /* same screen */
- if (! _cairo_xlib_surface_same_screen (dst, src))
- return FALSE;
-
- /* same depth (for core) */
- if (src->depth != dst->depth)
- return FALSE;
-
- /* if Render is supported, match picture formats */
- if (src->xrender_format != dst->xrender_format)
- return FALSE;
- else if (src->xrender_format != NULL)
- return TRUE;
-
- /* Without Render, match visuals instead */
- if (src->visual == dst->visual)
- return TRUE;
-
- return FALSE;
-}
+ cairo_xlib_surface_t *surface = abstract_surface;
-static cairo_bool_t
-_surface_has_alpha (cairo_xlib_surface_t *surface)
-{
- if (surface->xrender_format) {
- if (surface->xrender_format->type == PictTypeDirect &&
- surface->xrender_format->direct.alphaMask != 0)
- return TRUE;
- else
- return FALSE;
- } else {
- /* In the no-render case, we never have alpha */
- return FALSE;
- }
-}
+ rectangle->x = 0;
+ rectangle->y = 0;
-/* Returns true if the given operator and source-alpha combination
- * requires alpha compositing to complete.
- */
-static cairo_bool_t
-_operator_needs_alpha_composite (cairo_operator_t op,
- cairo_bool_t destination_has_alpha,
- cairo_bool_t source_has_alpha)
-{
- if (op == CAIRO_OPERATOR_SOURCE ||
- (! source_has_alpha &&
- (op == CAIRO_OPERATOR_OVER ||
- op == CAIRO_OPERATOR_ATOP ||
- op == CAIRO_OPERATOR_IN)))
- return destination_has_alpha;
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
return TRUE;
}
-/* There is a bug in most older X servers with compositing using a
- * untransformed repeating source pattern when the source is in off-screen
- * video memory, and another with repeated transformed images using a
- * general transform matrix. When these bugs could be triggered, we need a
- * fallback: in the common case where we have no transformation and the
- * source and destination have the same format/visual, we can do the
- * operation using the core protocol for the first bug, otherwise, we need
- * a software fallback.
- *
- * We can also often optimize a compositing operation by calling XCopyArea
- * for some common cases where there is no alpha compositing to be done.
- * We figure that out here as well.
- */
-typedef enum {
- DO_RENDER, /* use render */
- DO_XCOPYAREA, /* core protocol XCopyArea optimization/fallback */
- DO_XTILE, /* core protocol XSetTile optimization/fallback */
- DO_UNSUPPORTED /* software fallback */
-} composite_operation_t;
-
-/* Initial check for the render bugs; we need to recheck for the
- * offscreen-memory bug after we turn patterns into surfaces, since that
- * may introduce a repeating pattern for gradient patterns. We don't need
- * to check for the repeat+transform bug because gradient surfaces aren't
- * transformed.
- *
- * All we do here is reject cases where we *know* are going to
- * hit the bug and won't be able to use a core protocol fallback.
- */
-static composite_operation_t
-_categorize_composite_operation (cairo_xlib_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- cairo_bool_t have_mask)
-
-{
- if (!CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR (dst, op))
- return DO_UNSUPPORTED;
-
- if (! dst->buggy_repeat)
- return DO_RENDER;
-
- if (src_pattern->type != CAIRO_PATTERN_TYPE_SOLID &&
- src_pattern->extend == CAIRO_EXTEND_REPEAT)
- {
- /* Check for the bug with repeat patterns nad general transforms. */
- if (! _cairo_matrix_is_integer_translation (&src_pattern->matrix,
- NULL, NULL))
- {
- return DO_UNSUPPORTED;
- }
-
- if (have_mask ||
- !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
- {
- return DO_UNSUPPORTED;
- }
-
- if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
- cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) src_pattern;
-
- /* This is the case where we have the bug involving
- * untransformed repeating source patterns with off-screen
- * video memory; reject some cases where a core protocol
- * fallback is impossible.
- */
- if (_cairo_surface_is_xlib (surface_pattern->surface)) {
- cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) surface_pattern->surface;
-
- if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
- return DO_UNSUPPORTED;
-
- /* If these are on the same screen but otherwise incompatible,
- * make a copy as core drawing can't cross depths and doesn't
- * work right across visuals of the same depth
- */
- if (_cairo_xlib_surface_same_screen (dst, src) &&
- !_surfaces_compatible (dst, src))
- {
- return DO_UNSUPPORTED;
- }
- }
- }
- }
-
- return DO_RENDER;
-}
-
-/* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
- * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
- * did to turn gradients into a pattern, but most of the time we can handle
- * that case with core protocol fallback.
- *
- * Also check here if we can just use XCopyArea, instead of going through
- * Render.
- */
-static composite_operation_t
-_recategorize_composite_operation (cairo_xlib_surface_t *dst,
- cairo_operator_t op,
- cairo_xlib_surface_t *src,
- cairo_surface_attributes_t *src_attr,
- cairo_bool_t have_mask)
-{
- /* Can we use the core protocol? */
- if (! have_mask &&
- src->owns_pixmap &&
- src->depth == dst->depth &&
- _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
- ! _operator_needs_alpha_composite (op,
- _surface_has_alpha (dst),
- _surface_has_alpha (src)))
- {
- if (src_attr->extend == CAIRO_EXTEND_NONE)
- return DO_XCOPYAREA;
-
- if (dst->buggy_repeat && src_attr->extend == CAIRO_EXTEND_REPEAT)
- return DO_XTILE;
- }
-
- if (dst->buggy_repeat && src_attr->extend == CAIRO_EXTEND_REPEAT)
- return DO_UNSUPPORTED;
-
- if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
- return DO_UNSUPPORTED;
-
- if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
- return DO_UNSUPPORTED;
-
- return DO_RENDER;
-}
-
-static int
-_render_operator (cairo_operator_t op)
-{
- switch (op) {
- case CAIRO_OPERATOR_CLEAR:
- return PictOpClear;
-
- case CAIRO_OPERATOR_SOURCE:
- return PictOpSrc;
- case CAIRO_OPERATOR_OVER:
- return PictOpOver;
- case CAIRO_OPERATOR_IN:
- return PictOpIn;
- case CAIRO_OPERATOR_OUT:
- return PictOpOut;
- case CAIRO_OPERATOR_ATOP:
- return PictOpAtop;
-
- case CAIRO_OPERATOR_DEST:
- return PictOpDst;
- case CAIRO_OPERATOR_DEST_OVER:
- return PictOpOverReverse;
- case CAIRO_OPERATOR_DEST_IN:
- return PictOpInReverse;
- case CAIRO_OPERATOR_DEST_OUT:
- return PictOpOutReverse;
- case CAIRO_OPERATOR_DEST_ATOP:
- return PictOpAtopReverse;
-
- case CAIRO_OPERATOR_XOR:
- return PictOpXor;
- case CAIRO_OPERATOR_ADD:
- return PictOpAdd;
- case CAIRO_OPERATOR_SATURATE:
- return PictOpSaturate;
-
- case CAIRO_OPERATOR_MULTIPLY:
- return PictOpMultiply;
- case CAIRO_OPERATOR_SCREEN:
- return PictOpScreen;
- case CAIRO_OPERATOR_OVERLAY:
- return PictOpOverlay;
- case CAIRO_OPERATOR_DARKEN:
- return PictOpDarken;
- case CAIRO_OPERATOR_LIGHTEN:
- return PictOpLighten;
- case CAIRO_OPERATOR_COLOR_DODGE:
- return PictOpColorDodge;
- case CAIRO_OPERATOR_COLOR_BURN:
- return PictOpColorBurn;
- case CAIRO_OPERATOR_HARD_LIGHT:
- return PictOpHardLight;
- case CAIRO_OPERATOR_SOFT_LIGHT:
- return PictOpSoftLight;
- case CAIRO_OPERATOR_DIFFERENCE:
- return PictOpDifference;
- case CAIRO_OPERATOR_EXCLUSION:
- return PictOpExclusion;
- case CAIRO_OPERATOR_HSL_HUE:
- return PictOpHSLHue;
- case CAIRO_OPERATOR_HSL_SATURATION:
- return PictOpHSLSaturation;
- case CAIRO_OPERATOR_HSL_COLOR:
- return PictOpHSLColor;
- case CAIRO_OPERATOR_HSL_LUMINOSITY:
- return PictOpHSLLuminosity;
-
- default:
- ASSERT_NOT_REACHED;
- return PictOpOver;
- }
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *dst,
- const cairo_pattern_t *pattern,
- int x, int y,
- int width, int height,
- cairo_xlib_surface_t **surface_out,
- cairo_surface_attributes_t *attributes)
+static void
+_cairo_xlib_surface_get_font_options (void *abstract_surface,
+ cairo_font_options_t *options)
{
- switch (pattern->type) {
- case CAIRO_PATTERN_TYPE_LINEAR:
- case CAIRO_PATTERN_TYPE_RADIAL:
- {
- cairo_gradient_pattern_t *gradient =
- (cairo_gradient_pattern_t *) pattern;
- cairo_matrix_t matrix = pattern->matrix;
- cairo_xlib_surface_t *surface;
- char buf[CAIRO_STACK_BUFFER_SIZE];
- cairo_circle_double_t extremes[2];
- XFixed *stops;
- XRenderColor *colors;
- XRenderPictFormat *format;
- Picture picture;
- unsigned int i, n_stops;
-
- if (dst->buggy_gradients)
- break;
-
- /* The RENDER specification says that the inner circle has
- * to be completely contained inside the outer one. */
- if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL &&
- ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) gradient))
- break;
-
- assert (gradient->n_stops > 0);
- n_stops = MAX (gradient->n_stops, 2);
-
- if (n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
- {
- stops = (XFixed *) buf;
- }
- else
- {
- stops =
- _cairo_malloc_ab (n_stops,
- sizeof (XFixed) + sizeof (XRenderColor));
- if (unlikely (stops == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- colors = (XRenderColor *) (stops + n_stops);
- for (i = 0; i < gradient->n_stops; i++) {
- stops[i] =
- _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
-
- colors[i].red = gradient->stops[i].color.red_short;
- colors[i].green = gradient->stops[i].color.green_short;
- colors[i].blue = gradient->stops[i].color.blue_short;
- colors[i].alpha = gradient->stops[i].color.alpha_short;
- }
-
- /* RENDER does not support gradients with less than 2
- * stops. If a gradient has only a single stop, duplicate
- * it to make RENDER happy. */
- if (gradient->n_stops == 1) {
- stops[1] =
- _cairo_fixed_16_16_from_double (gradient->stops[0].offset);
-
- colors[1].red = gradient->stops[0].color.red_short;
- colors[1].green = gradient->stops[0].color.green_short;
- colors[1].blue = gradient->stops[0].color.blue_short;
- colors[1].alpha = gradient->stops[0].color.alpha_short;
- }
-
-#if 0
- /* For some weird reason the X server is sometimes getting
- * CreateGradient requests with bad length. So far I've only seen
- * XRenderCreateLinearGradient request with 4 stops sometime end up
- * with length field matching 0 stops at the server side. I've
- * looked at the libXrender code and I can't see anything that
- * could cause this behavior. However, for some reason having a
- * XSync call here seems to avoid the issue so I'll keep it here
- * until it's solved.
- */
- XSync (display->display, False);
-#endif
-
- _cairo_gradient_pattern_fit_to_range (gradient, PIXMAN_MAX_INT >> 1, &matrix, extremes);
-
- if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
- XLinearGradient grad;
-
- grad.p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
- grad.p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
- grad.p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
- grad.p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
-
- picture = XRenderCreateLinearGradient (display->display, &grad,
- stops, colors,
- n_stops);
- } else {
- XRadialGradient grad;
-
- grad.inner.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
- grad.inner.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
- grad.inner.radius = _cairo_fixed_16_16_from_double (extremes[0].radius);
- grad.outer.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
- grad.outer.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
- grad.outer.radius = _cairo_fixed_16_16_from_double (extremes[1].radius);
-
- picture = XRenderCreateRadialGradient (display->display, &grad,
- stops, colors,
- n_stops);
- }
-
- if (stops != (XFixed *) buf)
- free (stops);
-
- if (unlikely (picture == None))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- /* Wrap the remote Picture in an xlib surface. */
- format = _cairo_xlib_display_get_xrender_format (display,
- CAIRO_FORMAT_ARGB32);
-
- surface = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_internal (dst->screen, None,
- NULL, format,
- /* what could possibly go wrong? */
- XLIB_COORD_MAX, XLIB_COORD_MAX, 32);
- if (unlikely (surface->base.status)) {
- XRenderFreePicture (display->display, picture);
- return surface->base.status;
- }
-
- surface->src_picture = picture;
-
- attributes->matrix = matrix;
- attributes->extend = pattern->extend;
- attributes->filter = CAIRO_FILTER_NEAREST;
- attributes->x_offset = 0;
- attributes->y_offset = 0;
- attributes->has_component_alpha = FALSE;
-
- *surface_out = surface;
- return CAIRO_STATUS_SUCCESS;
- }
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_PATTERN_TYPE_SOLID:
- case CAIRO_PATTERN_TYPE_SURFACE:
- case CAIRO_PATTERN_TYPE_MESH:
- break;
- }
+ cairo_xlib_surface_t *surface = abstract_surface;
- return _cairo_pattern_acquire_surface (pattern, &dst->base,
- x, y, width, height,
- dst->buggy_pad_reflect ?
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **) surface_out,
- attributes);
+ *options = *_cairo_xlib_screen_get_font_options (surface->screen);
}
-static cairo_int_status_t
-_cairo_xlib_surface_acquire_pattern_surfaces (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *dst,
- const cairo_pattern_t *src,
- const cairo_pattern_t *mask,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- unsigned int width,
- unsigned int height,
- cairo_xlib_surface_t **src_out,
- cairo_xlib_surface_t **mask_out,
- cairo_surface_attributes_t *src_attr,
- cairo_surface_attributes_t *mask_attr)
-{
- if (! dst->buggy_gradients &&
- (src->type == CAIRO_PATTERN_TYPE_LINEAR ||
- src->type == CAIRO_PATTERN_TYPE_RADIAL ||
- (mask && (mask->type == CAIRO_PATTERN_TYPE_LINEAR ||
- mask->type == CAIRO_PATTERN_TYPE_RADIAL))))
- {
- cairo_int_status_t status;
-
- status = _cairo_xlib_surface_acquire_pattern_surface (display,
- dst, src,
- src_x, src_y,
- width, height,
- src_out,
- src_attr);
- if (unlikely (status))
- return status;
-
- if (mask) {
- status = _cairo_xlib_surface_acquire_pattern_surface (display,
- dst, mask,
- mask_x,
- mask_y,
- width,
- height,
- mask_out,
- mask_attr);
- if (unlikely (status)) {
- _cairo_pattern_release_surface (src, &(*src_out)->base,
- src_attr);
- return status;
- }
- } else {
- *mask_out = NULL;
- }
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return _cairo_pattern_acquire_surfaces (src, mask,
- &dst->base,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- dst->buggy_pad_reflect ?
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **) src_out,
- (cairo_surface_t **) mask_out,
- src_attr, mask_attr);
-}
static cairo_int_status_t
-_cairo_xlib_surface_upload(cairo_xlib_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- int src_x, int src_y,
- int dst_x, int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_region_t *clip_region)
+_cairo_xlib_surface_paint (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_clip_t *clip)
{
- cairo_image_surface_t *image;
- cairo_rectangle_int_t extents;
- cairo_status_t status;
- int tx, ty;
-
- if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- image = (cairo_image_surface_t *) ((cairo_surface_pattern_t *) pattern)->surface;
- if (image->base.type != CAIRO_SURFACE_TYPE_IMAGE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! (op == CAIRO_OPERATOR_SOURCE ||
- (op == CAIRO_OPERATOR_OVER &&
- (image->base.content & CAIRO_CONTENT_ALPHA) == 0)))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (image->base.backend->type != CAIRO_SURFACE_TYPE_IMAGE) {
- if (_cairo_surface_is_snapshot (&image->base)) {
- image = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) image)->target;
- extents.x = extents.y = 0;
- extents.width = image->width;
- extents.height = image->height;
- } else if (image->base.backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
- cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) image;
- image = (cairo_image_surface_t *) sub->target;
- src_x += sub->extents.x;
- src_y += sub->extents.y;
- extents = sub->extents;
- } else {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
- } else {
- extents.x = extents.y = 0;
- extents.width = image->width;
- extents.height = image->height;
- }
-
- if (image->format == CAIRO_FORMAT_INVALID)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- if (image->depth != surface->depth)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! _cairo_matrix_is_integer_translation (&pattern->matrix, &tx, &ty))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- src_x += tx;
- src_y += ty;
-
- /* XXX for EXTEND_NONE perform unbounded fixups? */
- if (src_x < extents.x ||
- src_y < extents.y ||
- src_x + width > (unsigned) extents.width ||
- src_y + height > (unsigned) extents.height)
- {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- status = cairo_device_acquire (surface->base.device);
- if (unlikely (status))
- return status;
-
- if (clip_region != NULL) {
- int n, num_rect;
-
- src_x -= dst_x;
- src_y -= dst_y;
-
- num_rect = cairo_region_num_rectangles (clip_region);
- for (n = 0; n < num_rect; n++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (clip_region, n, &rect);
- status = _draw_image_surface (surface, image,
- rect.x + src_x, rect.y + src_y,
- rect.width, rect.height,
- rect.x, rect.y);
- if (unlikely (status))
- break;
- }
- } else {
- status = _draw_image_surface (surface, image,
- src_x, src_y,
- width, height,
- dst_x, dst_y);
- }
-
- cairo_device_release (surface->base.device);
-
- return status;
+ cairo_xlib_surface_t *surface = _surface;
+ return _cairo_compositor_paint (surface->compositor,
+ &surface->base, op, source,
+ clip);
}
static cairo_int_status_t
-_cairo_xlib_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,
- cairo_region_t *clip_region)
+_cairo_xlib_surface_mask (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ const cairo_clip_t *clip)
{
- cairo_surface_attributes_t src_attr, mask_attr;
- cairo_xlib_surface_t *dst = abstract_dst;
- cairo_xlib_surface_t *src;
- cairo_xlib_surface_t *mask;
- cairo_xlib_display_t *display;
- cairo_int_status_t status;
- composite_operation_t operation;
- int itx, ity;
- cairo_bool_t is_integer_translation;
- GC gc;
-
- 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 UNSUPPORTED ("unsupported operation");
-
- X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable));
-
- if (mask_pattern == NULL) {
- /* Can we do a simple upload in-place? */
- status = _cairo_xlib_surface_upload(dst, op, src_pattern,
- src_x, src_y,
- dst_x, dst_y,
- width, height,
- clip_region);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
- status = _cairo_xlib_display_acquire (dst-> base.device, &display);
- if (unlikely (status))
- return status;
-
- status =
- _cairo_xlib_surface_acquire_pattern_surfaces (display, dst,
- src_pattern, mask_pattern,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- &src, &mask,
- &src_attr, &mask_attr);
- if (unlikely (status))
- goto BAIL0;
-
- /* check for fallback surfaces that we cannot handle ... */
- 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 = UNSUPPORTED ("unsupported operation");
- goto BAIL;
- }
-
- switch (operation)
- {
- case DO_RENDER:
- status = _cairo_xlib_surface_set_attributes (display,
- src, &src_attr,
- dst_x + width / 2.,
- dst_y + height / 2.);
- if (unlikely (status))
- goto BAIL;
-
- status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- goto BAIL;
-
- _cairo_xlib_surface_ensure_dst_picture (display, dst);
- if (mask) {
- status = _cairo_xlib_surface_set_attributes (display,
- mask, &mask_attr,
- dst_x + width / 2.,
- dst_y + height/ 2.);
- if (unlikely (status))
- goto BAIL;
-
- XRenderComposite (display->display,
- _render_operator (op),
- src->src_picture,
- mask->src_picture,
- dst->dst_picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- mask_x + mask_attr.x_offset,
- mask_y + mask_attr.y_offset,
- dst_x, dst_y,
- width, height);
- } else {
- XRenderComposite (display->display,
- _render_operator (op),
- src->src_picture,
- 0,
- dst->dst_picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- }
-
- break;
-
- case DO_XCOPYAREA:
- status = _cairo_xlib_surface_get_gc (display, dst, &gc);
- if (unlikely (status))
- goto BAIL;
-
- is_integer_translation =
- _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
- /* This is a pre-condition for DO_XCOPYAREA. */
- assert (is_integer_translation);
-
- if (clip_region == NULL) {
- XCopyArea (display->display, src->drawable, dst->drawable, gc,
- src_x + src_attr.x_offset + itx,
- src_y + src_attr.y_offset + ity,
- width, height,
- dst_x, dst_y);
- } else {
- int n, num_rects, x, y;
-
- x = src_x + src_attr.x_offset + itx - dst_x;
- y = src_y + src_attr.y_offset + ity - dst_y;
-
- num_rects = cairo_region_num_rectangles (clip_region);
- for (n = 0; n < num_rects; n++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (clip_region, n, &rect);
- XCopyArea (display->display, src->drawable, dst->drawable, gc,
- rect.x + x, rect.y + y,
- rect.width, rect.height,
- rect.x, rect.y);
- }
- }
-
- _cairo_xlib_surface_put_gc (display, dst, gc);
- break;
-
- case DO_XTILE:
- /* This case is only used for bug fallbacks, though we also use it for
- * the case where we don't have the RENDER extension, by forcing
- * buggy_repeat to TRUE.
- *
- * We've checked that we have a repeating unscaled source in
- * _recategorize_composite_operation.
- */
-
- status = _cairo_xlib_surface_get_gc (display, dst, &gc);
- if (unlikely (status))
- goto BAIL;
-
- is_integer_translation =
- _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
- /* This is a pre-condition for DO_XTILE. */
- assert (is_integer_translation);
-
- XSetTSOrigin (display->display, gc,
- - (itx + src_attr.x_offset), - (ity + src_attr.y_offset));
- XSetTile (display->display, gc, src->drawable);
-
- if (clip_region == NULL) {
- XFillRectangle (display->display, dst->drawable, gc,
- dst_x, dst_y, width, height);
- } else {
- int n, num_rects;
-
- num_rects = cairo_region_num_rectangles (clip_region);
- for (n = 0; n < num_rects; n++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (clip_region, n, &rect);
- XFillRectangle (display->display, dst->drawable, gc,
- rect.x, rect.y, rect.width, rect.height);
- }
- }
-
- _cairo_xlib_surface_put_gc (display, dst, gc);
- break;
-
- case DO_UNSUPPORTED:
- default:
- ASSERT_NOT_REACHED;
- }
-
- 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,
- mask ? mask->width : 0,
- mask ? mask->height : 0,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y, width, height,
- clip_region);
-
- BAIL:
- if (mask)
- _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
-
- _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
-
- BAIL0:
- cairo_device_release (&display->base);
-
- return status;
+ cairo_xlib_surface_t *surface = _surface;
+ return _cairo_compositor_mask (surface->compositor,
+ &surface->base, op, source, mask,
+ clip);
}
-/* XXX move this out of core and into acquire_pattern_surface() above. */
static cairo_int_status_t
-_cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects)
-{
- cairo_status_t status;
- cairo_solid_pattern_t solid;
- cairo_surface_t *solid_surface = NULL;
- cairo_surface_attributes_t attrs;
- cairo_xlib_display_t *display;
- GC gc;
- int i;
-
- _cairo_pattern_init_solid (&solid, color);
-
- status = _cairo_xlib_display_acquire (surface->base.device, &display);
- if (unlikely (status))
- return status;
-
- status = _cairo_xlib_surface_get_gc (display, surface, &gc);
- if (unlikely (status))
- return status;
-
- X_DEBUG ((display->display, "solid_fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
-
- status = _cairo_pattern_acquire_surface (&solid.base, &surface->base,
- 0, 0,
- ARRAY_LENGTH (dither_pattern[0]),
- ARRAY_LENGTH (dither_pattern),
- CAIRO_PATTERN_ACQUIRE_NONE,
- &solid_surface,
- &attrs);
- if (unlikely (status)) {
- _cairo_xlib_surface_put_gc (display, surface, gc);
- cairo_device_release (&display->base);
- return status;
- }
-
- assert (_cairo_surface_is_xlib (solid_surface));
-
- XSetTSOrigin (display->display, gc,
- - (surface->base.device_transform.x0 + attrs.x_offset),
- - (surface->base.device_transform.y0 + attrs.y_offset));
- XSetTile (display->display, gc,
- ((cairo_xlib_surface_t *) solid_surface)->drawable);
-
- for (i = 0; i < num_rects; i++) {
- XFillRectangle (display->display, surface->drawable, gc,
- rects[i].x, rects[i].y,
- rects[i].width, rects[i].height);
- }
-
- _cairo_xlib_surface_put_gc (display, surface, gc);
-
- _cairo_pattern_release_surface (&solid.base, solid_surface, &attrs);
-
- cairo_device_release (&display->base);
-
- return CAIRO_STATUS_SUCCESS;
+_cairo_xlib_surface_stroke (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
+{
+ cairo_xlib_surface_t *surface = _surface;
+ return _cairo_compositor_stroke (surface->compositor,
+ &surface->base, op, source,
+ path, style, ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
}
static cairo_int_status_t
-_cairo_xlib_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_xlib_display_t *display;
- XRenderColor render_color;
- cairo_status_t status;
- int i;
-
- if (!CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR (surface, op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
- if (op == CAIRO_OPERATOR_CLEAR ||
- ((op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER) &&
- CAIRO_COLOR_IS_OPAQUE (color)))
- {
- return _cairo_xlib_surface_solid_fill_rectangles (surface, color,
- rects, num_rects);
- }
-
- return UNSUPPORTED ("no support for FillRectangles with this op");
- }
-
- status = _cairo_xlib_display_acquire (surface->base.device, &display);
- if (unlikely (status))
- return status;
-
- X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
-
- render_color.red = color->red_short;
- render_color.green = color->green_short;
- 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 (display, surface);
- if (num_rects == 1) {
- /* Take advantage of the protocol compaction that libXrender performs
- * to amalgamate sequences of XRenderFillRectangle().
- */
- XRenderFillRectangle (display->display,
- _render_operator (op),
- surface->dst_picture,
- &render_color,
- rects->x,
- rects->y,
- rects->width,
- rects->height);
- } else {
- XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
- XRectangle *xrects = static_xrects;
-
- if (num_rects > ARRAY_LENGTH (static_xrects)) {
- xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
- if (unlikely (xrects == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
- }
-
- for (i = 0; i < num_rects; i++) {
- xrects[i].x = rects[i].x;
- xrects[i].y = rects[i].y;
- xrects[i].width = rects[i].width;
- xrects[i].height = rects[i].height;
- }
-
- XRenderFillRectangles (display->display,
- _render_operator (op),
- surface->dst_picture,
- &render_color, xrects, num_rects);
-
- if (xrects != static_xrects)
- free (xrects);
- }
-
-BAIL:
- cairo_device_release (&display->base);
- return status;
-}
-
-#define CAIRO_FIXED_16_16_MIN -32768
-#define CAIRO_FIXED_16_16_MAX 32767
-
-static cairo_bool_t
-_line_exceeds_16_16 (const cairo_line_t *line)
-{
- return
- line->p1.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
- line->p1.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
- line->p2.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
- line->p2.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
- line->p1.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
- line->p1.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
- line->p2.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
- line->p2.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX);
-}
-
-static void
-_project_line_x_onto_16_16 (const cairo_line_t *line,
- cairo_fixed_t top,
- cairo_fixed_t bottom,
- XLineFixed *out)
-{
- cairo_point_double_t p1, p2;
- double m;
-
- p1.x = _cairo_fixed_to_double (line->p1.x);
- p1.y = _cairo_fixed_to_double (line->p1.y);
-
- p2.x = _cairo_fixed_to_double (line->p2.x);
- p2.y = _cairo_fixed_to_double (line->p2.y);
-
- m = (p2.x - p1.x) / (p2.y - p1.y);
- out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
- out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
+_cairo_xlib_surface_fill (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
+{
+ cairo_xlib_surface_t *surface = _surface;
+ return _cairo_compositor_fill (surface->compositor,
+ &surface->base, op, source,
+ path, fill_rule, tolerance, antialias,
+ clip);
}
static cairo_int_status_t
-_cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *abstract_dst,
- cairo_antialias_t antialias,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps,
- cairo_region_t *clip_region)
+_cairo_xlib_surface_glyphs (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ const cairo_clip_t *clip)
{
- cairo_surface_attributes_t attributes;
- cairo_xlib_surface_t *dst = abstract_dst;
- cairo_xlib_surface_t *src;
- cairo_xlib_display_t *display;
- cairo_int_status_t status;
- composite_operation_t operation;
- int render_reference_x, render_reference_y;
- int render_src_x, render_src_y;
- XRenderPictFormat *pict_format;
- XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
- XTrapezoid *xtraps = xtraps_stack;
- int i;
-
- 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 UNSUPPORTED ("unsupported operation");
-
- status = _cairo_xlib_display_acquire (dst->base.device, &display);
- if (unlikely (status))
- return status;
-
- X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
-
- status = _cairo_xlib_surface_acquire_pattern_surface (display,
- dst,
- pattern,
- src_x, src_y,
- width, height,
- &src, &attributes);
- if (unlikely (status))
- goto BAIL0;
-
- operation = _recategorize_composite_operation (dst, op, src,
- &attributes, TRUE);
- if (operation == DO_UNSUPPORTED) {
- status = UNSUPPORTED ("unsupported operation");
- goto BAIL;
- }
-
- pict_format =
- _cairo_xlib_display_get_xrender_format (display,
- antialias == CAIRO_ANTIALIAS_NONE ? CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8);
-
- status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- goto BAIL;
-
- _cairo_xlib_surface_ensure_dst_picture (display, dst);
- _cairo_xlib_surface_set_precision (display, dst, antialias);
-
- status = _cairo_xlib_surface_set_attributes (display,
- src, &attributes,
- dst_x + width / 2.,
- dst_y + height / 2.);
- if (unlikely (status))
- goto BAIL;
-
- if (num_traps > ARRAY_LENGTH (xtraps_stack)) {
- xtraps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
- if (unlikely (xtraps == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
- }
-
- for (i = 0; i < num_traps; i++) {
- /* top/bottom will be clamped to surface bounds */
- xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
- xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
-
- /* However, all the other coordinates will have been left untouched so
- * as not to introduce numerical error. Recompute them if they
- * exceed the 16.16 limits.
- */
- if (unlikely (_line_exceeds_16_16 (&traps[i].left))) {
- _project_line_x_onto_16_16 (&traps[i].left,
- traps[i].top,
- traps[i].bottom,
- &xtraps[i].left);
- xtraps[i].left.p1.y = xtraps[i].top;
- xtraps[i].left.p2.y = xtraps[i].bottom;
- } else {
- xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
- xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
- xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
- xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
- }
-
- if (unlikely (_line_exceeds_16_16 (&traps[i].right))) {
- _project_line_x_onto_16_16 (&traps[i].right,
- traps[i].top,
- traps[i].bottom,
- &xtraps[i].right);
- xtraps[i].right.p1.y = xtraps[i].top;
- xtraps[i].right.p2.y = xtraps[i].bottom;
- } else {
- xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
- xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
- xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
- xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
- }
- }
-
- if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
- render_reference_x = _cairo_fixed_16_16_floor (xtraps[0].left.p1.x);
- render_reference_y = _cairo_fixed_16_16_floor (xtraps[0].left.p1.y);
- } else {
- render_reference_x = _cairo_fixed_16_16_floor (xtraps[0].left.p2.x);
- render_reference_y = _cairo_fixed_16_16_floor (xtraps[0].left.p2.y);
- }
-
- render_src_x = src_x + render_reference_x - dst_x;
- render_src_y = src_y + render_reference_y - dst_y;
-
- XRenderCompositeTrapezoids (display->display,
- _render_operator (op),
- src->src_picture, dst->dst_picture,
- pict_format,
- render_src_x + attributes.x_offset,
- render_src_y + attributes.y_offset,
- xtraps, num_traps);
-
- if (xtraps != xtraps_stack)
- free (xtraps);
-
- if (! _cairo_operator_bounded_by_mask (op)) {
- cairo_traps_t _traps;
- cairo_box_t box;
- cairo_rectangle_int_t extents;
-
- /* XRenderCompositeTrapezoids() creates a mask only large enough for the
- * trapezoids themselves, but if the operator is unbounded, then we need
- * to actually composite all the way out to the bounds.
- */
- /* XXX: update the interface to pass composite rects */
- _traps.traps = traps;
- _traps.num_traps = num_traps;
- _cairo_traps_extents (&_traps, &box);
- _cairo_box_round_to_rectangle (&box, &extents);
-
- status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
- &attributes,
- src->width, src->height,
- extents.width, extents.height,
- src_x, src_y,
- -extents.x + dst_x, -extents.y + dst_y,
- dst_x, dst_y,
- width, height,
- clip_region);
- }
-
- BAIL:
- _cairo_pattern_release_surface (pattern, &src->base, &attributes);
- BAIL0:
- cairo_device_release (&display->base);
-
- return status;
-}
-
-static cairo_bool_t
-_cairo_xlib_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *rectangle)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
-
- rectangle->x = 0;
- rectangle->y = 0;
-
- rectangle->width = surface->width;
- rectangle->height = surface->height;
-
- return TRUE;
-}
-
-static void
-_cairo_xlib_surface_get_font_options (void *abstract_surface,
- cairo_font_options_t *options)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
-
- *options = *_cairo_xlib_screen_get_font_options (surface->screen);
-}
-
-static void
-_cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
-
-static void
-_cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font);
-
-static cairo_bool_t
-_cairo_xlib_surface_is_similar (void *surface_a,
- void *surface_b)
-{
- return _cairo_xlib_surface_same_screen (surface_a, surface_b);
+ cairo_xlib_surface_t *surface = _surface;
+ return _cairo_compositor_glyphs (surface->compositor,
+ &surface->base, op, source,
+ glyphs, num_glyphs, scaled_font,
+ clip);
}
static const cairo_surface_backend_t cairo_xlib_surface_backend = {
@@ -3140,38 +1384,23 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_acquire_source_image,
_cairo_xlib_surface_release_source_image,
+ _cairo_xlib_surface_snapshot,
- _cairo_xlib_surface_acquire_dest_image,
- _cairo_xlib_surface_release_dest_image,
- _cairo_xlib_surface_clone_similar,
- _cairo_xlib_surface_composite,
- _cairo_xlib_surface_fill_rectangles,
- _cairo_xlib_surface_composite_trapezoids,
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_xlib_surface_get_extents,
- NULL, /* old_show_glyphs */
_cairo_xlib_surface_get_font_options,
+
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
- _cairo_xlib_surface_scaled_font_fini,
- _cairo_xlib_surface_scaled_glyph_fini,
- NULL, /* paint */
- NULL, /* mask */
- NULL, /* stroke */
- NULL, /* fill */
- _cairo_xlib_surface_show_glyphs,
-
- _cairo_xlib_surface_snapshot,
- _cairo_xlib_surface_is_similar,
-
- NULL, /* fill_stroke */
-
- _cairo_xlib_surface_create_solid_pattern_surface,
- _cairo_xlib_surface_can_repaint_solid_pattern_surface
+ _cairo_xlib_surface_paint,
+ _cairo_xlib_surface_mask,
+ _cairo_xlib_surface_stroke,
+ _cairo_xlib_surface_fill,
+ NULL, /* fill-stroke */
+ _cairo_xlib_surface_glyphs,
};
/**
@@ -3188,36 +1417,6 @@ _cairo_surface_is_xlib (cairo_surface_t *surface)
return surface->backend == &cairo_xlib_surface_backend;
}
-/* callback from CloseDisplay */
-static void
-_cairo_xlib_surface_detach_display (cairo_xlib_display_t *display, void *data)
-{
- cairo_xlib_surface_t *surface = cairo_container_of (data,
- cairo_xlib_surface_t,
- close_display_hook);
- Display *dpy;
-
- dpy = display->display;
-
- X_DEBUG ((dpy, "detach (drawable=%x)", (unsigned int) surface->drawable));
-
- if (surface->dst_picture != None) {
- XRenderFreePicture (dpy, surface->dst_picture);
- surface->dst_picture = None;
- }
-
- if (surface->src_picture != None) {
- XRenderFreePicture (dpy, surface->src_picture);
- surface->src_picture = None;
- }
-
- if (surface->owns_pixmap) {
- XFreePixmap (dpy, surface->drawable);
- surface->drawable = None;
- surface->owns_pixmap = FALSE;
- }
-}
-
static cairo_surface_t *
_cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen,
Drawable drawable,
@@ -3277,10 +1476,8 @@ found:
return _cairo_surface_create_in_error (_cairo_error (status));
}
- _cairo_xlib_display_get_xrender_version (display,
- &surface->render_major,
- &surface->render_minor);
- if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
+ surface->display = display;
+ if (CAIRO_RENDER_HAS_CREATE_PICTURE (display)) {
if (!xrender_format) {
if (visual) {
xrender_format = XRenderFindVisualFormat (display->display, visual);
@@ -3290,17 +1487,8 @@ found:
CAIRO_FORMAT_A1);
}
}
- } else {
- /* we cannot use XRender for this surface, so ensure we don't try */
- surface->render_major = -1;
- surface->render_minor = -1;
}
- /* initialize and hook into the CloseDisplay callback */
- surface->close_display_hook.func = _cairo_xlib_surface_detach_display;
- _cairo_xlib_add_close_display_hook (display,
- &surface->close_display_hook);
-
cairo_device_release (&display->base);
_cairo_surface_init (&surface->base,
@@ -3309,6 +1497,7 @@ found:
_xrender_format_to_content (xrender_format));
surface->screen = screen;
+ surface->compositor = display->compositor;
surface->drawable = drawable;
surface->owns_pixmap = FALSE;
@@ -3316,36 +1505,14 @@ found:
surface->width = width;
surface->height = height;
- surface->buggy_repeat = ! _cairo_xlib_display_has_repeat (screen->device);
- if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
- /* so we can use the XTile fallback */
- surface->buggy_repeat = TRUE;
- }
-
- surface->buggy_pad_reflect = ! _cairo_xlib_display_has_reflect (screen->device);
- if (! CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT (surface))
- surface->buggy_pad_reflect = TRUE;
-
- surface->buggy_gradients = ! _cairo_xlib_display_has_gradients (screen->device);
- if (! CAIRO_SURFACE_RENDER_HAS_GRADIENTS (surface))
- surface->buggy_gradients = TRUE;
+ surface->picture = None;
+ surface->precision = PolyModePrecise;
- surface->dst_picture = None;
- surface->src_picture = None;
+ surface->embedded_source.picture = None;
surface->visual = visual;
surface->xrender_format = xrender_format;
surface->depth = depth;
- surface->filter = CAIRO_FILTER_NEAREST;
- surface->extend = CAIRO_EXTEND_NONE;
- surface->has_component_alpha = FALSE;
- surface->precision = PolyModePrecise;
- surface->xtransform = identity;
-
- surface->clip_region = NULL;
- surface->clip_rects = surface->embedded_clip_rects;
- surface->num_clip_rects = 0;
- surface->clip_dirty = 0;
/*
* Compute the pixel format masks from either a XrenderFormat or
@@ -3411,6 +1578,11 @@ _cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
return NULL;
}
+static cairo_bool_t valid_size (int width, int height)
+{
+ return width > 0 && width <= XLIB_COORD_MAX && height > 0 && height <= XLIB_COORD_MAX;
+}
+
/**
* cairo_xlib_surface_create:
* @dpy: an X Display
@@ -3447,7 +1619,7 @@ cairo_xlib_surface_create (Display *dpy,
cairo_xlib_screen_t *screen;
cairo_status_t status;
- if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) {
+ if (! valid_size (width, height)) {
/* you're lying, and you know it! */
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
}
@@ -3490,7 +1662,7 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy,
cairo_xlib_screen_t *screen;
cairo_status_t status;
- if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0)
+ if (! valid_size (width, height))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
status = _cairo_xlib_screen_get (dpy, scr, &screen);
@@ -3536,7 +1708,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy,
cairo_xlib_screen_t *screen;
cairo_status_t status;
- if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0)
+ if (! valid_size (width, height))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
status = _cairo_xlib_screen_get (dpy, scr, &screen);
@@ -3602,25 +1774,24 @@ cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
int height)
{
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
- cairo_status_t status;
if (unlikely (abstract_surface->status))
return;
if (unlikely (abstract_surface->finished)) {
- status = _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+ _cairo_surface_set_error (abstract_surface,
+ _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
return;
}
if (! _cairo_surface_is_xlib (abstract_surface)) {
- status = _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+ _cairo_surface_set_error (abstract_surface,
+ _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
return;
}
- if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) {
- status = _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_INVALID_SIZE));
+ if (! valid_size (width, height)) {
+ _cairo_surface_set_error (abstract_surface,
+ _cairo_error (CAIRO_STATUS_INVALID_SIZE));
return;
}
@@ -3664,7 +1835,7 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
return;
}
- if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) {
+ if (! valid_size (width, height)) {
status = _cairo_surface_set_error (abstract_surface,
_cairo_error (CAIRO_STATUS_INVALID_SIZE));
return;
@@ -3683,30 +1854,14 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
X_DEBUG ((display->display, "set_drawable (drawable=%x)", (unsigned int) drawable));
- if (surface->dst_picture != None) {
- status = _cairo_xlib_display_queue_resource (
- display,
- XRenderFreePicture,
- surface->dst_picture);
- if (unlikely (status)) {
- status = _cairo_surface_set_error (&surface->base, status);
- return;
- }
-
- surface->dst_picture = None;
- }
-
- if (surface->src_picture != None) {
- status = _cairo_xlib_display_queue_resource (
- display,
- XRenderFreePicture,
- surface->src_picture);
+ if (surface->picture != None) {
+ XRenderFreePicture (display->display, surface->picture);
if (unlikely (status)) {
status = _cairo_surface_set_error (&surface->base, status);
return;
}
- surface->src_picture = None;
+ surface->picture = None;
}
cairo_device_release (&display->base);
@@ -3880,1013 +2035,4 @@ cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
return surface->height;
}
-enum {
- GLYPHSET_INDEX_ARGB32,
- GLYPHSET_INDEX_A8,
- GLYPHSET_INDEX_A1,
- NUM_GLYPHSETS
-};
-
-typedef struct _cairo_xlib_font_glyphset_free_glyphs {
- GlyphSet glyphset;
- int glyph_count;
- unsigned long glyph_indices[128];
-} cairo_xlib_font_glyphset_free_glyphs_t;
-
-typedef struct _cairo_xlib_font_glyphset_info {
- GlyphSet glyphset;
- cairo_format_t format;
- XRenderPictFormat *xrender_format;
- cairo_xlib_font_glyphset_free_glyphs_t *pending_free_glyphs;
-} cairo_xlib_font_glyphset_info_t;
-
-typedef struct _cairo_xlib_surface_font_private {
- cairo_scaled_font_t *scaled_font;
- cairo_xlib_hook_t close_display_hook;
- cairo_device_t *device;
- cairo_xlib_font_glyphset_info_t glyphset_info[NUM_GLYPHSETS];
-} cairo_xlib_surface_font_private_t;
-
-/* callback from CloseDisplay */
-static void
-_cairo_xlib_surface_remove_scaled_font (cairo_xlib_display_t *display,
- void *data)
-{
- cairo_xlib_surface_font_private_t *font_private;
- cairo_scaled_font_t *scaled_font;
-
- font_private = cairo_container_of (data,
- cairo_xlib_surface_font_private_t,
- close_display_hook);
- scaled_font = font_private->scaled_font;
-
- CAIRO_MUTEX_LOCK (scaled_font->mutex);
- font_private = scaled_font->surface_private;
- scaled_font->surface_private = NULL;
-
- _cairo_scaled_font_reset_cache (scaled_font);
- CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
-
- if (font_private != NULL) {
- int i;
-
- for (i = 0; i < NUM_GLYPHSETS; i++) {
- cairo_xlib_font_glyphset_info_t *glyphset_info;
-
- glyphset_info = &font_private->glyphset_info[i];
- if (glyphset_info->glyphset)
- XRenderFreeGlyphSet (display->display, glyphset_info->glyphset);
-
- free (glyphset_info->pending_free_glyphs);
- }
-
- cairo_device_destroy (font_private->device);
- free (font_private);
- }
-}
-
-static cairo_status_t
-_cairo_xlib_surface_font_init (cairo_xlib_display_t *display,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xlib_surface_font_private_t *font_private;
- int i;
-
- font_private = malloc (sizeof (cairo_xlib_surface_font_private_t));
- if (unlikely (font_private == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- font_private->scaled_font = scaled_font;
- font_private->device = cairo_device_reference (&display->base);
-
- /* initialize and hook into the CloseDisplay callback */
- font_private->close_display_hook.func =
- _cairo_xlib_surface_remove_scaled_font;
- _cairo_xlib_add_close_display_hook (display,
- &font_private->close_display_hook);
-
-
- for (i = 0; i < NUM_GLYPHSETS; i++) {
- cairo_xlib_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
- switch (i) {
- case GLYPHSET_INDEX_ARGB32: glyphset_info->format = CAIRO_FORMAT_ARGB32; break;
- case GLYPHSET_INDEX_A8: glyphset_info->format = CAIRO_FORMAT_A8; break;
- case GLYPHSET_INDEX_A1: glyphset_info->format = CAIRO_FORMAT_A1; break;
- default: ASSERT_NOT_REACHED; break;
- }
- glyphset_info->xrender_format = NULL;
- glyphset_info->glyphset = None;
- glyphset_info->pending_free_glyphs = NULL;
- }
-
- scaled_font->surface_private = font_private;
- scaled_font->surface_backend = &cairo_xlib_surface_backend;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
-{
- cairo_xlib_surface_font_private_t *font_private;
- cairo_status_t status;
-
- font_private = scaled_font->surface_private;
- if (font_private != NULL) {
- cairo_xlib_display_t *display;
- int i;
-
- status = _cairo_xlib_display_acquire (font_private->device, &display);
- if (status)
- goto BAIL;
-
- _cairo_xlib_remove_close_display_hook (display,
- &font_private->close_display_hook);
-
- for (i = 0; i < NUM_GLYPHSETS; i++) {
- cairo_xlib_font_glyphset_info_t *glyphset_info;
-
- glyphset_info = &font_private->glyphset_info[i];
-
- free (glyphset_info->pending_free_glyphs);
-
- if (glyphset_info->glyphset) {
- status = _cairo_xlib_display_queue_resource (display,
- XRenderFreeGlyphSet,
- glyphset_info->glyphset);
- (void) status; /* XXX cannot propagate failure */
- }
- }
-
- cairo_device_release (&display->base);
-BAIL:
- cairo_device_destroy (&display->base);
- free (font_private);
- }
-}
-
-static void
-_cairo_xlib_render_free_glyphs (Display *dpy,
- cairo_xlib_font_glyphset_free_glyphs_t *to_free)
-{
- XRenderFreeGlyphs (dpy,
- to_free->glyphset,
- to_free->glyph_indices,
- to_free->glyph_count);
-}
-
-static cairo_xlib_font_glyphset_info_t *
-_cairo_xlib_scaled_glyph_get_glyphset_info (cairo_scaled_glyph_t *scaled_glyph)
-{
- return scaled_glyph->surface_private;
-}
-
-static void
-_cairo_xlib_scaled_glyph_set_glyphset_info (cairo_scaled_glyph_t *scaled_glyph,
- cairo_xlib_font_glyphset_info_t *glyphset_info)
-{
- scaled_glyph->surface_private = glyphset_info;
-}
-
-static void
-_cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xlib_surface_font_private_t *font_private;
- cairo_xlib_font_glyphset_info_t *glyphset_info;
-
- if (scaled_font->finished)
- return;
-
- font_private = scaled_font->surface_private;
- glyphset_info = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph);
- if (font_private != NULL && glyphset_info != NULL) {
- cairo_xlib_font_glyphset_free_glyphs_t *to_free;
- cairo_status_t status;
-
- to_free = glyphset_info->pending_free_glyphs;
- if (to_free != NULL &&
- to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
- {
- cairo_xlib_display_t *display;
-
- status = _cairo_xlib_display_acquire (font_private->device, &display);
- if (status == CAIRO_STATUS_SUCCESS) {
- status = _cairo_xlib_display_queue_work (display,
- (cairo_xlib_notify_func) _cairo_xlib_render_free_glyphs,
- to_free,
- free);
- cairo_device_release (&display->base);
- }
- /* XXX cannot propagate failure */
- if (unlikely (status))
- free (to_free);
-
- to_free = glyphset_info->pending_free_glyphs = NULL;
- }
-
- if (to_free == NULL) {
- to_free = malloc (sizeof (cairo_xlib_font_glyphset_free_glyphs_t));
- if (unlikely (to_free == NULL)) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return; /* XXX cannot propagate failure */
- }
-
- to_free->glyphset = glyphset_info->glyphset;
- to_free->glyph_count = 0;
- glyphset_info->pending_free_glyphs = to_free;
- }
-
- to_free->glyph_indices[to_free->glyph_count++] =
- _cairo_scaled_glyph_index (scaled_glyph);
- }
-}
-
-static int
-_cairo_xlib_get_glyphset_index_for_format (cairo_format_t format)
-{
- if (format == CAIRO_FORMAT_A8)
- return GLYPHSET_INDEX_A8;
- if (format == CAIRO_FORMAT_A1)
- return GLYPHSET_INDEX_A1;
-
- assert (format == CAIRO_FORMAT_ARGB32);
- return GLYPHSET_INDEX_ARGB32;
-}
-
-static cairo_xlib_font_glyphset_info_t *
-_cairo_xlib_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scaled_font,
- cairo_format_t format)
-{
- cairo_xlib_surface_font_private_t *font_private;
- cairo_xlib_font_glyphset_info_t *glyphset_info;
- int glyphset_index;
-
- glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format);
- font_private = scaled_font->surface_private;
- glyphset_info = &font_private->glyphset_info[glyphset_index];
- if (glyphset_info->glyphset == None) {
- cairo_xlib_display_t *display;
-
- if (_cairo_xlib_display_acquire (font_private->device, &display))
- return NULL;
-
- glyphset_info->xrender_format =
- _cairo_xlib_display_get_xrender_format (display,
- glyphset_info->format);
- glyphset_info->glyphset = XRenderCreateGlyphSet (display->display,
- glyphset_info->xrender_format);
-
- cairo_device_release (&display->base);
- }
-
- return glyphset_info;
-}
-
-static cairo_bool_t
-_cairo_xlib_glyphset_info_has_pending_free_glyph (
- cairo_xlib_font_glyphset_info_t *glyphset_info,
- unsigned long glyph_index)
-{
- if (glyphset_info->pending_free_glyphs != NULL) {
- cairo_xlib_font_glyphset_free_glyphs_t *to_free;
- int i;
-
- to_free = glyphset_info->pending_free_glyphs;
- for (i = 0; i < to_free->glyph_count; i++) {
- if (to_free->glyph_indices[i] == glyph_index) {
- to_free->glyph_count--;
- memmove (&to_free->glyph_indices[i],
- &to_free->glyph_indices[i+1],
- (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
- return TRUE;
- }
- }
- }
-
- return FALSE;
-}
-
-static cairo_xlib_font_glyphset_info_t *
-_cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (
- cairo_scaled_font_t *scaled_font,
- unsigned long glyph_index,
- cairo_image_surface_t *surface)
-{
- cairo_xlib_surface_font_private_t *font_private;
- int i;
-
- font_private = scaled_font->surface_private;
- if (font_private == NULL)
- return NULL;
-
- if (surface != NULL) {
- i = _cairo_xlib_get_glyphset_index_for_format (surface->format);
- if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
- &font_private->glyphset_info[i],
- glyph_index))
- {
- return &font_private->glyphset_info[i];
- }
- } else {
- for (i = 0; i < NUM_GLYPHSETS; i++) {
- if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
- &font_private->glyphset_info[i],
- glyph_index))
- {
- return &font_private->glyphset_info[i];
- }
- }
- }
-
- return NULL;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
- cairo_scaled_font_t *scaled_font,
- cairo_scaled_glyph_t **pscaled_glyph)
-{
- XGlyphInfo glyph_info;
- unsigned long glyph_index;
- unsigned char *data;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_scaled_glyph_t *scaled_glyph = *pscaled_glyph;
- cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
- cairo_bool_t already_had_glyph_surface;
- cairo_xlib_font_glyphset_info_t *glyphset_info;
-
- glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
-
- /* check to see if we have a pending XRenderFreeGlyph for this glyph */
- glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (scaled_font, glyph_index, glyph_surface);
- if (glyphset_info != NULL) {
- _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (!glyph_surface) {
- status = _cairo_scaled_glyph_lookup (scaled_font,
- glyph_index,
- CAIRO_SCALED_GLYPH_INFO_METRICS |
- CAIRO_SCALED_GLYPH_INFO_SURFACE,
- pscaled_glyph);
- if (unlikely (status))
- return status;
-
- scaled_glyph = *pscaled_glyph;
- glyph_surface = scaled_glyph->surface;
- already_had_glyph_surface = FALSE;
- } else {
- already_had_glyph_surface = TRUE;
- }
-
- if (scaled_font->surface_private == NULL) {
- status = _cairo_xlib_surface_font_init (display, scaled_font);
- if (unlikely (status))
- return status;
- }
-
- glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_format (scaled_font,
- glyph_surface->format);
-
- /* XRenderAddGlyph does not handle a glyph surface larger than the extended maximum XRequest size. */
- {
- int len = cairo_format_stride_for_width (glyphset_info->format, glyph_surface->width) * glyph_surface->height;
- int max_request_size = (XExtendedMaxRequestSize (display->display) ? XExtendedMaxRequestSize (display->display)
- : XMaxRequestSize (display->display)) * 4 -
- sz_xRenderAddGlyphsReq -
- sz_xGlyphInfo -
- 8;
- if (len >= max_request_size)
- return UNSUPPORTED ("glyph too large for XRequest");
- }
-
- /* If the glyph surface has zero height or width, we create
- * a clear 1x1 surface, to avoid various X server bugs.
- */
- if (glyph_surface->width == 0 || glyph_surface->height == 0) {
- cairo_surface_t *tmp_surface;
-
- tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
- status = tmp_surface->status;
- if (unlikely (status))
- goto BAIL;
-
- tmp_surface->device_transform = glyph_surface->base.device_transform;
- tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
-
- glyph_surface = (cairo_image_surface_t *) tmp_surface;
- }
-
- /* If the glyph format does not match the font format, then we
- * create a temporary surface for the glyph image with the font's
- * format.
- */
- if (glyph_surface->format != glyphset_info->format) {
- cairo_surface_pattern_t pattern;
- cairo_surface_t *tmp_surface;
-
- tmp_surface = cairo_image_surface_create (glyphset_info->format,
- glyph_surface->width,
- glyph_surface->height);
- status = tmp_surface->status;
- if (unlikely (status))
- goto BAIL;
-
- tmp_surface->device_transform = glyph_surface->base.device_transform;
- tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
-
- _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
- status = _cairo_surface_paint (tmp_surface,
- CAIRO_OPERATOR_SOURCE, &pattern.base,
- NULL);
- _cairo_pattern_fini (&pattern.base);
-
- glyph_surface = (cairo_image_surface_t *) tmp_surface;
-
- if (unlikely (status))
- goto BAIL;
- }
-
- /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
- glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
- glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
- glyph_info.width = glyph_surface->width;
- glyph_info.height = glyph_surface->height;
- glyph_info.xOff = scaled_glyph->x_advance;
- glyph_info.yOff = scaled_glyph->y_advance;
-
- data = glyph_surface->data;
-
- /* flip formats around */
- switch (_cairo_xlib_get_glyphset_index_for_format (scaled_glyph->surface->format)) {
- case GLYPHSET_INDEX_A1:
- /* local bitmaps are always stored with bit == byte */
- if (_cairo_is_little_endian() != (BitmapBitOrder (display->display) == LSBFirst)) {
- int c = glyph_surface->stride * glyph_surface->height;
- unsigned char *d;
- unsigned char *new, *n;
-
- new = malloc (c);
- if (!new) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
- n = new;
- d = data;
- do {
- char b = *d++;
- b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
- b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
- b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
- *n++ = b;
- } while (--c);
- data = new;
- }
- break;
- case GLYPHSET_INDEX_A8:
- break;
- case GLYPHSET_INDEX_ARGB32:
- if (_cairo_is_little_endian() != (ImageByteOrder (display->display) == LSBFirst)) {
- unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
- const uint32_t *d;
- uint32_t *new, *n;
-
- new = malloc (4 * c);
- if (unlikely (new == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
- n = new;
- d = (uint32_t *) data;
- do {
- *n++ = bswap_32 (*d);
- d++;
- } while (--c);
- data = (uint8_t *) new;
- }
- break;
- default:
- ASSERT_NOT_REACHED;
- break;
- }
- /* XXX assume X server wants pixman padding. Xft assumes this as well */
-
- XRenderAddGlyphs (display->display, glyphset_info->glyphset,
- &glyph_index, &glyph_info, 1,
- (char *) data,
- glyph_surface->stride * glyph_surface->height);
-
- if (data != glyph_surface->data)
- free (data);
-
- _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
-
- BAIL:
- if (glyph_surface != scaled_glyph->surface)
- cairo_surface_destroy (&glyph_surface->base);
-
- /* if the scaled glyph didn't already have a surface attached
- * to it, release the created surface now that we have it
- * uploaded to the X server. If the surface has already been
- * there (eg. because image backend requested it), leave it in
- * the cache
- */
- if (!already_had_glyph_surface)
- _cairo_scaled_glyph_set_surface (scaled_glyph, scaled_font, NULL);
-
- return status;
-}
-
-typedef void (*cairo_xrender_composite_text_func_t)
- (Display *dpy,
- int op,
- Picture src,
- Picture dst,
- _Xconst XRenderPictFormat *maskFormat,
- int xSrc,
- int ySrc,
- int xDst,
- int yDst,
- _Xconst XGlyphElt8 *elts,
- int nelt);
-
-/* Build a struct of the same size of #cairo_glyph_t that can be used both as
- * an input glyph with double coordinates, and as "working" glyph with
- * integer from-current-point offsets. */
-typedef union {
- cairo_glyph_t d;
- unsigned long index;
- struct {
- unsigned long index;
- int x;
- int y;
- } i;
-} cairo_xlib_glyph_t;
-
-/* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
-COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t));
-
-/* Start a new element for the first glyph,
- * or for any glyph that has unexpected position,
- * or if current element has too many glyphs
- * (Xrender limits each element to 252 glyphs, we limit them to 128)
- *
- * These same conditions need to be mirrored between
- * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
- */
-#define _start_new_glyph_elt(count, glyph) \
- (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
-
-static cairo_status_t
-_emit_glyphs_chunk (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *dst,
- cairo_xlib_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- cairo_operator_t op,
- cairo_xlib_surface_t *src,
- cairo_surface_attributes_t *attributes,
- /* info for this chunk */
- int num_elts,
- int width,
- cairo_xlib_font_glyphset_info_t *glyphset_info)
-{
- /* Which XRenderCompositeText function to use */
- cairo_xrender_composite_text_func_t composite_text_func;
- int size;
-
- /* Element buffer stuff */
- XGlyphElt8 *elts;
- XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
-
- /* Reuse the input glyph array for output char generation */
- char *char8 = (char *) glyphs;
- unsigned short *char16 = (unsigned short *) glyphs;
- unsigned int *char32 = (unsigned int *) glyphs;
-
- int i;
- int nelt; /* Element index */
- int n; /* Num output glyphs in current element */
- int j; /* Num output glyphs so far */
-
- switch (width) {
- case 1:
- /* don't cast the 8-variant, to catch possible mismatches */
- composite_text_func = XRenderCompositeText8;
- size = sizeof (char);
- break;
- case 2:
- composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
- size = sizeof (unsigned short);
- break;
- default:
- case 4:
- composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
- size = sizeof (unsigned int);
- }
-
- /* Allocate element array */
- if (num_elts <= ARRAY_LENGTH (stack_elts)) {
- elts = stack_elts;
- } else {
- elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
- if (unlikely (elts == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- /* Fill them in */
- nelt = 0;
- n = 0;
- j = 0;
- for (i = 0; i < num_glyphs; i++) {
-
- /* Start a new element for first output glyph,
- * or for any glyph that has unexpected position,
- * or if current element has too many glyphs.
- *
- * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
- */
- if (_start_new_glyph_elt (j, &glyphs[i])) {
- if (j) {
- elts[nelt].nchars = n;
- nelt++;
- n = 0;
- }
- elts[nelt].chars = char8 + size * j;
- elts[nelt].glyphset = glyphset_info->glyphset;
- elts[nelt].xOff = glyphs[i].i.x;
- elts[nelt].yOff = glyphs[i].i.y;
- }
-
- switch (width) {
- case 1: char8 [j] = (char) glyphs[i].index; break;
- case 2: char16[j] = (unsigned short) glyphs[i].index; break;
- default:
- case 4: char32[j] = (unsigned int) glyphs[i].index; break;
- }
-
- n++;
- j++;
- }
-
- if (n) {
- elts[nelt].nchars = n;
- nelt++;
- }
-
- /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
- * expected number of xGlyphElts. */
- assert (nelt == num_elts);
-
- composite_text_func (display->display,
- _render_operator (op),
- src->src_picture,
- dst->dst_picture,
- glyphset_info->xrender_format,
- attributes->x_offset + elts[0].xOff,
- attributes->y_offset + elts[0].yOff,
- elts[0].xOff, elts[0].yOff,
- (XGlyphElt8 *) elts, nelt);
-
- if (elts != stack_elts)
- free (elts);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-/* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
- * enough room for padding */
-#define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
-
-static cairo_status_t
-_cairo_xlib_surface_emit_glyphs (cairo_xlib_display_t *display,
- cairo_xlib_surface_t *dst,
- cairo_xlib_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- cairo_operator_t op,
- cairo_xlib_surface_t *src,
- cairo_surface_attributes_t *attributes,
- int *remaining_glyphs)
-{
- int i;
- cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
- cairo_scaled_glyph_t *scaled_glyph;
- cairo_fixed_t x = 0, y = 0;
- cairo_xlib_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
-
- unsigned long max_index = 0;
- int width = 1;
- int num_elts = 0;
- int num_out_glyphs = 0;
-
- int max_request_size = XMaxRequestSize (display->display) * 4
- - MAX (sz_xRenderCompositeGlyphs8Req,
- MAX(sz_xRenderCompositeGlyphs16Req,
- sz_xRenderCompositeGlyphs32Req));
- int request_size = 0;
-
- _cairo_xlib_surface_ensure_dst_picture (display, dst);
-
- for (i = 0; i < num_glyphs; i++) {
- int this_x, this_y;
- int old_width;
-
- status = _cairo_scaled_glyph_lookup (scaled_font,
- glyphs[i].index,
- CAIRO_SCALED_GLYPH_INFO_METRICS,
- &scaled_glyph);
- if (unlikely (status))
- return status;
-
- /* The glyph coordinates must be representable in an int16_t.
- * When possible, they will be expressed as an offset from the
- * previous glyph, otherwise they will be an offset from the
- * surface origin. If we can't guarantee this to be possible,
- * fallback.
- */
- if (glyphs[i].d.x > INT16_MAX || glyphs[i].d.y > INT16_MAX ||
- glyphs[i].d.x < INT16_MIN || glyphs[i].d.y < INT16_MIN)
- {
- break;
- }
-
- this_x = _cairo_lround (glyphs[i].d.x);
- this_y = _cairo_lround (glyphs[i].d.y);
-
- /* Send unsent glyphs to the server */
- if (_cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph) == NULL) {
- status = _cairo_xlib_surface_add_glyph (display,
- scaled_font,
- &scaled_glyph);
- if (unlikely (status)) {
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- /* Break so we flush glyphs so far and let fallback code
- * handle the rest */
- break;
-
- return status;
- }
- }
-
- this_glyphset_info = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph);
- if (!glyphset_info)
- glyphset_info = this_glyphset_info;
-
- /* The invariant here is that we can always flush the glyphs
- * accumulated before this one, using old_width, and they
- * would fit in the request.
- */
- old_width = width;
-
- /* Update max glyph index */
- if (glyphs[i].index > max_index) {
- max_index = glyphs[i].index;
- if (max_index >= 65536)
- width = 4;
- else if (max_index >= 256)
- width = 2;
- if (width != old_width)
- request_size += (width - old_width) * num_out_glyphs;
- }
-
- /* If we will pass the max request size by adding this glyph,
- * flush current glyphs. Note that we account for a
- * possible element being added below.
- *
- * Also flush if changing glyphsets, as Xrender limits one mask
- * format per request, so we can either break up, or use a
- * wide-enough mask format. We do the former. One reason to
- * prefer the latter is the fact that Xserver ADDs all glyphs
- * to the mask first, and then composes that to final surface,
- * though it's not a big deal.
- *
- * If the glyph has a coordinate which cannot be represented
- * as a 16-bit offset from the previous glyph, flush the
- * current chunk. The current glyph will be the first one in
- * the next chunk, thus its coordinates will be an offset from
- * the destination origin. This offset is guaranteed to be
- * representable as 16-bit offset (otherwise we would have
- * fallen back).
- */
- if (request_size + width > max_request_size - _cairo_sz_xGlyphElt ||
- this_x - x > INT16_MAX || this_x - x < INT16_MIN ||
- this_y - y > INT16_MAX || this_y - y < INT16_MIN ||
- (this_glyphset_info != glyphset_info)) {
- status = _emit_glyphs_chunk (display, dst, glyphs, i,
- scaled_font, op, src, attributes,
- num_elts, old_width, glyphset_info);
- if (unlikely (status))
- return status;
-
- glyphs += i;
- num_glyphs -= i;
- i = 0;
- max_index = glyphs[i].index;
- width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
- request_size = 0;
- num_elts = 0;
- num_out_glyphs = 0;
- x = y = 0;
- glyphset_info = this_glyphset_info;
- }
-
- /* Convert absolute glyph position to relative-to-current-point
- * position */
- glyphs[i].i.x = this_x - x;
- glyphs[i].i.y = this_y - y;
-
- /* Start a new element for the first glyph,
- * or for any glyph that has unexpected position,
- * or if current element has too many glyphs.
- *
- * These same conditions are mirrored in _emit_glyphs_chunk().
- */
- if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
- num_elts++;
- request_size += _cairo_sz_xGlyphElt;
- }
-
- /* adjust current-position */
- x = this_x + scaled_glyph->x_advance;
- y = this_y + scaled_glyph->y_advance;
-
- num_out_glyphs++;
- request_size += width;
- }
-
- if (num_elts) {
- status = _emit_glyphs_chunk (display, dst, glyphs, i,
- scaled_font, op, src, attributes,
- num_elts, width, glyphset_info);
- }
-
- *remaining_glyphs = num_glyphs - i;
- if (*remaining_glyphs != 0 && status == CAIRO_INT_STATUS_SUCCESS)
- status = CAIRO_INT_STATUS_UNSUPPORTED;
-
- return status;
-}
-
-static cairo_bool_t
-_cairo_xlib_surface_owns_font (cairo_xlib_surface_t *dst,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xlib_surface_font_private_t *font_private;
-
- font_private = scaled_font->surface_private;
- if ((scaled_font->surface_backend != NULL &&
- scaled_font->surface_backend != &cairo_xlib_surface_backend) ||
- (font_private != NULL && font_private->device != dst->base.device))
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_show_glyphs (void *abstract_dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const 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;
- composite_operation_t operation;
- cairo_surface_attributes_t attributes;
- cairo_xlib_surface_t *src = NULL;
- cairo_xlib_display_t *display;
-
- if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst))
- 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 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
- * then the entire thing is copied to the destination surface,
- * including the fully transparent "background" of the rectangular
- * glyph surface. */
- if (op == CAIRO_OPERATOR_SOURCE)
- 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 (!_cairo_clip_is_region (clip))
- return UNSUPPORTED ("clip mask required");
-
- operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
- if (operation == DO_UNSUPPORTED)
- return UNSUPPORTED ("unsupported op");
-
- if (! _cairo_xlib_surface_owns_font (dst, scaled_font))
- return UNSUPPORTED ("unowned font");
-
- status = _cairo_xlib_display_acquire (dst->base.device, &display);
- if (unlikely (status))
- return status;
-
- X_DEBUG ((display->display, "show_glyphs (dst=%x)", (unsigned int) dst->drawable));
-
- status = _cairo_xlib_surface_set_clip_region (dst,
- _cairo_clip_get_region (clip));
- if (unlikely (status))
- goto BAIL0;
-
- /* After passing all those tests, we're now committed to rendering
- * these glyphs or to fail trying. We first upload any glyphs to
- * the X server that it doesn't have already, then we draw
- * them.
- */
-
- /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
- * the mask (the glyphs). This code below was executed as a side effect
- * of going through the _clip_and_composite fallback code for old_show_glyphs,
- * so PictOpClear was never used with CompositeText before.
- */
- if (op == CAIRO_OPERATOR_CLEAR) {
- src_pattern = &_cairo_pattern_white.base;
- op = CAIRO_OPERATOR_DEST_OUT;
- }
-
- if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
- status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
- 0, 0, 1, 1,
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **) &src,
- &attributes);
- if (unlikely (status))
- goto BAIL0;
- } else {
- cairo_rectangle_int_t glyph_extents;
-
- status = _cairo_scaled_font_glyph_device_extents (scaled_font,
- glyphs,
- num_glyphs,
- &glyph_extents,
- NULL);
- if (unlikely (status))
- goto BAIL0;
-
- status = _cairo_xlib_surface_acquire_pattern_surface (display,
- dst, src_pattern,
- glyph_extents.x,
- glyph_extents.y,
- glyph_extents.width,
- glyph_extents.height,
- &src, &attributes);
- if (unlikely (status))
- goto BAIL0;
- }
-
- operation = _recategorize_composite_operation (dst, op, src,
- &attributes, TRUE);
- if (operation == DO_UNSUPPORTED) {
- status = UNSUPPORTED ("unsupported op");
- goto BAIL1;
- }
-
- status = _cairo_xlib_surface_set_attributes (display, src, &attributes, 0, 0);
- if (unlikely (status))
- goto BAIL1;
-
- _cairo_scaled_font_freeze_cache (scaled_font);
- if (_cairo_xlib_surface_owns_font (dst, scaled_font)) {
- status = _cairo_xlib_surface_emit_glyphs (display,
- dst,
- (cairo_xlib_glyph_t *) glyphs,
- num_glyphs,
- scaled_font,
- op,
- src,
- &attributes,
- remaining_glyphs);
- } else {
- status = UNSUPPORTED ("unowned font");
- }
- _cairo_scaled_font_thaw_cache (scaled_font);
-
- BAIL1:
- if (src)
- _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
- BAIL0:
- cairo_device_release (&display->base);
-
- return status;
-}
-
#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */
diff --git a/src/cairo.c b/src/cairo.c
index 6f6d00e6..cbc39745 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -46,6 +46,7 @@
#include "cairo-path-private.h"
#include "cairo-pattern-private.h"
#include "cairo-surface-private.h"
+#include "cairo-surface-backend-private.h"
#include <assert.h>
diff --git a/src/cairo.h b/src/cairo.h
index 710d9978..f5450fec 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -2123,7 +2123,7 @@ cairo_surface_create_similar_image (cairo_surface_t *other,
cairo_public cairo_surface_t *
cairo_surface_map_to_image (cairo_surface_t *surface,
- const cairo_rectangle_t *extents);
+ const cairo_rectangle_int_t *extents);
cairo_public void
cairo_surface_unmap_image (cairo_surface_t *surface,
@@ -2145,6 +2145,45 @@ cairo_public cairo_surface_t *
cairo_surface_create_observer (cairo_surface_t *target,
cairo_surface_observer_mode_t mode);
+typedef void (*cairo_surface_observer_callback_t) (cairo_surface_t *observer,
+ cairo_surface_t *target,
+ void *data);
+
+cairo_public cairo_status_t
+cairo_surface_observer_add_paint_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data);
+
+cairo_public cairo_status_t
+cairo_surface_observer_add_mask_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data);
+
+cairo_public cairo_status_t
+cairo_surface_observer_add_fill_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data);
+
+cairo_public cairo_status_t
+cairo_surface_observer_add_stroke_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data);
+
+cairo_public cairo_status_t
+cairo_surface_observer_add_glyphs_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data);
+
+cairo_public cairo_status_t
+cairo_surface_observer_add_flush_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data);
+
+cairo_public cairo_status_t
+cairo_surface_observer_add_finish_callback (cairo_surface_t *abstract_surface,
+ cairo_surface_observer_callback_t func,
+ void *data);
+
cairo_public void
cairo_surface_observer_print (cairo_surface_t *surface,
cairo_write_func_t write_func,
@@ -2426,6 +2465,10 @@ cairo_recording_surface_ink_extents (cairo_surface_t *surface,
double *width,
double *height);
+cairo_public cairo_bool_t
+cairo_recording_surface_get_extents (cairo_surface_t *surface,
+ cairo_rectangle_t *extents);
+
/* Mime-surface (callback) functions */
typedef cairo_surface_t *(*cairo_mime_surface_acquire_t) (cairo_surface_t *mime_surface,
diff --git a/src/cairoint.h b/src/cairoint.h
index 5ae8b7a5..28f3e9f3 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -287,16 +287,14 @@ _cairo_boxes_get_extents (const cairo_box_t *boxes,
int num_boxes,
cairo_box_t *extents);
+cairo_private extern const cairo_rectangle_int_t _cairo_empty_rectangle;
+cairo_private extern const cairo_rectangle_int_t _cairo_unbounded_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;
+ *rect = _cairo_unbounded_rectangle;
}
-cairo_private extern const cairo_rectangle_int_t _cairo_empty_rectangle;
-cairo_private extern const cairo_rectangle_int_t _cairo_unbounded_rectangle;
cairo_private_no_warn cairo_bool_t
_cairo_rectangle_intersect (cairo_rectangle_int_t *dst,
@@ -327,47 +325,12 @@ cairo_private cairo_bool_t
_cairo_box_intersects_line_segment (cairo_box_t *box,
cairo_line_t *line) cairo_pure;
-/* cairo-array.c structures and functions */
-
-cairo_private void
-_cairo_array_init (cairo_array_t *array, unsigned int element_size);
-
-cairo_private void
-_cairo_array_fini (cairo_array_t *array);
-
-cairo_private cairo_status_t
-_cairo_array_grow_by (cairo_array_t *array, unsigned int additional);
-
-cairo_private void
-_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements);
-
-cairo_private cairo_status_t
-_cairo_array_append (cairo_array_t *array, const void *element);
-
-cairo_private cairo_status_t
-_cairo_array_append_multiple (cairo_array_t *array,
- const void *elements,
- unsigned int num_elements);
-
-cairo_private cairo_status_t
-_cairo_array_allocate (cairo_array_t *array,
- unsigned int num_elements,
- void **elements);
-
-cairo_private void *
-_cairo_array_index (cairo_array_t *array, unsigned int index);
-
-cairo_private const void *
-_cairo_array_index_const (const cairo_array_t *array, unsigned int index);
-
-cairo_private void
-_cairo_array_copy_element (const cairo_array_t *array, unsigned int index, void *dst);
-
-cairo_private unsigned int
-_cairo_array_num_elements (const cairo_array_t *array);
-
-cairo_private unsigned int
-_cairo_array_size (const cairo_array_t *array);
+cairo_private cairo_bool_t
+_cairo_spline_intersects (const cairo_point_t *a,
+ const cairo_point_t *b,
+ const cairo_point_t *c,
+ const cairo_point_t *d,
+ const cairo_box_t *box) cairo_pure;
typedef struct {
const cairo_user_data_key_t *key;
@@ -407,10 +370,6 @@ _cairo_user_data_array_foreach (cairo_user_data_array_t *array,
cairo_private unsigned long
_cairo_hash_string (const char *c);
-cairo_private void
-_cairo_pattern_get_ink_extents (const cairo_pattern_t *pattern,
- cairo_rectangle_int_t *extents);
-
cairo_private unsigned long
_cairo_hash_bytes (unsigned long hash,
const void *bytes,
@@ -518,21 +477,6 @@ struct _cairo_scaled_font_backend {
unsigned long
(*ucs4_to_index) (void *scaled_font,
uint32_t ucs4);
- cairo_warn cairo_int_status_t
- (*show_glyphs) (void *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_region_t *clip_region,
- int *remaining_glyphs);
/* Read data from a sfnt font table.
* @scaled_font: font
@@ -657,301 +601,6 @@ extern const cairo_private struct _cairo_font_face_backend _cairo_quartz_font_fa
#endif
-struct _cairo_surface_backend {
- cairo_surface_type_t type;
-
- cairo_warn cairo_status_t
- (*finish) (void *surface);
-
- cairo_t *
- (*create_context) (void *surface);
-
- cairo_surface_t *
- (*create_similar) (void *surface,
- cairo_content_t content,
- int width,
- int height);
- cairo_surface_t *
- (*create_similar_image) (void *surface,
- cairo_format_t format,
- int width,
- int height);
-
- cairo_surface_t *
- (*map_to_image) (void *surface,
- const cairo_rectangle_int_t *extents);
- cairo_int_status_t
- (*unmap_image) (void *surface,
- cairo_image_surface_t *image);
-
- cairo_warn cairo_status_t
- (*acquire_source_image) (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra);
-
- void
- (*release_source_image) (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra);
-
- cairo_warn cairo_status_t
- (*acquire_dest_image) (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect,
- void **image_extra);
-
- void
- (*release_dest_image) (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra);
-
- /* Create a new surface (@clone_out) with the following
- * characteristics:
- *
- * 1. It is as compatible as possible with @surface (in terms of
- * efficiency)
- *
- * 2. It has the same contents as @src within the given rectangle.
- *
- * 3. The offset of the similar surface with respect to the original
- * surface is returned in the clone_offset vector.
- * - if you clone the entire surface, this vector is zero.
- * - if you clone (src_x, src_y)x(w, h) the vector is (src_x, src_y);
- */
- cairo_warn cairo_status_t
- (*clone_similar) (void *surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- 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,
- const cairo_pattern_t *src,
- const cairo_pattern_t *mask,
- void *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,
- cairo_region_t *clip_region);
-
- cairo_warn cairo_int_status_t
- (*fill_rectangles) (void *surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects);
-
- /* XXX: dst should be the first argument for consistency */
- cairo_warn cairo_int_status_t
- (*composite_trapezoids) (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *dst,
- cairo_antialias_t antialias,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *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,
- cairo_region_t *clip_region);
-
-
- cairo_warn cairo_bool_t
- (*check_span_renderer) (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *dst,
- cairo_antialias_t antialias);
-
- cairo_warn cairo_int_status_t
- (*copy_page) (void *surface);
-
- cairo_warn cairo_int_status_t
- (*show_page) (void *surface);
-
- /* 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}.
- *
- * If this function is not implemented, or if it returns
- * FALSE the surface is considered to be
- * boundless and infinite bounds are used for it.
- */
- cairo_bool_t
- (*get_extents) (void *surface,
- cairo_rectangle_int_t *extents);
-
- /*
- * This is an optional entry to let the surface manage its own glyph
- * resources. If null, render against this surface, using image
- * surfaces as glyphs.
- */
- cairo_warn cairo_int_status_t
- (*old_show_glyphs) (cairo_scaled_font_t *font,
- cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *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);
-
- void
- (*get_font_options) (void *surface,
- cairo_font_options_t *options);
-
- cairo_warn cairo_status_t
- (*flush) (void *surface);
-
- cairo_warn cairo_status_t
- (*mark_dirty_rectangle) (void *surface,
- int x,
- int y,
- int width,
- int height);
-
- void
- (*scaled_font_fini) (cairo_scaled_font_t *scaled_font);
-
- void
- (*scaled_glyph_fini) (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font);
-
- /* OK, I'm starting over somewhat by defining the 5 top-level
- * drawing operators for the surface backend here with consistent
- * naming and argument-order conventions. */
- cairo_warn cairo_int_status_t
- (*paint) (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const 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,
- const cairo_clip_t *clip);
-
- cairo_warn cairo_int_status_t
- (*stroke) (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip);
-
- cairo_warn cairo_int_status_t
- (*fill) (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip);
-
- cairo_warn cairo_int_status_t
- (*show_glyphs) (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs);
-
- cairo_surface_t *
- (*snapshot) (void *surface);
-
- cairo_bool_t
- (*is_similar) (void *surface_a,
- void *surface_b);
-
- cairo_warn cairo_int_status_t
- (*fill_stroke) (void *surface,
- 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,
- const cairo_path_fixed_t*path,
- cairo_operator_t stroke_op,
- const cairo_pattern_t *stroke_source,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *stroke_ctm,
- const cairo_matrix_t *stroke_ctm_inverse,
- double stroke_tolerance,
- cairo_antialias_t stroke_antialias,
- const cairo_clip_t *clip);
-
- cairo_surface_t *
- (*create_solid_pattern_surface)
- (void *surface,
- const cairo_solid_pattern_t *solid_pattern);
-
- cairo_bool_t
- (*can_repaint_solid_pattern_surface)
- (void *surface,
- const cairo_solid_pattern_t *solid_pattern);
-
- cairo_bool_t
- (*has_show_text_glyphs) (void *surface);
-
- cairo_warn cairo_int_status_t
- (*show_text_glyphs) (void *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,
- const cairo_clip_t *clip);
-
- cairo_warn cairo_status_t
- (*acquire_source_image_transformed) (void *abstract_surface,
- cairo_matrix_t *device_transform,
- cairo_image_surface_t **image_out,
- void **image_extra);
-};
-
#define CAIRO_EXTEND_SURFACE_DEFAULT CAIRO_EXTEND_NONE
#define CAIRO_EXTEND_GRADIENT_DEFAULT CAIRO_EXTEND_PAD
#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_GOOD
@@ -970,23 +619,6 @@ struct _cairo_surface_attributes {
void *extra;
};
-typedef struct _cairo_traps {
- cairo_status_t status;
-
- const cairo_box_t *limits;
- int num_limits;
-
- unsigned int maybe_region : 1; /* hint: 0 implies that it cannot be */
- unsigned int has_intersections : 1;
- unsigned int is_rectilinear : 1;
- unsigned int is_rectangular : 1;
-
- int num_traps;
- int traps_size;
- cairo_trapezoid_t *traps;
- cairo_trapezoid_t traps_embedded[16];
-} cairo_traps_t;
-
#define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL
#define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL
@@ -1403,6 +1035,14 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
double tolerance,
cairo_polygon_t *polygon);
+cairo_private cairo_int_status_t
+_cairo_path_fixed_stroke_to_tristrip (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t*style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_tristrip_t *strip);
+
cairo_private cairo_status_t
_cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
@@ -1569,6 +1209,7 @@ _cairo_stroke_style_fini (cairo_stroke_style_t *style);
cairo_private void
_cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
+ const cairo_path_fixed_t *path,
const cairo_matrix_t *ctm,
double *dx, double *dy);
@@ -1601,7 +1242,7 @@ cairo_private cairo_status_t
_cairo_surface_copy_mime_data (cairo_surface_t *dst,
cairo_surface_t *src);
-cairo_private cairo_int_status_t
+cairo_private_no_warn cairo_int_status_t
_cairo_surface_set_error (cairo_surface_t *surface,
cairo_int_status_t status);
@@ -1625,17 +1266,7 @@ _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,
- const cairo_solid_pattern_t *solid_pattern);
-
-cairo_private cairo_int_status_t
-_cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other,
- cairo_surface_t *solid_surface,
- const cairo_solid_pattern_t *solid_pattern);
+ const cairo_color_t *color);
cairo_private void
_cairo_surface_init (cairo_surface_t *surface,
@@ -1648,34 +1279,6 @@ _cairo_surface_set_font_options (cairo_surface_t *surface,
cairo_font_options_t *options);
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,
- cairo_region_t *clip_region);
-
-cairo_private cairo_status_t
-_cairo_surface_fill_region (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_region_t *region);
-
-cairo_private cairo_status_t
-_cairo_surface_fill_rectangles (cairo_surface_t *surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects);
-
-cairo_private cairo_status_t
_cairo_surface_paint (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
@@ -1742,75 +1345,15 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
const cairo_clip_t *clip);
cairo_private cairo_status_t
-_cairo_surface_composite_trapezoids (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- cairo_antialias_t antialias,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- 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_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);
-
-cairo_private cairo_status_t
_cairo_surface_acquire_source_image (cairo_surface_t *surface,
cairo_image_surface_t **image_out,
void **image_extra);
-cairo_private cairo_status_t
-_cairo_surface_acquire_source_image_transformed (cairo_surface_t *surface,
- cairo_matrix_t *device_trasnform,
- cairo_image_surface_t **image_out,
- void **image_extra);
-
cairo_private void
_cairo_surface_release_source_image (cairo_surface_t *surface,
cairo_image_surface_t *image,
void *image_extra);
-cairo_private cairo_status_t
-_cairo_surface_acquire_dest_image (cairo_surface_t *surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect,
- void **image_extra);
-
-cairo_private void
-_cairo_surface_release_dest_image (cairo_surface_t *surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra);
-
-cairo_private cairo_status_t
-_cairo_surface_clone_similar (cairo_surface_t *surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out);
-
cairo_private cairo_surface_t *
_cairo_surface_snapshot (cairo_surface_t *surface);
@@ -1826,67 +1369,10 @@ _cairo_surface_has_snapshot (cairo_surface_t *surface,
cairo_private void
_cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
-cairo_private cairo_bool_t
-_cairo_surface_is_similar (cairo_surface_t *surface_a,
- cairo_surface_t *surface_b);
-
cairo_private_no_warn cairo_bool_t
_cairo_surface_get_extents (cairo_surface_t *surface,
cairo_rectangle_int_t *extents);
-cairo_private cairo_status_t
-_cairo_surface_old_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_region_t *clip_region);
-
-cairo_private cairo_status_t
-_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
- cairo_surface_attributes_t *src_attr,
- int src_width,
- int src_height,
- cairo_surface_attributes_t *mask_attr,
- int mask_width,
- int mask_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_composite_shape_fixup_unbounded (cairo_surface_t *dst,
- cairo_surface_attributes_t *src_attr,
- int src_width,
- int src_height,
- int mask_width,
- int mask_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_bool_t
-_cairo_surface_is_opaque (const cairo_surface_t *surface);
-
cairo_private void
_cairo_surface_set_device_scale (cairo_surface_t *surface,
double sx,
@@ -1999,22 +1485,12 @@ cairo_private cairo_image_surface_t *
_cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface,
cairo_format_t format);
-cairo_private void
-_cairo_image_surface_span_render_row (int y,
- const cairo_half_open_span_t *spans,
- unsigned num_spans,
- uint8_t *data,
- uint32_t stride);
-
cairo_private cairo_image_transparency_t
_cairo_image_analyze_transparency (cairo_image_surface_t *image);
cairo_private cairo_image_color_t
_cairo_image_analyze_color (cairo_image_surface_t *image);
-cairo_private cairo_bool_t
-_cairo_surface_is_image (const cairo_surface_t *surface) cairo_pure;
-
/* cairo-pen.c */
cairo_private cairo_status_t
_cairo_pen_init (cairo_pen_t *pen,
@@ -2079,6 +1555,9 @@ cairo_private cairo_status_t
_cairo_polygon_add_contour (cairo_polygon_t *polygon,
const cairo_contour_t *contour);
+cairo_private void
+_cairo_polygon_translate (cairo_polygon_t *polygon, int dx, int dy);
+
cairo_private cairo_status_t
_cairo_polygon_reduce (cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule);
@@ -2087,6 +1566,12 @@ cairo_private cairo_status_t
_cairo_polygon_intersect (cairo_polygon_t *a, int winding_a,
cairo_polygon_t *b, int winding_b);
+cairo_private cairo_status_t
+_cairo_polygon_intersect_with_boxes (cairo_polygon_t *polygon,
+ cairo_fill_rule_t *winding,
+ cairo_box_t *boxes,
+ int num_boxes);
+
static inline cairo_bool_t
_cairo_polygon_is_empty (const cairo_polygon_t *polygon)
{
@@ -2180,44 +1665,6 @@ _cairo_matrix_to_pixman_matrix_offset (const cairo_matrix_t *matrix,
int *out_x_offset,
int *out_y_offset);
-/* cairo-traps.c */
-cairo_private void
-_cairo_traps_init (cairo_traps_t *traps);
-
-cairo_private void
-_cairo_traps_init_with_clip (cairo_traps_t *traps,
- const cairo_clip_t *clip);
-
-cairo_private void
-_cairo_traps_limit (cairo_traps_t *traps,
- const cairo_box_t *boxes,
- int num_boxes);
-
-cairo_private cairo_status_t
-_cairo_traps_init_boxes (cairo_traps_t *traps,
- const cairo_boxes_t *boxes);
-
-cairo_private void
-_cairo_traps_clear (cairo_traps_t *traps);
-
-cairo_private void
-_cairo_traps_fini (cairo_traps_t *traps);
-
-#define _cairo_traps_status(T) (T)->status
-
-cairo_private void
-_cairo_traps_translate (cairo_traps_t *traps, int x, int y);
-
-cairo_private cairo_status_t
-_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
- const cairo_point_t *top_left,
- const cairo_point_t *bottom_right);
-
-cairo_private void
-_cairo_traps_add_trap (cairo_traps_t *traps,
- cairo_fixed_t top, cairo_fixed_t bottom,
- cairo_line_t *left, cairo_line_t *right);
-
cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
const cairo_polygon_t *polygon,
@@ -2250,23 +1697,6 @@ _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_poly
cairo_fill_rule_t fill_rule,
cairo_boxes_t *boxes);
-cairo_private int
-_cairo_traps_contain (const cairo_traps_t *traps,
- double x, double y);
-
-cairo_private void
-_cairo_traps_extents (const cairo_traps_t *traps,
- cairo_box_t *extents);
-
-cairo_private cairo_int_status_t
-_cairo_traps_extract_region (cairo_traps_t *traps,
- cairo_antialias_t antialias,
- cairo_region_t **region);
-
-cairo_private cairo_status_t
-_cairo_traps_path (const cairo_traps_t *traps,
- cairo_path_fixed_t *path);
-
cairo_private void
_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
cairo_trapezoid_t *src_traps,
@@ -2422,6 +1852,7 @@ 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_image);
slim_hidden_proto (cairo_surface_destroy);
slim_hidden_proto (cairo_surface_finish);
slim_hidden_proto (cairo_surface_flush);
diff --git a/src/skia/cairo-skia-context.cpp b/src/skia/cairo-skia-context.cpp
index 828f6e59..e5d48280 100644
--- a/src/skia/cairo-skia-context.cpp
+++ b/src/skia/cairo-skia-context.cpp
@@ -50,6 +50,7 @@
#include "cairo-path-private.h"
#include "cairo-pattern-private.h"
#include "cairo-skia-private.h"
+#include "cairo-surface-backend-private.h"
#include <SkShader.h>
#include <SkColorShader.h>
diff --git a/src/skia/cairo-skia-surface.cpp b/src/skia/cairo-skia-surface.cpp
index 4c10625a..56b4dca1 100644
--- a/src/skia/cairo-skia-surface.cpp
+++ b/src/skia/cairo-skia-surface.cpp
@@ -41,6 +41,8 @@
#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
+#include "cairo-surface-backend-private.h"
+#include "cairo-surface-fallback-private.h"
static cairo_skia_surface_t *
_cairo_skia_surface_create_internal (SkBitmap::Config config,
@@ -161,198 +163,6 @@ _cairo_skia_surface_get_font_options (void *abstract_surface,
_cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
}
-static cairo_rectangle_t *
-to_rectangle (cairo_rectangle_t *rf,
- cairo_rectangle_int_t *ri)
-{
- rf->x = ri->x;
- rf->y = ri->y;
- rf->width = ri->width;
- rf->height = ri->height;
- return rf;
-}
-
-static cairo_int_status_t
-_cairo_foreign_surface_paint (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_clip_t *clip)
-{
- cairo_surface_t *surface = (cairo_surface_t *) abstract_surface;
- cairo_surface_t *image;
- cairo_rectangle_int_t extents;
- cairo_rectangle_t rect;
- cairo_composite_rectangles_t composite;
- cairo_int_status_t status;
-
- _cairo_surface_get_extents (surface, &extents);
- status = _cairo_composite_rectangles_init_for_paint (&composite, &extents,
- op, source,
- clip);
- if (unlikely (status))
- return status;
-
- image = cairo_surface_map_to_image (surface,
- to_rectangle(&rect, &composite.unbounded));
- status = (cairo_int_status_t)
- _cairo_surface_paint (image, op, source, clip);
- cairo_surface_unmap_image (surface, image);
-
- _cairo_composite_rectangles_fini (&composite);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_foreign_surface_mask (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask,
- const cairo_clip_t *clip)
-{
- cairo_surface_t *surface =(cairo_surface_t *) abstract_surface;
- cairo_surface_t *image;
- cairo_rectangle_int_t extents;
- cairo_rectangle_t rect;
- cairo_composite_rectangles_t composite;
- cairo_int_status_t status;
-
- _cairo_surface_get_extents (surface, &extents);
- status = _cairo_composite_rectangles_init_for_mask (&composite, &extents,
- op, source, mask,
- clip);
- if (unlikely (status))
- return status;
-
- image = cairo_surface_map_to_image (surface,
- to_rectangle(&rect, &composite.unbounded));
- status = (cairo_int_status_t)
- _cairo_surface_mask (image, op, source, mask, clip);
- cairo_surface_unmap_image (surface, image);
-
- _cairo_composite_rectangles_fini (&composite);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_foreign_surface_stroke (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t*style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- cairo_surface_t *surface =(cairo_surface_t *) abstract_surface;
- cairo_surface_t *image;
- cairo_composite_rectangles_t composite;
- cairo_rectangle_int_t extents;
- cairo_rectangle_t rect;
- cairo_int_status_t status;
-
- _cairo_surface_get_extents (surface, &extents);
- status = _cairo_composite_rectangles_init_for_stroke (&composite, &extents,
- op, source,
- path, style, ctm,
- clip);
- if (unlikely (status))
- return status;
-
- image = cairo_surface_map_to_image (surface,
- to_rectangle(&rect, &composite.unbounded));
- status = (cairo_int_status_t)
- _cairo_surface_stroke (image, op, source, path, style, ctm, ctm_inverse, tolerance, antialias, clip);
- cairo_surface_unmap_image (surface, image);
-
- _cairo_composite_rectangles_fini (&composite);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_foreign_surface_fill (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- cairo_surface_t *surface =(cairo_surface_t *) abstract_surface;
- cairo_surface_t *image;
- cairo_composite_rectangles_t composite;
- cairo_rectangle_int_t extents;
- cairo_rectangle_t rect;
- cairo_int_status_t status;
-
- _cairo_surface_get_extents (surface, &extents);
- status = _cairo_composite_rectangles_init_for_fill (&composite, &extents,
- op, source, path,
- clip);
- if (unlikely (status))
- return status;
-
- image = cairo_surface_map_to_image (surface,
- to_rectangle(&rect, &composite.unbounded));
- status = (cairo_int_status_t)
- _cairo_surface_fill (image, op, source, path, fill_rule, tolerance, antialias, clip);
- cairo_surface_unmap_image (surface, image);
-
- _cairo_composite_rectangles_fini (&composite);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_foreign_surface_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,
- const cairo_clip_t *clip,
- int *num_remaining)
-{
- cairo_surface_t *surface =(cairo_surface_t *) abstract_surface;
- cairo_surface_t *image;
- cairo_composite_rectangles_t composite;
- cairo_rectangle_int_t extents;
- cairo_rectangle_t rect;
- cairo_int_status_t status;
- cairo_bool_t overlap;
-
- _cairo_surface_get_extents (surface, &extents);
- status = _cairo_composite_rectangles_init_for_glyphs (&composite, &extents,
- op, source,
- scaled_font,
- glyphs, num_glyphs,
- clip,
- &overlap);
- if (unlikely (status))
- return status;
-
- image = cairo_surface_map_to_image (surface,
- to_rectangle(&rect, &composite.unbounded));
- status = (cairo_int_status_t)
- _cairo_surface_show_text_glyphs (image,
- op, source,
- NULL, 0,
- glyphs, num_glyphs,
- NULL, 0, (cairo_text_cluster_flags_t)0,
- scaled_font,
- clip);
- cairo_surface_unmap_image (surface, image);
- _cairo_composite_rectangles_fini (&composite);
-
- *num_remaining = 0;
- return status;
-}
-
static const struct _cairo_surface_backend
cairo_skia_surface_backend = {
CAIRO_SURFACE_TYPE_SKIA,
@@ -366,33 +176,26 @@ cairo_skia_surface_backend = {
_cairo_skia_surface_unmap_image,
_cairo_skia_surface_acquire_source_image,
+ NULL, /* acquire transformed */
_cairo_skia_surface_release_source_image,
-
- NULL, NULL,
- NULL, /* clone similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ NULL, /* snapshot */
NULL, /* copy_page */
NULL, /* show_page */
_cairo_skia_surface_get_extents,
- NULL, /* old_show_glyphs */
_cairo_skia_surface_get_font_options,
+
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
- NULL, /* scaled_font_fini */
- NULL, /* scaled_glyph_fini */
/* XXX native surface functions? */
- _cairo_foreign_surface_paint,
- _cairo_foreign_surface_mask,
- _cairo_foreign_surface_stroke,
- _cairo_foreign_surface_fill,
- _cairo_foreign_surface_glyphs
+ _cairo_surface_fallback_paint,
+ _cairo_surface_fallback_mask,
+ _cairo_surface_fallback_stroke,
+ _cairo_surface_fallback_fill,
+ NULL, /* fill/stroke */
+ _cairo_surface_fallback_glyphs
};
/*
@@ -426,6 +229,7 @@ sk_config_to_pixman_format_code (SkBitmap::Config config,
return (pixman_format_code_t) -1;
}
}
+
static cairo_skia_surface_t *
_cairo_skia_surface_create_internal (SkBitmap::Config config,
bool opaque,
diff --git a/src/test-base-compositor-surface.c b/src/test-base-compositor-surface.c
new file mode 100644
index 00000000..9d957a45
--- /dev/null
+++ b/src/test-base-compositor-surface.c
@@ -0,0 +1,942 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "test-compositor-surface-private.h"
+
+#include "cairo-clip-private.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-compositor-private.h"
+#include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-region-private.h"
+#include "cairo-traps-private.h"
+
+/* The intention is that this is a surface that just works, and most
+ * important of all does not try to be clever!
+ */
+
+typedef cairo_int_status_t
+(*draw_func_t) (cairo_image_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents);
+
+static pixman_op_t
+_pixman_operator (cairo_operator_t op)
+{
+ switch ((int) op) {
+ case CAIRO_OPERATOR_CLEAR:
+ return PIXMAN_OP_CLEAR;
+
+ case CAIRO_OPERATOR_SOURCE:
+ return PIXMAN_OP_SRC;
+ case CAIRO_OPERATOR_OVER:
+ return PIXMAN_OP_OVER;
+ case CAIRO_OPERATOR_IN:
+ return PIXMAN_OP_IN;
+ case CAIRO_OPERATOR_OUT:
+ return PIXMAN_OP_OUT;
+ case CAIRO_OPERATOR_ATOP:
+ return PIXMAN_OP_ATOP;
+
+ case CAIRO_OPERATOR_DEST:
+ return PIXMAN_OP_DST;
+ case CAIRO_OPERATOR_DEST_OVER:
+ return PIXMAN_OP_OVER_REVERSE;
+ case CAIRO_OPERATOR_DEST_IN:
+ return PIXMAN_OP_IN_REVERSE;
+ case CAIRO_OPERATOR_DEST_OUT:
+ return PIXMAN_OP_OUT_REVERSE;
+ case CAIRO_OPERATOR_DEST_ATOP:
+ return PIXMAN_OP_ATOP_REVERSE;
+
+ case CAIRO_OPERATOR_XOR:
+ return PIXMAN_OP_XOR;
+ case CAIRO_OPERATOR_ADD:
+ return PIXMAN_OP_ADD;
+ case CAIRO_OPERATOR_SATURATE:
+ return PIXMAN_OP_SATURATE;
+
+ case CAIRO_OPERATOR_MULTIPLY:
+ return PIXMAN_OP_MULTIPLY;
+ case CAIRO_OPERATOR_SCREEN:
+ return PIXMAN_OP_SCREEN;
+ case CAIRO_OPERATOR_OVERLAY:
+ return PIXMAN_OP_OVERLAY;
+ case CAIRO_OPERATOR_DARKEN:
+ return PIXMAN_OP_DARKEN;
+ case CAIRO_OPERATOR_LIGHTEN:
+ return PIXMAN_OP_LIGHTEN;
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ return PIXMAN_OP_COLOR_DODGE;
+ case CAIRO_OPERATOR_COLOR_BURN:
+ return PIXMAN_OP_COLOR_BURN;
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ return PIXMAN_OP_HARD_LIGHT;
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ return PIXMAN_OP_SOFT_LIGHT;
+ case CAIRO_OPERATOR_DIFFERENCE:
+ return PIXMAN_OP_DIFFERENCE;
+ case CAIRO_OPERATOR_EXCLUSION:
+ return PIXMAN_OP_EXCLUSION;
+ case CAIRO_OPERATOR_HSL_HUE:
+ return PIXMAN_OP_HSL_HUE;
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ return PIXMAN_OP_HSL_SATURATION;
+ case CAIRO_OPERATOR_HSL_COLOR:
+ return PIXMAN_OP_HSL_COLOR;
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
+ return PIXMAN_OP_HSL_LUMINOSITY;
+
+ default:
+ ASSERT_NOT_REACHED;
+ return PIXMAN_OP_OVER;
+ }
+}
+
+static void
+_pixman_image_add_boxes (pixman_image_t *image,
+ int dst_x, int dst_y,
+ cairo_box_t *box,
+ int count)
+{
+ while (count--) {
+ pixman_trapezoid_t trap;
+
+ trap.top = _cairo_fixed_to_16_16 (box->p1.y);
+ trap.bottom = _cairo_fixed_to_16_16 (box->p2.y);
+
+ trap.left.p1.x = _cairo_fixed_to_16_16 (box->p1.x);
+ trap.left.p1.y = _cairo_fixed_to_16_16 (box->p1.y);
+ trap.left.p2.x = _cairo_fixed_to_16_16 (box->p1.x);
+ trap.left.p2.y = _cairo_fixed_to_16_16 (box->p2.y);
+
+ trap.right.p1.x = _cairo_fixed_to_16_16 (box->p2.x);
+ trap.right.p1.y = _cairo_fixed_to_16_16 (box->p1.y);
+ trap.right.p2.x = _cairo_fixed_to_16_16 (box->p2.x);
+ trap.right.p2.y = _cairo_fixed_to_16_16 (box->p2.y);
+
+ pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
+ box++;
+ }
+}
+
+static cairo_status_t
+combine_in_boxes (cairo_image_surface_t *dst,
+ cairo_box_t *box, int count,
+ const cairo_rectangle_int_t *extents)
+{
+ pixman_image_t *mask;
+
+ mask = pixman_image_create_bits (PIXMAN_a8,
+ extents->width, extents->height,
+ NULL, 0);
+ if (unlikely (mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ _pixman_image_add_boxes (mask, extents->x, extents->y, box, count);
+ pixman_image_composite32 (PIXMAN_OP_IN,
+ mask, NULL, dst->pixman_image,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ extents->width, extents->height);
+ pixman_image_unref (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_image_surface_t *
+create_composite_mask (cairo_image_surface_t *dst,
+ void *draw_closure,
+ draw_func_t draw_func,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_image_surface_t *surface;
+ cairo_int_status_t status;
+
+ surface = (cairo_image_surface_t *)
+ _cairo_surface_create_similar_solid (&dst->base,
+ CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height,
+ CAIRO_COLOR_TRANSPARENT);
+ if (unlikely (surface->base.status))
+ return surface;
+
+ status = draw_func (surface, draw_closure,
+ CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base,
+ extents->bounded.x, extents->bounded.y,
+ &extents->bounded);
+ if (unlikely (status))
+ goto error;
+
+ if (extents->clip->boxes) {
+ status = combine_in_boxes (surface,
+ extents->clip->boxes,
+ extents->clip->num_boxes,
+ &extents->bounded);
+ if (unlikely (status))
+ goto error;
+ }
+
+ if (extents->clip->path) {
+ status = _cairo_clip_combine_with_surface (extents->clip,
+ &surface->base,
+ extents->bounded.x,
+ extents->bounded.y);
+ if (unlikely (status))
+ goto error;
+ }
+
+ return surface;
+
+error:
+ cairo_surface_destroy (&surface->base);
+ return (cairo_image_surface_t *)_cairo_surface_create_in_error (status);
+}
+
+/* Handles compositing with a clip surface when the operator allows
+ * us to combine the clip with the mask
+ */
+static cairo_status_t
+clip_and_composite_with_mask (const cairo_composite_rectangles_t*extents,
+ draw_func_t draw_func,
+ void *draw_closure)
+{
+ cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
+ cairo_image_surface_t *mask;
+ pixman_image_t *src;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ int src_x, src_y;
+
+ mask = create_composite_mask (dst, draw_closure, draw_func, extents);
+ if (unlikely (mask->base.status))
+ return mask->base.status;
+
+ src = _pixman_image_for_pattern (dst,
+ &extents->source_pattern.base, FALSE,
+ &extents->bounded,
+ &extents->source_sample_area,
+ &src_x, &src_y);
+ if (unlikely (src == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto error;
+ }
+
+ pixman_image_composite32 (_pixman_operator (extents->op),
+ src, mask->pixman_image, dst->pixman_image,
+ extents->bounded.x + src_x,
+ extents->bounded.y + src_y,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+
+ pixman_image_unref (src);
+error:
+ cairo_surface_destroy (&mask->base);
+ return status;
+}
+
+/* Handles compositing with a clip surface when we have to do the operation
+ * in two pieces and combine them together.
+ */
+static cairo_status_t
+clip_and_composite_combine (const cairo_composite_rectangles_t*extents,
+ draw_func_t draw_func,
+ void *draw_closure)
+{
+ cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
+ cairo_image_surface_t *tmp, *clip;
+ int clip_x, clip_y;
+ cairo_status_t status;
+
+ tmp = (cairo_image_surface_t *)
+ _cairo_surface_create_similar_solid (&dst->base, dst->base.content,
+ extents->bounded.width,
+ extents->bounded.height,
+ CAIRO_COLOR_TRANSPARENT);
+ if (unlikely (tmp->base.status))
+ return tmp->base.status;
+
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ dst->pixman_image, NULL, tmp->pixman_image,
+ extents->bounded.x, extents->bounded.y,
+ 0, 0,
+ 0, 0,
+ extents->bounded.width, extents->bounded.height);
+
+ status = draw_func (tmp, draw_closure,
+ extents->op, &extents->source_pattern.base,
+ extents->bounded.x, extents->bounded.y,
+ &extents->bounded);
+ if (unlikely (status))
+ goto error;
+
+ clip = (cairo_image_surface_t *)
+ _cairo_clip_get_surface (extents->clip, &dst->base, &clip_x, &clip_y);
+ if (unlikely (clip->base.status))
+ goto error;
+
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+ clip->pixman_image, NULL, dst->pixman_image,
+ extents->bounded.x - clip_x, extents->bounded.y - clip_y,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ pixman_image_composite32 (PIXMAN_OP_ADD,
+ tmp->pixman_image, clip->pixman_image, dst->pixman_image,
+ 0, 0,
+ extents->bounded.x - clip_x, extents->bounded.y - clip_y,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+
+ cairo_surface_destroy (&clip->base);
+
+ error:
+ cairo_surface_destroy (&tmp->base);
+
+ return status;
+}
+
+/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
+ * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
+ */
+static cairo_status_t
+clip_and_composite_source (const cairo_composite_rectangles_t *extents,
+ draw_func_t draw_func,
+ void *draw_closure)
+{
+ cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
+ cairo_image_surface_t *mask;
+ pixman_image_t *src;
+ int src_x, src_y;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ mask = create_composite_mask (dst, draw_closure, draw_func, extents);
+ if (unlikely (mask->base.status))
+ return mask->base.status;
+
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+ mask->pixman_image, NULL, dst->pixman_image,
+ 0, 0,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+
+ src = _pixman_image_for_pattern (dst,
+ &extents->source_pattern.base, FALSE,
+ &extents->bounded,
+ &extents->source_sample_area,
+ &src_x, &src_y);
+ if (unlikely (src == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto error;
+ }
+
+ pixman_image_composite32 (PIXMAN_OP_ADD,
+ src, mask->pixman_image, dst->pixman_image,
+ extents->bounded.x + src_x, extents->bounded.y + src_y,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+
+ pixman_image_unref (src);
+
+error:
+ cairo_surface_destroy (&mask->base);
+ return status;
+}
+
+static cairo_status_t
+fixup_unbounded (const cairo_composite_rectangles_t *extents)
+{
+ cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
+ pixman_image_t *mask;
+ int mask_x, mask_y;
+
+ if (! _cairo_clip_is_region (extents->clip)) {
+ cairo_surface_t *clip;
+
+ clip = _cairo_clip_get_surface (extents->clip, &dst->base,
+ &mask_x, &mask_y);
+ if (unlikely (clip->status))
+ return clip->status;
+
+ mask = pixman_image_ref (((cairo_image_surface_t *)clip)->pixman_image);
+ cairo_surface_destroy (clip);
+ } else {
+ mask_x = mask_y = 0;
+ mask = _pixman_image_for_color (CAIRO_COLOR_WHITE);
+ if (unlikely (mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ /* top */
+ if (extents->bounded.y != extents->unbounded.y) {
+ int x = extents->unbounded.x;
+ int y = extents->unbounded.y;
+ int width = extents->unbounded.width;
+ int height = extents->bounded.y - y;
+
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+ mask, NULL, dst->pixman_image,
+ x - mask_x, y - mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* left */
+ if (extents->bounded.x != extents->unbounded.x) {
+ int x = extents->unbounded.x;
+ int y = extents->bounded.y;
+ int width = extents->bounded.x - x;
+ int height = extents->bounded.height;
+
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+ mask, NULL, dst->pixman_image,
+ x - mask_x, y - mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* right */
+ if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
+ int x = extents->bounded.x + extents->bounded.width;
+ int y = extents->bounded.y;
+ int width = extents->unbounded.x + extents->unbounded.width - x;
+ int height = extents->bounded.height;
+
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+ mask, NULL, dst->pixman_image,
+ x - mask_x, y - mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* bottom */
+ if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
+ int x = extents->unbounded.x;
+ int y = extents->bounded.y + extents->bounded.height;
+ int width = extents->unbounded.width;
+ int height = extents->unbounded.y + extents->unbounded.height - y;
+
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+ mask, NULL, dst->pixman_image,
+ x - mask_x, y - mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ pixman_image_unref (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+set_clip_region (cairo_composite_rectangles_t *extents)
+{
+ cairo_image_surface_t *dst = (cairo_image_surface_t *) extents->surface;
+ cairo_region_t *region = _cairo_clip_get_region (extents->clip);
+ pixman_region32_t *rgn = region ? &region->rgn : NULL;
+ if (! pixman_image_set_clip_region32 (dst->pixman_image, rgn))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+clip_and_composite (cairo_composite_rectangles_t *extents,
+ draw_func_t draw_func,
+ void *draw_closure)
+{
+ cairo_status_t status;
+
+ status = set_clip_region (extents);
+ if (unlikely (status))
+ return status;
+
+ if (extents->op == CAIRO_OPERATOR_SOURCE) {
+ status = clip_and_composite_source (extents, draw_func, draw_closure);
+ } else {
+ if (extents->op == CAIRO_OPERATOR_CLEAR) {
+ extents->source_pattern.solid = _cairo_pattern_white;
+ extents->op = CAIRO_OPERATOR_DEST_OUT;
+ }
+ if (! _cairo_clip_is_region (extents->clip)) {
+ if (extents->is_bounded)
+ status = clip_and_composite_with_mask (extents, draw_func, draw_closure);
+ else
+ status = clip_and_composite_combine (extents, draw_func, draw_closure);
+ } else {
+ status = draw_func ((cairo_image_surface_t *) extents->surface,
+ draw_closure,
+ extents->op,
+ &extents->source_pattern.base,
+ 0, 0,
+ &extents->bounded);
+ }
+ }
+
+ if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
+ status = fixup_unbounded (extents);
+
+ return status;
+}
+
+/* high-level compositor interface */
+
+static cairo_int_status_t
+composite_paint (cairo_image_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_rectangle_int_t sample;
+ pixman_image_t *src;
+ int src_x, src_y;
+
+ _cairo_pattern_sampled_area (pattern, extents, &sample);
+ src = _pixman_image_for_pattern (dst,
+ pattern, FALSE,
+ extents, &sample,
+ &src_x, &src_y);
+ if (unlikely (src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ pixman_image_composite32 (_pixman_operator (op),
+ src, NULL, dst->pixman_image,
+ extents->x + src_x, extents->y + src_y,
+ 0, 0,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+
+ pixman_image_unref (src);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+base_compositor_paint (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ return clip_and_composite (extents, composite_paint, NULL);
+}
+
+static cairo_int_status_t
+composite_mask (cairo_image_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_rectangle_int_t sample;
+ pixman_image_t *src, *mask;
+ int src_x, src_y;
+ int mask_x, mask_y;
+
+ _cairo_pattern_sampled_area (pattern, extents, &sample);
+ src = _pixman_image_for_pattern (dst, pattern, FALSE,
+ extents, &sample,
+ &src_x, &src_y);
+ if (unlikely (src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ _cairo_pattern_sampled_area (closure, extents, &sample);
+ mask = _pixman_image_for_pattern (dst, closure, TRUE,
+ extents, &sample,
+ &mask_x, &mask_y);
+ if (unlikely (mask == NULL)) {
+ pixman_image_unref (src);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ pixman_image_composite32 (_pixman_operator (op),
+ src, mask, dst->pixman_image,
+ extents->x + src_x, extents->y + src_y,
+ extents->x + mask_x, extents->y + mask_y,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+
+ pixman_image_unref (mask);
+ pixman_image_unref (src);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+base_compositor_mask (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents)
+{
+ return clip_and_composite (extents, composite_mask, &extents->mask_pattern.base);
+}
+
+typedef struct {
+ cairo_traps_t traps;
+ cairo_antialias_t antialias;
+} composite_traps_info_t;
+
+#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
+#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
+
+static cairo_bool_t
+line_exceeds_16_16 (const cairo_line_t *line)
+{
+ return
+ line->p1.x <= CAIRO_FIXED_16_16_MIN ||
+ line->p1.x >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p2.x <= CAIRO_FIXED_16_16_MIN ||
+ line->p2.x >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p1.y <= CAIRO_FIXED_16_16_MIN ||
+ line->p1.y >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p2.y <= CAIRO_FIXED_16_16_MIN ||
+ line->p2.y >= CAIRO_FIXED_16_16_MAX;
+}
+
+static void
+project_line_x_onto_16_16 (const cairo_line_t *line,
+ cairo_fixed_t top,
+ cairo_fixed_t bottom,
+ pixman_line_fixed_t *out)
+{
+ /* XXX use fixed-point arithmetic? */
+ cairo_point_double_t p1, p2;
+ double m;
+
+ p1.x = _cairo_fixed_to_double (line->p1.x);
+ p1.y = _cairo_fixed_to_double (line->p1.y);
+
+ p2.x = _cairo_fixed_to_double (line->p2.x);
+ p2.y = _cairo_fixed_to_double (line->p2.y);
+
+ m = (p2.x - p1.x) / (p2.y - p1.y);
+ out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
+ out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
+}
+
+static void
+_pixman_image_add_traps (pixman_image_t *image,
+ int dst_x, int dst_y,
+ cairo_traps_t *traps)
+{
+ cairo_trapezoid_t *t = traps->traps;
+ int num_traps = traps->num_traps;
+ while (num_traps--) {
+ pixman_trapezoid_t trap;
+
+ /* top/bottom will be clamped to surface bounds */
+ trap.top = _cairo_fixed_to_16_16 (t->top);
+ trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
+
+ /* However, all the other coordinates will have been left untouched so
+ * as not to introduce numerical error. Recompute them if they
+ * exceed the 16.16 limits.
+ */
+ if (unlikely (line_exceeds_16_16 (&t->left))) {
+ project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
+ trap.left.p1.y = trap.top;
+ trap.left.p2.y = trap.bottom;
+ } else {
+ trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
+ trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
+ trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
+ trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
+ }
+
+ if (unlikely (line_exceeds_16_16 (&t->right))) {
+ project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
+ trap.right.p1.y = trap.top;
+ trap.right.p2.y = trap.bottom;
+ } else {
+ trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
+ trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
+ trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
+ trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
+ }
+
+ pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
+ t++;
+ }
+}
+
+static cairo_int_status_t
+composite_traps (cairo_image_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents)
+{
+ composite_traps_info_t *info = closure;
+ cairo_rectangle_int_t sample;
+ pixman_image_t *src, *mask;
+ int src_x, src_y;
+
+ _cairo_pattern_sampled_area (pattern, extents, &sample);
+ src = _pixman_image_for_pattern (dst, pattern, FALSE,
+ extents, &sample,
+ &src_x, &src_y);
+ if (unlikely (src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ mask = pixman_image_create_bits (info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8,
+ extents->width, extents->height,
+ NULL, 0);
+ if (unlikely (mask == NULL)) {
+ pixman_image_unref (src);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ _pixman_image_add_traps (mask, extents->x, extents->y, &info->traps);
+ pixman_image_composite32 (_pixman_operator (op),
+ src, mask, dst->pixman_image,
+ extents->x + src_x - dst_x, extents->y + src_y - dst_y,
+ 0, 0,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+
+ pixman_image_unref (mask);
+ pixman_image_unref (src);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+trim_extents_to_traps (cairo_composite_rectangles_t *extents,
+ cairo_traps_t *traps)
+{
+ cairo_box_t box;
+
+ /* X trims the affected area to the extents of the trapezoids, so
+ * we need to compensate when fixing up the unbounded area.
+ */
+ _cairo_traps_extents (traps, &box);
+ return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
+}
+
+static cairo_int_status_t
+base_compositor_stroke (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ composite_traps_info_t info;
+ cairo_int_status_t status;
+
+ info.antialias = antialias;
+ _cairo_traps_init_with_clip (&info.traps, extents->clip);
+ status = _cairo_path_fixed_stroke_to_traps (path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ &info.traps);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = trim_extents_to_traps (extents, &info.traps);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = clip_and_composite (extents, composite_traps, &info);
+ _cairo_traps_fini (&info.traps);
+
+ return status;
+}
+
+static cairo_int_status_t
+base_compositor_fill (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ composite_traps_info_t info;
+ cairo_int_status_t status;
+
+ info.antialias = antialias;
+ _cairo_traps_init_with_clip (&info.traps, extents->clip);
+ status = _cairo_path_fixed_fill_to_traps (path,
+ fill_rule, tolerance,
+ &info.traps);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = trim_extents_to_traps (extents, &info.traps);
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS))
+ status = clip_and_composite (extents, composite_traps, &info);
+ _cairo_traps_fini (&info.traps);
+
+ return status;
+}
+
+static cairo_int_status_t
+composite_glyphs (cairo_image_surface_t *dst,
+ void *closure,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_composite_glyphs_info_t *info = closure;
+ pixman_image_t *mask;
+ cairo_status_t status;
+ int i;
+
+ mask = pixman_image_create_bits (PIXMAN_a8,
+ extents->width, extents->height,
+ NULL, 0);
+ if (unlikely (mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ status = CAIRO_STATUS_SUCCESS;
+ _cairo_scaled_font_freeze_cache (info->font);
+ for (i = 0; i < info->num_glyphs; i++) {
+ cairo_image_surface_t *glyph_surface;
+ cairo_scaled_glyph_t *scaled_glyph;
+ unsigned long glyph_index = info->glyphs[i].index;
+ int x, y;
+
+ status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+
+ if (unlikely (status))
+ break;
+
+ glyph_surface = scaled_glyph->surface;
+ if (glyph_surface->width && glyph_surface->height) {
+ /* round glyph locations to the nearest pixel */
+ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+ x = _cairo_lround (info->glyphs[i].x -
+ glyph_surface->base.device_transform.x0);
+ y = _cairo_lround (info->glyphs[i].y -
+ glyph_surface->base.device_transform.y0);
+
+ pixman_image_composite32 (PIXMAN_OP_ADD,
+ glyph_surface->pixman_image, NULL, mask,
+ 0, 0,
+ 0, 0,
+ x - extents->x, y - extents->y,
+ glyph_surface->width,
+ glyph_surface->height);
+ }
+ }
+ _cairo_scaled_font_thaw_cache (info->font);
+
+ if (status == CAIRO_STATUS_SUCCESS) {
+ cairo_rectangle_int_t sample;
+ pixman_image_t *src;
+ int src_x, src_y;
+
+ _cairo_pattern_sampled_area (pattern, extents, &sample);
+ src = _pixman_image_for_pattern (dst, pattern, FALSE,
+ extents, &sample,
+ &src_x, &src_y);
+ if (src != NULL) {
+ dst_x = extents->x - dst_x;
+ dst_y = extents->y - dst_y;
+ pixman_image_composite32 (_pixman_operator (op),
+ src, mask, dst->pixman_image,
+ src_x + dst_x, src_y + dst_y,
+ 0, 0,
+ dst_x, dst_y,
+ extents->width, extents->height);
+ pixman_image_unref (src);
+ } else
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ pixman_image_unref (mask);
+
+ return status;
+}
+
+static cairo_int_status_t
+base_compositor_glyphs (const cairo_compositor_t *_compositor,
+ cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_bool_t overlap)
+{
+ cairo_composite_glyphs_info_t info;
+
+ info.font = scaled_font;
+ info.glyphs = glyphs;
+ info.num_glyphs = num_glyphs;
+
+ return clip_and_composite (extents, composite_glyphs, &info);
+}
+
+static const cairo_compositor_t base_compositor = {
+ &__cairo_no_compositor,
+
+ base_compositor_paint,
+ base_compositor_mask,
+ base_compositor_stroke,
+ base_compositor_fill,
+ base_compositor_glyphs,
+};
+
+cairo_surface_t *
+_cairo_test_base_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height)
+{
+ return test_compositor_surface_create (&base_compositor,
+ content, width, height);
+}
diff --git a/src/test-wrapping-surface.h b/src/test-compositor-surface-private.h
index 4c1e28d7..47e2a432 100644
--- a/src/test-wrapping-surface.h
+++ b/src/test-compositor-surface-private.h
@@ -1,7 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2005 Red Hat, Inc
- * Copyright © 2009 Chris Wilson
+ * Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -28,24 +27,27 @@
*
* The Original Code is the cairo graphics library.
*
- * The Initial Developer of the Original Code is Red Hat, Inc.
+ * The Initial Developer of the Original Code is Intel Corporation
*
* Contributor(s):
- * Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
-#ifndef TEST_WRAPPING_SURFACE_H
-#define TEST_WRAPPING_SURFACE_H
+#ifndef TEST_COMPOSITOR_SURFACE_PRIVATE_H
+#define TEST_COMPOSITOR_SURFACE_PRIVATE_H
#include "cairo.h"
+#include "test-compositor-surface.h"
+
CAIRO_BEGIN_DECLS
-cairo_surface_t *
-_cairo_test_wrapping_surface_create (cairo_surface_t *target);
+cairo_private cairo_surface_t *
+test_compositor_surface_create (const cairo_compositor_t *compositor,
+ cairo_content_t content,
+ int width,
+ int height);
CAIRO_END_DECLS
-#endif /* TEST_WRAPPING_SURFACE_H */
-
+#endif /* TEST_COMPOSITOR_SURFACE_PRIVATE H */
diff --git a/src/test-compositor-surface.c b/src/test-compositor-surface.c
new file mode 100644
index 00000000..356c16c6
--- /dev/null
+++ b/src/test-compositor-surface.c
@@ -0,0 +1,259 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Intel Corporation
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "test-compositor-surface-private.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-surface-backend-private.h"
+
+typedef struct _test_compositor_surface {
+ cairo_image_surface_t base;
+} test_compositor_surface_t;
+
+static const cairo_surface_backend_t test_compositor_surface_backend;
+
+cairo_surface_t *
+test_compositor_surface_create (const cairo_compositor_t *compositor,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ test_compositor_surface_t *surface;
+ pixman_image_t *pixman_image;
+ pixman_format_code_t pixman_format;
+
+ switch (content) {
+ case CAIRO_CONTENT_ALPHA:
+ pixman_format = PIXMAN_a8;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ pixman_format = PIXMAN_x8r8g8b8;
+ break;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ pixman_format = PIXMAN_a8r8g8b8;
+ break;
+ default:
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
+ }
+
+ pixman_image = pixman_image_create_bits (pixman_format, width, height,
+ NULL, 0);
+ if (unlikely (pixman_image == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ surface = malloc (sizeof (test_compositor_surface_t));
+ if (unlikely (surface == NULL)) {
+ pixman_image_unref (pixman_image);
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ _cairo_surface_init (&surface->base.base,
+ &test_compositor_surface_backend,
+ NULL, /* device */
+ content);
+ _cairo_image_surface_init (&surface->base, pixman_image, pixman_format);
+
+ surface->base.compositor = compositor;
+
+ return &surface->base.base;
+}
+
+static cairo_surface_t *
+test_compositor_surface_create_similar (void *abstract_surface,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ test_compositor_surface_t *surface = abstract_surface;
+
+ return test_compositor_surface_create (surface->base.compositor,
+ content, width, height);
+}
+
+static cairo_int_status_t
+test_compositor_surface_paint (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_clip_t *clip)
+{
+ test_compositor_surface_t *surface = _surface;
+ return _cairo_compositor_paint (surface->base.compositor,
+ _surface, op, source,
+ clip);
+}
+
+static cairo_int_status_t
+test_compositor_surface_mask (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ const cairo_clip_t *clip)
+{
+ test_compositor_surface_t *surface = _surface;
+ return _cairo_compositor_mask (surface->base.compositor,
+ _surface, op, source, mask,
+ clip);
+}
+
+static cairo_int_status_t
+test_compositor_surface_stroke (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
+{
+ test_compositor_surface_t *surface = _surface;
+ return _cairo_compositor_stroke (surface->base.compositor,
+ _surface, op, source,
+ path, style, ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
+}
+
+static cairo_int_status_t
+test_compositor_surface_fill (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
+{
+ test_compositor_surface_t *surface = _surface;
+ return _cairo_compositor_fill (surface->base.compositor,
+ _surface, op, source,
+ path, fill_rule, tolerance, antialias,
+ clip);
+}
+
+static cairo_int_status_t
+test_compositor_surface_glyphs (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ const cairo_clip_t *clip)
+{
+ test_compositor_surface_t *surface = _surface;
+ return _cairo_compositor_glyphs (surface->base.compositor,
+ _surface, op, source,
+ glyphs, num_glyphs, scaled_font,
+ clip);
+}
+
+static const cairo_surface_backend_t test_compositor_surface_backend = {
+ CAIRO_SURFACE_TYPE_IMAGE,
+ _cairo_image_surface_finish,
+ _cairo_default_context_create,
+
+ test_compositor_surface_create_similar,
+ NULL, /* create similar image */
+ _cairo_image_surface_map_to_image,
+ _cairo_image_surface_unmap_image,
+
+ _cairo_image_surface_acquire_source_image,
+ _cairo_image_surface_release_source_image,
+ _cairo_image_surface_snapshot,
+
+ NULL, /* copy_page */
+ NULL, /* show_page */
+
+ _cairo_image_surface_get_extents,
+ _cairo_image_surface_get_font_options,
+
+ NULL, /* flush */
+ NULL, /* mark_dirty_rectangle */
+
+ test_compositor_surface_paint,
+ test_compositor_surface_mask,
+ test_compositor_surface_stroke,
+ test_compositor_surface_fill,
+ NULL, /* fill/stroke */
+ test_compositor_surface_glyphs,
+};
+
+static const cairo_compositor_t *
+get_fallback_compositor (void)
+{
+ return &_cairo_fallback_compositor;
+}
+
+cairo_surface_t *
+_cairo_test_fallback_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height)
+{
+ return test_compositor_surface_create (get_fallback_compositor(),
+ content, width, height);
+}
+
+cairo_surface_t *
+_cairo_test_mask_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height)
+{
+ return test_compositor_surface_create (_cairo_image_mask_compositor_get(),
+ content, width, height);
+}
+
+cairo_surface_t *
+_cairo_test_traps_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height)
+{
+ return test_compositor_surface_create (_cairo_image_traps_compositor_get(),
+ content, width, height);
+}
+
+cairo_surface_t *
+_cairo_test_spans_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height)
+{
+ return test_compositor_surface_create (_cairo_image_spans_compositor_get(),
+ content, width, height);
+}
diff --git a/src/test-fallback-surface.h b/src/test-compositor-surface.h
index e7071511..8d8af2d5 100644
--- a/src/test-fallback-surface.h
+++ b/src/test-compositor-surface.h
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -27,24 +27,45 @@
*
* The Original Code is the cairo graphics library.
*
- * The Initial Developer of the Original Code is Red Hat, Inc.
+ * The Initial Developer of the Original Code is Intel Corporation
*
* Contributor(s):
- * Carl Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
*/
-#ifndef TEST_FALLBACK_SURFACE_H
-#define TEST_FALLBACK_SURFACE_H
+#ifndef TEST_COMPOSITOR_SURFACE_H
+#define TEST_COMPOSITOR_SURFACE_H
#include "cairo.h"
CAIRO_BEGIN_DECLS
cairo_surface_t *
-_cairo_test_fallback_surface_create (cairo_content_t content,
- int width,
- int height);
+_cairo_test_fallback_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height);
+
+
+cairo_surface_t *
+_cairo_test_mask_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height);
+
+cairo_surface_t *
+_cairo_test_traps_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height);
+
+cairo_surface_t *
+_cairo_test_spans_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height);
+
+cairo_surface_t *
+_cairo_test_base_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height);
CAIRO_END_DECLS
-#endif /* TEST_FALLBACK_SURFACE_H */
+#endif /* TEST_COMPOSITOR_SURFACE_H */
diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c
deleted file mode 100644
index 1dce221d..00000000
--- a/src/test-fallback-surface.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * 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>
- */
-
-/* This isn't a "real" surface, but just something to be used by the
- * test suite to test a mythical backend that uses nothing but
- * fallbacks.
- *
- * The defining feature of this backend is that it has as many %NULL
- * backend function entries as possible. The ones that aren't %NULL are
- * simply those that must be implemented to have working fallbacks.
- * (Except for create_similar---fallbacks would work fine without
- * that---I implemented it here in order to create as many surfaces as
- * possible of type test_fallback_surface_t during the test suite
- * run).
- *
- * It's possible that this code might serve as a good starting point
- * for someone working on bringing up a new backend, starting with the
- * minimal all-fallbacks approach and working up gradually from
- * there.
- */
-
-#include "cairoint.h"
-
-#include "test-fallback-surface.h"
-#include "cairo-default-context-private.h"
-#include "cairo-error-private.h"
-
-typedef struct _test_fallback_surface {
- cairo_surface_t base;
-
- /* This is a cairo_image_surface to hold the actual contents. */
- cairo_surface_t *backing;
-} test_fallback_surface_t;
-
-static const cairo_surface_backend_t test_fallback_surface_backend;
-
-slim_hidden_proto (_cairo_test_fallback_surface_create);
-
-cairo_surface_t *
-_cairo_test_fallback_surface_create (cairo_content_t content,
- int width,
- int height)
-{
- test_fallback_surface_t *surface;
- cairo_surface_t *backing;
-
- backing = _cairo_image_surface_create_with_content (content, width, height);
- if (cairo_surface_status (backing))
- return backing;
-
- surface = malloc (sizeof (test_fallback_surface_t));
- if (unlikely (surface == NULL)) {
- cairo_surface_destroy (backing);
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- }
-
- _cairo_surface_init (&surface->base,
- &test_fallback_surface_backend,
- NULL, /* device */
- content);
-
- surface->backing = backing;
-
- return &surface->base;
-}
-slim_hidden_def (_cairo_test_fallback_surface_create);
-
-static cairo_surface_t *
-_test_fallback_surface_create_similar (void *abstract_surface,
- cairo_content_t content,
- int width,
- int height)
-{
- assert (CAIRO_CONTENT_VALID (content));
-
- return _cairo_test_fallback_surface_create (content,
- width, height);
-}
-
-static cairo_status_t
-_test_fallback_surface_finish (void *abstract_surface)
-{
- test_fallback_surface_t *surface = abstract_surface;
-
- cairo_surface_destroy (surface->backing);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_test_fallback_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- test_fallback_surface_t *surface = abstract_surface;
-
- return _cairo_surface_acquire_source_image (surface->backing,
- image_out, image_extra);
-}
-
-static void
-_test_fallback_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- test_fallback_surface_t *surface = abstract_surface;
-
- _cairo_surface_release_source_image (surface->backing,
- image, image_extra);
-}
-
-static cairo_status_t
-_test_fallback_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect_out,
- void **image_extra)
-{
- test_fallback_surface_t *surface = abstract_surface;
-
- return _cairo_surface_acquire_dest_image (surface->backing,
- interest_rect,
- image_out,
- image_rect_out,
- image_extra);
-}
-
-static void
-_test_fallback_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
-{
- test_fallback_surface_t *surface = abstract_surface;
-
- _cairo_surface_release_dest_image (surface->backing,
- interest_rect,
- image,
- image_rect,
- image_extra);
-}
-
-static cairo_status_t
-_test_fallback_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
-{
- test_fallback_surface_t *surface = abstract_surface;
-
- if (src->backend == surface->base.backend) {
- *clone_offset_x = 0;
- *clone_offset_y = 0;
- *clone_out = cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_bool_t
-_test_fallback_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *rectangle)
-{
- test_fallback_surface_t *surface = abstract_surface;
-
- return _cairo_surface_get_extents (surface->backing, rectangle);
-}
-
-static const cairo_surface_backend_t test_fallback_surface_backend = {
- CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
- _test_fallback_surface_finish,
- _cairo_default_context_create,
-
- _test_fallback_surface_create_similar,
- NULL, /* create similar image */
- NULL, /* map_to_image */
- NULL, /* unmap_image */
-
- _test_fallback_surface_acquire_source_image,
- _test_fallback_surface_release_source_image,
- _test_fallback_surface_acquire_dest_image,
- _test_fallback_surface_release_dest_image,
- _test_fallback_surface_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_fallback_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 */
- NULL, /* paint */
- NULL, /* mask */
- NULL, /* stroke */
- NULL, /* fill */
- NULL, /* show_glyphs */
- NULL /* snapshot */
-};
diff --git a/src/test-fallback16-surface.c b/src/test-fallback16-surface.c
deleted file mode 100644
index 5ec501a0..00000000
--- a/src/test-fallback16-surface.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * 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>
- */
-
-/* This isn't a "real" surface, but just something to be used by the
- * test suite to force use of a non-standard pixman image fallback - as
- * may be exposed by xlib fallbacks with weird xservers, for example.
- */
-
-#include "cairoint.h"
-
-#include "test-fallback16-surface.h"
-#include "cairo-default-context-private.h"
-#include "cairo-error-private.h"
-
-typedef struct _test_fallback16_surface {
- cairo_surface_t base;
-
- /* This is a cairo_image_surface to hold the actual contents. */
- cairo_surface_t *backing;
-} test_fallback16_surface_t;
-
-static const cairo_surface_backend_t test_fallback16_surface_backend;
-
-slim_hidden_proto (_cairo_test_fallback16_surface_create);
-
-cairo_surface_t *
-_cairo_test_fallback16_surface_create (cairo_content_t content,
- int width,
- int height)
-{
- test_fallback16_surface_t *surface;
- cairo_surface_t *backing;
- pixman_format_code_t format;
-
- format = content & CAIRO_CONTENT_ALPHA ? PIXMAN_a1r5g5b5: PIXMAN_r5g6b5;
-
- backing = _cairo_image_surface_create_with_pixman_format (NULL, format,
- width, height,
- -1);
- if (cairo_surface_status (backing))
- return backing;
-
- surface = malloc (sizeof (test_fallback16_surface_t));
- if (unlikely (surface == NULL)) {
- cairo_surface_destroy (backing);
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- }
-
- _cairo_surface_init (&surface->base,
- &test_fallback16_surface_backend,
- NULL, /* device */
- content);
-
- surface->backing = backing;
-
- return &surface->base;
-}
-slim_hidden_def (_cairo_test_fallback16_surface_create);
-
-static cairo_surface_t *
-_test_fallback16_surface_create_similar (void *abstract_surface,
- cairo_content_t content,
- int width,
- int height)
-{
- assert (CAIRO_CONTENT_VALID (content));
-
- return _cairo_test_fallback16_surface_create (content, width, height);
-}
-
-static cairo_status_t
-_test_fallback16_surface_finish (void *abstract_surface)
-{
- test_fallback16_surface_t *surface = abstract_surface;
-
- cairo_surface_destroy (surface->backing);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_test_fallback16_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- test_fallback16_surface_t *surface = abstract_surface;
-
- return _cairo_surface_acquire_source_image (surface->backing,
- image_out, image_extra);
-}
-
-static void
-_test_fallback16_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- test_fallback16_surface_t *surface = abstract_surface;
-
- _cairo_surface_release_source_image (surface->backing,
- image, image_extra);
-}
-
-static cairo_status_t
-_test_fallback16_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect_out,
- void **image_extra)
-{
- test_fallback16_surface_t *surface = abstract_surface;
-
- return _cairo_surface_acquire_dest_image (surface->backing,
- interest_rect,
- image_out,
- image_rect_out,
- image_extra);
-}
-
-static void
-_test_fallback16_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
-{
- test_fallback16_surface_t *surface = abstract_surface;
-
- _cairo_surface_release_dest_image (surface->backing,
- interest_rect,
- image,
- image_rect,
- image_extra);
-}
-
-static cairo_status_t
-_test_fallback16_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
-{
- test_fallback16_surface_t *surface = abstract_surface;
-
- if (src->backend == surface->base.backend) {
- *clone_offset_x = 0;
- *clone_offset_y = 0;
- *clone_out = cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- } else {
- return _cairo_surface_clone_similar (surface->backing, src,
- src_x, src_y,
- width, height,
- clone_offset_x, clone_offset_y,
- clone_out);
- }
-}
-
-static cairo_bool_t
-_test_fallback16_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *rectangle)
-{
- test_fallback16_surface_t *surface = abstract_surface;
-
- return _cairo_surface_get_extents (surface->backing, rectangle);
-}
-
-static const cairo_surface_backend_t test_fallback16_surface_backend = {
- CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
- _test_fallback16_surface_finish,
- _cairo_default_context_create,
-
- _test_fallback16_surface_create_similar,
- NULL, /* create similar image */
- NULL, /* map to image */
- NULL, /* unmap image */
-
- _test_fallback16_surface_acquire_source_image,
- _test_fallback16_surface_release_source_image,
- _test_fallback16_surface_acquire_dest_image,
- _test_fallback16_surface_release_dest_image,
- _test_fallback16_surface_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_fallback16_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 */
- NULL, /* paint */
- NULL, /* mask */
- NULL, /* stroke */
- NULL, /* fill */
- NULL, /* show_glyphs */
- NULL /* snapshot */
-};
diff --git a/src/test-null-compositor-surface.c b/src/test-null-compositor-surface.c
new file mode 100644
index 00000000..021dfe75
--- /dev/null
+++ b/src/test-null-compositor-surface.c
@@ -0,0 +1,480 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2011 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Intel Corporation
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+
+#include "cairoint.h"
+
+#include "test-null-compositor-surface.h"
+
+#include "cairo-compositor-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-error-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-surface-backend-private.h"
+#include "cairo-spans-compositor-private.h"
+#include "cairo-spans-private.h"
+
+typedef struct _test_compositor_surface {
+ cairo_image_surface_t base;
+} test_compositor_surface_t;
+
+static const cairo_surface_backend_t test_compositor_surface_backend;
+
+static cairo_surface_t *
+test_compositor_surface_create (const cairo_compositor_t *compositor,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ test_compositor_surface_t *surface;
+ pixman_image_t *pixman_image;
+ pixman_format_code_t pixman_format;
+
+ switch (content) {
+ case CAIRO_CONTENT_ALPHA:
+ pixman_format = PIXMAN_a8;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ pixman_format = PIXMAN_x8r8g8b8;
+ break;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ pixman_format = PIXMAN_a8r8g8b8;
+ break;
+ default:
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
+ }
+
+ pixman_image = pixman_image_create_bits (pixman_format, width, height,
+ NULL, 0);
+ if (unlikely (pixman_image == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ surface = malloc (sizeof (test_compositor_surface_t));
+ if (unlikely (surface == NULL)) {
+ pixman_image_unref (pixman_image);
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ _cairo_surface_init (&surface->base.base,
+ &test_compositor_surface_backend,
+ NULL, /* device */
+ content);
+ _cairo_image_surface_init (&surface->base, pixman_image, pixman_format);
+
+ surface->base.compositor = compositor;
+
+ return &surface->base.base;
+}
+
+static cairo_surface_t *
+test_compositor_surface_create_similar (void *abstract_surface,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ test_compositor_surface_t *surface = abstract_surface;
+
+ return test_compositor_surface_create (surface->base.compositor,
+ content, width, height);
+}
+
+static cairo_int_status_t
+test_compositor_surface_paint (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_clip_t *clip)
+{
+ test_compositor_surface_t *surface = _surface;
+ return _cairo_compositor_paint (surface->base.compositor,
+ _surface, op, source,
+ clip);
+}
+
+static cairo_int_status_t
+test_compositor_surface_mask (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ const cairo_clip_t *clip)
+{
+ test_compositor_surface_t *surface = _surface;
+ return _cairo_compositor_mask (surface->base.compositor,
+ _surface, op, source, mask,
+ clip);
+}
+
+static cairo_int_status_t
+test_compositor_surface_stroke (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
+{
+ test_compositor_surface_t *surface = _surface;
+ return _cairo_compositor_stroke (surface->base.compositor,
+ _surface, op, source,
+ path, style, ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
+}
+
+static cairo_int_status_t
+test_compositor_surface_fill (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
+{
+ test_compositor_surface_t *surface = _surface;
+ return _cairo_compositor_fill (surface->base.compositor,
+ _surface, op, source,
+ path, fill_rule, tolerance, antialias,
+ clip);
+}
+
+static cairo_int_status_t
+test_compositor_surface_glyphs (void *_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ const cairo_clip_t *clip)
+{
+ test_compositor_surface_t *surface = _surface;
+ return _cairo_compositor_glyphs (surface->base.compositor,
+ _surface, op, source,
+ glyphs, num_glyphs, scaled_font,
+ clip);
+}
+
+static const cairo_surface_backend_t test_compositor_surface_backend = {
+ CAIRO_SURFACE_TYPE_IMAGE,
+ _cairo_image_surface_finish,
+ _cairo_default_context_create,
+
+ test_compositor_surface_create_similar,
+ NULL, /* create similar image */
+ _cairo_image_surface_map_to_image,
+ _cairo_image_surface_unmap_image,
+
+ _cairo_image_surface_acquire_source_image,
+ _cairo_image_surface_release_source_image,
+ NULL, /* snapshot */
+
+ NULL, /* copy_page */
+ NULL, /* show_page */
+
+ _cairo_image_surface_get_extents,
+ _cairo_image_surface_get_font_options,
+
+ NULL, /* flush */
+ NULL, /* mark_dirty_rectangle */
+
+ test_compositor_surface_paint,
+ test_compositor_surface_mask,
+ test_compositor_surface_stroke,
+ test_compositor_surface_fill,
+ NULL, /* fill/stroke */
+ test_compositor_surface_glyphs,
+};
+
+static cairo_int_status_t
+acquire (void *abstract_dst)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+release (void *abstract_dst)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+set_clip_region (void *_surface,
+ cairo_region_t *region)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+has_snapshot (void *_dst,
+ const cairo_pattern_t *pattern)
+{
+ return FALSE;
+}
+
+static cairo_surface_t *
+pattern_to_surface (cairo_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_bool_t is_mask,
+ const cairo_rectangle_int_t *extents,
+ const cairo_rectangle_int_t *sample,
+ int *src_x, int *src_y)
+{
+ return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
+}
+
+static cairo_int_status_t
+fill_boxes (void *_dst,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+draw_image_boxes (void *_dst,
+ cairo_image_surface_t *image,
+ cairo_boxes_t *boxes,
+ int dx, int dy)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+lerp (void *_dst,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_boxes (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ cairo_surface_t *abstract_mask,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ cairo_boxes_t *boxes,
+ const cairo_rectangle_int_t *extents)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_traps (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *abstract_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_antialias_t antialias,
+ cairo_traps_t *traps)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+check_composite_glyphs (const cairo_composite_rectangles_t *extents,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int *num_glyphs)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_glyphs (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+finish_spans (void *abstract_renderer)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+span_renderer_init (cairo_abstract_span_renderer_t *_r,
+ const cairo_composite_rectangles_t *composite,
+ cairo_bool_t needs_clip)
+{
+ cairo_span_renderer_t *r = (cairo_span_renderer_t *)_r;
+ r->render_rows = spans;
+ r->finish = finish_spans;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+span_renderer_fini (cairo_abstract_span_renderer_t *_r,
+ cairo_int_status_t status)
+{
+}
+
+static const cairo_compositor_t *
+no_fallback_compositor_get (void)
+{
+ return &__cairo_no_compositor;
+}
+
+static const cairo_compositor_t *
+no_traps_compositor_get (void)
+{
+ static cairo_traps_compositor_t compositor;
+
+ if (compositor.base.delegate == NULL) {
+ _cairo_traps_compositor_init (&compositor,
+ no_fallback_compositor_get ());
+
+ compositor.acquire = acquire;
+ compositor.release = release;
+ compositor.set_clip_region = set_clip_region;
+ compositor.pattern_to_surface = pattern_to_surface;
+ compositor.has_snapshot = has_snapshot;
+ compositor.draw_image_boxes = draw_image_boxes;
+ //compositor.copy_boxes = copy_boxes;
+ compositor.fill_boxes = fill_boxes;
+ //compositor.check_composite = check_composite;
+ compositor.composite = composite;
+ compositor.lerp = lerp;
+ //compositor.check_composite_boxes = check_composite_boxes;
+ compositor.composite_boxes = composite_boxes;
+ //compositor.check_composite_traps = check_composite_traps;
+ compositor.composite_traps = composite_traps;
+ compositor.check_composite_glyphs = check_composite_glyphs;
+ compositor.composite_glyphs = composite_glyphs;
+ }
+
+ return &compositor.base;
+}
+
+static const cairo_compositor_t *
+no_spans_compositor_get (void)
+{
+ static cairo_spans_compositor_t compositor;
+
+ if (compositor.base.delegate == NULL) {
+ _cairo_spans_compositor_init (&compositor,
+ no_traps_compositor_get());
+
+ //compositor.acquire = acquire;
+ //compositor.release = release;
+ compositor.fill_boxes = fill_boxes;
+ //compositor.check_composite_boxes = check_composite_boxes;
+ compositor.composite_boxes = composite_boxes;
+ //compositor.check_span_renderer = check_span_renderer;
+ compositor.renderer_init = span_renderer_init;
+ compositor.renderer_fini = span_renderer_fini;
+ }
+
+ return &compositor.base;
+}
+
+cairo_surface_t *
+_cairo_test_no_fallback_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height)
+{
+ return test_compositor_surface_create (no_fallback_compositor_get(),
+ content, width, height);
+}
+
+cairo_surface_t *
+_cairo_test_no_traps_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height)
+{
+ return test_compositor_surface_create (no_traps_compositor_get(),
+ content, width, height);
+}
+
+cairo_surface_t *
+_cairo_test_no_spans_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height)
+{
+ return test_compositor_surface_create (no_spans_compositor_get(),
+ content, width, height);
+}
diff --git a/src/test-fallback16-surface.h b/src/test-null-compositor-surface.h
index 51a78d30..52d864b2 100644
--- a/src/test-fallback16-surface.h
+++ b/src/test-null-compositor-surface.h
@@ -1,7 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2005 Red Hat, Inc
- * Copyright © 2009 Chris Wilson
+ * Copyright © 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -28,25 +27,34 @@
*
* The Original Code is the cairo graphics library.
*
- * The Initial Developer of the Original Code is Red Hat, Inc.
+ * The Initial Developer of the Original Code is Intel Corporation
*
* Contributor(s):
- * Carl Worth <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
-#ifndef TEST_FALLBACK16_SURFACE_H
-#define TEST_FALLBACK16_SURFACE_H
+#ifndef TEST_NULL_COMPOSITOR_SURFACE_H
+#define TEST_NULL_COMPOSITOR_SURFACE_H
#include "cairo.h"
CAIRO_BEGIN_DECLS
cairo_surface_t *
-_cairo_test_fallback16_surface_create (cairo_content_t content,
- int width,
- int height);
+_cairo_test_no_fallback_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height);
+
+cairo_surface_t *
+_cairo_test_no_traps_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height);
+
+cairo_surface_t *
+_cairo_test_no_spans_compositor_surface_create (cairo_content_t content,
+ int width,
+ int height);
CAIRO_END_DECLS
-#endif /* TEST_FALLBACK16_SURFACE_H */
+#endif /* TEST_NULL_COMPOSITOR_SURFACE_H */
diff --git a/src/test-null-surface.c b/src/test-null-surface.c
deleted file mode 100644
index 1eae89c1..00000000
--- a/src/test-null-surface.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * Contributor(s):
- * Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-/* This isn't a "real" surface, but just something to be used by the
- * test suite to test a mythical backend that does nothing, i.e. it
- * solely useful for measuring the overhead of the cairo public API.
- */
-
-#include "cairoint.h"
-
-#include "test-null-surface.h"
-
-#include "cairo-default-context-private.h"
-#include "cairo-error-private.h"
-
-slim_hidden_proto (_cairo_test_null_surface_create);
-
-static cairo_int_status_t
-_return_success (void)
-{
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* These typedefs are just to silence the compiler... */
-typedef cairo_int_status_t
-(*_paint_func) (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const 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,
- const cairo_clip_t *clip);
-
-typedef cairo_int_status_t
-(*_stroke_func) (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip);
-
-typedef cairo_int_status_t
-(*_fill_func) (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t*path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip);
-
-typedef cairo_int_status_t
-(*_show_glyphs_func) (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs);
-
-typedef cairo_int_status_t
-(*_show_text_glyphs_func) (void *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,
- const cairo_clip_t *clip);
-
-static cairo_surface_t *
-_cairo_null_surface_create_similar (void *other,
- cairo_content_t content,
- int width, int height)
-{
- return _cairo_test_null_surface_create (content);
-}
-
-static cairo_bool_t
-_cairo_null_surface_get_extents (void *surface,
- cairo_rectangle_int_t *extents)
-{
- return FALSE;
-}
-
-static cairo_bool_t
-_cairo_null_surface_has_show_text_glyphs (void *surface)
-{
- return TRUE;
-}
-
-static const cairo_surface_backend_t null_surface_backend = {
- CAIRO_INTERNAL_SURFACE_TYPE_NULL,
- NULL, /* finish */
- _cairo_default_context_create,
-
- _cairo_null_surface_create_similar,
- NULL, /* create similar image */
- NULL, /* map_to_image */
- NULL, /* unmap image */
-
- NULL, /* acquire_source_image */
- NULL, /* release_source_image */
- NULL, /* acquire_dest_image */
- NULL, /* 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 */
- _cairo_null_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 */
- (_paint_func) _return_success, /* paint */
- (_mask_func) _return_success, /* mask */
- (_stroke_func) _return_success, /* stroke */
- (_fill_func) _return_success, /* fill */
- (_show_glyphs_func) _return_success, /* show_glyphs */
- NULL, /* snapshot */
- NULL, /* is_similar */
- NULL, /* fill_stroke */
- NULL, /* create_solid_pattern_surface */
- NULL, /* can_repaint_solid_pattern_surface */
- _cairo_null_surface_has_show_text_glyphs,
- (_show_text_glyphs_func) _return_success, /* show_text_glyphs */
-};
-
-cairo_surface_t *
-_cairo_test_null_surface_create (cairo_content_t content)
-{
- cairo_surface_t *surface;
-
- surface = malloc (sizeof (cairo_surface_t));
- if (unlikely (surface == NULL)) {
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- }
-
- _cairo_surface_init (surface,
- &null_surface_backend,
- NULL, /* device */
- content);
-
- return surface;
-}
-slim_hidden_def (_cairo_test_null_surface_create);
diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c
index 1e95c5fc..e3c8a917 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -52,6 +52,7 @@
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-paginated-private.h"
+#include "cairo-surface-backend-private.h"
typedef struct _test_paginated_surface {
cairo_surface_t base;
@@ -254,23 +255,16 @@ static const cairo_surface_backend_t test_paginated_surface_backend = {
NULL, /* acquire_source_image */
NULL, /* release_source_image */
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- NULL, /* composite */
- NULL, /* fill_rectangles */
- NULL, /* composite_trapezoids */
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ NULL, /* snapshot */
+
NULL, /* copy_page */
NULL, /* show_page */
+
_test_paginated_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 */
/* Here is the more "modern" section of the surface backend
* interface which is mostly just drawing functions */
@@ -279,14 +273,8 @@ static const cairo_surface_backend_t test_paginated_surface_backend = {
_test_paginated_surface_mask,
_test_paginated_surface_stroke,
_test_paginated_surface_fill,
+ NULL, /* fill-stroke */
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_paginated_surface_has_show_text_glyphs,
_test_paginated_surface_show_text_glyphs
};
diff --git a/src/test-wrapping-surface.c b/src/test-wrapping-surface.c
deleted file mode 100644
index 7552886b..00000000
--- a/src/test-wrapping-surface.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/* 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * 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-default-context-private.h"
-#include "cairo-error-private.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,
- NULL, /* device */
- 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,
- const 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,
- const 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,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- 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,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const 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,
- const 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_finish,
- _cairo_default_context_create,
-
- _test_wrapping_surface_create_similar,
- NULL, /* create similar image */
- NULL, /* map to image */
- NULL, /* unmap image */
-
- _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/test/Makefile.refs b/test/Makefile.refs
index b09f7810..68f721ac 100644
--- a/test/Makefile.refs
+++ b/test/Makefile.refs
@@ -6,6 +6,8 @@ REFERENCE_IMAGES = \
a1-bug.ref.png \
a1-bug.xlib.ref.png \
a1-clip-fill-equal.ref.png \
+ a1-clip-fill-rule.argb32.ref.png \
+ a1-clip-fill-rule.rgb24.ref.png \
a1-clip-fill.ref.png \
a1-clip-paint.ref.png \
a1-clip-stroke.ref.png \
@@ -18,6 +20,7 @@ REFERENCE_IMAGES = \
a1-rasterisation-rectangles.ref.png \
a1-rasterisation-triangles.quartz.xfail.png \
a1-rasterisation-triangles.ref.png \
+ a1-rectilinear-grid.ref.png \
a1-sample.ref.png \
a1-traps-sample.quartz.xfail.png \
a1-traps-sample.ref.png \
@@ -885,6 +888,8 @@ REFERENCE_IMAGES = \
over-between-source.svg12.rgb24.xfail.png \
over-between-source.xlib.ref.png \
over-between-source.xlib.rgb24.ref.png \
+ overlapping-boxes.argb32.ref.png \
+ overlapping-boxes.rgb24.ref.png \
overlapping-dash-caps.ref.png \
overlapping-glyphs.argb32.ref.png \
overlapping-glyphs.pdf.argb32.xfail.png \
@@ -1155,6 +1160,7 @@ REFERENCE_IMAGES = \
set-source.ref.png \
set-source.rgb24.ref.png \
shape-general-convex.ref.png \
+ shape-sierpinski.ref.png \
show-glyphs-advance.image16.ref.png \
show-glyphs-advance.ps.ref.png \
show-glyphs-advance.quartz.ref.png \
@@ -1299,9 +1305,6 @@ REFERENCE_IMAGES = \
svg-surface-source.rgb24.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.svg12.argb32.xfail.png \
- test-fallback16-surface-source.svg12.rgb24.xfail.png \
text-antialias-gray.image16.ref.png \
text-antialias-gray.quartz.ref.png \
text-antialias-gray.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 526ac8a8..05bcdd0c 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -211,6 +211,7 @@ test_sources = \
over-around-source.c \
over-below-source.c \
over-between-source.c \
+ overlapping-boxes.c \
overlapping-glyphs.c \
overlapping-dash-caps.c \
paint.c \
@@ -273,6 +274,7 @@ test_sources = \
show-glyphs-many.c \
show-text-current-point.c \
shape-general-convex.c \
+ shape-sierpinski.c \
skew-extreme.c \
smask.c \
smask-fill.c \
@@ -373,9 +375,6 @@ svg_surface_test_sources = \
svg-clip.c \
svg-surface-source.c
-test_fallback16_surface_test_sources = \
- test-fallback16-surface-source.c
-
xcb_surface_test_sources = \
xcb-surface-source.c
diff --git a/test/a1-clip-fill-rule.argb32.ref.png b/test/a1-clip-fill-rule.argb32.ref.png
new file mode 100644
index 00000000..c3ba9dd5
--- /dev/null
+++ b/test/a1-clip-fill-rule.argb32.ref.png
Binary files differ
diff --git a/test/a1-clip-fill-rule.rgb24.ref.png b/test/a1-clip-fill-rule.rgb24.ref.png
new file mode 100644
index 00000000..6fe9346b
--- /dev/null
+++ b/test/a1-clip-fill-rule.rgb24.ref.png
Binary files differ
diff --git a/test/a1-rectilinear-grid.ref.png b/test/a1-rectilinear-grid.ref.png
new file mode 100644
index 00000000..2dfb85e1
--- /dev/null
+++ b/test/a1-rectilinear-grid.ref.png
Binary files differ
diff --git a/test/cairo-test-trace.c b/test/cairo-test-trace.c
index 146ca6fe..296a229d 100644
--- a/test/cairo-test-trace.c
+++ b/test/cairo-test-trace.c
@@ -93,8 +93,10 @@
#define DEBUG 0
+#define ignore_image_differences 0 /* XXX make me a cmdline option! */
+
#define DATA_SIZE (256 << 20)
-#define SHM_PATH_XXX "/shmem-cairo-trace"
+#define SHM_PATH_XXX "/.shmem-cairo-trace"
typedef struct _test_trace {
/* Options from command-line */
@@ -163,6 +165,8 @@ struct surface_tag {
};
static const cairo_user_data_key_t surface_tag;
+#define TARGET_NAME(T) ((T) ? (T)->name : "recording")
+
#if CAIRO_HAS_REAL_PTHREAD
#define tr_die(t) t->is_recording ? pthread_exit(NULL) : exit(1)
#else
@@ -253,7 +257,7 @@ send_recording_surface (test_runner_t *tr,
closure->end_line,
-1,
width, height,
- cairo_surface_get_type (closure->surface) == CAIRO_SURFACE_TYPE_IMAGE ? 0 : (long) closure->surface,
+ (long) closure->surface,
};
unsigned long offset;
unsigned long serial;
@@ -320,7 +324,8 @@ send_surface (test_runner_t *tr,
unsigned long serial;
if (DEBUG > 1) {
- printf ("send-surface: '%s'\n", tr->name);
+ printf ("send-surface: '%s', is-recording? %d\n",
+ tr->name, tr->is_recording);
}
if (cairo_surface_get_type (source) == CAIRO_SURFACE_TYPE_IMAGE) {
@@ -390,7 +395,8 @@ send_surface (test_runner_t *tr,
static cairo_surface_t *
_surface_create (void *closure,
cairo_content_t content,
- double width, double height)
+ double width, double height,
+ long uid)
{
test_runner_t *tr = closure;
cairo_surface_t *surface;
@@ -416,6 +422,13 @@ _context_create (void *closure, cairo_surface_t *surface)
test_runner_t *tr = closure;
struct context_closure *l;
+ if (DEBUG) {
+ fprintf (stderr, "%s: starting context %lu on line %d\n",
+ tr->name ? tr->name : "recording" ,
+ tr->context_id + 1,
+ cairo_script_interpreter_get_line_number (tr->csi));
+ }
+
l = xmalloc (sizeof (*l));
l->next = tr->contexts;
l->start_line = cairo_script_interpreter_get_line_number (tr->csi);
@@ -438,6 +451,12 @@ _context_destroy (void *closure, void *ptr)
while ((l = *prev) != NULL) {
if (l->context == ptr) {
+ if (DEBUG) {
+ fprintf (stderr, "%s: context %lu complete on line %d\n",
+ tr->name ? tr->name : "recording" ,
+ tr->context_id,
+ cairo_script_interpreter_get_line_number (tr->csi));
+ }
l->end_line =
cairo_script_interpreter_get_line_number (tr->csi);
if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) {
@@ -623,7 +642,7 @@ record (void *arg)
* 2. Runs in the same process, but separate thread.
*/
static pid_t
-spawn_recorder (const char *socket_path, const char *trace)
+spawn_recorder (const char *socket_path, const char *trace, test_runner_t **out)
{
test_runner_t *tr;
pthread_t id;
@@ -652,7 +671,7 @@ spawn_recorder (const char *socket_path, const char *trace)
tr->trace = trace;
tr->surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA,
- 0, 0);
+ NULL);
if (tr->surface == NULL) {
cleanup_recorder (tr);
return -1;
@@ -667,6 +686,8 @@ spawn_recorder (const char *socket_path, const char *trace)
}
pthread_attr_destroy (&attr);
+
+ *out = tr;
return pid;
}
#endif
@@ -814,6 +835,11 @@ matches_reference (struct slave *slave)
bb += stride;
}
break;
+
+ case CAIRO_FORMAT_RGB30:
+ case CAIRO_FORMAT_RGB16_565:
+ case CAIRO_FORMAT_INVALID:
+ assert (0);
}
return TRUE;
@@ -825,6 +851,9 @@ check_images (struct slave *slaves, int num_slaves)
{
int n;
+ if (ignore_image_differences)
+ return TRUE;
+
for (n = 0; n < num_slaves; n++) {
if (slaves[n].reference == NULL)
continue;
@@ -861,29 +890,59 @@ write_images (const char *trace, struct slave *slave, int num_slaves)
}
static void
+write_result (const char *trace, struct slave *slave)
+{
+ static int index;
+ char *filename;
+
+ xasprintf (&filename, "%s-%s-pass-%d-%d-%d.png",
+ trace, slave->target->name, ++index,
+ slave->start_line, slave->end_line);
+ cairo_surface_write_to_png (slave->image, filename);
+ free (filename);
+}
+
+static void
write_trace (const char *trace, struct slave *slave)
{
#if CAIRO_HAS_SCRIPT_SURFACE
- cairo_device_t *ctx,
- cairo_surface_t *script;
+ cairo_device_t *script;
char *filename;
- cairo_t *cr;
+
+ assert (slave->is_recording);
xasprintf (&filename, "%s-fail.trace", trace);
- ctx = cairo_script_create (filename);
- script = cairo_script_surface_create (ctx,
- cairo_surface_get_content (slave->image),
- slave->width,
- slave->height);
- cairo_device_destroy (ctx);
+
+ script = cairo_script_create (filename);
+ cairo_script_from_recording_surface (script, slave->image);
+ cairo_device_destroy (script);
+
free (filename);
+#endif
+}
- cr = cairo_create (slave->image);
- cairo_set_source_surface (cr, script, 0, 0);
- cairo_paint (cr);
- cairo_destroy (cr);
+static void
+dump_traces (test_runner_t *tr,
+ const char *trace,
+ const char *target,
+ const char *fail)
+{
+#if CAIRO_HAS_SCRIPT_SURFACE
+ struct context_closure *c;
+
+ for (c = tr->contexts; c; c = c->next) {
+ cairo_device_t *script;
+ char *filename;
+
+ xasprintf (&filename, "%s-%s-%s.%lu.trace",
+ trace, target, fail, c->start_line);
+
+ script = cairo_script_create (filename);
+ cairo_script_from_recording_surface (script, c->surface);
+ cairo_device_destroy (script);
- cairo_surface_destroy (script);
+ free (filename);
+ }
#endif
}
@@ -907,14 +966,16 @@ allocate_image_for_slave (uint8_t *base,
slave->height = rq.height;
if (DEBUG > 1) {
- printf ("allocate-image-for-slave: %s %lu [%lu, %lu] %ldx%ld=> %lu\n",
- slave->target->name,
+ printf ("allocate-image-for-slave: %s %lu [%lu, %lu] %ldx%ld stride=%lu => %lu, is-recording? %d\n",
+ TARGET_NAME (slave->target),
slave->image_serial,
slave->start_line,
slave->end_line,
slave->width,
slave->height,
- offset);
+ rq.stride,
+ offset,
+ slave->is_recording);
}
if (slave->is_recording) {
@@ -1031,14 +1092,14 @@ test_run (void *base,
offset = image,
&slaves[i]);
if (! writen (pfd[n].fd, &offset, sizeof (offset)))
- goto out;
+ goto done;
} else {
readn (pfd[n].fd,
&slaves[i].image_ready,
sizeof (slaves[i].image_ready));
if (DEBUG) {
printf ("slave '%s' reports completion on %lu (expecting %lu)\n",
- slaves[i].target->name,
+ TARGET_NAME (slaves[i].target),
slaves[i].image_ready,
slaves[i].image_serial);
}
@@ -1062,7 +1123,8 @@ test_run (void *base,
if (DEBUG > 1) {
printf ("all saves report completion\n");
}
- if (! check_images (slaves, num_slaves)) {
+ if (slaves[0].end_line >= slaves[0].start_line &&
+ ! check_images (slaves, num_slaves)) {
error->context_id = slaves[0].image_serial;
error->start_line = slaves[0].start_line;
error->end_line = slaves[0].end_line;
@@ -1082,6 +1144,8 @@ test_run (void *base,
goto out;
}
+ if (0) write_result (trace, &slaves[1]);
+
/* ack */
for (i = 0; i < num_slaves; i++) {
cairo_surface_destroy (slaves[i].image);
@@ -1089,7 +1153,7 @@ test_run (void *base,
if (DEBUG > 1) {
printf ("sending continuation to '%s'\n",
- slaves[i].target->name);
+ TARGET_NAME (slaves[i].target));
}
if (! writen (slaves[i].fd,
&slaves[i].image_serial,
@@ -1129,7 +1193,6 @@ out:
slaves[n].image_serial = 0;
slaves[n].image_ready = 0;
- ret = FALSE;
}
free (pfd);
@@ -1137,51 +1200,6 @@ out:
return ret;
}
-/* Paginated surfaces require finalization and external converters and so
- * are not suitable for this basic technique.
- */
-static cairo_bool_t
-target_is_measurable (const cairo_boilerplate_target_t *target)
-{
- if (target->content != CAIRO_CONTENT_COLOR_ALPHA)
- return FALSE;
-
- switch (target->expected_type) {
- case CAIRO_SURFACE_TYPE_IMAGE:
- if (strcmp (target->name, "pdf") == 0 ||
- strcmp (target->name, "ps") == 0)
- {
- return FALSE;
- }
- else
- {
- return TRUE;
- }
- case CAIRO_SURFACE_TYPE_XLIB:
- case CAIRO_SURFACE_TYPE_XCB:
- case CAIRO_SURFACE_TYPE_GLITZ:
- case CAIRO_SURFACE_TYPE_QUARTZ:
- case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE:
- case CAIRO_SURFACE_TYPE_WIN32:
- case CAIRO_SURFACE_TYPE_BEOS:
- case CAIRO_SURFACE_TYPE_DIRECTFB:
- case CAIRO_SURFACE_TYPE_OS2:
- case CAIRO_SURFACE_TYPE_QT:
- return TRUE;
-
- case CAIRO_SURFACE_TYPE_PDF:
- case CAIRO_SURFACE_TYPE_PS:
- case CAIRO_SURFACE_TYPE_SCRIPT:
- case CAIRO_SURFACE_TYPE_SVG:
- case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
- case CAIRO_SURFACE_TYPE_RECORDING:
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
static int
server_socket (const char *socket_path)
{
@@ -1241,6 +1259,7 @@ _test_trace (test_trace_t *test,
const char *shm_path = SHM_PATH_XXX;
const cairo_boilerplate_target_t *target, *image;
struct slave *slaves, *s;
+ test_runner_t *recorder = NULL;
pid_t slave;
char socket_dir[] = "/tmp/cairo-test-trace.XXXXXX";
char *socket_path;
@@ -1249,6 +1268,9 @@ _test_trace (test_trace_t *test,
void *base;
cairo_bool_t ret = FALSE;
+ if (DEBUG)
+ printf ("setting up trace '%s'\n", trace);
+
/* create a socket to control the test runners */
if (mkdtemp (socket_dir) == NULL) {
fprintf (stderr, "Unable to create temporary name for socket\n");
@@ -1265,8 +1287,8 @@ _test_trace (test_trace_t *test,
/* allocate some shared memory */
fd = server_shm (shm_path);
if (fd == -1) {
- fprintf (stderr, "Unable to create shared memory '%s'\n",
- shm_path);
+ fprintf (stderr, "Unable to create shared memory '%s': %s\n",
+ shm_path, strerror (errno));
goto cleanup_sk;
}
@@ -1277,7 +1299,7 @@ _test_trace (test_trace_t *test,
#if CAIRO_HAS_REAL_PTHREAD
/* set-up a recording-surface to reconstruct errors */
- slave = spawn_recorder (socket_path, trace);
+ slave = spawn_recorder (socket_path, trace, &recorder);
if (slave < 0) {
fprintf (stderr, "Unable to create recording surface\n");
goto cleanup_sk;
@@ -1297,7 +1319,12 @@ _test_trace (test_trace_t *test,
struct slave *master;
target = test->targets[i];
- if (target == image || ! target_is_measurable (target))
+
+ if (DEBUG)
+ printf ("setting up target[%d]? '%s' (image? %d, measurable? %d)\n",
+ i, target->name, target == image, target->is_measurable);
+
+ if (target == image || ! target->is_measurable)
continue;
/* find a matching slave to use as a reference for this target */
@@ -1356,14 +1383,22 @@ cleanup:
while (s-- > slaves) {
int status;
+ if (s->fd != -1)
+ close (s->fd);
+
+ cairo_surface_destroy (s->image);
+ cairo_surface_destroy (s->difference);
+
if (s->is_recording) /* in-process */
continue;
kill (s->pid, SIGKILL);
waitpid (s->pid, &status, 0);
- ret &= WIFEXITED (status) && WEXITSTATUS (status) == 0;
- if (WIFSIGNALED (status) && WTERMSIG(status) != SIGKILL)
+ if (WIFSIGNALED (status) && WTERMSIG(status) != SIGKILL) {
fprintf (stderr, "%s crashed\n", s->target->name);
+ if (recorder)
+ dump_traces (recorder, trace, s->target->name, "crash");
+ }
}
free (slaves);
shm_unlink (shm_path);
@@ -1630,6 +1665,8 @@ main (int argc, char *argv[])
parse_options (&test, argc, argv);
+ shm_unlink (SHM_PATH_XXX);
+
if (getenv ("CAIRO_TRACE_DIR") != NULL)
trace_dir = getenv ("CAIRO_TRACE_DIR");
diff --git a/test/clear-source.c b/test/clear-source.c
index a4c3db2f..5410932f 100644
--- a/test/clear-source.c
+++ b/test/clear-source.c
@@ -128,7 +128,7 @@ static operation_t operations[] = {
glyphs
};
- static cairo_test_status_t
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
cairo_content_t contents[] = { CAIRO_CONTENT_COLOR_ALPHA, CAIRO_CONTENT_COLOR, CAIRO_CONTENT_ALPHA };
diff --git a/test/clip-fill-rule.c b/test/clip-fill-rule.c
index 8351d868..035b9a83 100644
--- a/test/clip-fill-rule.c
+++ b/test/clip-fill-rule.c
@@ -66,9 +66,22 @@ draw (cairo_t *cr, int width, int height)
return CAIRO_TEST_SUCCESS;
}
+static cairo_test_status_t
+a1_draw (cairo_t *cr, int width, int height)
+{
+ cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+ return draw (cr, width, height);
+}
+
CAIRO_TEST (clip_fill_rule,
"Tests interaction of clipping with cairo_set_fill_rule",
"clip", /* keywords */
NULL, /* requirements */
STAR_SIZE * 2 + 2, STAR_SIZE + 2,
NULL, draw)
+CAIRO_TEST (a1_clip_fill_rule,
+ "Tests interaction of clipping with cairo_set_fill_rule",
+ "clip", /* keywords */
+ NULL, /* requirements */
+ STAR_SIZE * 2 + 2, STAR_SIZE + 2,
+ NULL, a1_draw)
diff --git a/test/map-to-image.c b/test/map-to-image.c
index b7d6df8a..0262245a 100644
--- a/test/map-to-image.c
+++ b/test/map-to-image.c
@@ -89,7 +89,7 @@ static cairo_test_status_t
bit (cairo_t *cr, int width, int height)
{
cairo_surface_t *surface;
- cairo_rectangle_t extents;
+ cairo_rectangle_int_t extents;
cairo_format_t format;
uint8_t *data;
@@ -117,7 +117,7 @@ static cairo_test_status_t
fill (cairo_t *cr, int width, int height)
{
cairo_surface_t *surface;
- cairo_rectangle_t extents;
+ cairo_rectangle_int_t extents;
cairo_t *cr2;
extents.x = extents.y = extents.width = extents.height = 1;
diff --git a/test/overlapping-boxes.argb32.ref.png b/test/overlapping-boxes.argb32.ref.png
new file mode 100644
index 00000000..278e62a8
--- /dev/null
+++ b/test/overlapping-boxes.argb32.ref.png
Binary files differ
diff --git a/test/overlapping-boxes.c b/test/overlapping-boxes.c
new file mode 100644
index 00000000..92211ee0
--- /dev/null
+++ b/test/overlapping-boxes.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/* Not strictly overlapping, but it does highlight the error in
+ * an optimisation of fill-box handling that I frequently am
+ * tempted to write.
+ */
+
+#include "cairo-test.h"
+
+#define WIDTH (20)
+#define HEIGHT (20)
+
+static void
+border (cairo_t *cr)
+{
+ cairo_rectangle (cr, 1, 1, 8, 8);
+ cairo_rectangle (cr, 1.25, 1.25, 7.5, 7.5);
+ cairo_rectangle (cr, 1.75, 1.75, 6.5, 6.5);
+ cairo_rectangle (cr, 2, 2, 6, 6);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+
+ border (cr);
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_fill (cr);
+
+ cairo_translate (cr, 10, 0);
+
+ border (cr);
+ cairo_set_source_rgb (cr, 0, 0, 1);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_fill (cr);
+
+ cairo_translate (cr, 0, 10);
+
+ cairo_rectangle (cr, 0, 0, 10, 10);
+ cairo_clip (cr);
+
+ border (cr);
+ cairo_set_source_rgb (cr, 0, 1, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_IN);
+ cairo_fill (cr);
+
+ cairo_reset_clip (cr);
+
+ cairo_translate (cr, -10, 0);
+
+ cairo_rectangle (cr, 0, 0, 10, 10);
+ cairo_clip (cr);
+
+ border (cr);
+ cairo_set_source_rgb (cr, 0, 0, 1);
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ cairo_fill (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (overlapping_boxes,
+ "A sub-pixel double border to highlight the danger in an easy optimisation",
+ "fill", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw)
diff --git a/test/overlapping-boxes.rgb24.ref.png b/test/overlapping-boxes.rgb24.ref.png
new file mode 100644
index 00000000..f35d0e6b
--- /dev/null
+++ b/test/overlapping-boxes.rgb24.ref.png
Binary files differ
diff --git a/test/rectilinear-grid.c b/test/rectilinear-grid.c
index 1baadf73..8c6b7fca 100644
--- a/test/rectilinear-grid.c
+++ b/test/rectilinear-grid.c
@@ -70,9 +70,23 @@ draw (cairo_t *cr, int width, int height)
return CAIRO_TEST_SUCCESS;
}
+static cairo_test_status_t
+aligned (cairo_t *cr, int width, int height)
+{
+ cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+ return draw (cr, width, height);
+}
+
CAIRO_TEST (rectilinear_grid,
"Test rectilinear rasterizer (covering partial pixels)",
"rectilinear", /* keywords */
NULL, /* requirements */
SIZE, SIZE,
NULL, draw)
+
+CAIRO_TEST (a1_rectilinear_grid,
+ "Test rectilinear rasterizer (covering whole pixels)",
+ "rectilinear", /* keywords */
+ NULL, /* requirements */
+ SIZE, SIZE,
+ NULL, aligned)
diff --git a/test/shape-sierpinski.c b/test/shape-sierpinski.c
new file mode 100644
index 00000000..9d201706
--- /dev/null
+++ b/test/shape-sierpinski.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/* I thought I spied a bug... */
+
+#include "cairo-test.h"
+
+#define WIDTH (1024)
+#define HEIGHT (600)
+
+static const double m_1_sqrt_3 = 0.577359269;
+
+static void
+T (cairo_t *cr, int size)
+{
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, size, 0);
+ cairo_line_to (cr, size/2, size*m_1_sqrt_3);
+
+ size /= 2;
+ if (size >= 4) {
+ T (cr, size);
+ cairo_save (cr); {
+ cairo_translate (cr, size, 0);
+ T (cr, size);
+ } cairo_restore (cr);
+ cairo_save (cr); {
+ cairo_translate (cr, size/2, size*m_1_sqrt_3);
+ T (cr, size);
+ } cairo_restore (cr);
+ }
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+
+ cairo_translate (cr, 0, 8);
+
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_set_line_width (cr, 1.);
+
+ T (cr, WIDTH);
+
+ cairo_translate (cr, 0, 2*HEIGHT-16);
+ cairo_scale (cr, 1, -1);
+
+ T (cr, WIDTH);
+
+ cairo_stroke (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (shape_sierpinski,
+ "A fractal triangle",
+ "stroke", /* keywords */
+ NULL, /* requirements */
+ WIDTH, 2*HEIGHT,
+ NULL, draw)
diff --git a/test/shape-sierpinski.ref.png b/test/shape-sierpinski.ref.png
new file mode 100644
index 00000000..69755d27
--- /dev/null
+++ b/test/shape-sierpinski.ref.png
Binary files differ
diff --git a/test/test-fallback16-surface-source.c b/test/test-fallback16-surface-source.c
deleted file mode 100644
index 7e9f920f..00000000
--- a/test/test-fallback16-surface-source.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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"
-#include <test-fallback16-surface.h>
-
-#include "surface-source.c"
-
-static cairo_surface_t *
-create_source_surface (int size)
-{
- return _cairo_test_fallback16_surface_create (CAIRO_CONTENT_COLOR_ALPHA,
- size, size);
-}
-
-CAIRO_TEST (test_fallback16_surface_source,
- "Test using a 16-bit image (e.g. a low bit-depth XServer) surface as the source",
- "source", /* keywords */
- NULL, /* requirements */
- SIZE, SIZE,
- preamble, draw)
diff --git a/test/test-fallback16-surface-source.ps.ref.png b/test/test-fallback16-surface-source.ps.ref.png
deleted file mode 100644
index f686a068..00000000
--- a/test/test-fallback16-surface-source.ps.ref.png
+++ /dev/null
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
deleted file mode 100644
index 6ebcaf9a..00000000
--- a/test/test-fallback16-surface-source.svg12.argb32.xfail.png
+++ /dev/null
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
deleted file mode 100644
index 6ebcaf9a..00000000
--- a/test/test-fallback16-surface-source.svg12.rgb24.xfail.png
+++ /dev/null
Binary files differ
diff --git a/test/zero-mask.c b/test/zero-mask.c
index 29edd0a5..3d2f34d0 100644
--- a/test/zero-mask.c
+++ b/test/zero-mask.c
@@ -92,7 +92,7 @@ mask_with_alpha_surface (cairo_t *cr)
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT);
cairo_mask (cr, pattern);
-
+
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
}
@@ -106,7 +106,7 @@ mask_with_nonclear_surface (cairo_t *cr)
16, 8, 4);
cairo_mask_surface (cr, surface, 0, 0);
-
+
cairo_surface_destroy (surface);
}
@@ -175,7 +175,7 @@ draw (cairo_t *cr, int width, int height)
for (op = 0; op < ARRAY_LENGTH (operators); op++) {
cairo_set_operator (cr, operators[op]);
-
+
for (i = 0; i < ARRAY_LENGTH (mask_funcs); i++) {
cairo_save (cr);
cairo_translate (cr, i * (RECT + SPACE), op * (RECT + SPACE));
diff --git a/util/cairo-script/cairo-script-interpreter.c b/util/cairo-script/cairo-script-interpreter.c
index a5c81255..bdd52554 100644
--- a/util/cairo-script/cairo-script-interpreter.c
+++ b/util/cairo-script/cairo-script-interpreter.c
@@ -396,6 +396,7 @@ _csi_init (csi_t *ctx)
ctx->status = CSI_STATUS_SUCCESS;
ctx->ref_count = 1;
+ ctx->scanner.line_number = -1;
status = _csi_hash_table_init (&ctx->strings, _intern_string_equal);
if (status)
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index 36dbbb90..ad1a2015 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -3630,8 +3630,7 @@ _map_to_image (csi_t *ctx)
csi_object_t obj;
csi_array_t *array;
csi_status_t status;
- cairo_rectangle_t extents;
- cairo_rectangle_t *r;
+ cairo_rectangle_int_t extents, *r;
cairo_surface_t *surface;
check (2);
@@ -3647,11 +3646,12 @@ _map_to_image (csi_t *ctx)
switch (array->stack.len) {
case 0:
r = NULL;
+ break;
case 4:
- extents.x = _csi_object_as_real (&array->stack.objects[0]);
- extents.y = _csi_object_as_real (&array->stack.objects[1]);
- extents.width = _csi_object_as_real (&array->stack.objects[2]);
- extents.height = _csi_object_as_real (&array->stack.objects[3]);
+ extents.x = floor (_csi_object_as_real (&array->stack.objects[0]));
+ extents.y = floor (_csi_object_as_real (&array->stack.objects[1]));
+ extents.width = ceil (_csi_object_as_real (&array->stack.objects[2]));
+ extents.height = ceil (_csi_object_as_real (&array->stack.objects[3]));
r = &extents;
break;
default:
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index a6de76f1..65f8fbac 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -3625,7 +3625,7 @@ cairo_surface_create_similar_image (cairo_surface_t *other,
cairo_surface_t *
cairo_surface_map_to_image (cairo_surface_t *surface,
- const cairo_rectangle_t *extents)
+ const cairo_rectangle_int_t *extents)
{
cairo_surface_t *ret;
@@ -3638,18 +3638,14 @@ cairo_surface_map_to_image (cairo_surface_t *surface,
Object *obj = _create_surface (ret);
if (extents) {
- _trace_printf ("[ %f %f %f %f ] map-to-image dup /s%ld exch def\n",
+ _trace_printf ("[%d %d %d %d] map-to-image\n",
extents->x, extents->y,
- extents->width,
- extents->height,
- obj->token);
- obj->width = extents->width;
+ extents->width, extents->height);
+ obj->width = extents->width;
obj->height = extents->height;
} else {
- _trace_printf ("[ ] map-to-image dup /s%ld exch def\n",
- obj->token);
+ _trace_printf ("[ ] map-to-image\n");
}
- obj->defined = TRUE;
_push_object (obj);
_write_unlock ();
}
@@ -3669,6 +3665,7 @@ cairo_surface_unmap_image (cairo_surface_t *surface,
_trace_printf ("/s%ld /s%ld unmap-image\n",
_get_surface_id (surface),
_get_surface_id (image));
+ _consume_operand ();
_write_unlock ();
}
@@ -4892,24 +4889,52 @@ cairo_script_surface_create_for_target (cairo_device_t *device,
#endif
#if CAIRO_HAS_TEST_SURFACES
-#include <test-fallback-surface.h>
+#include <test-paginated-surface.h>
+cairo_surface_t *
+_cairo_test_paginated_surface_create (cairo_surface_t *surface)
+{
+ cairo_surface_t *ret;
+
+ _enter_trace ();
+
+ ret = DLCALL (_cairo_test_paginated_surface_create, surface);
+
+ _emit_line_info ();
+ if (_write_lock ()) {
+ Object *obj = _create_surface (ret);
+
+ /* XXX store initial data? */
+ _trace_printf ("dict\n"
+ " /type /test-paginated set\n"
+ " /target s%ld set\n"
+ " surface dup /s%ld exch def\n",
+ _get_surface_id (surface),
+ obj->token);
+ _push_object (obj);
+ _write_unlock ();
+ }
+
+ _exit_trace ();
+ return ret;
+}
+
+#include <test-compositor-surface.h>
+
cairo_surface_t *
-_cairo_test_fallback_surface_create (cairo_content_t content,
- int width,
- int height)
+_cairo_test_fallback_compositor_surface_create (cairo_content_t content, int width, int height)
{
cairo_surface_t *ret;
_enter_trace ();
- ret = DLCALL (_cairo_test_fallback_surface_create, content, width, height);
+ ret = DLCALL (_cairo_test_fallback_compositor_surface_create, content, width, height);
_emit_line_info ();
if (_write_lock ()) {
Object *obj = _create_surface (ret);
_trace_printf ("dict\n"
- " /type /test-fallback set\n"
+ " /type /test-fallback-compositor set\n"
" /content //%s set\n"
" /width %d set\n"
" /height %d set\n"
@@ -4917,8 +4942,6 @@ _cairo_test_fallback_surface_create (cairo_content_t content,
_content_to_string (content),
width, height,
obj->token);
- obj->width = width;
- obj->height = height;
obj->defined = TRUE;
_push_object (obj);
_write_unlock ();
@@ -4928,27 +4951,29 @@ _cairo_test_fallback_surface_create (cairo_content_t content,
return ret;
}
-#include <test-paginated-surface.h>
cairo_surface_t *
-_cairo_test_paginated_surface_create (cairo_surface_t *surface)
+_cairo_test_mask_compositor_surface_create (cairo_content_t content, int width, int height)
{
cairo_surface_t *ret;
_enter_trace ();
- ret = DLCALL (_cairo_test_paginated_surface_create, surface);
+ ret = DLCALL (_cairo_test_mask_compositor_surface_create, content, width, height);
_emit_line_info ();
if (_write_lock ()) {
Object *obj = _create_surface (ret);
- /* XXX store initial data? */
_trace_printf ("dict\n"
- " /type /test-paginated set\n"
- " /target s%ld set\n"
+ " /type /test-mask-compositor set\n"
+ " /content //%s set\n"
+ " /width %d set\n"
+ " /height %d set\n"
" surface dup /s%ld exch def\n",
- _get_surface_id (surface),
+ _content_to_string (content),
+ width, height,
obj->token);
+ obj->defined = TRUE;
_push_object (obj);
_write_unlock ();
}
@@ -4957,26 +4982,58 @@ _cairo_test_paginated_surface_create (cairo_surface_t *surface)
return ret;
}
+cairo_surface_t *
+_cairo_test_spans_compositor_surface_create (cairo_content_t content, int width, int height)
+{
+ cairo_surface_t *ret;
+
+ _enter_trace ();
+
+ ret = DLCALL (_cairo_test_spans_compositor_surface_create, content, width, height);
+
+ _emit_line_info ();
+ if (_write_lock ()) {
+ Object *obj = _create_surface (ret);
+
+ _trace_printf ("dict\n"
+ " /type /test-spans-compositor set\n"
+ " /content //%s set\n"
+ " /width %d set\n"
+ " /height %d set\n"
+ " surface dup /s%ld exch def\n",
+ _content_to_string (content),
+ width, height,
+ obj->token);
+ obj->defined = TRUE;
+ _push_object (obj);
+ _write_unlock ();
+ }
+
+ _exit_trace ();
+ return ret;
+}
-#include <test-null-surface.h>
cairo_surface_t *
-_cairo_test_null_surface_create (cairo_content_t content)
+_cairo_test_traps_compositor_surface_create (cairo_content_t content, int width, int height)
{
cairo_surface_t *ret;
_enter_trace ();
- ret = DLCALL (_cairo_test_null_surface_create, content);
+ ret = DLCALL (_cairo_test_traps_compositor_surface_create, content, width, height);
_emit_line_info ();
if (_write_lock ()) {
Object *obj = _create_surface (ret);
_trace_printf ("dict\n"
- " /type /test-null set\n"
+ " /type /test-traps-compositor set\n"
" /content //%s set\n"
+ " /width %d set\n"
+ " /height %d set\n"
" surface dup /s%ld exch def\n",
_content_to_string (content),
+ width, height,
obj->token);
obj->defined = TRUE;
_push_object (obj);
@@ -4986,6 +5043,7 @@ _cairo_test_null_surface_create (cairo_content_t content)
_exit_trace ();
return ret;
}
+
#endif
cairo_surface_t *
diff --git a/util/show-polygon.c b/util/show-polygon.c
index 9571363b..fc1444db 100644
--- a/util/show-polygon.c
+++ b/util/show-polygon.c
@@ -49,6 +49,8 @@ typedef struct _PolygonViewClass {
G_DEFINE_TYPE (PolygonView, polygon_view, GTK_TYPE_WIDGET)
+double highlight = -1;
+
static void draw_edges (cairo_t *cr, polygon_t *p, gdouble sf, int dir)
{
int n;
@@ -59,8 +61,8 @@ static void draw_edges (cairo_t *cr, polygon_t *p, gdouble sf, int dir)
if (e->dir != dir)
continue;
- cairo_arc (cr, e->p1.x, e->p1.y, 3/sf, 0, 2*M_PI);
- cairo_arc (cr, e->p2.x, e->p2.y, 3/sf, 0, 2*M_PI);
+ cairo_arc (cr, e->p1.x, e->p1.y, 2/sf, 0, 2*M_PI);
+ cairo_arc (cr, e->p2.x, e->p2.y, 2/sf, 0, 2*M_PI);
cairo_fill (cr);
}
@@ -140,6 +142,17 @@ pixmap_create (PolygonView *self, cairo_surface_t *target)
draw_polygon (cr, polygon, sf);
}
+
+ if (highlight != -1) {
+ cairo_move_to (cr, extents.p1.x, highlight);
+ cairo_line_to (cr, extents.p2.x, highlight);
+ cairo_set_source_rgb (cr, 0, .7, 0);
+ cairo_save (cr);
+ cairo_identity_matrix (cr);
+ cairo_set_line_width (cr, 1.);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
} cairo_restore (cr);
cairo_destroy (cr);
@@ -228,6 +241,17 @@ polygon_view_draw (PolygonView *self, cairo_t *cr)
draw_polygon (cr, polygon, zoom);
}
+
+ if (highlight != -1) {
+ cairo_move_to (cr, extents.p1.x, highlight);
+ cairo_line_to (cr, extents.p2.x, highlight);
+ cairo_set_source_rgb (cr, 0, .7, 0);
+ cairo_save (cr);
+ cairo_identity_matrix (cr);
+ cairo_set_line_width (cr, 1.);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
} cairo_restore (cr);
/* grid */
@@ -563,6 +587,9 @@ main (int argc, char **argv)
fclose (file);
}
+ if (argc > 2)
+ highlight = atof (argv[2]);
+
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "delete-event",
G_CALLBACK (gtk_main_quit), NULL);