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