diff options
193 files changed, 7741 insertions, 5903 deletions
@@ -9,6 +9,12 @@ API additions: Finally exporting the internal meta-surface so that applications have a method to record and replay a sequence of drawing commands. + cairo_in_clip() + + Determines whether a given point is inside the current clip. + ??? Should this be called cairo_in_paint() instead? in-clip is the test + that is performed, but in-paint would be similar to in-fill and in-stroke. + New utilities: cairo-test-trace diff --git a/boilerplate/cairo-boilerplate-glitz-glx.c b/boilerplate/cairo-boilerplate-glitz-glx.c index 6dfdb7fe..6e3cfec3 100644 --- a/boilerplate/cairo-boilerplate-glitz-glx.c +++ b/boilerplate/cairo-boilerplate-glitz-glx.c @@ -33,7 +33,6 @@ static const cairo_user_data_key_t glitz_closure_key; typedef struct _glitz_glx_target_closure { - glitz_target_closure_base_t base; Display *dpy; int scr; Window win; @@ -206,9 +205,6 @@ _cairo_boilerplate_glitz_glx_create_surface (const char *name, if (cairo_surface_status (surface)) goto FAIL_CLOSE_DISPLAY; - gxtc->base.width = width; - gxtc->base.height = height; - gxtc->base.content = content; status = cairo_surface_set_user_data (surface, &glitz_closure_key, gxtc, NULL); if (status == CAIRO_STATUS_SUCCESS) diff --git a/boilerplate/cairo-boilerplate-pdf.c b/boilerplate/cairo-boilerplate-pdf.c index 166ba1c9..e941d46f 100644 --- a/boilerplate/cairo-boilerplate-pdf.c +++ b/boilerplate/cairo-boilerplate-pdf.c @@ -129,7 +129,6 @@ _cairo_boilerplate_pdf_finish_surface (cairo_surface_t *surface) if (status) return status; - cairo_surface_finish (surface); status = cairo_surface_status (surface); if (status) return status; diff --git a/boilerplate/cairo-boilerplate-ps.c b/boilerplate/cairo-boilerplate-ps.c index 0fdd0cfa..40148dde 100644 --- a/boilerplate/cairo-boilerplate-ps.c +++ b/boilerplate/cairo-boilerplate-ps.c @@ -178,6 +178,7 @@ _cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface) if (ptc->target) { cairo_t *cr; + cr = cairo_create (ptc->target); cairo_set_source_surface (cr, surface, 0, 0); cairo_paint (cr); @@ -188,7 +189,6 @@ _cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface) if (status) return status; - cairo_surface_finish (surface); status = cairo_surface_status (surface); if (status) return status; @@ -197,11 +197,7 @@ _cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface) } cairo_surface_finish (surface); - status = cairo_surface_status (surface); - if (status) - return status; - - return CAIRO_STATUS_SUCCESS; + return cairo_surface_status (surface); } static cairo_status_t diff --git a/boilerplate/cairo-boilerplate-qt.cpp b/boilerplate/cairo-boilerplate-qt.cpp index 5d8d3f93..8f19811f 100644 --- a/boilerplate/cairo-boilerplate-qt.cpp +++ b/boilerplate/cairo-boilerplate-qt.cpp @@ -30,7 +30,7 @@ * The Initial Developer of the Original Code is Chris Wilson. */ -#include "cairo-boilerplate.h" +#include "cairo-boilerplate-private.h" #include <cairo-qt.h> @@ -108,4 +108,6 @@ static const cairo_boilerplate_target_t targets[] = { _cairo_boilerplate_qt_cleanup }, }; +extern "C" { CAIRO_BOILERPLATE (qt, targets) +} diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c index 9d03b203..45e085ce 100644 --- a/boilerplate/cairo-boilerplate-svg.c +++ b/boilerplate/cairo-boilerplate-svg.c @@ -166,7 +166,6 @@ _cairo_boilerplate_svg_finish_surface (cairo_surface_t *surface) if (status) return status; - cairo_surface_finish (surface); status = cairo_surface_status (surface); if (status) return status; diff --git a/boilerplate/cairo-boilerplate-test-surfaces.c b/boilerplate/cairo-boilerplate-test-surfaces.c index 849627fd..501866ba 100644 --- a/boilerplate/cairo-boilerplate-test-surfaces.c +++ b/boilerplate/cairo-boilerplate-test-surfaces.c @@ -33,6 +33,7 @@ #include <test-paginated-surface.h> #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,9,3) #include <test-null-surface.h> +#include <test-wrapping-surface.h> #endif #include <cairo-types-private.h> @@ -49,7 +50,8 @@ _cairo_boilerplate_test_fallback_create_surface (const char *name, void **closure) { *closure = NULL; - return _cairo_test_fallback_surface_create (content, width, height); + return _cairo_test_fallback_surface_create (content, + ceil (width), ceil (height)); } static cairo_surface_t * @@ -64,7 +66,8 @@ _cairo_boilerplate_test_fallback16_create_surface (const char *name, void **closure) { *closure = NULL; - return _cairo_test_fallback16_surface_create (content, width, height); + return _cairo_test_fallback16_surface_create (content, + ceil (width), ceil (height)); } static cairo_surface_t * @@ -89,11 +92,7 @@ _cairo_boilerplate_test_null_create_surface (const char *name, static const cairo_user_data_key_t test_paginated_closure_key; typedef struct { - unsigned char *data; - cairo_content_t content; - int width; - int height; - int stride; + cairo_surface_t *target; } test_paginated_closure_t; static cairo_surface_t * @@ -115,18 +114,10 @@ _cairo_boilerplate_test_paginated_create_surface (const char *name, *closure = tpc = xmalloc (sizeof (test_paginated_closure_t)); format = cairo_boilerplate_format_from_content (content); + tpc->target = cairo_image_surface_create (format, + ceil (width), ceil (height)); - tpc->content = content; - tpc->width = width; - tpc->height = height; - tpc->stride = cairo_format_stride_for_width (format, width); - tpc->data = xcalloc (tpc->stride, height); - - surface = _cairo_test_paginated_surface_create_for_data (tpc->data, - tpc->content, - tpc->width, - tpc->height, - tpc->stride); + surface = _cairo_test_paginated_surface_create (tpc->target); if (cairo_surface_status (surface)) goto CLEANUP; @@ -139,8 +130,9 @@ _cairo_boilerplate_test_paginated_create_surface (const char *name, cairo_surface_destroy (surface); surface = cairo_boilerplate_surface_create_in_error (status); + cairo_surface_destroy (tpc->target); + CLEANUP: - free (tpc->data); free (tpc); return surface; } @@ -160,8 +152,6 @@ static cairo_status_t _cairo_boilerplate_test_paginated_surface_write_to_png (cairo_surface_t *surface, const char *filename) { - cairo_surface_t *image; - cairo_format_t format; test_paginated_closure_t *tpc; cairo_status_t status; @@ -172,19 +162,7 @@ _cairo_boilerplate_test_paginated_surface_write_to_png (cairo_surface_t *surface return status; tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key); - - format = cairo_boilerplate_format_from_content (tpc->content); - - image = cairo_image_surface_create_for_data (tpc->data, - format, - tpc->width, - tpc->height, - tpc->stride); - - status = cairo_surface_write_to_png (image, filename); - cairo_surface_destroy (image); - - return status; + return cairo_surface_write_to_png (tpc->target, filename); } static cairo_surface_t * @@ -193,7 +171,6 @@ _cairo_boilerplate_test_paginated_get_image_surface (cairo_surface_t *surface, int width, int height) { - cairo_format_t format; test_paginated_closure_t *tpc; cairo_status_t status; @@ -208,30 +185,7 @@ _cairo_boilerplate_test_paginated_get_image_surface (cairo_surface_t *surface, return cairo_boilerplate_surface_create_in_error (status); tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key); - - format = cairo_boilerplate_format_from_content (tpc->content); - - if (0) { - return cairo_image_surface_create_for_data (tpc->data + tpc->stride * (tpc->height - height) + 4 * (tpc->width - width), /* hide the device offset */ - format, - width, - height, - tpc->stride); - } else { - cairo_surface_t *image, *surface; - - image = cairo_image_surface_create_for_data (tpc->data, - format, - tpc->width, - tpc->height, - tpc->stride); - cairo_surface_set_device_offset (image, - tpc->width - width, - tpc->height - height); - surface = _cairo_boilerplate_get_image_surface (image, 0, width, height); - cairo_surface_destroy (image); - return surface; - } + return _cairo_boilerplate_get_image_surface (tpc->target, 0, width, height); } static void @@ -239,10 +193,40 @@ _cairo_boilerplate_test_paginated_cleanup (void *closure) { test_paginated_closure_t *tpc = closure; - free (tpc->data); + cairo_surface_destroy (tpc->target); free (tpc); } +static cairo_surface_t * +_cairo_boilerplate_test_wrapping_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + int id, + void **closure) +{ +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,9,3) + cairo_surface_t *target; + cairo_surface_t *surface; + cairo_format_t format; + + *closure = NULL; + + format = cairo_boilerplate_format_from_content (content); + target = cairo_image_surface_create (format, ceil (width), ceil (height)); + surface = _cairo_test_wrapping_surface_create (target); + cairo_surface_destroy (target); + + return surface; +#else + *closure = NULL; + return NULL; +#endif +} + static const cairo_boilerplate_target_t targets[] = { { "test-fallback", "image", NULL, NULL, @@ -305,6 +289,15 @@ static const cairo_boilerplate_target_t targets[] = { FALSE, TRUE }, { + "test-wrapping", "image", NULL, NULL, + CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING, + CAIRO_CONTENT_COLOR_ALPHA, 0, + _cairo_boilerplate_test_wrapping_create_surface, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + }, + { "null", "image", NULL, NULL, CAIRO_INTERNAL_SURFACE_TYPE_NULL, CAIRO_CONTENT_COLOR_ALPHA, 0, diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c index ea88c691..a0810457 100644 --- a/boilerplate/cairo-boilerplate.c +++ b/boilerplate/cairo-boilerplate.c @@ -32,6 +32,10 @@ #include <cairo-types-private.h> #include <cairo-scaled-font-private.h> +#if CAIRO_HAS_SCRIPT_SURFACE +#include <cairo-script.h> +#endif + /* get the "real" version info instead of dummy cairo-version.h */ #undef CAIRO_VERSION_H #include "../cairo-version.h" @@ -136,48 +140,74 @@ _cairo_boilerplate_meta_create_surface (const char *name, int id, void **closure) { + cairo_rectangle_t extents; + *closure = NULL; - return cairo_meta_surface_create (content, width, height); + + extents.x = 0; + extents.y = 0; + extents.width = width; + extents.height = height; + return cairo_meta_surface_create (content, &extents); } +const cairo_user_data_key_t cairo_boilerplate_output_basename_key; + +#if CAIRO_HAS_SCRIPT_SURFACE +static cairo_status_t +stdio_write (void *closure, const unsigned char *data, unsigned int len) +{ + if (fwrite (data, len, 1, closure) != 1) + return CAIRO_STATUS_WRITE_ERROR; + + return CAIRO_STATUS_SUCCESS; +} +#endif + cairo_surface_t * _cairo_boilerplate_get_image_surface (cairo_surface_t *src, int page, int width, int height) { - cairo_surface_t *surface; + FILE *file = NULL; + cairo_surface_t *surface, *image; cairo_t *cr; + cairo_status_t status; if (cairo_surface_status (src)) return cairo_surface_reference (src); -#if 0 - if (cairo_surface_get_type (src) == CAIRO_SURFACE_TYPE_IMAGE) { - int ww = cairo_image_surface_get_width (src); - int hh = cairo_image_surface_get_height (src); - if (width == ww && hh == height) { - return cairo_surface_reference (src); - } else { - cairo_format_t format = cairo_image_surface_get_format (src); - unsigned char *data = cairo_image_surface_get_data (src); - int stride = cairo_image_surface_get_stride (src); - - data += stride * (hh - height) + 4 * (ww - width); - return cairo_image_surface_create_for_data (data, - format, - width, - height, - stride); - } - } -#endif - if (page != 0) return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); /* extract sub-surface */ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + image = cairo_surface_reference (surface); + + /* open a logging channel (only interesting for meta surfaces) */ +#if CAIRO_HAS_SCRIPT_SURFACE + if (cairo_surface_get_type (src) == CAIRO_SURFACE_TYPE_META) { + const char *test_name; + + test_name = cairo_surface_get_user_data (src, + &cairo_boilerplate_output_basename_key); + if (test_name != NULL) { + char *filename; + + xasprintf (&filename, "%s.out.trace", test_name); + file = fopen (filename, "w"); + free (filename); + + if (file != NULL) { + surface = cairo_script_surface_create_for_target (image, + stdio_write, + file); + } + } + } +#endif + cr = cairo_create (surface); cairo_surface_destroy (surface); @@ -185,10 +215,17 @@ _cairo_boilerplate_get_image_surface (cairo_surface_t *src, cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); - surface = cairo_surface_reference (cairo_get_target (cr)); + status = cairo_status (cr); + if (status) { + cairo_surface_destroy (image); + image = cairo_surface_reference (cairo_get_target (cr)); + } cairo_destroy (cr); - return surface; + if (file != NULL) + fclose (file); + + return image; } cairo_surface_t * @@ -705,8 +742,13 @@ cairo_boilerplate_convert_to_image (const char *filename, int page) image = cairo_boilerplate_image_surface_create_from_ppm_stream (file); ret = pclose (file); + /* check for fatal errors from the interpreter */ + if (ret) { /* any2pmm should never die... */ + cairo_surface_destroy (image); + return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_INVALID_STATUS); + } - if (cairo_surface_status (image) == CAIRO_STATUS_READ_ERROR) { + if (ret == 0 && cairo_surface_status (image) == CAIRO_STATUS_READ_ERROR) { if (flags == 0) { /* Try again in a standalone process. */ cairo_surface_destroy (image); @@ -715,12 +757,6 @@ cairo_boilerplate_convert_to_image (const char *filename, int page) } } - if (cairo_surface_status (image) == CAIRO_STATUS_SUCCESS && ret != 0) { - cairo_surface_destroy (image); - image = - cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR); - }; - return image; } diff --git a/boilerplate/cairo-boilerplate.h b/boilerplate/cairo-boilerplate.h index aaa196c5..377d2f91 100644 --- a/boilerplate/cairo-boilerplate.h +++ b/boilerplate/cairo-boilerplate.h @@ -99,6 +99,8 @@ CAIRO_BEGIN_DECLS * PDF surfaces. */ #define CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED ((unsigned int) -1) +extern const cairo_user_data_key_t cairo_boilerplate_output_basename_key; + cairo_content_t cairo_boilerplate_content (cairo_content_t content); diff --git a/perf/unaligned-clip.c b/perf/unaligned-clip.c index 7fd5245e..f379b61e 100644 --- a/perf/unaligned-clip.c +++ b/perf/unaligned-clip.c @@ -49,6 +49,9 @@ do_unaligned_clip (cairo_t *cr, int width, int height) cairo_rectangle (cr, 55, 55, 35, 35); cairo_clip (cr); + /* And paint something to force the clip to be evaluated. */ + cairo_paint (cr); + cairo_perf_timer_stop (); cairo_restore (cr); diff --git a/src/Makefile.sources b/src/Makefile.sources index c5c14f73..d6fa582a 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -79,11 +79,14 @@ cairo_private = \ cairo-path-private.h \ cairo-private.h \ cairo-reference-count-private.h \ + cairo-region-private.h \ cairo-scaled-font-private.h \ cairo-skiplist-private.h \ cairo-spans-private.h \ cairo-surface-fallback-private.h \ cairo-surface-private.h \ + cairo-surface-clipper-private.h \ + cairo-surface-wrapper-private.h \ cairo-types-private.h \ cairo-user-font-private.h \ cairo-wideint-private.h \ @@ -138,6 +141,8 @@ cairo_sources = \ cairo-stroke-style.c \ cairo-surface.c \ cairo-surface-fallback.c \ + cairo-surface-clipper.c \ + cairo-surface-wrapper.c \ cairo-tor-scan-converter.c \ cairo-system.c \ cairo-traps.c \ @@ -198,12 +203,14 @@ cairo_test_surfaces_private = \ test-fallback16-surface.h \ test-null-surface.h \ test-paginated-surface.h \ + test-wrapping-surface.h \ $(NULL) cairo_test_surfaces_sources = \ test-fallback-surface.c \ test-fallback16-surface.c \ test-null-surface.c \ test-paginated-surface.c \ + test-wrapping-surface.c \ $(NULL) cairo_xlib_headers = cairo-xlib.h diff --git a/src/cairo-analysis-surface-private.h b/src/cairo-analysis-surface-private.h index 28bfd3bf..f67caf90 100644 --- a/src/cairo-analysis-surface-private.h +++ b/src/cairo-analysis-surface-private.h @@ -38,13 +38,11 @@ #include "cairoint.h" cairo_private cairo_surface_t * -_cairo_analysis_surface_create (cairo_surface_t *target, - int width, - int height); +_cairo_analysis_surface_create (cairo_surface_t *target); cairo_private void _cairo_analysis_surface_set_ctm (cairo_surface_t *surface, - cairo_matrix_t *ctm); + const cairo_matrix_t *ctm); cairo_private void _cairo_analysis_surface_get_ctm (cairo_surface_t *surface, diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index 3a1b2f9f..eb1e87d4 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -39,13 +39,12 @@ #include "cairo-analysis-surface-private.h" #include "cairo-paginated-private.h" #include "cairo-meta-surface-private.h" +#include "cairo-region-private.h" typedef struct { cairo_surface_t base; - int width; - int height; - cairo_surface_t *target; + cairo_surface_t *target; cairo_bool_t first_op; cairo_bool_t has_supported; @@ -53,7 +52,6 @@ typedef struct { cairo_region_t supported_region; cairo_region_t fallback_region; - cairo_rectangle_int_t current_clip; cairo_box_t page_bbox; cairo_bool_t has_ctm; @@ -97,61 +95,38 @@ static cairo_int_status_t _analyze_meta_surface_pattern (cairo_analysis_surface_t *surface, const cairo_pattern_t *pattern) { - cairo_surface_t *analysis = &surface->base; const cairo_surface_pattern_t *surface_pattern; - cairo_status_t status; cairo_bool_t old_has_ctm; cairo_matrix_t old_ctm, p2d; - cairo_rectangle_int_t old_clip; - cairo_rectangle_int_t meta_extents; - int old_width; - int old_height; + cairo_status_t status; assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); surface_pattern = (const cairo_surface_pattern_t *) pattern; assert (_cairo_surface_is_meta (surface_pattern->surface)); - old_width = surface->width; - old_height = surface->height; - old_clip = surface->current_clip; - status = _cairo_surface_get_extents (surface_pattern->surface, &meta_extents); - if (_cairo_status_is_error (status)) - return status; - - surface->width = meta_extents.width; - surface->height = meta_extents.height; - surface->current_clip.x = 0; - surface->current_clip.y = 0; - surface->current_clip.width = surface->width; - surface->current_clip.height = surface->height; old_ctm = surface->ctm; old_has_ctm = surface->has_ctm; + p2d = pattern->matrix; status = cairo_matrix_invert (&p2d); - /* _cairo_pattern_set_matrix guarantees invertibility */ assert (status == CAIRO_STATUS_SUCCESS); cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm); - surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm); + surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm); status = _cairo_meta_surface_replay_and_create_regions (surface_pattern->surface, - analysis); - if (status == CAIRO_STATUS_SUCCESS) - status = analysis->status; + &surface->base); surface->ctm = old_ctm; surface->has_ctm = old_has_ctm; - surface->current_clip = old_clip; - surface->width = old_width; - surface->height = old_height; return status; } static cairo_int_status_t -_add_operation (cairo_analysis_surface_t *surface, - cairo_rectangle_int_t *rect, - cairo_int_status_t backend_status) +_add_operation (cairo_analysis_surface_t *surface, + cairo_rectangle_int_t *rect, + cairo_int_status_t backend_status) { cairo_int_status_t status; cairo_box_t bbox; @@ -174,26 +149,33 @@ _add_operation (cairo_analysis_surface_t *surface, _cairo_box_from_rectangle (&bbox, rect); if (surface->has_ctm) { - - _cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL); - - if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) { - /* Even though the operation is not visible we must be - * careful to not allow unsupported operations to be - * replayed to the backend during - * CAIRO_PAGINATED_MODE_RENDER */ - if (backend_status == CAIRO_STATUS_SUCCESS || - backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) - { - return CAIRO_STATUS_SUCCESS; - } - else - { - return CAIRO_INT_STATUS_IMAGE_FALLBACK; + int tx, ty; + + if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) { + rect->x += tx; + rect->y += ty; + } else { + _cairo_matrix_transform_bounding_box_fixed (&surface->ctm, + &bbox, NULL); + + if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) { + /* Even though the operation is not visible we must be + * careful to not allow unsupported operations to be + * replayed to the backend during + * CAIRO_PAGINATED_MODE_RENDER */ + if (backend_status == CAIRO_STATUS_SUCCESS || + backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) + { + return CAIRO_STATUS_SUCCESS; + } + else + { + return CAIRO_INT_STATUS_IMAGE_FALLBACK; + } } - } - _cairo_box_round_to_rectangle (&bbox, rect); + _cairo_box_round_to_rectangle (&bbox, rect); + } } if (surface->first_op) { @@ -234,8 +216,7 @@ _add_operation (cairo_analysis_surface_t *surface, * this region will be emitted as native operations. */ surface->has_supported = TRUE; - status = cairo_region_union_rectangle (&surface->supported_region, rect); - return status; + return cairo_region_union_rectangle (&surface->supported_region, rect); } /* Add the operation to the unsupported region. This region will @@ -270,101 +251,101 @@ _cairo_analysis_surface_finish (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_analysis_surface_intersect_clip_path (void *abstract_surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) +static cairo_bool_t +_cairo_analysis_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) { cairo_analysis_surface_t *surface = abstract_surface; - if (path == NULL) { - surface->current_clip.x = 0; - surface->current_clip.y = 0; - surface->current_clip.width = surface->width; - surface->current_clip.height = surface->height; - } else { - cairo_rectangle_int_t extents; - cairo_bool_t is_empty; + return _cairo_surface_get_extents (surface->target, rectangle); +} - _cairo_path_fixed_approximate_clip_extents (path, &extents); - is_empty = _cairo_rectangle_intersect (&surface->current_clip, - &extents); - } +static void +_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip) +{ + const cairo_rectangle_int_t *clip_extents; + cairo_bool_t is_empty; - return CAIRO_STATUS_SUCCESS; + clip_extents = NULL; + if (clip != NULL) + clip_extents = _cairo_clip_get_extents (clip); + + if (clip_extents != NULL) + is_empty = _cairo_rectangle_intersect (extents, clip_extents); } -static cairo_int_status_t -_cairo_analysis_surface_get_extents (void *abstract_surface, - cairo_rectangle_int_t *rectangle) +static void +_cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip, + cairo_rectangle_int_t *extents) { - cairo_analysis_surface_t *surface = abstract_surface; + cairo_bool_t is_empty; - return _cairo_surface_get_extents (surface->target, rectangle); + is_empty = _cairo_surface_get_extents (&surface->base, extents); + + if (_cairo_operator_bounded_by_source (op)) { + cairo_rectangle_int_t source_extents; + + _cairo_pattern_get_extents (source, &source_extents); + is_empty = _cairo_rectangle_intersect (extents, &source_extents); + } + + _rectangle_intersect_clip (extents, clip); } static cairo_int_status_t _cairo_analysis_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *paint_extents) + cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; - cairo_status_t status, backend_status; + cairo_status_t backend_status; cairo_rectangle_int_t extents; - cairo_bool_t is_empty; - if (!surface->target->backend->paint) + if (surface->target->backend->paint == NULL) { backend_status = CAIRO_INT_STATUS_UNSUPPORTED; - else - backend_status = (*surface->target->backend->paint) (surface->target, op, - source, NULL); + } else { + backend_status = + surface->target->backend->paint (surface->target, + op, source, clip); + if (_cairo_status_is_error (backend_status)) + return backend_status; + } if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) backend_status = _analyze_meta_surface_pattern (surface, source); - status = _cairo_surface_get_extents (&surface->base, &extents); - if (_cairo_status_is_error (status)) - return status; - - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_int_t source_extents; - - status = _cairo_pattern_get_extents (source, &source_extents); - if (unlikely (status)) - return status; - - is_empty = _cairo_rectangle_intersect (&extents, &source_extents); - } - - is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip); - if (paint_extents) - *paint_extents = extents; - - status = _add_operation (surface, &extents, backend_status); + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); - return status; + return _add_operation (surface, &extents, backend_status); } static cairo_int_status_t -_cairo_analysis_surface_mask (void *abstract_surface, - cairo_operator_t op, +_cairo_analysis_surface_mask (void *abstract_surface, + cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *mask_extents) + cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; - cairo_int_status_t status, backend_status; + cairo_int_status_t backend_status; cairo_rectangle_int_t extents; cairo_bool_t is_empty; - if (!surface->target->backend->mask) + if (surface->target->backend->mask == NULL) { backend_status = CAIRO_INT_STATUS_UNSUPPORTED; - else - backend_status = (*surface->target->backend->mask) (surface->target, op, - source, mask, NULL); + } else { + backend_status = + surface->target->backend->mask (surface->target, + op, source, mask, clip); + if (_cairo_status_is_error (backend_status)) + return backend_status; + } if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) { cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS; @@ -395,37 +376,19 @@ _cairo_analysis_surface_mask (void *abstract_surface, backend_mask_status); } - status = _cairo_surface_get_extents (&surface->base, &extents); - if (_cairo_status_is_error (status)) - return status; - - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_int_t source_extents; - - status = _cairo_pattern_get_extents (source, &source_extents); - if (unlikely (status)) - return status; - - is_empty = _cairo_rectangle_intersect (&extents, &source_extents); - } + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); if (_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_int_t mask_extents; - status = _cairo_pattern_get_extents (mask, &mask_extents); - if (unlikely (status)) - return status; - + _cairo_pattern_get_extents (mask, &mask_extents); is_empty = _cairo_rectangle_intersect (&extents, &mask_extents); - } - - is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip); - if (mask_extents) - *mask_extents = extents; - status = _add_operation (surface, &extents, backend_status); + } - return status; + return _add_operation (surface, &extents, backend_status); } static cairo_int_status_t @@ -438,55 +401,61 @@ _cairo_analysis_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *stroke_extents) + cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; - cairo_status_t status, backend_status; + cairo_status_t backend_status; cairo_rectangle_int_t extents; cairo_bool_t is_empty; - if (!surface->target->backend->stroke) + if (surface->target->backend->stroke == NULL) { backend_status = CAIRO_INT_STATUS_UNSUPPORTED; - else - backend_status = (*surface->target->backend->stroke) (surface->target, op, - source, path, style, - ctm, ctm_inverse, - tolerance, antialias, NULL); + } else { + backend_status = + surface->target->backend->stroke (surface->target, op, + source, path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + if (_cairo_status_is_error (backend_status)) + return backend_status; + } if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) backend_status = _analyze_meta_surface_pattern (surface, source); - status = _cairo_surface_get_extents (&surface->base, &extents); - if (_cairo_status_is_error (status)) - return status; - - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_int_t source_extents; - - status = _cairo_pattern_get_extents (source, &source_extents); - if (unlikely (status)) - return status; - - is_empty = _cairo_rectangle_intersect (&extents, &source_extents); - } - - is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip); + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); if (_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_int_t mask_extents; - _cairo_path_fixed_approximate_stroke_extents (path, - style, ctm, - &mask_extents); + /* If the backend can handle the stroke, then mark the approximate + * extents of the operation. However, if we need to fallback in order + * to draw the stroke, then ensure that the fallback is as tight as + * possible -- both to minimise output file size and to ensure good + * quality printed output for neighbouring regions. + */ + if (backend_status == CAIRO_STATUS_SUCCESS) { + _cairo_path_fixed_approximate_stroke_extents (path, + style, ctm, + &mask_extents); + } else { + cairo_status_t status; + + status = _cairo_path_fixed_stroke_extents (path, style, + ctm, ctm_inverse, + tolerance, + &mask_extents); + if (unlikely (status)) + return status; + } is_empty = _cairo_rectangle_intersect (&extents, &mask_extents); } - if (stroke_extents) - *stroke_extents = extents; - status = _add_operation (surface, &extents, backend_status); - - return status; + return _add_operation (surface, &extents, backend_status); } static cairo_int_status_t @@ -497,53 +466,49 @@ _cairo_analysis_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *fill_extents) + cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; - cairo_status_t status, backend_status; + cairo_status_t backend_status; cairo_rectangle_int_t extents; cairo_bool_t is_empty; - if (!surface->target->backend->fill) + if (surface->target->backend->fill == NULL) { backend_status = CAIRO_INT_STATUS_UNSUPPORTED; - else - backend_status = (*surface->target->backend->fill) (surface->target, op, - source, path, fill_rule, - tolerance, antialias, NULL); + } else { + backend_status = + surface->target->backend->fill (surface->target, op, + source, path, fill_rule, + tolerance, antialias, + clip); + if (_cairo_status_is_error (backend_status)) + return backend_status; + } if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) backend_status = _analyze_meta_surface_pattern (surface, source); - status = _cairo_surface_get_extents (&surface->base, &extents); - if (_cairo_status_is_error (status)) - return status; - - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_int_t source_extents; - - status = _cairo_pattern_get_extents (source, &source_extents); - if (unlikely (status)) - return status; - - is_empty = _cairo_rectangle_intersect (&extents, &source_extents); - } - - is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip); + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); if (_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_int_t mask_extents; - _cairo_path_fixed_approximate_fill_extents (path, - &mask_extents); - + /* We want speed for the likely case where the operation can be + * performed natively, but accuracy if we have to resort to + * using images. + */ + if (backend_status == CAIRO_STATUS_SUCCESS) { + _cairo_path_fixed_approximate_fill_extents (path, &mask_extents); + } else { + _cairo_path_fixed_fill_extents (path, fill_rule, tolerance, + &mask_extents); + } is_empty = _cairo_rectangle_intersect (&extents, &mask_extents); } - if (fill_extents) - *fill_extents = extents; - - status = _add_operation (surface, &extents, backend_status); - return status; + return _add_operation (surface, &extents, backend_status); } static cairo_int_status_t @@ -553,8 +518,8 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *show_glyphs_extents) + cairo_clip_t *clip, + int *remaining_glyphs) { cairo_analysis_surface_t *surface = abstract_surface; cairo_status_t status, backend_status; @@ -562,41 +527,42 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, cairo_bool_t is_empty; /* Adapted from _cairo_surface_show_glyphs */ - if (surface->target->backend->show_glyphs) - backend_status = (*surface->target->backend->show_glyphs) (surface->target, op, - source, - glyphs, num_glyphs, - scaled_font, - remaining_glyphs, NULL); - else if (surface->target->backend->show_text_glyphs) - backend_status = surface->target->backend->show_text_glyphs (surface->target, op, - source, - NULL, 0, - glyphs, num_glyphs, - NULL, 0, - FALSE, - scaled_font, NULL); + if (surface->target->backend->show_glyphs != NULL) { + backend_status = + surface->target->backend->show_glyphs (surface->target, op, + source, + glyphs, num_glyphs, + scaled_font, + clip, + remaining_glyphs); + if (_cairo_status_is_error (backend_status)) + return backend_status; + } + else if (surface->target->backend->show_text_glyphs != NULL) + { + backend_status = + surface->target->backend->show_text_glyphs (surface->target, op, + source, + NULL, 0, + glyphs, num_glyphs, + NULL, 0, + FALSE, + scaled_font, + clip); + if (_cairo_status_is_error (backend_status)) + return backend_status; + } else + { backend_status = CAIRO_INT_STATUS_UNSUPPORTED; + } if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) backend_status = _analyze_meta_surface_pattern (surface, source); - status = _cairo_surface_get_extents (&surface->base, &extents); - if (_cairo_status_is_error (status)) - return status; - - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_int_t source_extents; - - status = _cairo_pattern_get_extents (source, &source_extents); - if (unlikely (status)) - return status; - - is_empty = _cairo_rectangle_intersect (&extents, &source_extents); - } - - is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip); + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); if (_cairo_operator_bounded_by_mask (op)) { status = _cairo_scaled_font_glyph_device_extents (scaled_font, @@ -608,12 +574,8 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface, is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents); } - if (show_glyphs_extents) - *show_glyphs_extents = extents; - - status = _add_operation (surface, &extents, backend_status); - return status; + return _add_operation (surface, &extents, backend_status); } static cairo_bool_t @@ -636,7 +598,7 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *show_text_glyphs_extents) + cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; cairo_status_t status, backend_status; @@ -645,20 +607,33 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, /* Adapted from _cairo_surface_show_glyphs */ backend_status = CAIRO_INT_STATUS_UNSUPPORTED; - if (surface->target->backend->show_text_glyphs) - backend_status = surface->target->backend->show_text_glyphs (surface->target, op, - source, - utf8, utf8_len, - glyphs, num_glyphs, - clusters, num_clusters, cluster_flags, - scaled_font, NULL); - if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) { + if (surface->target->backend->show_text_glyphs != NULL) { + backend_status = + surface->target->backend->show_text_glyphs (surface->target, op, + source, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font, + clip); + if (_cairo_status_is_error (backend_status)) + return backend_status; + } + if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && + surface->target->backend->show_glyphs != NULL) + { int remaining_glyphs = num_glyphs; - backend_status = surface->target->backend->show_glyphs (surface->target, op, - source, - glyphs, num_glyphs, - scaled_font, - &remaining_glyphs, NULL); + backend_status = + surface->target->backend->show_glyphs (surface->target, op, + source, + glyphs, num_glyphs, + scaled_font, + clip, + &remaining_glyphs); + if (_cairo_status_is_error (backend_status)) + return backend_status; + glyphs += num_glyphs - remaining_glyphs; num_glyphs = remaining_glyphs; if (remaining_glyphs == 0) @@ -668,21 +643,9 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) backend_status = _analyze_meta_surface_pattern (surface, source); - status = _cairo_surface_get_extents (&surface->base, &extents); - if (_cairo_status_is_error (status)) - return status; - - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_int_t source_extents; - - status = _cairo_pattern_get_extents (source, &source_extents); - if (unlikely (status)) - return status; - - is_empty = _cairo_rectangle_intersect (&extents, &source_extents); - } - - is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip); + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); if (_cairo_operator_bounded_by_mask (op)) { status = _cairo_scaled_font_glyph_device_extents (scaled_font, @@ -694,12 +657,8 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents); } - if (show_text_glyphs_extents) - *show_text_glyphs_extents = extents; - - status = _add_operation (surface, &extents, backend_status); - return status; + return _add_operation (surface, &extents, backend_status); } static const cairo_surface_backend_t cairo_analysis_surface_backend = { @@ -718,8 +677,6 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - NULL, /* set_clip_region */ - _cairo_analysis_surface_intersect_clip_path, _cairo_analysis_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -734,7 +691,6 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = { _cairo_analysis_surface_show_glyphs, NULL, /* snapshot */ NULL, /* is_similar */ - NULL, /* reset */ NULL, /* fill_stroke */ NULL, /* create_solid_pattern_surface */ NULL, /* can_repaint_solid_pattern_surface */ @@ -743,9 +699,7 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = { }; cairo_surface_t * -_cairo_analysis_surface_create (cairo_surface_t *target, - int width, - int height) +_cairo_analysis_surface_create (cairo_surface_t *target) { cairo_analysis_surface_t *surface; cairo_status_t status; @@ -763,8 +717,6 @@ _cairo_analysis_surface_create (cairo_surface_t *target, _cairo_surface_init (&surface->base, &cairo_analysis_surface_backend, CAIRO_CONTENT_COLOR_ALPHA); - surface->width = width; - surface->height = height; cairo_matrix_init_identity (&surface->ctm); surface->has_ctm = FALSE; @@ -781,24 +733,12 @@ _cairo_analysis_surface_create (cairo_surface_t *target, surface->page_bbox.p2.x = 0; surface->page_bbox.p2.y = 0; - if (width == -1 && height == -1) { - surface->current_clip.x = CAIRO_RECT_INT_MIN; - surface->current_clip.y = CAIRO_RECT_INT_MIN; - surface->current_clip.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; - surface->current_clip.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; - } else { - surface->current_clip.x = 0; - surface->current_clip.y = 0; - surface->current_clip.width = width; - surface->current_clip.height = height; - } - return &surface->base; } void _cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface, - cairo_matrix_t *ctm) + const cairo_matrix_t *ctm) { cairo_analysis_surface_t *surface; @@ -808,7 +748,7 @@ _cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface, surface = (cairo_analysis_surface_t *) abstract_surface; surface->ctm = *ctm; - surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm); + surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm); } void @@ -872,21 +812,17 @@ _return_success (void) /* These typedefs are just to silence the compiler... */ typedef cairo_int_status_t -(*_set_clip_region_func) (void *surface, - cairo_region_t *region); - -typedef cairo_int_status_t (*_paint_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); typedef cairo_int_status_t (*_mask_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); typedef cairo_int_status_t (*_stroke_func) (void *surface, @@ -898,7 +834,7 @@ typedef cairo_int_status_t cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); typedef cairo_int_status_t (*_fill_func) (void *surface, @@ -908,7 +844,7 @@ typedef cairo_int_status_t cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); typedef cairo_int_status_t (*_show_glyphs_func) (void *surface, @@ -917,8 +853,8 @@ typedef cairo_int_status_t cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip, + int *remaining_glyphs); static const cairo_surface_backend_t cairo_null_surface_backend = { CAIRO_INTERNAL_SURFACE_TYPE_NULL, @@ -937,8 +873,6 @@ static const cairo_surface_backend_t cairo_null_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - (_set_clip_region_func) _return_success, /* set_clip_region */ - NULL, /* intersect_clip_path */ NULL, /* get_extents */ NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -953,7 +887,6 @@ static const cairo_surface_backend_t cairo_null_surface_backend = { (_show_glyphs_func) _return_success, /* show_glyphs */ NULL, /* snapshot */ NULL, /* is_similar */ - NULL, /* reset */ NULL, /* fill_stroke */ NULL, /* create_solid_pattern_surface */ NULL, /* can_repaint_solid_pattern_surface */ diff --git a/src/cairo-beos-surface.cpp b/src/cairo-beos-surface.cpp index e527272e..6fbdc470 100644 --- a/src/cairo-beos-surface.cpp +++ b/src/cairo-beos-surface.cpp @@ -56,6 +56,8 @@ struct cairo_beos_surface_t { cairo_surface_t base; + cairo_region_t *clip_region; + BView* view; /* @@ -70,7 +72,6 @@ struct cairo_beos_surface_t { BBitmap* bitmap; - // If true, surface and view should be deleted when this surface is // destroyed bool owns_bitmap_view; @@ -101,27 +102,28 @@ _cairo_beos_surface_create_internal (BView* view, BBitmap* bmp, bool owns_bitmap_view = false); -static BRect -_cairo_rect_to_brect (const cairo_rectangle_int16_t* rect) +static inline BRect +_cairo_rectangle_to_brect (const cairo_rectangle_int_t* rect) { // A BRect is one pixel wider than you'd think - return BRect(rect->x, rect->y, rect->x + rect->width - 1, - rect->y + rect->height - 1); + return BRect (rect->x, rect->y, + rect->x + rect->width - 1, + rect->y + rect->height - 1); } -static cairo_rectangle_int16_t -_brect_to_cairo_rect (const BRect& rect) +static inline cairo_rectangle_int_t +_brect_to_cairo_rectangle (const BRect &rect) { - cairo_rectangle_int16_t retval; - retval.x = int(rect.left + 0.5); - retval.y = int(rect.top + 0.5); - retval.width = rect.IntegerWidth() + 1; - retval.height = rect.IntegerHeight() + 1; + cairo_rectangle_int_t retval; + retval.x = floor (rect.left); + retval.y = floor (rect.top); + retval.width = ceil (rect.right) - retval.x + 1; + retval.height = ceil (rect.bottom) - rectval.y + 1; return retval; } -static rgb_color -_cairo_color_to_be_color (const cairo_color_t* color) +static inline rgb_color +_cairo_color_to_be_color (const cairo_color_t *color) { // This factor ensures a uniform distribution of numbers const float factor = 256 - 1e-5; @@ -199,32 +201,8 @@ _cairo_beos_view_to_bitmap (BView* view, return ERROR; } -inline unsigned char -unpremultiply (unsigned char color, - unsigned char alpha) -{ - if (alpha == 0) - return 0; - // plus alpha/2 to round instead of truncate - return (color * 255 + alpha / 2) / alpha; -} - -inline unsigned char -premultiply (unsigned char color, - unsigned char alpha) -{ - // + 127 to round, instead of truncate - return (color * alpha + 127) / 255; -} - -/** - * unpremultiply_rgba: - * - * Takes an input in ABGR premultiplied image data and unmultiplies it. - * The result is stored in retdata. - **/ static void -unpremultiply_rgba (unsigned char* data, +unpremultiply_bgra (unsigned char* data, int width, int height, int stride, @@ -235,52 +213,108 @@ unpremultiply_rgba (unsigned char* data, in < end; in += stride, out += stride) { - for (int i = 0; i < width; ++i) { - // XXX for a big-endian platform this'd have to change - int idx = 4 * i; - unsigned char alpha = in[idx + 3]; - out[idx + 0] = unpremultiply(in[idx + 0], alpha); // B - out[idx + 1] = unpremultiply(in[idx + 1], alpha); // G - out[idx + 2] = unpremultiply(in[idx + 2], alpha); // R - out[idx + 3] = in[idx + 3]; // Alpha + for (int i = 0; i < width; i ++) { + uint8_t *b = &out[4*i]; + uint32_t pixel; + uint8_t alpha; + + memcpy (&pixel, &data[4*i], sizeof (uint32_t)); + alpha = pixel & 0xff; + if (alpha == 0) { + b[0] = b[1] = b[2] = b[3] = 0; + } else { + b[0] = (((pixel >> 24) & 0xff) * 255 + alpha / 2) / alpha; + b[1] = (((pixel >> 16) & 0xff) * 255 + alpha / 2) / alpha; + b[2] = (((pixel >> 8) & 0xff) * 255 + alpha / 2) / alpha; + b[3] = alpha; + } } } } -/** - * premultiply_rgba: - * - * Takes an input in ABGR non-premultiplied image data and premultiplies it. - * The returned data must be freed with free(). - **/ +static inline int +multiply_alpha (int alpha, int color) +{ + int temp = (alpha * color) + 0x80; + return ((temp + (temp >> 8)) >> 8); +} + static unsigned char* -premultiply_rgba (unsigned char* data, +premultiply_bgra (unsigned char* data, int width, int height, int stride) { - unsigned char* retdata = reinterpret_cast<unsigned char*>(_cairo_malloc_ab(height, stride)); + uint8_t * retdata = reinterpret_cast<unsigned char*>(_cairo_malloc_ab(height, stride)); if (!retdata) return NULL; - unsigned char* end = data + stride * height; - for (unsigned char* in = data, *out = retdata; + uint8_t * end = data + stride * height; + for (uint8_t * in = data, *out = retdata; in < end; in += stride, out += stride) { - for (int i = 0; i < width; ++i) { - // XXX for a big-endian platform this'd have to change - int idx = 4 * i; - unsigned char alpha = in[idx + 3]; - out[idx + 0] = premultiply(in[idx + 0], alpha); // B - out[idx + 1] = premultiply(in[idx + 1], alpha); // G - out[idx + 2] = premultiply(in[idx + 2], alpha); // R - out[idx + 3] = in[idx + 3]; // Alpha + for (int i = 0; i < width; i ++) { + uint8_t *base = &in[4*i]; + uint8_t alpha = base[3]; + uint32_t p; + + if (alpha == 0) { + p = 0; + } else { + uint8_t blue = base[0]; + uint8_t green = base[1]; + uint8_t red = base[2]; + + if (alpha != 0xff) { + blue = multiply_alpha (alpha, blue); + green = multiply_alpha (alpha, green); + red = multiply_alpha (alpha, red); + } + p = (alpha << 0) | (red << 8) | (green << 16) | (blue << 24); + } + memcpy (&out[4*i], &p, sizeof (uint32_t)); } } return retdata; } +static cairo_int_status_t +_cairo_beos_surface_set_clip_region (cairo_beos_surface_t *surface, + cairo_region_t *region) +{ + cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( + abstract_surface); + AutoLockView locker(surface->view); + assert (locker); + + if (region == surface->clip_region) + return CAIRO_INT_STATUS_SUCCESS; + + cairo_region_destroy (surface->clip_region); + surface->clip_region = cairo_region_reference (region); + + if (region == NULL) { + // No clipping + surface->view->ConstrainClippingRegion(NULL); + return CAIRO_INT_STATUS_SUCCESS; + } + + int count = cairo_region_num_rectangles (region); + BRegion bregion; + for (int i = 0; i < count; ++i) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (region, i, &rect); + // Have to substract one, because for pixman, the second coordinate + // lies outside the rectangle. + bregion.Include (_cairo_rectangle_to_brect (&rect)); + } + surface->view->ConstrainClippingRegion(&bregion); + return CAIRO_INT_STATUS_SUCCESS; +} + + /** * _cairo_beos_bitmap_to_surface: * @@ -309,8 +343,8 @@ _cairo_beos_bitmap_to_surface (BBitmap* bitmap) return imgsurf; } - cairo_format_t cformat = format == B_RGB32 ? CAIRO_FORMAT_RGB24 - : CAIRO_FORMAT_ARGB32; + cairo_format_t cformat = format == B_RGB32 ? + CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32; BRect bounds(bitmap->Bounds()); unsigned char* bits = reinterpret_cast<unsigned char*>(bitmap->Bits()); @@ -318,8 +352,8 @@ _cairo_beos_bitmap_to_surface (BBitmap* bitmap) int height = bounds.IntegerHeight() + 1; unsigned char* premultiplied; if (cformat == CAIRO_FORMAT_ARGB32) { - premultiplied = premultiply_rgba(bits, width, height, - bitmap->BytesPerRow()); + premultiplied = premultiply_bgra (bits, width, height, + bitmap->BytesPerRow()); } else { premultiplied = reinterpret_cast<unsigned char*>( _cairo_malloc_ab(bitmap->BytesPerRow(), height)); @@ -327,7 +361,7 @@ _cairo_beos_bitmap_to_surface (BBitmap* bitmap) memcpy(premultiplied, bits, bitmap->BytesPerRow() * height); } if (!premultiplied) - return NULL; + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); cairo_image_surface_t* surf = reinterpret_cast<cairo_image_surface_t*> (cairo_image_surface_create_for_data(premultiplied, @@ -355,11 +389,11 @@ _cairo_image_surface_to_bitmap (cairo_image_surface_t* surface) switch (surface->format) { case CAIRO_FORMAT_ARGB32: { BBitmap* data = new BBitmap(size, B_RGBA32); - unpremultiply_rgba(surface->data, - surface->width, - surface->height, - surface->stride, - reinterpret_cast<unsigned char*>(data->Bits())); + unpremultiply_bgra (surface->data, + surface->width, + surface->height, + surface->stride, + reinterpret_cast<unsigned char*>(data->Bits())); return data; } case CAIRO_FORMAT_RGB24: { @@ -384,44 +418,44 @@ _cairo_op_to_be_op (cairo_operator_t cairo_op, drawing_mode* beos_op) { switch (cairo_op) { - - case CAIRO_OPERATOR_SOURCE: - *beos_op = B_OP_COPY; - return true; - case CAIRO_OPERATOR_OVER: - *beos_op = B_OP_ALPHA; - return true; - - case CAIRO_OPERATOR_ADD: - // Does not actually work + case CAIRO_OPERATOR_SOURCE: + *beos_op = B_OP_COPY; + return true; + case CAIRO_OPERATOR_OVER: + *beos_op = B_OP_ALPHA; + return true; + + case CAIRO_OPERATOR_ADD: + // Does not actually work + // XXX This is a fundamental compositing operator, it has to work! #if 1 - return false; + return false; #else - *beos_op = B_OP_ADD; - return true; + *beos_op = B_OP_ADD; + return true; #endif - case CAIRO_OPERATOR_CLEAR: - // Does not map to B_OP_ERASE - it replaces the dest with the low - // color, instead of transparency; could be done by setting low - // color appropriately. + case CAIRO_OPERATOR_CLEAR: + // Does not map to B_OP_ERASE - it replaces the dest with the low + // color, instead of transparency; could be done by setting low + // color appropriately. - case CAIRO_OPERATOR_IN: - case CAIRO_OPERATOR_OUT: - case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_ATOP: - case CAIRO_OPERATOR_DEST: - case CAIRO_OPERATOR_DEST_OVER: - case CAIRO_OPERATOR_DEST_IN: - case CAIRO_OPERATOR_DEST_OUT: - case CAIRO_OPERATOR_DEST_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_DEST_ATOP: - case CAIRO_OPERATOR_XOR: - case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_SATURATE: - default: - return false; - }; + default: + return false; + } } static cairo_surface_t * @@ -430,8 +464,6 @@ _cairo_beos_surface_create_similar (void *abstract_surface, int width, int height) { - fprintf(stderr, "Creating similar\n"); - cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( abstract_surface); @@ -444,9 +476,7 @@ _cairo_beos_surface_create_similar (void *abstract_surface, BBitmap* bmp; switch (content) { case CAIRO_CONTENT_ALPHA: - // Can't support this natively - return _cairo_image_surface_create_with_content(content, width, - height); + return NULL; case CAIRO_CONTENT_COLOR_ALPHA: bmp = new BBitmap(rect, B_RGBA32, true); break; @@ -470,10 +500,9 @@ _cairo_beos_surface_create_similar (void *abstract_surface, } break; default: - assert(0); + ASSERT_NOT_REACHED; return NULL; - - }; + } BView* view = new BView(rect, "Cairo bitmap view", B_FOLLOW_ALL_SIDES, 0); bmp->AddChild(view); return _cairo_beos_surface_create_internal(view, bmp, true); @@ -495,6 +524,8 @@ _cairo_beos_surface_finish (void *abstract_surface) surface->bitmap = NULL; } + cairo_region_destroy (surface->clip_region); + return CAIRO_STATUS_SUCCESS; } @@ -503,7 +534,6 @@ _cairo_beos_surface_acquire_source_image (void *abstract_surfa cairo_image_surface_t **image_out, void **image_extra) { - fprintf(stderr, "Getting source image\n"); cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( abstract_surface); AutoLockView locker(surface->view); @@ -514,9 +544,9 @@ _cairo_beos_surface_acquire_source_image (void *abstract_surfa surface->view->Sync(); if (surface->bitmap) { - *image_out = _cairo_beos_bitmap_to_surface(surface->bitmap); - if (!*image_out) - return CAIRO_STATUS_NO_MEMORY; + *image_out = _cairo_beos_bitmap_to_surface (surface->bitmap); + if (unlikely ((*image_out)->base.status)) + return (*image_out)->base.status; *image_extra = NULL; return CAIRO_STATUS_SUCCESS; @@ -526,10 +556,10 @@ _cairo_beos_surface_acquire_source_image (void *abstract_surfa if (_cairo_beos_view_to_bitmap(surface->view, &bmp) != OK) return CAIRO_STATUS_NO_MEMORY; /// XXX incorrect if the error was NOT_VISIBLE - *image_out = _cairo_beos_bitmap_to_surface(bmp); - if (!*image_out) { + *image_out = _cairo_beos_bitmap_to_surface (bmp); + if (unlikely ((*image_out)->base.status)) { delete bmp; - return CAIRO_STATUS_NO_MEMORY; + return (*image_out)->base.status; } *image_extra = bmp; @@ -543,17 +573,17 @@ _cairo_beos_surface_release_source_image (void *abstract_surfac { cairo_surface_destroy (&image->base); - BBitmap* bmp = static_cast<BBitmap*>(image_extra); - delete bmp; + if (image_extra != NULL) { + BBitmap* bmp = static_cast<BBitmap*>(image_extra); + delete bmp; + } } - - static cairo_status_t _cairo_beos_surface_acquire_dest_image (void *abstract_surface, - cairo_rectangle_int16_t *interest_rect, + cairo_rectangle_int_t *interest_rect, cairo_image_surface_t **image_out, - cairo_rectangle_int16_t *image_rect, + cairo_rectangle_int_t *image_rect, void **image_extra) { cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( @@ -563,14 +593,14 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface, if (!locker) { *image_out = NULL; *image_extra = NULL; - return CAIRO_STATUS_SUCCESS; + return (cairo_status_t) CAIRO_INT_STATUS_NOTHING_TO_DO; } if (surface->bitmap) { surface->view->Sync(); *image_out = _cairo_beos_bitmap_to_surface(surface->bitmap); - if (!*image_out) - return CAIRO_STATUS_NO_MEMORY; + if (unlikely ((*image_out)->base.status)) + return (*image_out)->base.status; image_rect->x = 0; image_rect->y = 0; @@ -581,7 +611,7 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } - BRect b_interest_rect(_cairo_rect_to_brect(interest_rect)); + BRect b_interest_rect (_cairo_rectangle_to_brect (interest_rect)); BRect rect; BBitmap* bitmap; @@ -595,18 +625,11 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface, if (status == ERROR) return CAIRO_STATUS_NO_MEMORY; - *image_rect = _brect_to_cairo_rect(rect); - -#if 0 - fprintf(stderr, "Requested: (cairo rects) (%ix%i) dim (%u, %u) returning (%ix%i) dim (%u, %u)\n", - interest_rect->x, interest_rect->y, interest_rect->width, interest_rect->height, - image_rect->x, image_rect->y, image_rect->width, image_rect->height); -#endif - + *image_rect = _brect_to_cairo_rectangle(rect); *image_out = _cairo_beos_bitmap_to_surface(bitmap); delete bitmap; - if (!*image_out) - return CAIRO_STATUS_NO_MEMORY; + if (unlikely ((*image_out)->base.status)) + return (*image_out)->base.status; *image_extra = NULL; @@ -616,13 +639,11 @@ _cairo_beos_surface_acquire_dest_image (void *abstract_surface, static void _cairo_beos_surface_release_dest_image (void *abstract_surface, - cairo_rectangle_int16_t *intersect_rect, + cairo_rectangle_int_t *intersect_rect, cairo_image_surface_t *image, - cairo_rectangle_int16_t *image_rect, + cairo_rectangle_int_t *image_rect, void *image_extra) { - fprintf(stderr, "Fallback drawing\n"); - cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( abstract_surface); @@ -634,9 +655,9 @@ _cairo_beos_surface_release_dest_image (void *abstract_surface, surface->view->PushState(); surface->view->SetDrawingMode(B_OP_COPY); - BRect rect(_cairo_rect_to_brect(image_rect)); - surface->view->DrawBitmap(bitmap_to_draw, rect); + surface->view->DrawBitmap (bitmap_to_draw, + _cairo_rectangle_to_brect (image_rect)); surface->view->PopState(); @@ -649,17 +670,19 @@ _cairo_beos_surface_composite (cairo_operator_t op, cairo_pattern_t *src, cairo_pattern_t *mask, void *dst, - int src_x, + int src_x, int src_y, int mask_x, int mask_y, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( dst); + cairo_int_status_t status; AutoLockView locker(surface->view); if (!locker) return CAIRO_INT_STATUS_SUCCESS; @@ -684,6 +707,10 @@ _cairo_beos_surface_composite (cairo_operator_t op, if (!_cairo_matrix_is_integer_translation(&src->matrix, &itx, &ity)) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_beos_surface_set_clip_region (surface, clip_region); + if (unlikely (status)) + return status; + BRect srcRect(src_x + itx, src_y + ity, src_x + itx + width - 1, @@ -731,8 +758,6 @@ _cairo_beos_surface_composite (cairo_operator_t op, return CAIRO_INT_STATUS_UNSUPPORTED; } - fprintf(stderr, "Composite\n"); - // Draw it on screen. surface->view->PushState(); @@ -767,24 +792,17 @@ _cairo_beos_surface_composite (cairo_operator_t op, } -static void -_cairo_beos_surface_fill_rectangle (cairo_beos_surface_t *surface, - cairo_rectangle_int16_t *rect) -{ - BRect brect(_cairo_rect_to_brect(rect)); - surface->view->FillRect(brect); -} - static cairo_int_status_t _cairo_beos_surface_fill_rectangles (void *abstract_surface, cairo_operator_t op, const cairo_color_t *color, - cairo_rectangle_int16_t *rects, - int num_rects) + cairo_rectangle_int_t *rects, + int num_rects, + cairo_region_t *clip_region) { - fprintf(stderr, "Drawing %i rectangles\n", num_rects); cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( abstract_surface); + cairo_int_status_t status; if (num_rects <= 0) return CAIRO_INT_STATUS_SUCCESS; @@ -797,6 +815,10 @@ _cairo_beos_surface_fill_rectangles (void *abstract_surface, if (!_cairo_op_to_be_op(op, &mode)) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_beos_surface_set_clip_region (surface, clip_region); + if (unlikely (status)) + return status; + rgb_color be_color = _cairo_color_to_be_color(color); if (mode == B_OP_ALPHA && be_color.alpha == 0xFF) @@ -808,9 +830,9 @@ _cairo_beos_surface_fill_rectangles (void *abstract_surface, if (mode == B_OP_COPY && be_color.alpha != 0xFF && (!surface->bitmap || surface->bitmap->ColorSpace() != B_RGBA32)) { - be_color.red = premultiply(be_color.red, be_color.alpha); - be_color.green = premultiply(be_color.green, be_color.alpha); - be_color.blue = premultiply(be_color.blue, be_color.alpha); + be_color.red = color->red_short >> 8; + be_color.green = color->green_short >> 8; + be_color.blue = color->blue_short >> 8; } surface->view->PushState(); @@ -822,65 +844,26 @@ _cairo_beos_surface_fill_rectangles (void *abstract_surface, else surface->view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY); - for (int i = 0; i < num_rects; ++i) { - _cairo_beos_surface_fill_rectangle(surface, &rects[i]); - } + for (int i = 0; i < num_rects; ++i) + surface->view->FillRect (_cairo_rectangle_to_brect (&rects[i])); surface->view->PopState(); return CAIRO_INT_STATUS_SUCCESS; } - - -static cairo_int_status_t -_cairo_beos_surface_set_clip_region (void *abstract_surface, - pixman_region16_t *region) -{ - fprintf(stderr, "Setting clip region\n"); - cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( - abstract_surface); - AutoLockView locker(surface->view); - if (!locker) - return CAIRO_INT_STATUS_SUCCESS; - - if (region == NULL) { - // No clipping - surface->view->ConstrainClippingRegion(NULL); - return CAIRO_INT_STATUS_SUCCESS; - } - - int count = pixman_region_num_rects(region); - pixman_box16_t* rects = pixman_region_rects(region); - BRegion bregion; - for (int i = 0; i < count; ++i) { - // Have to substract one, because for pixman, the second coordinate - // lies outside the rectangle. - bregion.Include(BRect(rects[i].x1, rects[i].y1, rects[i].x2 - 1, rects[i].y2 - 1)); - } - surface->view->ConstrainClippingRegion(&bregion); - return CAIRO_INT_STATUS_SUCCESS; -} - -static cairo_int_status_t +static cairo_bool_t _cairo_beos_surface_get_extents (void *abstract_surface, - cairo_rectangle_int16_t *rectangle) + cairo_rectangle_int_t *rectangle) { cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>( abstract_surface); AutoLockView locker(surface->view); if (!locker) - return CAIRO_INT_STATUS_UNSUPPORTED; - - BRect size = surface->view->Bounds(); - - *rectangle = _brect_to_cairo_rect(size); + return FALSE; - // Make sure to have our upperleft edge as (0,0) - rectangle->x = 0; - rectangle->y = 0; - - return CAIRO_INT_STATUS_SUCCESS; + *rectangle = _brect_to_cairo_rectangle (surface->view->Bounds()); + return TRUE; } static const struct _cairo_surface_backend cairo_beos_surface_backend = { @@ -899,8 +882,6 @@ static const struct _cairo_surface_backend cairo_beos_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - _cairo_beos_surface_set_clip_region, - NULL, /* intersect_clip_path */ _cairo_beos_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -938,7 +919,9 @@ _cairo_beos_surface_create_internal (BView* view, surface->bitmap = bmp; surface->owns_bitmap_view = owns_bitmap_view; - return (cairo_surface_t *) surface; + surface->clip_region = NULL; + + return &surface->base; } /** diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h index 4229e4fb..8a3e867a 100644 --- a/src/cairo-clip-private.h +++ b/src/cairo-clip-private.h @@ -43,6 +43,11 @@ extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil; +enum { + CAIRO_CLIP_PATH_HAS_REGION = 0x1, + CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED = 0x2 +}; + struct _cairo_clip_path { cairo_reference_count_t ref_count; cairo_path_fixed_t path; @@ -50,84 +55,74 @@ struct _cairo_clip_path { double tolerance; cairo_antialias_t antialias; cairo_clip_path_t *prev; + + cairo_rectangle_int_t extents; + + /* partial caches */ + unsigned int flags; + cairo_region_t *region; + cairo_surface_t *surface; }; struct _cairo_clip { - cairo_clip_mode_t mode; + /* can be used as a cairo_hash_entry_t for live clips */ + cairo_clip_path_t *path; cairo_bool_t all_clipped; - /* - * Mask-based clipping for cases where the backend - * clipping isn't sufficiently able. - * - * The rectangle here represents the - * portion of the destination surface that this - * clip surface maps to, it does not - * represent the extents of the clip region or - * clip paths - */ - cairo_surface_t *surface; - cairo_rectangle_int_t surface_rect; - /* - * Surface clip serial number to store - * in the surface when this clip is set - */ - unsigned int serial; - /* - * A clip region that can be placed in the surface - */ - cairo_region_t *region; - /* - * If the surface supports path clipping, we store the list of - * clipping paths that has been set here as a linked list. - */ - cairo_clip_path_t *path; }; cairo_private void -_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target); +_cairo_clip_init (cairo_clip_t *clip); cairo_private cairo_status_t +_cairo_clip_init_rectangle (cairo_clip_t *clip, + const cairo_rectangle_int_t *rect); + +cairo_private void _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other); cairo_private cairo_status_t -_cairo_clip_init_deep_copy (cairo_clip_t *clip, - cairo_clip_t *other, - cairo_surface_t *target); +_cairo_clip_init_copy_transformed (cairo_clip_t *clip, + cairo_clip_t *other, + const cairo_matrix_t *matrix); cairo_private void _cairo_clip_reset (cairo_clip_t *clip); cairo_private cairo_status_t _cairo_clip_clip (cairo_clip_t *clip, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias, - cairo_surface_t *target); + cairo_antialias_t antialias); cairo_private cairo_status_t -_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip, - cairo_rectangle_int_t *rectangle); +_cairo_clip_apply_clip (cairo_clip_t *clip, + const cairo_clip_t *other); -cairo_private cairo_status_t -_cairo_clip_intersect_to_region (cairo_clip_t *clip, - cairo_region_t *region); +cairo_private const cairo_rectangle_int_t * +_cairo_clip_get_extents (const cairo_clip_t *clip); -cairo_private cairo_status_t -_cairo_clip_combine_to_surface (cairo_clip_t *clip, - cairo_operator_t op, - cairo_surface_t *dst, - int dst_x, - int dst_y, - const cairo_rectangle_int_t *extents); +cairo_private cairo_surface_t * +_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst); + +cairo_private cairo_int_status_t +_cairo_clip_get_region (cairo_clip_t *clip, + cairo_region_t **region); cairo_private void _cairo_clip_translate (cairo_clip_t *clip, cairo_fixed_t tx, cairo_fixed_t ty); +cairo_private void +_cairo_clip_transform (cairo_clip_t *clip, + const cairo_matrix_t *transform); + +cairo_private void +_cairo_clip_drop_cache (cairo_clip_t *clip); + cairo_private cairo_rectangle_list_t* _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate); diff --git a/src/cairo-clip.c b/src/cairo-clip.c index 79e4cbe6..93348945 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -3,6 +3,7 @@ * * Copyright © 2002 University of Southern California * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Chris Wilson * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -35,802 +36,777 @@ * Contributor(s): * Carl D. Worth <cworth@cworth.org> * Kristian Høgsberg <krh@redhat.com> + * Chris Wilson <chris@chris-wilson.co.uk> */ #include "cairoint.h" #include "cairo-clip-private.h" +#include "cairo-path-fixed-private.h" -static cairo_clip_path_t * -_cairo_clip_path_reference (cairo_clip_path_t *clip_path); +/* Keep a stash of recently freed clip_paths, since we need to + * reallocate them frequently. + */ +#define MAX_FREED_POOL_SIZE 4 +typedef struct { + void *pool[MAX_FREED_POOL_SIZE]; + int top; +} freed_pool_t; -static void -_cairo_clip_path_destroy (cairo_clip_path_t *clip_path); +static freed_pool_t clip_path_pool; -void -_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target) +static void * +_atomic_fetch (void **slot) { - if (target && target->backend) - clip->mode = _cairo_surface_get_clip_mode (target); - else - clip->mode = CAIRO_CLIP_MODE_MASK; - - clip->all_clipped = FALSE; + return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL); +} - clip->surface = NULL; - clip->surface_rect.x = 0; - clip->surface_rect.y = 0; - clip->surface_rect.width = 0; - clip->surface_rect.height = 0; +static cairo_bool_t +_atomic_store (void **slot, void *ptr) +{ + return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr) == NULL; +} - clip->serial = 0; +static void * +_freed_pool_get (freed_pool_t *pool) +{ + void *ptr; + int i; - clip->region = NULL; + i = pool->top - 1; + if (i < 0) + i = 0; - clip->path = NULL; -} + ptr = _atomic_fetch (&pool->pool[i]); + if (ptr != NULL) { + pool->top = i; + return ptr; + } -cairo_status_t -_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other) -{ - clip->mode = other->mode; - - clip->all_clipped = other->all_clipped; - - clip->surface = cairo_surface_reference (other->surface); - clip->surface_rect = other->surface_rect; - - clip->serial = other->serial; - - if (other->region) { - cairo_status_t status; - - clip->region = cairo_region_copy (other->region); - - status = cairo_region_status (clip->region); - if (unlikely (status)) { - cairo_surface_destroy (clip->surface); - cairo_region_destroy (clip->region); - clip->region = NULL; - - return status; + /* either empty or contended */ + for (i = ARRAY_LENGTH (pool->pool); i--;) { + ptr = _atomic_fetch (&pool->pool[i]); + if (ptr != NULL) { + pool->top = i; + return ptr; } - } else { - clip->region = NULL; } - - clip->path = _cairo_clip_path_reference (other->path); - return CAIRO_STATUS_SUCCESS; + /* empty */ + pool->top = 0; + return NULL; } -void -_cairo_clip_reset (cairo_clip_t *clip) +static void +_freed_pool_put (freed_pool_t *pool, void *ptr) { - clip->all_clipped = FALSE; - - /* destroy any existing clip-region artifacts */ - cairo_surface_destroy (clip->surface); - clip->surface = NULL; - - clip->serial = 0; + int i = pool->top; - if (clip->region) { - cairo_region_destroy (clip->region); + if (_atomic_store (&pool->pool[i], ptr)) { + pool->top = i + 1; + return; + } - clip->region = NULL; + /* either full or contended */ + for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) { + if (_atomic_store (&pool->pool[i], ptr)) { + pool->top = i + 1; + return; + } } - _cairo_clip_path_destroy (clip->path); - clip->path = NULL; + /* full */ + pool->top = ARRAY_LENGTH (pool->pool); + free (ptr); } static void -_cairo_clip_set_all_clipped (cairo_clip_t *clip, cairo_surface_t *target) +_freed_pool_reset (freed_pool_t *pool) { - _cairo_clip_reset (clip); + int i; - clip->all_clipped = TRUE; - clip->serial = _cairo_surface_allocate_clip_serial (target); + for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) { + free (pool->pool[i]); + pool->pool[i] = NULL; + } } - -static cairo_status_t -_cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path, - cairo_rectangle_int_t *rectangle) +static cairo_clip_path_t * +_cairo_clip_path_create (cairo_clip_t *clip) { - while (clip_path) { - cairo_rectangle_int_t extents; + cairo_clip_path_t *clip_path; - _cairo_path_fixed_approximate_clip_extents (&clip_path->path, &extents); + clip_path = _freed_pool_get (&clip_path_pool); + if (unlikely (clip_path == NULL)) { + clip_path = malloc (sizeof (cairo_clip_path_t)); + if (unlikely (clip_path == NULL)) + return NULL; + } - if (! _cairo_rectangle_intersect (rectangle, &extents)) - return CAIRO_STATUS_SUCCESS; + CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1); - clip_path = clip_path->prev; - } + clip_path->flags = 0; + clip_path->region = NULL; + clip_path->surface = NULL; - return CAIRO_STATUS_SUCCESS; + clip_path->prev = clip->path; + clip->path = clip_path; + + return clip_path; } -cairo_status_t -_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip, - cairo_rectangle_int_t *rectangle) +static cairo_clip_path_t * +_cairo_clip_path_reference (cairo_clip_path_t *clip_path) { - cairo_status_t status; - cairo_bool_t is_empty; + if (clip_path == NULL) + return NULL; - if (!clip) - return CAIRO_STATUS_SUCCESS; + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count)); - if (clip->all_clipped) { - *rectangle = clip->surface_rect; - return CAIRO_STATUS_SUCCESS; - } + _cairo_reference_count_inc (&clip_path->ref_count); - if (clip->path) { - status = _cairo_clip_path_intersect_to_rectangle (clip->path, - rectangle); - if (unlikely (status)) - return status; - } + return clip_path; +} + +static void +_cairo_clip_path_destroy (cairo_clip_path_t *clip_path) +{ + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count)); - if (clip->region) { - cairo_rectangle_int_t extents; + if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count)) + return; - cairo_region_get_extents (clip->region, &extents); - is_empty = _cairo_rectangle_intersect (rectangle, &extents); - if (is_empty) - return CAIRO_STATUS_SUCCESS; - } + _cairo_path_fixed_fini (&clip_path->path); + if (clip_path->region != NULL) + cairo_region_destroy (clip_path->region); + if (clip_path->surface != NULL) + cairo_surface_destroy (clip_path->surface); - if (clip->surface) - is_empty = _cairo_rectangle_intersect (rectangle, &clip->surface_rect); + if (clip_path->prev != NULL) + _cairo_clip_path_destroy (clip_path->prev); - return CAIRO_STATUS_SUCCESS; + _freed_pool_put (&clip_path_pool, clip_path); +} + +void +_cairo_clip_init (cairo_clip_t *clip) +{ + clip->all_clipped = FALSE; + clip->path = NULL; } +static void +_cairo_clip_set_all_clipped (cairo_clip_t *clip) +{ + clip->all_clipped = TRUE; + if (clip->path != NULL) { + _cairo_clip_path_destroy (clip->path); + clip->path = NULL; + } +} + +/* XXX consider accepting a matrix, no users yet. */ cairo_status_t -_cairo_clip_intersect_to_region (cairo_clip_t *clip, - cairo_region_t *region) +_cairo_clip_init_rectangle (cairo_clip_t *clip, + const cairo_rectangle_int_t *rect) { + cairo_clip_path_t *clip_path; cairo_status_t status; - if (!clip) + _cairo_clip_init (clip); + if (rect == NULL) return CAIRO_STATUS_SUCCESS; - if (clip->all_clipped) - return cairo_region_intersect_rectangle (region, &clip->surface_rect); - - if (clip->path) { - /* Intersect clip path into region. */ + if (rect->width == 0 || rect->height == 0) { + _cairo_clip_set_all_clipped (clip); + return CAIRO_STATUS_SUCCESS; } - if (clip->region) { - status = cairo_region_intersect (region, clip->region); - if (unlikely (status)) - return status; - } + clip_path = _cairo_clip_path_create (clip); + if (unlikely (clip_path == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); - if (clip->surface) - return cairo_region_intersect_rectangle (region, &clip->surface_rect); + _cairo_path_fixed_init (&clip_path->path); + + status = _cairo_path_fixed_move_to (&clip_path->path, + _cairo_fixed_from_int (rect->x), + _cairo_fixed_from_int (rect->y)); + assert (status == CAIRO_STATUS_SUCCESS); + status = _cairo_path_fixed_rel_line_to (&clip_path->path, + _cairo_fixed_from_int (rect->width), + _cairo_fixed_from_int (0)); + assert (status == CAIRO_STATUS_SUCCESS); + status = _cairo_path_fixed_rel_line_to (&clip_path->path, + _cairo_fixed_from_int (0), + _cairo_fixed_from_int (rect->height)); + assert (status == CAIRO_STATUS_SUCCESS); + status = _cairo_path_fixed_rel_line_to (&clip_path->path, + _cairo_fixed_from_int (-rect->width), + _cairo_fixed_from_int (0)); + assert (status == CAIRO_STATUS_SUCCESS); + status = _cairo_path_fixed_close_path (&clip_path->path); + assert (status == CAIRO_STATUS_SUCCESS); + + clip_path->extents = *rect; + clip_path->fill_rule = CAIRO_FILL_RULE_WINDING; + clip_path->tolerance = 1; + clip_path->antialias = CAIRO_ANTIALIAS_NONE; + + /* could preallocate the region if it proves worthwhile */ return CAIRO_STATUS_SUCCESS; } -/* Combines the region of clip->surface given by extents in - * device backend coordinates into the given temporary surface, - * which has its origin at dst_x, dst_y in backend coordinates - */ -cairo_status_t -_cairo_clip_combine_to_surface (cairo_clip_t *clip, - cairo_operator_t op, - cairo_surface_t *dst, - int dst_x, - int dst_y, - const cairo_rectangle_int_t *extents) +void +_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other) { - cairo_surface_pattern_t pattern; - cairo_status_t status; - - if (clip->all_clipped) - return CAIRO_STATUS_SUCCESS; - - _cairo_pattern_init_for_surface (&pattern, clip->surface); - - status = _cairo_surface_composite (op, - &pattern.base, - NULL, - dst, - extents->x - clip->surface_rect.x, - extents->y - clip->surface_rect.y, - 0, 0, - extents->x - dst_x, - extents->y - dst_y, - extents->width, extents->height); - - _cairo_pattern_fini (&pattern.base); + if (other != NULL) { + clip->all_clipped = other->all_clipped; + clip->path = _cairo_clip_path_reference (other->path); + } else { + clip->all_clipped = FALSE; + clip->path = NULL; + } +} - return status; +void +_cairo_clip_reset (cairo_clip_t *clip) +{ + clip->all_clipped = FALSE; + if (clip->path != NULL) { + _cairo_clip_path_destroy (clip->path); + clip->path = NULL; + } } static cairo_status_t _cairo_clip_intersect_path (cairo_clip_t *clip, - cairo_path_fixed_t *path, + const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_clip_path_t *clip_path; cairo_status_t status; + cairo_rectangle_int_t extents; + + if (clip->path != NULL) { + if (_cairo_path_fixed_equal (&clip->path->path, path)) { + if (clip->path->fill_rule == fill_rule) { + if (path->is_rectilinear || + (tolerance == clip->path->tolerance && + antialias == clip->path->antialias)) + { + return CAIRO_STATUS_SUCCESS; + } + } + } + } - if (clip->mode != CAIRO_CLIP_MODE_PATH) - return CAIRO_INT_STATUS_UNSUPPORTED; + _cairo_path_fixed_approximate_clip_extents (path, &extents); + if (extents.width == 0 || extents.height == 0) { + _cairo_clip_set_all_clipped (clip); + return CAIRO_STATUS_SUCCESS; + } + + if (clip->path != NULL) { + cairo_box_t box; + + if (! _cairo_rectangle_intersect (&extents, &clip->path->extents)) { + _cairo_clip_set_all_clipped (clip); + return CAIRO_STATUS_SUCCESS; + } + + /* does this clip wholly subsume the others? */ + if (_cairo_path_fixed_is_box (path, &box)) { + if (box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) && + box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) && + box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) && + box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height)) + { + return CAIRO_STATUS_SUCCESS; + } + } + } - clip_path = malloc (sizeof (cairo_clip_path_t)); + clip_path = _cairo_clip_path_create (clip); if (unlikely (clip_path == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_path_fixed_init_copy (&clip_path->path, path); if (unlikely (status)) { - free (clip_path); + clip->path = clip->path->prev; + _cairo_clip_path_destroy (clip_path); return status; } - CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1); + clip_path->extents = extents; clip_path->fill_rule = fill_rule; clip_path->tolerance = tolerance; clip_path->antialias = antialias; - clip_path->prev = clip->path; - clip->path = clip_path; return CAIRO_STATUS_SUCCESS; } -static cairo_clip_path_t * -_cairo_clip_path_reference (cairo_clip_path_t *clip_path) -{ - if (clip_path == NULL) - return NULL; - - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count)); - - _cairo_reference_count_inc (&clip_path->ref_count); - - return clip_path; -} - -static void -_cairo_clip_path_destroy (cairo_clip_path_t *clip_path) -{ - if (clip_path == NULL) - return; - - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count)); - - if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count)) - return; - - _cairo_path_fixed_fini (&clip_path->path); - _cairo_clip_path_destroy (clip_path->prev); - free (clip_path); -} - - -static cairo_int_status_t -_cairo_clip_intersect_region (cairo_clip_t *clip, - cairo_traps_t *traps, - cairo_surface_t *target) +cairo_status_t +_cairo_clip_clip (cairo_clip_t *clip, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) { - cairo_region_t *region; - cairo_int_status_t status; - if (clip->all_clipped) return CAIRO_STATUS_SUCCESS; - if (clip->mode != CAIRO_CLIP_MODE_REGION) - return CAIRO_INT_STATUS_UNSUPPORTED; - - status = _cairo_traps_extract_region (traps, ®ion); - if (status) - return status; - - if (clip->region) { - status = cairo_region_intersect (clip->region, region); - cairo_region_destroy (region); - } else { - clip->region = region; + /* catch the empty clip path */ + if (_cairo_path_fixed_fill_is_empty (path)) { + _cairo_clip_set_all_clipped (clip); + return CAIRO_STATUS_SUCCESS; } - clip->serial = _cairo_surface_allocate_clip_serial (target); - - if (!clip->region || cairo_region_is_empty (clip->region)) - _cairo_clip_set_all_clipped (clip, target); - - return status; + return _cairo_clip_intersect_path (clip, + path, fill_rule, tolerance, + antialias); } static cairo_status_t -_cairo_clip_intersect_mask (cairo_clip_t *clip, - cairo_traps_t *traps, - cairo_antialias_t antialias, - cairo_surface_t *target) +_cairo_clip_path_reapply_clip_path_transform (cairo_clip_t *clip, + cairo_clip_path_t *other_path, + const cairo_matrix_t *matrix) { - cairo_pattern_union_t pattern; - cairo_box_t extents; - cairo_rectangle_int_t surface_rect, target_rect; - cairo_surface_t *surface = NULL; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - - if (clip->all_clipped) - return CAIRO_STATUS_SUCCESS; + cairo_status_t status; + cairo_clip_path_t *clip_path; + cairo_bool_t is_empty; - /* Represent the clip as a mask surface. We create a new surface - * the size of the intersection of the old mask surface and the - * extents of the new clip path. */ + if (other_path->prev != NULL) { + status = _cairo_clip_path_reapply_clip_path_transform (clip, + other_path->prev, + matrix); + if (unlikely (status)) + return status; + } - _cairo_traps_extents (traps, &extents); - _cairo_box_round_to_rectangle (&extents, &surface_rect); + clip_path = _cairo_clip_path_create (clip); + if (unlikely (clip_path == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); - if (clip->surface != NULL) { - if (! _cairo_rectangle_intersect (&surface_rect, &clip->surface_rect)) - goto DONE; + status = _cairo_path_fixed_init_copy (&clip_path->path, + &other_path->path); + if (unlikely (status)) { + _cairo_clip_path_destroy (clip_path); + return status; } - /* Intersect with the target surface rectangle so we don't use - * more memory and time than we need to. */ - status = _cairo_surface_get_extents (target, &target_rect); - if (status == CAIRO_STATUS_SUCCESS) { - if (! _cairo_rectangle_intersect (&surface_rect, &target_rect)) - goto DONE; + _cairo_path_fixed_transform (&clip_path->path, matrix); + _cairo_path_fixed_approximate_clip_extents (&clip_path->path, + &clip_path->extents); + if (clip_path->prev != NULL) { + is_empty = _cairo_rectangle_intersect (&clip_path->extents, + &clip_path->prev->extents); } - if (surface_rect.width == 0 || surface_rect.height == 0) - goto DONE; + clip_path->fill_rule = other_path->fill_rule; + clip_path->tolerance = other_path->tolerance; + clip_path->antialias = other_path->antialias; - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - /* The clipping operation should ideally be something like the following to - * avoid having to do as many passes over the data + return CAIRO_STATUS_SUCCESS; +} - if (clip->surface != NULL) { - _cairo_pattern_init_for_surface (&pattern.surface, clip->surface); - } else { - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - } - status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN, - &pattern.base, - surface, - antialias, - 0, 0, - 0, 0, - surface_rect.width, - surface_rect.height, - traps->traps, - traps->num_traps); - - However this operation is not accelerated by pixman - - I believe the best possible operation would probably an unbounded SRC - operator. Using SRC we could potentially avoid having to initialize - the surface which would be ideal from an efficiency point of view. - However, CAIRO_OPERATOR_SOURCE is bounded by the trapezoid mask and - _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_SOURCE) will assert - because it assumes CAIRO_OPERATOR_SOURCE has been converted into other - operations. - */ +static cairo_status_t +_cairo_clip_path_reapply_clip_path_translate (cairo_clip_t *clip, + cairo_clip_path_t *other_path, + int tx, int ty) +{ + cairo_status_t status; + cairo_clip_path_t *clip_path; - surface = _cairo_surface_create_similar_solid (target, - CAIRO_CONTENT_ALPHA, - surface_rect.width, - surface_rect.height, - CAIRO_COLOR_TRANSPARENT); - if (surface->status) { - _cairo_pattern_fini (&pattern.base); - return surface->status; + if (other_path->prev != NULL) { + status = _cairo_clip_path_reapply_clip_path_translate (clip, + other_path->prev, + tx, ty); + if (unlikely (status)) + return status; } - /* Render the new clipping path into the new mask surface. */ - - _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y); - - status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD, - &pattern.base, - surface, - antialias, - 0, 0, - 0, 0, - surface_rect.width, - surface_rect.height, - traps->traps, - traps->num_traps); - - _cairo_pattern_fini (&pattern.base); + clip_path = _cairo_clip_path_create (clip); + if (unlikely (clip_path == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + status = _cairo_path_fixed_init_copy (&clip_path->path, + &other_path->path); if (unlikely (status)) { - cairo_surface_destroy (surface); + _cairo_clip_path_destroy (clip_path); return status; } - /* If there was a clip surface already, combine it with the new - * mask surface using the IN operator, so we get the intersection - * of the old and new clipping paths. */ - - if (clip->surface != NULL) { - _cairo_pattern_init_for_surface (&pattern.surface, clip->surface); + _cairo_path_fixed_translate (&clip_path->path, + _cairo_fixed_from_int (tx), + _cairo_fixed_from_int (ty)); - status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - &pattern.base, - NULL, - surface, - surface_rect.x - clip->surface_rect.x, - surface_rect.y - clip->surface_rect.y, - 0, 0, - 0, 0, - surface_rect.width, - surface_rect.height); + clip_path->fill_rule = other_path->fill_rule; + clip_path->tolerance = other_path->tolerance; + clip_path->antialias = other_path->antialias; - _cairo_pattern_fini (&pattern.base); - - if (unlikely (status)) { - cairo_surface_destroy (surface); - return status; - } + clip_path->flags = other_path->flags; + if (other_path->region != NULL) { + clip_path->region = cairo_region_copy (other_path->region); + cairo_region_translate (clip_path->region, tx, ty); } + clip_path->surface = cairo_surface_reference (other_path->surface); - DONE: - cairo_surface_destroy (clip->surface); - clip->surface = surface; - clip->surface_rect = surface_rect; - clip->serial = _cairo_surface_allocate_clip_serial (target); + clip_path->extents = other_path->extents; + clip_path->extents.x += tx; + clip_path->extents.y += ty; - if (surface_rect.width == 0 || surface_rect.height == 0) - _cairo_clip_set_all_clipped (clip, target); - - return status; + return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_clip_intersect_mask_using_spans (cairo_clip_t *clip, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - cairo_surface_t *target) +cairo_status_t +_cairo_clip_init_copy_transformed (cairo_clip_t *clip, + cairo_clip_t *other, + const cairo_matrix_t *matrix) { - cairo_span_renderer_t *renderer = NULL; - cairo_pattern_union_t pattern; - cairo_rectangle_int_t surface_rect; - cairo_surface_t *surface = NULL; - cairo_status_t status; - cairo_operator_t op; - cairo_composite_rectangles_t rects; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + int tx, ty; - if (clip->all_clipped) + if (other == NULL) { + _cairo_clip_init (clip); return CAIRO_STATUS_SUCCESS; - - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - - /* If we have a clip surface we're going to use IN to combine our - * new clip with the old clip. The ADD is done to a transparent - * surface, as that's a fast way of doing it currently. We should - * really be using SOURCE instead, but _cairo_surface_composite() - * checks that it's not called with SOURCE or DEST. */ - op = clip->surface ? CAIRO_OPERATOR_IN : CAIRO_OPERATOR_ADD; - - /* Test if the target can composite spans. We're going to assume - * this is a good indicator of whether a similar surface is going - * to be able to composite spans too. */ - if ( !_cairo_surface_check_span_renderer (op, - &pattern.base, - target, - antialias, - NULL)) - { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto BAIL; } - status = _cairo_surface_get_extents (target, &surface_rect); - if (status) - goto BAIL; + if (other->all_clipped) { + _cairo_clip_init (clip); + clip->all_clipped = TRUE; + return CAIRO_STATUS_SUCCESS; + } - /* We'll create a new surface the size of the intersection of the - * old mask surface and the extents of the new clip path. */ - { - cairo_rectangle_int_t extents; + if (_cairo_matrix_is_identity (matrix)) { + _cairo_clip_init_copy (clip, other); + return CAIRO_STATUS_SUCCESS; + } - _cairo_path_fixed_approximate_clip_extents (path, &extents); - if (! _cairo_rectangle_intersect (&surface_rect, &extents)) - goto SUCCESS; + if (other->path != NULL) { + _cairo_clip_init (clip); - if (clip->surface != NULL && - ! _cairo_rectangle_intersect (&surface_rect, &clip->surface_rect)) - goto SUCCESS; + /* if we only need to translate, so we can reuse the caches... */ + /* XXX we still loose the benefit of constructs when the copy is + * deleted though. Indirect clip_paths? + */ + if (_cairo_matrix_is_integer_translation (matrix, &tx, &ty)) { + status = _cairo_clip_path_reapply_clip_path_translate (clip, + other->path, + tx, ty); + } else { + status = _cairo_clip_path_reapply_clip_path_transform (clip, + other->path, + matrix); + if (clip->path->extents.width == 0 && + clip->path->extents.height == 0) + { + _cairo_clip_set_all_clipped (clip); + } + } } - /* Make the new mask surface and optionally initialise it from the - * previous clip if we have one. */ - surface = _cairo_surface_create_similar_solid (target, - CAIRO_CONTENT_ALPHA, - surface_rect.width, - surface_rect.height, - CAIRO_COLOR_TRANSPARENT); - if (surface->status) { - _cairo_pattern_fini (&pattern.base); - return surface->status; - } - - if (clip->surface) { - cairo_surface_pattern_t old_clip; - _cairo_pattern_init_for_surface (&old_clip, clip->surface); - status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, - &old_clip.base, - NULL, - surface, - surface_rect.x - clip->surface_rect.x, - surface_rect.y - clip->surface_rect.y, - 0, 0, - 0, 0, - surface_rect.width, - surface_rect.height); - _cairo_pattern_fini (&old_clip.base); - if (status) - goto BAIL; - } + return status; +} - _cairo_composite_rectangles_init (&rects, - surface_rect.x, - surface_rect.y, - surface_rect.width, - surface_rect.height); - rects.dst.x = 0; - rects.dst.y = 0; - - /* Render the new clipping path into the new mask surface. We've - * chosen op to either combine the new clip path with the existing - * clip mask (if there is one) or just render it. */ - status =_cairo_path_fixed_fill_using_spans (op, &pattern.base, - path, surface, - fill_rule, tolerance, - antialias, &rects); - if (status) - goto BAIL; +static cairo_status_t +_cairo_clip_apply_clip_path (cairo_clip_t *clip, + const cairo_clip_path_t *path) +{ + cairo_status_t status; - SUCCESS: - if (clip->surface != NULL) - cairo_surface_destroy (clip->surface); - clip->surface = surface; - clip->surface_rect = surface_rect; - clip->serial = _cairo_surface_allocate_clip_serial (target); - surface = NULL; - - if (surface_rect.width == 0 || surface_rect.height == 0) - _cairo_clip_set_all_clipped (clip, target); - - BAIL: - if (renderer) - renderer->destroy(renderer); - if (surface) - cairo_surface_destroy (surface); - _cairo_pattern_fini (&pattern.base); - return status; + if (path->prev != NULL) + status = _cairo_clip_apply_clip_path (clip, path->prev); + + return _cairo_clip_intersect_path (clip, + &path->path, + path->fill_rule, + path->tolerance, + path->antialias); } cairo_status_t -_cairo_clip_clip (cairo_clip_t *clip, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - cairo_surface_t *target) +_cairo_clip_apply_clip (cairo_clip_t *clip, + const cairo_clip_t *other) { cairo_status_t status; - cairo_rectangle_int_t limits, extents; - cairo_traps_t traps; - cairo_box_t ignored_box; - cairo_bool_t have_limits; if (clip->all_clipped) return CAIRO_STATUS_SUCCESS; - /* catch the empty clip path */ - if (! path->has_current_point) { - _cairo_clip_set_all_clipped (clip, target); + if (other->all_clipped) { + _cairo_clip_set_all_clipped (clip); return CAIRO_STATUS_SUCCESS; } - status = _cairo_clip_intersect_path (clip, - path, fill_rule, tolerance, - antialias); - if (status == CAIRO_STATUS_SUCCESS) - clip->serial = _cairo_surface_allocate_clip_serial (target); + status = CAIRO_STATUS_SUCCESS; + if (other->path != NULL) + status = _cairo_clip_apply_clip_path (clip, other->path); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + return status; +} + +static cairo_int_status_t +_cairo_clip_path_to_region (cairo_clip_path_t *clip_path) +{ + cairo_int_status_t status; + cairo_traps_t traps; + cairo_region_t *prev = NULL; + cairo_box_t box; - /* TODO: allow ANTIALIAS_NONE when we have a mono scan converter - * again. */ - if (antialias != CAIRO_ANTIALIAS_NONE && - !_cairo_path_fixed_is_box (path, &ignored_box) && - !_cairo_path_fixed_is_region (path)) + if (clip_path->flags & + (CAIRO_CLIP_PATH_HAS_REGION | + CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED)) { - status = _cairo_clip_intersect_mask_using_spans ( - clip, path, fill_rule, tolerance, antialias, target); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + return clip_path->flags & CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED ? + CAIRO_INT_STATUS_UNSUPPORTED : + CAIRO_STATUS_SUCCESS; } - _cairo_traps_init (&traps); - - /* Limit the traps to the target surface and current clip - * - so we don't add more traps than needed. */ - have_limits = FALSE; - if (clip->region != NULL) { - cairo_region_get_extents (clip->region, &limits); - have_limits = TRUE; + if (! clip_path->path.maybe_fill_region) { + clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED; + return CAIRO_INT_STATUS_UNSUPPORTED; } - if (clip->surface != NULL) { - if (have_limits) { - if (! _cairo_rectangle_intersect (&limits, &clip->surface_rect)) { - _cairo_clip_set_all_clipped (clip, target); - return CAIRO_STATUS_SUCCESS; - } - } else { - limits = clip->surface_rect; - have_limits = TRUE; + /* first retrieve the region for our antecedents */ + if (clip_path->prev != NULL) { + status = _cairo_clip_path_to_region (clip_path->prev); + if (status) { + clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED; + return status; } - } - status = _cairo_surface_get_extents (target, &extents); - if (status == CAIRO_STATUS_SUCCESS) { - if (have_limits) { - if (! _cairo_rectangle_intersect (&limits, &extents)) { - _cairo_clip_set_all_clipped (clip, target); - return CAIRO_STATUS_SUCCESS; - } - } else { - limits = extents; - have_limits = TRUE; - } + prev = clip_path->prev->region; } - if (have_limits) { - cairo_box_t box; + /* now extract the region for ourselves */ - _cairo_box_from_rectangle (&box, &limits); - _cairo_traps_limit (&traps, &box); - } + /* XXX fixed fill to region */ + _cairo_traps_init (&traps); + + _cairo_box_from_rectangle (&box, &clip_path->extents); + _cairo_traps_limit (&traps, &box); - status = _cairo_path_fixed_fill_to_traps (path, - fill_rule, - tolerance, + status = _cairo_path_fixed_fill_to_traps (&clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, &traps); if (unlikely (status)) - goto bail; + return status; - status = _cairo_clip_intersect_region (clip, &traps, target); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto bail; + status = _cairo_traps_extract_region (&traps, &clip_path->region); + _cairo_traps_fini (&traps); - status = _cairo_clip_intersect_mask (clip, &traps, antialias, target); + if (status) { + clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED; + return status; + } - bail: - _cairo_traps_fini (&traps); + if (prev != NULL) { + status = cairo_region_intersect (clip_path->region, prev); + if (unlikely (status)) + return status; + } - return status; + clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION; + return CAIRO_STATUS_SUCCESS; } -void -_cairo_clip_translate (cairo_clip_t *clip, - cairo_fixed_t tx, - cairo_fixed_t ty) +cairo_surface_t * +_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target) { - if (clip->all_clipped) - return; + cairo_surface_t *surface; + cairo_pattern_union_t pattern; + cairo_status_t status; + cairo_clip_path_t *clip_path = clip->path; + const cairo_rectangle_int_t *clip_extents = &clip_path->extents; + cairo_region_t *clip_region; + cairo_bool_t need_translate; - if (clip->region) { - cairo_region_translate (clip->region, - _cairo_fixed_integer_part (tx), - _cairo_fixed_integer_part (ty)); - } + assert (clip_path != NULL); - if (clip->surface) { - clip->surface_rect.x += _cairo_fixed_integer_part (tx); - clip->surface_rect.y += _cairo_fixed_integer_part (ty); + if (clip_path->surface != NULL && + clip_path->surface->backend == target->backend) + { + return cairo_surface_reference (clip_path->surface); } - if (clip->path) { - cairo_clip_path_t *clip_path = clip->path; - cairo_matrix_t matrix; - - cairo_matrix_init_translate (&matrix, - _cairo_fixed_to_double (tx), - _cairo_fixed_to_double (ty)); + surface = _cairo_surface_create_similar_solid (target, + CAIRO_CONTENT_ALPHA, + clip_extents->width, + clip_extents->height, + CAIRO_COLOR_TRANSPARENT, + FALSE); + if (surface == NULL) { + if (clip_path->surface != NULL && + clip_path->surface->backend == &_cairo_image_surface_backend) + { + return cairo_surface_reference (clip_path->surface); + } - while (clip_path) { - _cairo_path_fixed_transform (&clip_path->path, &matrix); - clip_path = clip_path->prev; - } + surface = + _cairo_image_surface_create_with_content (CAIRO_CONTENT_ALPHA, + clip_extents->width, + clip_extents->height); } -} + if (unlikely (surface->status)) + return surface; -static cairo_status_t -_cairo_clip_path_reapply_clip_path (cairo_clip_t *clip, - cairo_clip_path_t *clip_path) -{ - cairo_status_t status; + _cairo_pattern_init_solid (&pattern.solid, + CAIRO_COLOR_WHITE, + CAIRO_CONTENT_COLOR); - if (clip_path->prev) { - status = _cairo_clip_path_reapply_clip_path (clip, clip_path->prev); - if (_cairo_status_is_error (status)) - return status; - } + status = _cairo_clip_get_region (clip, &clip_region); + if (_cairo_status_is_error (status)) + goto BAIL; - return _cairo_clip_intersect_path (clip, - &clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - clip_path->antialias); -} + need_translate = clip_extents->x || clip_extents->y; + if (status == CAIRO_STATUS_SUCCESS) { + if (need_translate) { + cairo_region_translate (clip_region, + -clip_extents->x, -clip_extents->y); + } + status = _cairo_surface_fill_region (surface, + CAIRO_OPERATOR_ADD, + CAIRO_COLOR_WHITE, + clip_region); + if (need_translate) { + cairo_region_translate (clip_region, + clip_extents->x, clip_extents->y); + } + if (unlikely (status)) + goto BAIL; -cairo_status_t -_cairo_clip_init_deep_copy (cairo_clip_t *clip, - cairo_clip_t *other, - cairo_surface_t *target) -{ - cairo_status_t status; + goto DONE; + } else { + if (need_translate) { + _cairo_path_fixed_translate (&clip_path->path, + _cairo_fixed_from_int (-clip_extents->x), + _cairo_fixed_from_int (-clip_extents->y)); + } + status = _cairo_surface_fill (surface, + CAIRO_OPERATOR_ADD, + &pattern.base, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias, + NULL); + if (need_translate) { + _cairo_path_fixed_translate (&clip_path->path, + _cairo_fixed_from_int (clip_extents->x), + _cairo_fixed_from_int (clip_extents->y)); + } - _cairo_clip_init (clip, target); + if (unlikely (status)) + goto BAIL; + } - if (other->mode != clip->mode) { - /* We should reapply the original clip path in this case, and let - * whatever the right handling is happen */ - } else { - if (other->region) { - clip->region = cairo_region_copy (other->region); - if (unlikely ((status = cairo_region_status (clip->region)))) - goto BAIL; - } + while ((clip_path = clip_path->prev) != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + if (_cairo_status_is_error (status)) + goto BAIL; - if (other->surface) { - int dx, dy; - status = _cairo_surface_clone_similar (target, other->surface, - CAIRO_CONTENT_ALPHA, - 0, - 0, - other->surface_rect.width, - other->surface_rect.height, - &dx, &dy, - &clip->surface); + if (status == CAIRO_STATUS_SUCCESS) { + cairo_region_translate (clip_region, + -clip_extents->x, -clip_extents->y); + status = _cairo_surface_fill_region (surface, + CAIRO_OPERATOR_IN, + CAIRO_COLOR_WHITE, + clip_region); + cairo_region_translate (clip_region, + clip_extents->x, clip_extents->y); if (unlikely (status)) goto BAIL; - clip->surface_rect = other->surface_rect; - - /* src offset was 0, so we expect an exact replica of the surface */ - assert (dx == 0); - assert (dy == 0); - } - - if (other->path) { - status = _cairo_clip_path_reapply_clip_path (clip, other->path); - if (_cairo_status_is_error (status)) + goto DONE; + } else { + if (clip_path->surface != NULL && + clip_path->surface->backend == surface->backend) + { + _cairo_pattern_init_for_surface (&pattern.surface, + clip_path->surface); + cairo_matrix_init_translate (&pattern.base.matrix, + -clip_path->extents.x + clip_extents->x, + -clip_path->extents.y + clip_extents->y); + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_IN, + &pattern.base, + NULL); + + _cairo_pattern_fini (&pattern.base); + + if (unlikely (status)) + goto BAIL; + + goto DONE; + } else { + /* XXX build intermediate surfaces? */ + if (need_translate) { + _cairo_path_fixed_translate (&clip_path->path, + _cairo_fixed_from_int (-clip_extents->x), + _cairo_fixed_from_int (-clip_extents->y)); + } + status = _cairo_surface_fill (surface, + CAIRO_OPERATOR_IN, + &pattern.base, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias, + NULL); + if (need_translate) { + _cairo_path_fixed_translate (&clip_path->path, + _cairo_fixed_from_int (clip_extents->x), + _cairo_fixed_from_int (clip_extents->y)); + } + } + if (unlikely (status)) goto BAIL; - } + } } - return CAIRO_STATUS_SUCCESS; +DONE: + cairo_surface_destroy (clip->path->surface); + return clip->path->surface = cairo_surface_reference (surface); BAIL: - if (clip->region) - cairo_region_destroy (clip->region); - if (clip->surface) - cairo_surface_destroy (clip->surface); + cairo_surface_destroy (surface); + return _cairo_surface_create_in_error (status); +} - return status; +const cairo_rectangle_int_t * +_cairo_clip_get_extents (const cairo_clip_t *clip) +{ + if (clip->path == NULL) + return NULL; + + return &clip->path->extents; +} + +void +_cairo_clip_drop_cache (cairo_clip_t *clip) +{ + cairo_clip_path_t *clip_path; + + if (clip->path == NULL) + return; + + clip_path = clip->path; + do { + if (clip_path->region != NULL) { + cairo_region_destroy (clip_path->region); + clip_path->region = NULL; + } + + if (clip_path->surface != NULL) { + cairo_surface_destroy (clip_path->surface); + clip_path->surface = NULL; + } + + clip_path->flags = 0; + } while ((clip_path = clip_path->prev) != NULL); } const cairo_rectangle_list_t _cairo_rectangles_nil = @@ -862,42 +838,90 @@ _cairo_clip_int_rect_to_user (cairo_gstate_t *gstate, return is_tight; } +cairo_int_status_t +_cairo_clip_get_region (cairo_clip_t *clip, + cairo_region_t **region) +{ + cairo_int_status_t status; + + *region = NULL; + if (clip->all_clipped) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + if (clip->path == NULL) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_clip_path_to_region (clip->path); + if (status) + return status; + + *region = clip->path->region; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_rectangle_list_t * +_cairo_rectangle_list_create_in_error (cairo_status_t status) +{ + cairo_rectangle_list_t *list; + + if (status == CAIRO_STATUS_NO_MEMORY) + return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; + if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE) + return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable; + + list = malloc (sizeof (*list)); + if (unlikely (list == NULL)) { + _cairo_error_throw (status); + return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; + } + + list->status = status; + list->rectangles = NULL; + list->num_rectangles = 0; + + return list; +} + cairo_rectangle_list_t * _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate) { +#define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S)); + cairo_rectangle_list_t *list; cairo_rectangle_t *rectangles = NULL; + cairo_int_status_t status; + cairo_region_t *region; int n_rects = 0; + int i; - if (clip->all_clipped) + status = _cairo_clip_get_region (clip, ®ion); + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { goto DONE; - - if (clip->path || clip->surface) { - _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE); - return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable; + } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE) + } else if (unlikely (status)) { + return ERROR_LIST (status); } - if (clip->region) { - int i; - - n_rects = cairo_region_num_rectangles (clip->region); - + if (region != NULL) { + n_rects = cairo_region_num_rectangles (region); if (n_rects) { rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t)); if (unlikely (rectangles == NULL)) { - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; + return ERROR_LIST (CAIRO_STATUS_NO_MEMORY); } for (i = 0; i < n_rects; ++i) { cairo_rectangle_int_t clip_rect; - cairo_region_get_rectangle (clip->region, i, &clip_rect); - - if (!_cairo_clip_int_rect_to_user(gstate, &clip_rect, &rectangles[i])) { - _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE); + cairo_region_get_rectangle (region, i, &clip_rect); + + if (! _cairo_clip_int_rect_to_user (gstate, + &clip_rect, + &rectangles[i])) + { free (rectangles); - return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable; + return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE); } } } @@ -908,31 +932,31 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate) rectangles = malloc(sizeof (cairo_rectangle_t)); if (unlikely (rectangles == NULL)) { - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; + return ERROR_LIST (CAIRO_STATUS_NO_MEMORY); } - if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate), &extents) || - !_cairo_clip_int_rect_to_user(gstate, &extents, rectangles)) + if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate), + &extents) || + ! _cairo_clip_int_rect_to_user (gstate, &extents, rectangles)) { - _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE); free (rectangles); - return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable; + return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE); } } DONE: list = malloc (sizeof (cairo_rectangle_list_t)); if (unlikely (list == NULL)) { - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); free (rectangles); - return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; + return ERROR_LIST (CAIRO_STATUS_NO_MEMORY); } list->status = CAIRO_STATUS_SUCCESS; list->rectangles = rectangles; list->num_rectangles = n_rects; return list; + +#undef ERROR_LIST } /** @@ -955,3 +979,9 @@ cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list) free (rectangle_list->rectangles); free (rectangle_list); } + +void +_cairo_clip_reset_static_data (void) +{ + _freed_pool_reset (&clip_path_pool); +} diff --git a/src/cairo-debug.c b/src/cairo-debug.c index d4548f15..4dccebeb 100644 --- a/src/cairo-debug.c +++ b/src/cairo-debug.c @@ -75,6 +75,8 @@ cairo_debug_reset_static_data (void) _cairo_pattern_reset_static_data (); + _cairo_clip_reset_static_data (); + CAIRO_MUTEX_FINALIZE (); } diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c index f7de84ca..967b0447 100644 --- a/src/cairo-directfb-surface.c +++ b/src/cairo-directfb-surface.c @@ -38,14 +38,16 @@ #include "cairoint.h" #include "cairo-directfb.h" +#include "cairo-clip-private.h" + +#include <pixman.h> + #include <directfb.h> #include <direct/types.h> #include <direct/debug.h> #include <direct/memcpy.h> #include <direct/util.h> -#include "cairo-clip-private.h" - /* * Rectangle works fine. * Bugs 361377, 359553, 359243 in Gnome BTS are caused @@ -68,6 +70,8 @@ */ #define DFB_SHOW_GLYPHS 1 +#define PIXMAN_invalid (pixman_format_code_t) 0 + D_DEBUG_DOMAIN (CairoDFB_Acquire, "CairoDFB/Acquire", "Cairo DirectFB Acquire"); D_DEBUG_DOMAIN (CairoDFB_Clip, "CairoDFB/Clip", "Cairo DirectFB Clipping"); @@ -78,17 +82,15 @@ D_DEBUG_DOMAIN (CairoDFB_Surface, "CairoDFB/Surface", "Cairo DirectFB Surface"); /*****************************************************************************/ typedef struct _cairo_directfb_surface { - cairo_surface_t base; - cairo_format_t format; - cairo_content_t content; + cairo_surface_t base; - IDirectFB *dfb; - IDirectFBSurface *dfbsurface; - IDirectFBSurface *tmpsurface; + pixman_format_code_t pixman_format; + cairo_bool_t supported_destination; - cairo_bool_t has_clip; - DFBRegion *clips; - int n_clips; + IDirectFB *dfb; + IDirectFBSurface *dfbsurface; + IDirectFBSurface *tmpsurface; + pixman_format_code_t tmpformat; int width; int height; @@ -119,13 +121,18 @@ static int _directfb_argb_font = 0; /*****************************************************************************/ -#define RUN_CLIPPED(surface, clip, func) {\ - if ((surface)->has_clip) {\ - int k;\ - for (k = 0; k < (surface)->n_clips; k++) {\ +#define RUN_CLIPPED(surface, clip_region, clip, func) {\ + if ((clip_region) != NULL) {\ + int n_clips = cairo_region_num_rectangles (clip_region), n; \ + for (n = 0; n < n_clips; n++) {\ if (clip) {\ - DFBRegion reg = (surface)->clips[k];\ - DFBRegion *cli = (clip);\ + DFBRegion reg, *cli = (clip); \ + cairo_rectangle_int_t rect; \ + cairo_region_get_rectangle (clip_region, n, &rect); \ + reg.x1 = rect.x; \ + reg.y1 = rect.y; \ + reg.x2 = rect.x + rect.width - 1; \ + reg.y2 = rect.y + rect.height - 1; \ if (reg.x2 < cli->x1 || reg.y2 < cli->y1 ||\ reg.x1 > cli->x2 || reg.y1 > cli->y2)\ continue;\ @@ -139,8 +146,14 @@ static int _directfb_argb_font = 0; reg.y2 = cli->y2;\ (surface)->dfbsurface->SetClip ((surface)->dfbsurface, ®);\ } else {\ - (surface)->dfbsurface->SetClip ((surface)->dfbsurface,\ - &(surface)->clips[k]);\ + DFBRegion reg; \ + cairo_rectangle_int_t rect; \ + cairo_region_get_rectangle (clip_region, n, &rect); \ + reg.x1 = rect.x; \ + reg.y1 = rect.y; \ + reg.x2 = rect.x + rect.width - 1; \ + reg.y2 = rect.y + rect.height - 1; \ + (surface)->dfbsurface->SetClip ((surface)->dfbsurface, ®); \ }\ func;\ }\ @@ -150,19 +163,19 @@ static int _directfb_argb_font = 0; }\ } -#define TRANSFORM_POINT2X(m, x, y, ret_x, ret_y) {\ - double _x = (x);\ - double _y = (y);\ - (ret_x) = (_x * (m).xx + (m).x0);\ - (ret_y) = (_y * (m).yy + (m).y0);\ -} +#define TRANSFORM_POINT2X(m, x, y, ret_x, ret_y) do { \ + double _x = (x); \ + double _y = (y); \ + (ret_x) = (_x * (m).xx + (m).x0); \ + (ret_y) = (_y * (m).yy + (m).y0); \ +} while (0) -#define TRANSFORM_POINT3X(m, x, y, ret_x, ret_y) {\ - double _x = (x);\ - double _y = (y);\ - (ret_x) = (_x * (m).xx + _y * (m).xy + (m).x0);\ - (ret_y) = (_x * (m).yx + _y * (m).yy + (m).y0);\ -} +#define TRANSFORM_POINT3X(m, x, y, ret_x, ret_y) do { \ + double _x = (x); \ + double _y = (y); \ + (ret_x) = (_x * (m).xx + _y * (m).xy + (m).x0); \ + (ret_y) = (_x * (m).yx + _y * (m).yy + (m).y0); \ +} while (0) /* XXX: A1 has a different bits ordering in cairo. * Probably we should drop it. @@ -200,23 +213,65 @@ _cairo_to_directfb_format (cairo_format_t format) return -1; } -static inline cairo_format_t -_directfb_to_cairo_format (DFBSurfacePixelFormat format) +static inline pixman_format_code_t +_directfb_to_pixman_format (DFBSurfacePixelFormat format) { switch (format) { - case DSPF_RGB32: - return CAIRO_FORMAT_RGB24; - case DSPF_ARGB: - return CAIRO_FORMAT_ARGB32; - case DSPF_A8: - return CAIRO_FORMAT_A8; - case DSPF_A1: - return CAIRO_FORMAT_A1; - default: - break; + case DSPF_UNKNOWN: return PIXMAN_invalid; + case DSPF_ARGB1555: return PIXMAN_a1r5g5b5; + case DSPF_RGB16: return PIXMAN_r5g6b5; + case DSPF_RGB24: return PIXMAN_r8g8b8; + case DSPF_RGB32: return PIXMAN_x8r8g8b8; + case DSPF_ARGB: return PIXMAN_a8r8g8b8; + case DSPF_A8: return PIXMAN_a8; + case DSPF_YUY2: return PIXMAN_yuy2; + case DSPF_RGB332: return PIXMAN_r3g3b2; + case DSPF_UYVY: return PIXMAN_invalid; + case DSPF_I420: return PIXMAN_invalid; + case DSPF_YV12: return PIXMAN_yv12; + case DSPF_LUT8: return PIXMAN_invalid; + case DSPF_ALUT44: return PIXMAN_invalid; + case DSPF_AiRGB: return PIXMAN_invalid; + case DSPF_A1: return PIXMAN_a1; /* bit reversed, oops */ + case DSPF_NV12: return PIXMAN_invalid; + case DSPF_NV16: return PIXMAN_invalid; + case DSPF_ARGB2554: return PIXMAN_invalid; + case DSPF_ARGB4444: return PIXMAN_a4r4g4b4; + case DSPF_NV21: return PIXMAN_invalid; + case DSPF_AYUV: return PIXMAN_invalid; + case DSPF_A4: return PIXMAN_a4; + case DSPF_ARGB1666: return PIXMAN_invalid; + case DSPF_ARGB6666: return PIXMAN_invalid; + case DSPF_RGB18: return PIXMAN_invalid; + case DSPF_LUT2: return PIXMAN_invalid; + case DSPF_RGB444: return PIXMAN_x4r4g4b4; + case DSPF_RGB555: return PIXMAN_x1r5g5b5; + case DSPF_BGR555: return PIXMAN_x1b5g5r5; } + return PIXMAN_invalid; +} - return -1; +static inline DFBSurfacePixelFormat +_directfb_from_pixman_format (pixman_format_code_t format) +{ + switch ((int) format) { + case PIXMAN_a1r5g5b5: return DSPF_ARGB1555; + case PIXMAN_r5g6b5: return DSPF_RGB16; + case PIXMAN_r8g8b8: return DSPF_RGB24; + case PIXMAN_x8r8g8b8: return DSPF_RGB32; + case PIXMAN_a8r8g8b8: return DSPF_ARGB; + case PIXMAN_a8: return DSPF_A8; + case PIXMAN_yuy2: return DSPF_YUY2; + case PIXMAN_r3g3b2: return DSPF_RGB332; + case PIXMAN_yv12: return DSPF_YV12; + case PIXMAN_a1: return DSPF_A1; /* bit reversed, oops */ + case PIXMAN_a4r4g4b4: return DSPF_ARGB4444; + case PIXMAN_a4: return DSPF_A4; + case PIXMAN_x4r4g4b4: return DSPF_RGB444; + case PIXMAN_x1r5g5b5: return DSPF_RGB555; + case PIXMAN_x1b5g5r5: return DSPF_BGR555; + default: return 0; + } } static cairo_bool_t @@ -350,17 +405,14 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface, IDirectFBSurface *buffer = NULL; DFBRectangle source_rect; cairo_surface_t *image; - cairo_format_t cairo_format; + pixman_image_t *pixman_image; + pixman_format_code_t pixman_format; cairo_status_t status; void *data; int pitch; - if (surface->format == (cairo_format_t) -1 || - (lock_flags & DSLF_WRITE && surface->has_clip)) - { - DFBSurfaceCapabilities caps; - - if (intrest_rec) { + if (surface->pixman_format == PIXMAN_invalid) { + if (intrest_rec != NULL) { source_rect.x = intrest_rec->x; source_rect.y = intrest_rec->y; source_rect.w = intrest_rec->width; @@ -372,30 +424,38 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface, &source_rect.w, &source_rect.h); } - if (surface->tmpsurface) { + if (surface->tmpsurface != NULL) { int w, h; + surface->tmpsurface->GetSize (surface->tmpsurface, &w, &h); if (w < source_rect.w || h < source_rect.h) { surface->tmpsurface->Release (surface->tmpsurface); surface->tmpsurface = NULL; + surface->tmpformat = PIXMAN_invalid; } } - cairo_format = _cairo_format_from_content (surface->content); - if (!surface->tmpsurface) { + if (surface->tmpsurface == NULL) { + DFBSurfacePixelFormat format; + D_DEBUG_AT (CairoDFB_Acquire, "Allocating buffer for surface %p.\n", surface); + format = _cairo_to_directfb_format (_cairo_format_from_content (surface->base.content)); status = - _directfb_buffer_surface_create (surface->dfb, - _cairo_to_directfb_format (cairo_format), + _directfb_buffer_surface_create (surface->dfb, format, source_rect.w, source_rect.h, &surface->tmpsurface); - if (status) + if (unlikely (status)) goto ERROR; + + surface->tmpformat = _directfb_to_pixman_format (format); } buffer = surface->tmpsurface; + pixman_format = surface->tmpformat; + /* surface->dfbsurface->GetCapabilities (surface->dfbsurface, &caps); + DFBSurfaceCapabilities caps; if (caps & DSCAPS_FLIPPING) { DFBRegion region = { .x1 = source_rect.x, .y1 = source_rect.y, .x2 = source_rect.x + source_rect.w - 1, @@ -406,7 +466,7 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface, } else { /*might be a subsurface get the offset*/ surface->dfbsurface->GetVisibleRectangle (surface->dfbsurface, &source_rect); - cairo_format = surface->format; + pixman_format = surface->pixman_format; buffer = surface->dfbsurface; } @@ -416,9 +476,16 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface, goto ERROR; } - image = cairo_image_surface_create_for_data (data, cairo_format, - source_rect.w, source_rect.h, - pitch); + pixman_image = pixman_image_create_bits (pixman_format, + source_rect.w, source_rect.h, + data, pitch); + if (pixman_image == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto ERROR; + } + + image = _cairo_image_surface_create_for_pixman_image (pixman_image, + pixman_format); status = image->status; if (status) goto ERROR; @@ -451,37 +518,27 @@ ERROR: } static cairo_surface_t * -_cairo_directfb_surface_create_similar (void *abstract_src, - cairo_content_t content, - int width, - int height) +_cairo_directfb_surface_create_internal (IDirectFB *dfb, + DFBSurfacePixelFormat format, + cairo_content_t content, + int width, + int height) { - cairo_directfb_surface_t *source = abstract_src; cairo_directfb_surface_t *surface; - cairo_format_t format; cairo_status_t status; - D_DEBUG_AT (CairoDFB_Surface, - "%s( src=%p, content=0x%x, width=%d, height=%d).\n", - __FUNCTION__, source, content, width, height); - - width = (width <= 0) ? 1 : width; - height = (height<= 0) ? 1 : height; - - format = _cairo_format_from_content (content); surface = calloc (1, sizeof (cairo_directfb_surface_t)); if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - surface->dfb = source->dfb; + surface->dfb = dfb; if (width < 8 || height < 8) { IDirectFBSurface *tmp; DFBRectangle rect = { .x=0, .y=0, .w=width, .h=height }; /* Some cards (e.g. Matrox) don't support surfaces smaller than 8x8 */ - status = _directfb_buffer_surface_create (surface->dfb, - _cairo_to_directfb_format (format), + status = _directfb_buffer_surface_create (dfb, format, MAX (width, 8), MAX (height, 8), &tmp); if (status) { @@ -492,11 +549,9 @@ _cairo_directfb_surface_create_similar (void *abstract_src, tmp->GetSubSurface (tmp, &rect, &surface->dfbsurface); tmp->Release (tmp); } else { - status = - _directfb_buffer_surface_create (surface->dfb, - _cairo_to_directfb_format (format), - width, height, - &surface->dfbsurface); + status = _directfb_buffer_surface_create (dfb, format, + width, height, + &surface->dfbsurface); if (status) { free (surface); return _cairo_surface_create_in_error (status); @@ -506,8 +561,9 @@ _cairo_directfb_surface_create_similar (void *abstract_src, _cairo_surface_init (&surface->base, &_cairo_directfb_surface_backend, content); - surface->format = format; - surface->content = content; + surface->pixman_format = _directfb_to_pixman_format (format); + surface->supported_destination = pixman_format_supported_destination (surface->pixman_format); + surface->width = width; surface->height = height; surface->local = TRUE; @@ -516,6 +572,27 @@ _cairo_directfb_surface_create_similar (void *abstract_src, return &surface->base; } +static cairo_surface_t * +_cairo_directfb_surface_create_similar (void *abstract_src, + cairo_content_t content, + int width, + int height) +{ + cairo_directfb_surface_t *other = abstract_src; + DFBSurfacePixelFormat format; + + D_DEBUG_AT (CairoDFB_Surface, + "%s( src=%p, content=0x%x, width=%d, height=%d).\n", + __FUNCTION__, other, content, width, height); + + width = (width <= 0) ? 1 : width; + height = (height<= 0) ? 1 : height; + + format = _cairo_to_directfb_format (_cairo_format_from_content (content)); + return _cairo_directfb_surface_create_internal (other->dfb, format, + content, width, height); +} + static cairo_status_t _cairo_directfb_surface_finish (void *data) { @@ -523,12 +600,6 @@ _cairo_directfb_surface_finish (void *data) D_DEBUG_AT (CairoDFB_Surface, "%s( surface=%p ).\n", __FUNCTION__, surface); - if (surface->clips) { - free (surface->clips); - surface->clips = NULL; - surface->n_clips = 0; - } - if (surface->tmpsurface) { surface->tmpsurface->Release (surface->tmpsurface); surface->tmpsurface = NULL; @@ -564,11 +635,10 @@ _cairo_directfb_surface_release_source_image (void *abstract_su cairo_image_surface_t *image, void *image_extra) { - cairo_directfb_surface_t *surface = abstract_surface; IDirectFBSurface *buffer = image_extra; D_DEBUG_AT (CairoDFB_Acquire, - "%s( surface=%p ).\n", __FUNCTION__, surface); + "%s( release=%p ).\n", __FUNCTION__, abstract_surface); buffer->Unlock (buffer); @@ -620,10 +690,10 @@ _cairo_directfb_surface_release_dest_image (void *abstract_surf .y2 = interest_rect->y + interest_rect->height - 1 }; surface->dfbsurface->SetBlittingFlags (surface->dfbsurface, DSBLIT_NOFX); - RUN_CLIPPED (surface, ®ion, - surface->dfbsurface->Blit (surface->dfbsurface, - buffer, NULL, - image_rect->x, image_rect->y)); + surface->dfbsurface->SetClip (surface->dfbsurface, ®ion); + surface->dfbsurface->Blit (surface->dfbsurface, + buffer, NULL, + image_rect->x, image_rect->y); } cairo_surface_destroy (&image->base); @@ -655,56 +725,51 @@ _cairo_directfb_surface_clone_similar (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } else if (_cairo_surface_is_image (src)) { cairo_image_surface_t *image_src = (cairo_image_surface_t *) src; - unsigned char *dst, *src = image_src->data; - int pitch; - int i, j; + DFBSurfacePixelFormat format; DFBResult ret; + pixman_image_t *pixman_image; + void *data; + int pitch; - clone = (cairo_directfb_surface_t *) - _cairo_directfb_surface_create_similar (surface, - _cairo_content_from_format (image_src->format), - width, height); - if (clone == NULL) + format = _directfb_from_pixman_format (image_src->pixman_format); + if (format == 0) return CAIRO_INT_STATUS_UNSUPPORTED; - if (clone->base.status) + + clone = (cairo_directfb_surface_t *) + _cairo_directfb_surface_create_internal (surface->dfb, format, + image_src->base.content, + width, height); + if (unlikely (clone->base.status)) return clone->base.status; ret = clone->dfbsurface->Lock (clone->dfbsurface, - DSLF_WRITE, (void *)&dst, &pitch); + DSLF_WRITE, (void *)&data, &pitch); if (ret) { DirectFBError ("IDirectFBSurface::Lock()", ret); cairo_surface_destroy (&clone->base); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } - src += image_src->stride * src_y; - if (image_src->format == CAIRO_FORMAT_A1) { - /* A1 -> A8 */ - dst -= src_x; - for (i = 0; i < height; i++) { - for (j = src_x; j < src_x + width; j++) - dst[j] = (src[j>>3] & (1 << (j&7))) ? 0xff : 0x00; - dst += pitch; - src += image_src->stride; - } - } else { - int len; - - if (image_src->format == CAIRO_FORMAT_A8) { - src += src_x; - len = width; - } else { - src += src_x * 4; - len = width * 4; - } - - for (i = 0; i < height; i++) { - direct_memcpy (dst, src, len); - dst += pitch; - src += image_src->stride; - } + pixman_image = pixman_image_create_bits (clone->pixman_format, + width, height, + data, pitch); + if (unlikely (pixman_image == NULL)) { + DirectFBError ("IDirectFBSurface::Lock()", ret); + cairo_surface_destroy (&clone->base); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); } + pixman_image_composite (PIXMAN_OP_SRC, + image_src->pixman_image, + NULL, + pixman_image, + src_x, src_y, + 0, 0, + 0, 0, + width, height); + + pixman_image_unref (pixman_image); + clone->dfbsurface->Unlock (clone->dfbsurface); *clone_offset_x = src_x; @@ -745,8 +810,6 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst, return CAIRO_INT_STATUS_UNSUPPORTED; if (mask_pattern) { - cairo_solid_pattern_t *pattern; - return CAIRO_INT_STATUS_UNSUPPORTED; if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID) { const cairo_pattern_t *tmp; @@ -794,7 +857,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst, return CAIRO_INT_STATUS_UNSUPPORTED; } - if (src->content == CAIRO_CONTENT_COLOR) { + if ((src->base.content & CAIRO_CONTENT_ALPHA) == 0) { if (sblend == DSBF_SRCALPHA) sblend = DSBF_ONE; else if (sblend == DSBF_INVSRCALPHA) @@ -806,7 +869,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst, dblend = DSBF_ZERO; } - if (dst->content == CAIRO_CONTENT_COLOR) { + if ((dst->base.content & CAIRO_CONTENT_ALPHA) == 0) { if (sblend == DSBF_DESTALPHA) sblend = DSBF_ONE; else if (sblend == DSBF_INVDESTALPHA) @@ -913,7 +976,8 @@ _cairo_directfb_surface_composite (cairo_operator_t op, int mask_x, int mask_y, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_directfb_surface_t *dst = abstract_dst; cairo_directfb_surface_t *src; @@ -930,6 +994,9 @@ _cairo_directfb_surface_composite (cairo_operator_t op, __FUNCTION__, op, src_pattern, mask_pattern, dst, src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height); + if (! dst->supported_destination) + return CAIRO_INT_STATUS_UNSUPPORTED; + status = _directfb_prepare_composite (dst, src_pattern, mask_pattern, op, &src_x, &src_y, &mask_x, &mask_y, width, height, &src, &src_attr); @@ -956,7 +1023,7 @@ _cairo_directfb_surface_composite (cairo_operator_t op, src_x += src_attr.x_offset; src_y += src_attr.y_offset; - switch (accel) { + switch ((int) accel) { case DFXL_BLIT: { DFBRectangle sr; @@ -974,11 +1041,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op, if (src_attr.extend == CAIRO_EXTEND_NONE) { D_DEBUG_AT (CairoDFB_Render, "Running Blit().\n"); - RUN_CLIPPED (dst, NULL, + RUN_CLIPPED (dst, clip_region, NULL, dst->dfbsurface->Blit (dst->dfbsurface, src->dfbsurface, - &sr, - dst_x, dst_y)); + &sr, dst_x, dst_y)); } else if (src_attr.extend == CAIRO_EXTEND_REPEAT) { DFBRegion clip; @@ -989,11 +1055,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op, D_DEBUG_AT (CairoDFB_Render, "Running TileBlit().\n"); - RUN_CLIPPED (dst, &clip, + RUN_CLIPPED (dst, clip_region, &clip, dst->dfbsurface->TileBlit (dst->dfbsurface, src->dfbsurface, - &sr, - dst_x, dst_y)); + &sr, dst_x, dst_y)); } break; } @@ -1020,9 +1085,10 @@ _cairo_directfb_surface_composite (cairo_operator_t op, D_DEBUG_AT (CairoDFB_Render, "Running StretchBlit().\n"); - RUN_CLIPPED (dst, NULL, + RUN_CLIPPED (dst, clip_region, NULL, dst->dfbsurface->StretchBlit (dst->dfbsurface, - src->dfbsurface, &sr, &dr)); + src->dfbsurface, + &sr, &dr)); break; } @@ -1044,29 +1110,25 @@ _cairo_directfb_surface_composite (cairo_operator_t op, src->dfbsurface->GetSize (src->dfbsurface, &w, &h); - TRANSFORM_POINT3X (src_attr.matrix, - x1, y1, v[0].x, v[0].y); + TRANSFORM_POINT3X (src_attr.matrix, x1, y1, v[0].x, v[0].y); v[0].z = 0; v[0].w = 1; v[0].s = x1 / w; v[0].t = y1 / h; - TRANSFORM_POINT3X (src_attr.matrix, - x2, y1, v[1].x, v[1].y); + TRANSFORM_POINT3X (src_attr.matrix, x2, y1, v[1].x, v[1].y); v[1].z = 0; v[1].w = 1; v[1].s = x2 / w; v[1].t = y1 / h; - TRANSFORM_POINT3X (src_attr.matrix, - x2, y2, v[2].x, v[2].y); + TRANSFORM_POINT3X (src_attr.matrix, x2, y2, v[2].x, v[2].y); v[2].z = 0; v[2].w = 1; v[2].s = x2 / w; v[2].t = y2 / h; - TRANSFORM_POINT3X (src_attr.matrix, - x1, y2, v[3].x, v[3].y); + TRANSFORM_POINT3X (src_attr.matrix, x1, y2, v[3].x, v[3].y); v[3].z = 0; v[3].w = 1; v[3].s = x1 / w; @@ -1079,9 +1141,11 @@ _cairo_directfb_surface_composite (cairo_operator_t op, D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n"); - RUN_CLIPPED (dst, &clip, + RUN_CLIPPED (dst, clip_region, &clip, dst->dfbsurface->TextureTriangles (dst->dfbsurface, - src->dfbsurface, v, NULL, 4, DTTF_FAN)); + src->dfbsurface, + v, NULL, + 4, DTTF_FAN)); break; } @@ -1092,7 +1156,7 @@ _cairo_directfb_surface_composite (cairo_operator_t op, _directfb_finish_composite (dst, src_pattern, &src->base, &src_attr); - return status; + return CAIRO_STATUS_SUCCESS; } #endif /* DFB_COMPOSITE */ @@ -1115,8 +1179,8 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface "%s( dst=%p, op=%d, color=%p, rects=%p, n_rects=%d ).\n", __FUNCTION__, dst, op, color, rects, n_rects); - if (! _cairo_operator_bounded_by_source (op)) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (! dst->supported_destination) + return CAIRO_INT_STATUS_UNSUPPORTED; if (! _directfb_get_operator (op, &sblend, &dblend)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1132,7 +1196,7 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface else if (dblend == DSBF_INVSRCALPHA) dblend = DSBF_ZERO; } - if (dst->content == CAIRO_CONTENT_COLOR) { + if ((dst->base.content & CAIRO_CONTENT_ALPHA) == 0) { if (sblend == DSBF_DESTALPHA) sblend = DSBF_ONE; else if (sblend == DSBF_INVDESTALPHA) @@ -1164,7 +1228,7 @@ _cairo_directfb_surface_fill_rectangles (void *abstract_surface r[i].h = rects[i].height; } - RUN_CLIPPED (dst, NULL, + RUN_CLIPPED (dst, NULL, NULL, dst->dfbsurface->FillRectangles (dst->dfbsurface, r, n_rects)); return CAIRO_STATUS_SUCCESS; @@ -1182,7 +1246,8 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int num_traps) + int num_traps, + cairo_region_t *clip_region) { cairo_directfb_surface_t *dst = abstract_dst; cairo_directfb_surface_t *src; @@ -1197,6 +1262,9 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op, __FUNCTION__, op, pattern, dst, antialias, src_x, src_y, dst_x, dst_y, width, height, traps, num_traps); + if (! dst->supported_destination) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (antialias != CAIRO_ANTIALIAS_NONE) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1291,7 +1359,7 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op, D_DEBUG_AT (CairoDFB_Render, "Running TextureTriangles().\n"); - RUN_CLIPPED (dst, NULL, + RUN_CLIPPED (dst, clip_region, NULL, dst->dfbsurface->TextureTriangles (dst->dfbsurface, src->dfbsurface, vertex, NULL, n, @@ -1306,64 +1374,7 @@ _cairo_directfb_surface_composite_trapezoids (cairo_operator_t op, } #endif /* DFB_COMPOSITE_TRAPEZOIDS */ -static cairo_int_status_t -_cairo_directfb_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region) -{ - cairo_directfb_surface_t *surface = abstract_surface; - - D_DEBUG_AT (CairoDFB_Clip, - "%s( surface=%p, region=%p ).\n", - __FUNCTION__, surface, region); - - if (region) { - int n_rects; - cairo_status_t status; - int i; - - surface->has_clip = TRUE; - - n_rects = cairo_region_num_rectangles (region); - - if (n_rects == 0) - return CAIRO_STATUS_SUCCESS; - - if (surface->n_clips != n_rects) { - if (surface->clips) - free (surface->clips); - - surface->clips = _cairo_malloc_ab (n_rects, sizeof (DFBRegion)); - if (!surface->clips) { - surface->n_clips = 0; - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - - surface->n_clips = n_rects; - } - - for (i = 0; i < n_rects; i++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (region, i, &rect); - - surface->clips[i].x1 = rect.x; - surface->clips[i].y1 = rect.y; - surface->clips[i].x2 = rect.x + rect.width - 1; - surface->clips[i].y2 = rect.y + rect.height - 1; - } - } else { - surface->has_clip = FALSE; - if (surface->clips) { - free (surface->clips); - surface->clips = NULL; - surface->n_clips = 0; - } - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t +static cairo_bool_t _cairo_directfb_abstract_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -1383,7 +1394,7 @@ _cairo_directfb_abstract_surface_get_extents (void *abstract_su rectangle->width = surface->width; rectangle->height = surface->height; - return CAIRO_STATUS_SUCCESS; + return TRUE; } #if DFB_SHOW_GLYPHS @@ -1422,6 +1433,7 @@ _directfb_destroy_font_cache (cairo_directfb_font_cache_t *cache) free (cache); } +/* XXX hook into rtree font cache from drm */ static cairo_status_t _directfb_acquire_font_cache (cairo_directfb_surface_t *surface, cairo_scaled_font_t *scaled_font, @@ -1473,6 +1485,7 @@ _directfb_acquire_font_cache (cairo_directfb_surface_t *surface, case CAIRO_FORMAT_A8: case CAIRO_FORMAT_ARGB32: break; + case CAIRO_FORMAT_RGB24: default: D_DEBUG_AT (CairoDFB_Font, " -> Unsupported font format %d!\n", img->format); @@ -1705,8 +1718,8 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip, + int *remaining_glyphs) { cairo_directfb_surface_t *dst = abstract_dst; cairo_directfb_font_cache_t *cache; @@ -1718,28 +1731,29 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst, DFBPoint points[num_glyphs]; int num; const cairo_color_t *color; - + cairo_region_t *clip_region = NULL; D_DEBUG_AT (CairoDFB_Font, "%s( dst=%p, op=%d, pattern=%p, glyphs=%p, num_glyphs=%d, scaled_font=%p ).\n", __FUNCTION__, dst, op, pattern, glyphs, num_glyphs, scaled_font); + if (! dst->supported_destination) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) return CAIRO_INT_STATUS_UNSUPPORTED; /* Fallback if we need to emulate clip regions */ - if (dst->base.clip && - (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION || - dst->base.clip->surface != NULL)) - { - return CAIRO_INT_STATUS_UNSUPPORTED; + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO); + if (status) + return status; } /* XXX Unbounded operators are not handled correctly */ if (! _cairo_operator_bounded_by_mask (op)) return CAIRO_INT_STATUS_UNSUPPORTED; - if (! _cairo_operator_bounded_by_source (op)) - return CAIRO_INT_STATUS_UNSUPPORTED; if (! _directfb_get_operator (op, &sblend, &dblend) || sblend == DSBF_DESTALPHA || sblend == DSBF_INVDESTALPHA) @@ -1788,7 +1802,7 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst, D_DEBUG_AT (CairoDFB_Font, "Running BatchBlit().\n"); - RUN_CLIPPED (dst, NULL, + RUN_CLIPPED (dst, clip_region, NULL, dst->dfbsurface->BatchBlit (dst->dfbsurface, cache->dfbsurface, rects, points, num)); @@ -1835,8 +1849,6 @@ _cairo_directfb_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - _cairo_directfb_surface_set_clip_region,/* set_clip_region */ - NULL, /* intersect_clip_path */ _cairo_directfb_abstract_surface_get_extents,/* get_extents */ NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -1860,7 +1872,6 @@ _cairo_directfb_surface_backend = { #endif NULL, /* snapshot */ _cairo_directfb_surface_is_similar, - NULL /* reset */ }; @@ -1933,8 +1944,8 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface) dfbsurface->GetSize (dfbsurface, &surface->width, &surface->height); surface->dfb = dfb; surface->dfbsurface = dfbsurface; - surface->format = _directfb_to_cairo_format (format); - surface->content = _directfb_format_to_content (format); + surface->pixman_format = _directfb_to_pixman_format (format); + surface->supported_destination = pixman_format_supported_destination (surface->pixman_format); dfbsurface->GetCapabilities (dfbsurface, &caps); if (caps & DSCAPS_PREMULTIPLIED) @@ -1942,7 +1953,7 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface) _cairo_surface_init (&surface->base, &_cairo_directfb_surface_backend, - surface->content); + _directfb_format_to_content (format)); return &surface->base; } diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 6c6ff59f..26f4a833 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -1146,7 +1146,7 @@ _render_glyph_bitmap (FT_Face face, cairo_image_surface_t **surface) { FT_GlyphSlot glyphslot = face->glyph; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_status_t status; FT_Error error; /* According to the FreeType docs, glyphslot->format could be @@ -1162,7 +1162,9 @@ _render_glyph_bitmap (FT_Face face, if (error == FT_Err_Out_Of_Memory) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - status = _get_bitmap_surface (&glyphslot->bitmap, FALSE, font_options, surface); + status = _get_bitmap_surface (&glyphslot->bitmap, + FALSE, font_options, + surface); if (unlikely (status)) return status; @@ -1177,7 +1179,7 @@ _render_glyph_bitmap (FT_Face face, -glyphslot->bitmap_left, +glyphslot->bitmap_top); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -1275,11 +1277,8 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, _cairo_pattern_init_for_surface (&pattern, &(*surface)->base); cairo_pattern_set_matrix (&pattern.base, &transformed_to_original); - status = _cairo_surface_composite (CAIRO_OPERATOR_OVER, - &pattern.base, NULL, image, - 0, 0, 0, 0, 0, 0, - width, - height); + status = _cairo_surface_paint (image, CAIRO_OPERATOR_OVER, + &pattern.base, NULL); _cairo_pattern_fini (&pattern.base); @@ -1301,7 +1300,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, cairo_surface_set_device_offset (&(*surface)->base, _cairo_lround (origin_x), _cairo_lround (origin_y)); - return status; + return CAIRO_STATUS_SUCCESS; } static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = { @@ -1390,8 +1389,8 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret) ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL; } -#ifdef FC_HINT_STYLE - if (FcPatternGetInteger (pattern, +#ifdef FC_HINT_STYLE + if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) hintstyle = FC_HINT_FULL; @@ -1400,7 +1399,7 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret) switch (hintstyle) { case FC_HINT_NONE: - ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE; + ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE; break; case FC_HINT_SLIGHT: ft_options.base.hint_style = CAIRO_HINT_STYLE_SLIGHT; @@ -1444,14 +1443,14 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret) if (vertical_layout) ft_options.load_flags |= FT_LOAD_VERTICAL_LAYOUT; - + #ifndef FC_EMBOLDEN #define FC_EMBOLDEN "embolden" #endif if (FcPatternGetBool (pattern, FC_EMBOLDEN, 0, &embolden) != FcResultMatch) embolden = FcFalse; - + if (embolden) ft_options.extra_flags |= CAIRO_FT_OPTIONS_EMBOLDEN; @@ -1468,7 +1467,7 @@ _cairo_ft_options_merge (cairo_ft_options_t *options, /* clear load target mode */ load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(other->load_flags))); - + if (load_flags & FT_LOAD_NO_HINTING) other->base.hint_style = CAIRO_HINT_STYLE_NONE; @@ -1479,7 +1478,7 @@ _cairo_ft_options_merge (cairo_ft_options_t *options, } if (other->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL && - (options->base.antialias == CAIRO_ANTIALIAS_DEFAULT || + (options->base.antialias == CAIRO_ANTIALIAS_DEFAULT || options->base.antialias == CAIRO_ANTIALIAS_GRAY)) { options->base.antialias = CAIRO_ANTIALIAS_SUBPIXEL; options->base.subpixel_order = other->base.subpixel_order; @@ -1934,12 +1933,12 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, x2 = (metrics->horiBearingX + metrics->width + 63) & -64; y1 = (-metrics->horiBearingY) & -64; y2 = (-metrics->horiBearingY + metrics->height + 63) & -64; - + advance = ((metrics->horiAdvance + 32) & -64); - + fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor; fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor; - + fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor; fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor; @@ -1950,12 +1949,12 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, x2 = (metrics->vertBearingX + metrics->width + 63) & -64; y1 = (metrics->vertBearingY) & -64; y2 = (metrics->vertBearingY + metrics->height + 63) & -64; - + advance = ((metrics->vertAdvance + 32) & -64); - + fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor; fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor; - + fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor; fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor; @@ -1969,7 +1968,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, if (!vertical_layout) { fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) * x_factor; fs_metrics.y_bearing = DOUBLE_FROM_26_6 (-metrics->horiBearingY) * y_factor; - + if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE) fs_metrics.x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance) * x_factor; else @@ -1978,7 +1977,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, } else { fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingX) * x_factor; fs_metrics.y_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingY) * y_factor; - + fs_metrics.x_advance = 0 * x_factor; if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE) fs_metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance) * y_factor; @@ -2154,7 +2153,7 @@ static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = { _cairo_ft_scaled_glyph_init, NULL, /* text_to_glyphs */ _cairo_ft_ucs4_to_index, - NULL, /* show_glyphs */ + NULL, /* show_glyphs */ _cairo_ft_load_truetype_table, _cairo_ft_index_to_ucs4 }; @@ -2911,10 +2910,10 @@ cairo_bool_t _cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font) { cairo_ft_scaled_font_t *ft_scaled_font; - + if (!_cairo_scaled_font_is_ft (scaled_font)) return FALSE; - + ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font; if (ft_scaled_font->ft_options.load_flags & FT_LOAD_VERTICAL_LAYOUT) return TRUE; diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 3d37fe09..5d8ff603 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -56,6 +56,7 @@ typedef struct _cairo_gl_surface { int width, height; GLuint tex; /* GL texture object containing our data. */ + GLuint depth_stencil_tex; GLuint fb; /* GL framebuffer object wrapping our data. */ } cairo_gl_surface_t; diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c index 571fc963..92c670d3 100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -312,6 +312,10 @@ _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format, case PIXMAN_g1: case PIXMAN_yuy2: case PIXMAN_yv12: +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16) + case PIXMAN_x2r10g10b10: + case PIXMAN_a2r10g10b10: +#endif default: return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -766,6 +770,8 @@ _cairo_gl_surface_finish (void *abstract_surface) glDeleteFramebuffersEXT (1, &surface->fb); glDeleteTextures (1, &surface->tex); + if (surface->depth_stencil_tex) + glDeleteTextures (1, &surface->depth_stencil_tex); if (surface->ctx->current_target == surface) surface->ctx->current_target = NULL; @@ -1264,16 +1270,20 @@ _cairo_gl_surface_composite (cairo_operator_t op, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_gl_surface_t *dst = abstract_dst; cairo_surface_attributes_t *src_attributes, *mask_attributes = NULL; cairo_gl_context_t *ctx; - GLfloat vertices[4][2]; - GLfloat texcoord_src[4][2]; - GLfloat texcoord_mask[4][2]; + struct gl_point { + GLfloat x, y; + } vertices_stack[8], texcoord_src_stack[8], texcoord_mask_stack[8]; + struct gl_point *vertices = vertices_stack; + struct gl_point *texcoord_src = texcoord_src_stack; + struct gl_point *texcoord_mask = texcoord_mask_stack; cairo_status_t status; - int i; + int num_vertices, i; GLenum err; cairo_gl_composite_setup_t setup; @@ -1345,27 +1355,62 @@ _cairo_gl_surface_composite (cairo_operator_t op, } } - vertices[0][0] = dst_x; - vertices[0][1] = dst_y; - vertices[1][0] = dst_x + width; - vertices[1][1] = dst_y; - vertices[2][0] = dst_x + width; - vertices[2][1] = dst_y + height; - vertices[3][0] = dst_x; - vertices[3][1] = dst_y + height; + if (clip_region != NULL) { + int num_rectangles; + + num_rectangles = cairo_region_num_rectangles (clip_region); + if (num_rectangles * 4 > ARRAY_LENGTH (vertices_stack)) { + vertices = _cairo_malloc_ab (num_rectangles, + 4*3*sizeof (vertices[0])); + if (unlikely (vertices == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CONTEXT_RELEASE; + } + + texcoord_src = vertices + num_rectangles * 4; + texcoord_mask = texcoord_src + num_rectangles * 4; + } + + for (i = 0; i < num_rectangles; i++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (clip_region, i, &rect); + vertices[4*i + 0].x = rect.x; + vertices[4*i + 0].y = rect.y; + vertices[4*i + 1].x = rect.x + rect.width; + vertices[4*i + 1].y = rect.y; + vertices[4*i + 2].x = rect.x + rect.width; + vertices[4*i + 2].y = rect.y + rect.height; + vertices[4*i + 3].x = rect.x; + vertices[4*i + 3].y = rect.y + rect.height; + } + + num_vertices = 4 * num_rectangles; + } else { + vertices[0].x = dst_x; + vertices[0].y = dst_y; + vertices[1].x = dst_x + width; + vertices[1].y = dst_y; + vertices[2].x = dst_x + width; + vertices[2].y = dst_y + height; + vertices[3].x = dst_x; + vertices[3].y = dst_y + height; + + num_vertices = 4; + } glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices); glEnableClientState (GL_VERTEX_ARRAY); if (setup.src.type == OPERAND_TEXTURE) { - for (i = 0; i < 4; i++) { + for (i = 0; i < num_vertices; i++) { double s, t; - s = vertices[i][0]; - t = vertices[i][1]; + s = vertices[i].x; + t = vertices[i].y; cairo_matrix_transform_point (&src_attributes->matrix, &s, &t); - texcoord_src[i][0] = s; - texcoord_src[i][1] = t; + texcoord_src[i].x = s; + texcoord_src[i].y = t; } glClientActiveTexture (GL_TEXTURE0); @@ -1375,14 +1420,14 @@ _cairo_gl_surface_composite (cairo_operator_t op, if (mask != NULL) { if (setup.mask.type == OPERAND_TEXTURE) { - for (i = 0; i < 4; i++) { + for (i = 0; i < num_vertices; i++) { double s, t; - s = vertices[i][0]; - t = vertices[i][1]; + s = vertices[i].x; + t = vertices[i].y; cairo_matrix_transform_point (&mask_attributes->matrix, &s, &t); - texcoord_mask[i][0] = s; - texcoord_mask[i][1] = t; + texcoord_mask[i].x = s; + texcoord_mask[i].y = t; } glClientActiveTexture (GL_TEXTURE1); @@ -1391,7 +1436,7 @@ _cairo_gl_surface_composite (cairo_operator_t op, } } - glDrawArrays (GL_TRIANGLE_FAN, 0, 4); + glDrawArrays (GL_QUADS, 0, num_vertices); glDisable (GL_BLEND); @@ -1410,13 +1455,17 @@ _cairo_gl_surface_composite (cairo_operator_t op, while ((err = glGetError ())) fprintf (stderr, "GL error 0x%08x\n", (int) err); + CONTEXT_RELEASE: _cairo_gl_context_release (ctx); _cairo_gl_operand_destroy (&setup.src); if (mask != NULL) _cairo_gl_operand_destroy (&setup.mask); - return CAIRO_STATUS_SUCCESS; + if (vertices != vertices_stack) + free (vertices); + + return status; } static cairo_int_status_t @@ -1429,7 +1478,8 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int num_traps) + int num_traps, + cairo_region_t *clip_region) { cairo_gl_surface_t *dst = abstract_dst; cairo_surface_pattern_t traps_pattern; @@ -1447,7 +1497,8 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op, src_x, src_y, 0, 0, dst_x, dst_y, - width, height); + width, height, + clip_region); _cairo_pattern_fini (&traps_pattern.base); @@ -1737,6 +1788,7 @@ _cairo_gl_surface_span_renderer_finish (void *abstract_renderer) glDisable (GL_TEXTURE_2D); glDisable (GL_BLEND); + glDisable (GL_DEPTH_TEST); return CAIRO_STATUS_SUCCESS; } @@ -1756,27 +1808,112 @@ _cairo_gl_surface_check_span_renderer (cairo_operator_t op, return TRUE; } +static void +_cairo_gl_surface_ensure_depth_buffer (cairo_gl_surface_t *surface) +{ + if (surface->depth_stencil_tex) + return; + + glGenTextures (1, &surface->depth_stencil_tex); + glBindTexture (GL_TEXTURE_2D, surface->depth_stencil_tex); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, + surface->width, surface->height, 0, + GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL); + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, + GL_DEPTH_ATTACHMENT_EXT, + GL_TEXTURE_2D, + surface->depth_stencil_tex, 0); + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, + GL_STENCIL_ATTACHMENT_EXT, + GL_TEXTURE_2D, + surface->depth_stencil_tex, 0); +} + + +static cairo_status_t +_cairo_gl_surface_set_clip_region (cairo_gl_surface_t *surface, + cairo_region_t *clip_region) +{ + GLfloat vertices_stack[CAIRO_STACK_ARRAY_LENGTH(GLfloat)], *vertices; + int num_rectangles, i, n; + + if (clip_region == NULL) + return CAIRO_STATUS_SUCCESS; + + num_rectangles = cairo_region_num_rectangles (clip_region); + + vertices = vertices_stack; + if (num_rectangles * 8 > ARRAY_LENGTH (vertices_stack)) { + vertices = _cairo_malloc_ab (num_rectangles, + 4*3*sizeof (vertices[0])); + if (unlikely (vertices == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + for (i = n = 0; i < num_rectangles; i++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (clip_region, i, &rect); + vertices[n++] = rect.x; + vertices[n++] = rect.y; + vertices[n++] = rect.x + rect.width; + vertices[n++] = rect.y; + vertices[n++] = rect.x + rect.width; + vertices[n++] = rect.y + rect.height; + vertices[n++] = rect.x; + vertices[n++] = rect.y +rect. height; + } + + _cairo_gl_surface_ensure_depth_buffer (surface); + + glDisable (GL_BLEND); + glDepthFunc (GL_ALWAYS); + glEnable (GL_DEPTH_TEST); + glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + glDepthMask (GL_TRUE); + glClear (GL_DEPTH_BUFFER_BIT); + + glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices); + glEnableClientState (GL_VERTEX_ARRAY); + glDrawArrays (GL_QUADS, 0, 4 * num_rectangles); + glDisableClientState (GL_VERTEX_ARRAY); + + glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDepthFunc (GL_EQUAL); + glDepthMask (GL_FALSE); + + if (vertices != vertices_stack) + free (vertices); + + return CAIRO_STATUS_SUCCESS; +} + static cairo_span_renderer_t * _cairo_gl_surface_create_span_renderer (cairo_operator_t op, const cairo_pattern_t *src, void *abstract_dst, cairo_antialias_t antialias, - const cairo_composite_rectangles_t *rects) + const cairo_composite_rectangles_t *rects, + cairo_region_t *clip_region) { cairo_gl_surface_t *dst = abstract_dst; - cairo_gl_surface_span_renderer_t *renderer = calloc (1, sizeof (*renderer)); + cairo_gl_surface_span_renderer_t *renderer; cairo_status_t status; int width = rects->width; int height = rects->height; cairo_surface_attributes_t *src_attributes; GLenum err; - if (renderer == NULL) - return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY); - if (!GLEW_ARB_vertex_buffer_object) return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED); + renderer = calloc (1, sizeof (*renderer)); + if (unlikely (renderer == NULL)) + return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY); + renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy; renderer->base.finish = _cairo_gl_surface_span_renderer_finish; renderer->base.render_row = @@ -1801,6 +1938,12 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op, _cairo_gl_set_destination (dst); + status = _cairo_gl_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) { + _cairo_gl_surface_span_renderer_destroy (renderer); + return _cairo_span_renderer_create_in_error (status); + } + src_attributes = &renderer->setup.src.operand.texture.attributes; status = _cairo_gl_set_operator (dst, op); @@ -1838,7 +1981,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op, return &renderer->base; } -static cairo_int_status_t +static cairo_bool_t _cairo_gl_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -1849,7 +1992,7 @@ _cairo_gl_surface_get_extents (void *abstract_surface, rectangle->width = surface->width; rectangle->height = surface->height; - return CAIRO_STATUS_SUCCESS; + return TRUE; } static void @@ -1888,20 +2031,21 @@ static const cairo_surface_backend_t _cairo_gl_surface_backend = { CAIRO_SURFACE_TYPE_GL, _cairo_gl_surface_create_similar, _cairo_gl_surface_finish, + _cairo_gl_surface_acquire_source_image, _cairo_gl_surface_release_source_image, _cairo_gl_surface_acquire_dest_image, _cairo_gl_surface_release_dest_image, + _cairo_gl_surface_clone_similar, _cairo_gl_surface_composite, _cairo_gl_surface_fill_rectangles, _cairo_gl_surface_composite_trapezoids, _cairo_gl_surface_create_span_renderer, _cairo_gl_surface_check_span_renderer, + NULL, /* copy_page */ NULL, /* show_page */ - NULL, /* set_clip_region */ - NULL, /* intersect_clip_path */ _cairo_gl_surface_get_extents, NULL, /* old_show_glyphs */ _cairo_gl_surface_get_font_options, diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index 81881290..a649d500 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -27,6 +27,7 @@ #include "cairoint.h" #include "cairo-glitz.h" #include "cairo-glitz-private.h" +#include "cairo-region-private.h" typedef struct _cairo_glitz_surface { cairo_surface_t base; @@ -34,6 +35,7 @@ typedef struct _cairo_glitz_surface { glitz_surface_t *surface; glitz_format_t *format; + cairo_region_t *clip_region; cairo_bool_t has_clip; glitz_box_t *clip_boxes; int num_clip_boxes; @@ -50,6 +52,7 @@ _cairo_glitz_surface_finish (void *abstract_surface) if (surface->clip_boxes) free (surface->clip_boxes); + cairo_region_destroy (surface->clip_region); glitz_surface_destroy (surface->surface); return CAIRO_STATUS_SUCCESS; @@ -107,43 +110,6 @@ _cairo_glitz_surface_create_similar (void *abstract_src, } static cairo_status_t -_cairo_glitz_get_boxes_from_region (cairo_region_t *region, - glitz_box_t **boxes, - int *nboxes) -{ - pixman_box32_t *pboxes; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - - int n, i; - - n = 0; - pboxes = pixman_region32_rectangles (®ion->rgn, &n); - if (n == 0) { - *nboxes = 0; - return CAIRO_STATUS_SUCCESS; - } - - if (n > *nboxes) { - *boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t)); - if (*boxes == NULL) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto done; - } - } - - for (i = 0; i < n; i++) { - (*boxes)[i].x1 = pboxes[i].x1; - (*boxes)[i].y1 = pboxes[i].y1; - (*boxes)[i].x2 = pboxes[i].x2; - (*boxes)[i].y2 = pboxes[i].y2; - } - - *nboxes = n; -done: - return status; -} - -static cairo_status_t _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, cairo_rectangle_int_t *interest, cairo_image_surface_t **image_out, @@ -463,6 +429,8 @@ _is_supported_operator (cairo_operator_t op) case CAIRO_OPERATOR_ADD: return TRUE; + default: + ASSERT_NOT_REACHED; case CAIRO_OPERATOR_SATURATE: /* nobody likes saturate, expect that it's required to do * seamless polygons! @@ -485,6 +453,7 @@ _is_supported_operator (cairo_operator_t op) return FALSE; } } + static glitz_operator_t _glitz_operator (cairo_operator_t op) { @@ -686,9 +655,9 @@ _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t *pattern, } src = (cairo_glitz_surface_t *) - _cairo_surface_create_similar_scratch (&dst->base, - CAIRO_CONTENT_COLOR_ALPHA, - gradient->n_stops, 1); + _cairo_glitz_surface_create_similar (&dst->base, + CAIRO_CONTENT_COLOR_ALPHA, + gradient->n_stops, 1); if (src->base.status) { glitz_buffer_destroy (buffer); free (data); @@ -914,6 +883,77 @@ _cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface, a->params, a->n_params); } +static cairo_status_t +_cairo_glitz_get_boxes_from_region (cairo_region_t *region, + glitz_box_t **boxes, + int *nboxes) +{ + pixman_box32_t *pboxes; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + int n, i; + + n = 0; + pboxes = pixman_region32_rectangles (®ion->rgn, &n); + if (n == 0) { + *nboxes = 0; + return CAIRO_STATUS_SUCCESS; + } + + if (n > *nboxes) { + *boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t)); + if (*boxes == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto done; + } + } + + for (i = 0; i < n; i++) { + (*boxes)[i].x1 = pboxes[i].x1; + (*boxes)[i].y1 = pboxes[i].y1; + (*boxes)[i].x2 = pboxes[i].x2; + (*boxes)[i].y2 = pboxes[i].y2; + } + + *nboxes = n; +done: + return status; +} + +static cairo_status_t +_cairo_glitz_surface_set_clip_region (void *abstract_surface, + cairo_region_t *region) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + if (region == surface->clip_region) + return CAIRO_STATUS_SUCCESS; + + cairo_region_destroy (surface->clip_region); + surface->clip_region = cairo_region_reference (region); + + if (region != NULL) { + cairo_status_t status; + + status = _cairo_glitz_get_boxes_from_region (region, + &surface->clip_boxes, + &surface->num_clip_boxes); + if (status) + return status; + + glitz_surface_set_clip_region (surface->surface, + 0, 0, + surface->clip_boxes, + surface->num_clip_boxes); + surface->has_clip = TRUE; + } else { + glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); + surface->has_clip = FALSE; + } + + return CAIRO_STATUS_SUCCESS; +} + static cairo_int_status_t _cairo_glitz_surface_composite (cairo_operator_t op, const cairo_pattern_t *src_pattern, @@ -926,7 +966,8 @@ _cairo_glitz_surface_composite (cairo_operator_t op, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_glitz_surface_attributes_t src_attr, mask_attr; cairo_glitz_surface_t *dst = abstract_dst; @@ -940,6 +981,10 @@ _cairo_glitz_surface_composite (cairo_operator_t op, if (_glitz_ensure_target (dst->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_glitz_surface_set_clip_region (dst, clip_region); + if (status) + return status; + status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern, dst, src_x, src_y, @@ -1006,7 +1051,8 @@ _cairo_glitz_surface_composite (cairo_operator_t op, mask_width, mask_height, src_x, src_y, mask_x, mask_y, - dst_x, dst_y, width, height); + dst_x, dst_y, width, height, + clip_region); } if (mask) @@ -1037,11 +1083,15 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, glitz_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (glitz_rectangle_t)]; glitz_rectangle_t *glitz_rects = stack_rects; glitz_rectangle_t *current_rect; + cairo_status_t status; int i; if (! _is_supported_operator (op)) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_glitz_surface_set_clip_region (dst, NULL); + assert (status == CAIRO_STATUS_SUCCESS); + if (n_rects > ARRAY_LENGTH (stack_rects)) { glitz_rects = _cairo_malloc_ab (n_rects, sizeof (glitz_rectangle_t)); if (glitz_rects == NULL) @@ -1104,12 +1154,12 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst, _cairo_surface_create_similar_solid (&dst->base, CAIRO_CONTENT_COLOR_ALPHA, 1, 1, - (cairo_color_t *) color); - if (src->base.status) - { + (cairo_color_t *) color, + FALSE); + if (src == NULL || src->base.status) { if (glitz_rects != stack_rects) free (glitz_rects); - return src->base.status; + return src ? src->base.status : CAIRO_INT_STATUS_UNSUPPORTED; } glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); @@ -1153,7 +1203,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int n_traps) + int n_traps, + cairo_region_t *clip_region) { cairo_glitz_surface_attributes_t attributes; cairo_glitz_surface_t *dst = abstract_dst; @@ -1179,6 +1230,10 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, if (_glitz_ensure_target (dst->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_glitz_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + return status; + /* Convert traps to pixman traps */ if (n_traps > ARRAY_LENGTH (stack_traps)) { pixman_traps = _cairo_malloc_ab (n_traps, sizeof (pixman_trapezoid_t)); @@ -1321,7 +1376,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, n_traps, (pixman_trapezoid_t *) pixman_traps); mask = (cairo_glitz_surface_t *) - _cairo_surface_create_similar_scratch (&dst->base, + _cairo_glitz_surface_create_similar (&dst->base, CAIRO_CONTENT_ALPHA, width, height); status = mask->base.status; @@ -1378,7 +1433,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, src_x, src_y, 0, 0, dst_x, dst_y, - width, height); + width, height, + clip_region); } FAIL: @@ -1393,35 +1449,7 @@ FAIL: return status; } -static cairo_int_status_t -_cairo_glitz_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region) -{ - cairo_glitz_surface_t *surface = abstract_surface; - - if (region != NULL) { - cairo_status_t status; - - status = _cairo_glitz_get_boxes_from_region (region, - &surface->clip_boxes, - &surface->num_clip_boxes); - if (status) - return status; - - glitz_surface_set_clip_region (surface->surface, - 0, 0, - surface->clip_boxes, - surface->num_clip_boxes); - surface->has_clip = TRUE; - } else { - glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); - surface->has_clip = FALSE; - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t +static cairo_bool_t _cairo_glitz_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -1432,7 +1460,7 @@ _cairo_glitz_surface_get_extents (void *abstract_surface, rectangle->width = glitz_surface_get_width (surface->surface); rectangle->height = glitz_surface_get_height (surface->surface); - return CAIRO_STATUS_SUCCESS; + return TRUE; } #define CAIRO_GLITZ_AREA_AVAILABLE 0 @@ -2035,7 +2063,8 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, unsigned int width, unsigned int height, cairo_glyph_t *glyphs, - int num_glyphs) + int num_glyphs, + cairo_region_t *clip_region) { cairo_glitz_surface_attributes_t attributes; cairo_glitz_surface_glyph_private_t *glyph_private; @@ -2078,6 +2107,10 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, if (_glitz_ensure_target (dst->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_glitz_surface_set_clip_region (dst, NULL); + if (unlikely (status)) + return status; + status = _cairo_glitz_pattern_acquire_surface (pattern, dst, src_x, src_y, width, height, @@ -2326,25 +2359,13 @@ _cairo_glitz_surface_is_similar (void *surface_a, return drawable_a == drawable_b; } -static cairo_status_t -_cairo_glitz_surface_reset (void *abstract_surface) -{ - cairo_glitz_surface_t *surface = abstract_surface; - cairo_status_t status; - - status = _cairo_glitz_surface_set_clip_region (surface, NULL); - if (status) - return status; - - return CAIRO_STATUS_SUCCESS; -} - static const cairo_surface_backend_t cairo_glitz_surface_backend = { CAIRO_SURFACE_TYPE_GLITZ, _cairo_glitz_surface_create_similar, _cairo_glitz_surface_finish, _cairo_glitz_surface_acquire_source_image, _cairo_glitz_surface_release_source_image, + _cairo_glitz_surface_acquire_dest_image, _cairo_glitz_surface_release_dest_image, _cairo_glitz_surface_clone_similar, @@ -2353,10 +2374,9 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = { _cairo_glitz_surface_composite_trapezoids, NULL, /* create_span_renderer */ NULL, /* check_span_renderer */ + NULL, /* copy_page */ NULL, /* show_page */ - _cairo_glitz_surface_set_clip_region, - NULL, /* intersect_clip_path */ _cairo_glitz_surface_get_extents, _cairo_glitz_surface_old_show_glyphs, NULL, /* get_font_options */ @@ -2373,8 +2393,6 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = { _cairo_glitz_surface_snapshot, _cairo_glitz_surface_is_similar, - - _cairo_glitz_surface_reset }; static const cairo_surface_backend_t * @@ -2424,6 +2442,7 @@ cairo_glitz_surface_create (glitz_surface_t *surface) crsurface->has_clip = FALSE; crsurface->clip_boxes = NULL; crsurface->num_clip_boxes = 0; + crsurface->clip_region = NULL; return &crsurface->base; } diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 8f206ad9..2257db0f 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -100,7 +100,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate, _cairo_font_options_init_default (&gstate->font_options); - _cairo_clip_init (&gstate->clip, target); + _cairo_clip_init (&gstate->clip); gstate->target = cairo_surface_reference (target); gstate->parent_target = NULL; @@ -164,14 +164,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) _cairo_font_options_init_copy (&gstate->font_options , &other->font_options); - status = _cairo_clip_init_copy (&gstate->clip, &other->clip); - if (unlikely (status)) { - _cairo_stroke_style_fini (&gstate->stroke_style); - cairo_font_face_destroy (gstate->font_face); - cairo_scaled_font_destroy (gstate->scaled_font); - cairo_scaled_font_destroy (gstate->previous_scaled_font); - return status; - } + _cairo_clip_init_copy (&gstate->clip, &other->clip); gstate->target = cairo_surface_reference (other->target); /* parent_target is always set to NULL; it's only ever set by redirect_target */ @@ -299,7 +292,7 @@ _cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist) cairo_status_t _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) { - cairo_status_t status; + cairo_matrix_t matrix; /* If this gstate is already redirected, this is an error; we need a * new gstate to be able to redirect */ @@ -315,18 +308,15 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) * since its ref is now owned by gstate->parent_target */ gstate->target = cairo_surface_reference (child); - _cairo_clip_reset (&gstate->clip); - status = _cairo_clip_init_deep_copy (&gstate->clip, &gstate->next->clip, child); - if (unlikely (status)) - return status; - /* The clip is in surface backend coordinates for the previous target; * translate it into the child's backend coordinates. */ - _cairo_clip_translate (&gstate->clip, - _cairo_fixed_from_double (child->device_transform.x0 - gstate->parent_target->device_transform.x0), - _cairo_fixed_from_double (child->device_transform.y0 - gstate->parent_target->device_transform.y0)); - - return CAIRO_STATUS_SUCCESS; + cairo_matrix_init_translate (&matrix, + child->device_transform.x0 - gstate->parent_target->device_transform.x0, + child->device_transform.y0 - gstate->parent_target->device_transform.y0); + _cairo_clip_reset (&gstate->clip); + return _cairo_clip_init_copy_transformed (&gstate->clip, + &gstate->next->clip, + &matrix); } /** @@ -870,43 +860,63 @@ _cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate, &gstate->ctm_inverse); } +#define _gstate_get_clip(g) ((g)->clip.path ? &(g)->clip : NULL) + +static cairo_bool_t +_clipped (const cairo_gstate_t *gstate) +{ + cairo_rectangle_int_t extents; + + if (gstate->clip.all_clipped) + return TRUE; + + if (gstate->clip.path == NULL) + return FALSE; + + if (_cairo_surface_get_extents (gstate->target, &extents)) { + if (! _cairo_rectangle_intersect (&extents, + &gstate->clip.path->extents)) + { + return TRUE; + } + } + + return FALSE; +} + cairo_status_t _cairo_gstate_paint (cairo_gstate_t *gstate) { - cairo_status_t status; cairo_pattern_union_t pattern; - if (gstate->source->status) + if (unlikely (gstate->source->status)) return gstate->source->status; - status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (unlikely (status)) - return status; + if (_clipped (gstate)) + return CAIRO_STATUS_SUCCESS; _cairo_gstate_copy_transformed_source (gstate, &pattern.base); return _cairo_surface_paint (gstate->target, gstate->op, &pattern.base, - NULL); + _gstate_get_clip (gstate)); } cairo_status_t _cairo_gstate_mask (cairo_gstate_t *gstate, cairo_pattern_t *mask) { - cairo_status_t status; cairo_pattern_union_t source_pattern, mask_pattern; - if (mask->status) + if (unlikely (mask->status)) return mask->status; - if (gstate->source->status) + if (unlikely (gstate->source->status)) return gstate->source->status; - status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (unlikely (status)) - return status; + if (_clipped (gstate)) + return CAIRO_STATUS_SUCCESS; _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask); @@ -915,24 +925,22 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, gstate->op, &source_pattern.base, &mask_pattern.base, - NULL); + _gstate_get_clip (gstate)); } cairo_status_t _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { - cairo_status_t status; cairo_pattern_union_t source_pattern; - if (gstate->source->status) + if (unlikely (gstate->source->status)) return gstate->source->status; if (gstate->stroke_style.line_width <= 0.0) return CAIRO_STATUS_SUCCESS; - status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (unlikely (status)) - return status; + if (_clipped (gstate)) + return CAIRO_STATUS_SUCCESS; _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); @@ -945,7 +953,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) &gstate->ctm_inverse, gstate->tolerance, gstate->antialias, - NULL); + _gstate_get_clip (gstate)); } cairo_status_t @@ -1009,15 +1017,26 @@ BAIL: cairo_status_t _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { - cairo_status_t status; cairo_pattern_union_t pattern; - if (gstate->source->status) + if (unlikely (gstate->source->status)) return gstate->source->status; - status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (unlikely (status)) - return status; + if (_clipped (gstate)) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_path_fixed_fill_is_empty (path)) { + if (_cairo_operator_bounded_by_mask (gstate->op)) + return CAIRO_STATUS_SUCCESS; + + _cairo_pattern_init_solid (&pattern.solid, + CAIRO_COLOR_TRANSPARENT, + CAIRO_CONTENT_COLOR_ALPHA); + return _cairo_surface_paint (gstate->target, + CAIRO_OPERATOR_CLEAR, + &pattern.base, + _gstate_get_clip (gstate)); + } _cairo_gstate_copy_transformed_source (gstate, &pattern.base); @@ -1028,23 +1047,56 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) gstate->fill_rule, gstate->tolerance, gstate->antialias, - NULL); + _gstate_get_clip (gstate)); } -void +cairo_bool_t _cairo_gstate_in_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path, double x, - double y, - cairo_bool_t *inside_ret) + double y) +{ + _cairo_gstate_user_to_backend (gstate, &x, &y); + + return _cairo_path_fixed_in_fill (path, + gstate->fill_rule, + gstate->tolerance, + x, y); +} + +cairo_bool_t +_cairo_gstate_in_clip (cairo_gstate_t *gstate, + double x, + double y) { + cairo_clip_path_t *clip_path; + + if (gstate->clip.all_clipped) + return FALSE; + + clip_path = gstate->clip.path; + if (clip_path == NULL) + return TRUE; + _cairo_gstate_user_to_backend (gstate, &x, &y); - _cairo_path_fixed_in_fill (path, - gstate->fill_rule, - gstate->tolerance, - x, y, - inside_ret); + if (x < clip_path->extents.x || + x >= clip_path->extents.x + clip_path->extents.width || + y < clip_path->extents.y || + y >= clip_path->extents.y + clip_path->extents.height) + { + return FALSE; + } + + do { + if (! _cairo_path_fixed_in_fill (&clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + x, y)) + return FALSE; + } while ((clip_path = clip_path->prev) != NULL); + + return TRUE; } cairo_status_t @@ -1179,26 +1231,31 @@ cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { return _cairo_clip_clip (&gstate->clip, - path, gstate->fill_rule, gstate->tolerance, - gstate->antialias, gstate->target); + path, gstate->fill_rule, + gstate->tolerance, gstate->antialias); } -static cairo_status_t +static cairo_bool_t _cairo_gstate_int_clip_extents (cairo_gstate_t *gstate, cairo_rectangle_int_t *extents) { - cairo_status_t status; + const cairo_rectangle_int_t *clip_extents; + cairo_bool_t is_bounded; - status = _cairo_surface_get_extents (gstate->target, extents); - if (unlikely (status)) - return status; + is_bounded = _cairo_surface_get_extents (gstate->target, extents); - status = _cairo_clip_intersect_to_rectangle (&gstate->clip, extents); + clip_extents = _cairo_clip_get_extents (&gstate->clip); + if (clip_extents != NULL) { + cairo_bool_t is_empty; - return status; + is_empty = _cairo_rectangle_intersect (extents, clip_extents); + is_bounded = TRUE; + } + + return is_bounded; } -cairo_status_t +cairo_bool_t _cairo_gstate_clip_extents (cairo_gstate_t *gstate, double *x1, double *y1, @@ -1207,11 +1264,9 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate, { cairo_rectangle_int_t extents; double px1, py1, px2, py2; - cairo_status_t status; - status = _cairo_gstate_int_clip_extents (gstate, &extents); - if (unlikely (status)) - return status; + if (! _cairo_gstate_int_clip_extents (gstate, &extents)) + return FALSE; px1 = extents.x; py1 = extents.y; @@ -1231,7 +1286,7 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate, if (y2) *y2 = py2; - return CAIRO_STATUS_SUCCESS; + return TRUE; } cairo_rectangle_list_t* @@ -1576,12 +1631,11 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, cairo_text_cluster_t *transformed_clusters; cairo_status_t status; - if (gstate->source->status) + if (unlikely (gstate->source->status)) return gstate->source->status; - status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (unlikely (status)) - return status; + if (_clipped (gstate)) + return CAIRO_STATUS_SUCCESS; status = _cairo_gstate_ensure_scaled_font (gstate); if (unlikely (status)) @@ -1635,7 +1689,8 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, * * Needless to say, do this only if show_text_glyphs is not available. */ if (cairo_surface_has_show_text_glyphs (gstate->target) || - _cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) { + _cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) + { status = _cairo_surface_show_text_glyphs (gstate->target, gstate->op, &source_pattern.base, @@ -1643,8 +1698,11 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, transformed_glyphs, num_glyphs, transformed_clusters, num_clusters, cluster_flags, - gstate->scaled_font, NULL); - } else { + gstate->scaled_font, + _gstate_get_clip (gstate)); + } + else + { cairo_path_fixed_t path; _cairo_path_fixed_init (&path); @@ -1653,14 +1711,16 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, transformed_glyphs, num_glyphs, &path); - if (status == CAIRO_STATUS_SUCCESS) - status = _cairo_surface_fill (gstate->target, - gstate->op, - &source_pattern.base, - &path, - CAIRO_FILL_RULE_WINDING, - gstate->tolerance, - gstate->scaled_font->options.antialias, NULL); + if (status == CAIRO_STATUS_SUCCESS) { + status = _cairo_surface_fill (gstate->target, + gstate->op, + &source_pattern.base, + &path, + CAIRO_FILL_RULE_WINDING, + gstate->tolerance, + gstate->scaled_font->options.antialias, + _gstate_get_clip (gstate)); + } _cairo_path_fixed_fini (&path); } @@ -1765,17 +1825,12 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, cairo_matrix_t *device_transform = &gstate->target->device_transform; cairo_bool_t drop = FALSE; double x1 = 0, x2 = 0, y1 = 0, y2 = 0; - cairo_status_t status; if (num_transformed_glyphs != NULL) { cairo_rectangle_int_t surface_extents; drop = TRUE; - status = _cairo_gstate_int_clip_extents (gstate, &surface_extents); - if (_cairo_status_is_error (status)) - return status; - - if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) { drop = FALSE; /* unbounded surface */ } else { double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font); diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 278654af..c7ceb262 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -37,6 +37,9 @@ #include "cairoint.h" +#include "cairo-clip-private.h" +#include "cairo-region-private.h" + static cairo_format_t _cairo_format_from_pixman_format (pixman_format_code_t pixman_format) { @@ -64,6 +67,14 @@ _cairo_format_from_pixman_format (pixman_format_code_t pixman_format) case PIXMAN_x2b10g10r10: case PIXMAN_a2b10g10r10: #endif +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1) + case PIXMAN_b8g8r8x8: + case PIXMAN_b8g8r8a8: +#endif +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16) + case PIXMAN_x2r10g10b10: + case PIXMAN_a2r10g10b10: +#endif default: return CAIRO_FORMAT_INVALID; } @@ -88,6 +99,12 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format) #if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9) case PIXMAN_a2b10g10r10: #endif +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1) + case PIXMAN_b8g8r8a8: +#endif +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16) + case PIXMAN_a2r10g10b10: +#endif return CAIRO_CONTENT_COLOR_ALPHA; case PIXMAN_x8r8g8b8: case PIXMAN_x8b8g8r8: @@ -113,6 +130,12 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format) #if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9) case PIXMAN_x2b10g10r10: #endif +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1) + case PIXMAN_b8g8r8x8: +#endif +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16) + case PIXMAN_x2r10g10b10: +#endif return CAIRO_CONTENT_COLOR; case PIXMAN_a8: case PIXMAN_a1: @@ -143,7 +166,6 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, surface->format = _cairo_format_from_pixman_format (pixman_format); surface->data = (unsigned char *) pixman_image_get_data (pixman_image); surface->owns_data = FALSE; - surface->has_clip = FALSE; surface->transparency = CAIRO_IMAGE_UNKNOWN; surface->width = pixman_image_get_width (pixman_image); @@ -151,6 +173,8 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, surface->stride = pixman_image_get_stride (pixman_image); surface->depth = pixman_image_get_depth (pixman_image); + surface->clip_region = NULL; + return &surface->base; } @@ -725,6 +749,8 @@ _cairo_image_surface_finish (void *abstract_surface) surface->data = NULL; } + cairo_region_destroy (surface->clip_region); + return CAIRO_STATUS_SUCCESS; } @@ -974,25 +1000,52 @@ _pixman_operator (cairo_operator_t op) } } +static cairo_status_t +_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, + cairo_region_t *region) +{ + if (region == surface->clip_region) + return CAIRO_STATUS_SUCCESS; + + if (cairo_region_equal (surface->clip_region, region)) + return CAIRO_STATUS_SUCCESS; + + cairo_region_destroy (surface->clip_region); + surface->clip_region = cairo_region_reference (region); + + if (! pixman_image_set_clip_region32 (surface->pixman_image, + region ? ®ion->rgn : NULL)) + { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + return CAIRO_STATUS_SUCCESS; +} + static cairo_int_status_t -_cairo_image_surface_composite (cairo_operator_t op, +_cairo_image_surface_composite (cairo_operator_t op, const cairo_pattern_t *src_pattern, const cairo_pattern_t *mask_pattern, void *abstract_dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height) + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, + cairo_region_t *clip_region) { - cairo_surface_attributes_t src_attr, mask_attr; + cairo_surface_attributes_t src_attr, mask_attr; cairo_image_surface_t *dst = abstract_dst; cairo_image_surface_t *src; cairo_image_surface_t *mask; - cairo_int_status_t status; + cairo_int_status_t status; + + status = _cairo_image_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + return status; status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern, &dst->base, @@ -1013,8 +1066,7 @@ _cairo_image_surface_composite (cairo_operator_t op, if (unlikely (status)) goto CLEANUP_SURFACES; - if (mask) - { + if (mask) { status = _cairo_image_surface_set_attributes (mask, &mask_attr, dst_x + width / 2., dst_y + height / 2.); @@ -1031,9 +1083,7 @@ _cairo_image_surface_composite (cairo_operator_t op, mask_y + mask_attr.y_offset, dst_x, dst_y, width, height); - } - else - { + } else { pixman_image_composite (_pixman_operator (op), src->pixman_image, NULL, @@ -1045,7 +1095,7 @@ _cairo_image_surface_composite (cairo_operator_t op, width, height); } - if (! _cairo_operator_bounded_by_source (op)) + if (! _cairo_operator_bounded_by_source (op)) { status = _cairo_surface_composite_fixup_unbounded (&dst->base, &src_attr, src->width, src->height, mask ? &mask_attr : NULL, @@ -1053,7 +1103,9 @@ _cairo_image_surface_composite (cairo_operator_t op, mask ? mask->height : 0, src_x, src_y, mask_x, mask_y, - dst_x, dst_y, width, height); + dst_x, dst_y, width, height, + clip_region); + } CLEANUP_SURFACES: if (mask) @@ -1078,7 +1130,7 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, pixman_rectangle16_t *pixman_rects = stack_rects; int i; - cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_int_status_t status; if (CAIRO_INJECT_FAULT ()) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -1088,6 +1140,9 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, pixman_color.blue = color->blue_short; pixman_color.alpha = color->alpha_short; + status = _cairo_image_surface_set_clip_region (surface, NULL); + assert (status == CAIRO_STATUS_SUCCESS); + if (num_rects > ARRAY_LENGTH (stack_rects)) { pixman_rects = _cairo_malloc_ab (num_rects, sizeof (pixman_rectangle16_t)); if (unlikely (pixman_rects == NULL)) @@ -1101,7 +1156,8 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, pixman_rects[i].height = rects[i].height; } - /* XXX: pixman_fill_rectangles() should be implemented */ + /* XXX: pixman_fill_region() should be implemented */ + status = CAIRO_STATUS_SUCCESS; if (! pixman_image_fill_rectangles (_pixman_operator (op), surface->pixman_image, &pixman_color, @@ -1165,7 +1221,8 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int num_traps) + int num_traps, + cairo_region_t *clip_region) { cairo_surface_attributes_t attributes; cairo_image_surface_t *dst = abstract_dst; @@ -1186,22 +1243,26 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, * contained within the surface is bounded by [dst_x,dst_y,width,height]; * the Cairo core code passes bounds based on the trapezoid extents. * - * Currently the check surface->has_clip is needed for correct + * Currently the check clip_region == NULL is needed for correct * functioning, since pixman_add_trapezoids() doesn't obey the * surface clip, which is a libpixman bug , but there's no harm in * falling through to the general case when the surface is clipped * since libpixman would have to generate an intermediate mask anyways. */ if (op == CAIRO_OPERATOR_ADD && + clip_region == NULL && _cairo_pattern_is_opaque_solid (pattern) && dst->base.content == CAIRO_CONTENT_ALPHA && - ! dst->has_clip && antialias != CAIRO_ANTIALIAS_NONE) { _pixman_add_trapezoids (dst->pixman_image, 0, 0, traps, num_traps); return CAIRO_STATUS_SUCCESS; } + status = _cairo_image_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + return status; + status = _cairo_pattern_acquire_surface (pattern, &dst->base, CAIRO_CONTENT_COLOR_ALPHA, src_x, src_y, width, height, @@ -1238,14 +1299,16 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, pixman_image_unref (mask); - if (! _cairo_operator_bounded_by_mask (op)) + if (! _cairo_operator_bounded_by_mask (op)) { status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base, &attributes, src->width, src->height, width, height, src_x, src_y, 0, 0, - dst_x, dst_y, width, height); + dst_x, dst_y, width, height, + clip_region); + } CLEANUP_SOURCE: _cairo_pattern_release_surface (pattern, &src->base, &attributes); @@ -1382,7 +1445,7 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer) rects->dst.x, rects->dst.y, width, height); - if (! _cairo_operator_bounded_by_mask (renderer->op)) + if (! _cairo_operator_bounded_by_mask (renderer->op)) { status = _cairo_surface_composite_shape_fixup_unbounded ( &dst->base, src_attributes, @@ -1391,7 +1454,9 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer) rects->src.x, rects->src.y, 0, 0, /* mask.x, mask.y */ rects->dst.x, rects->dst.y, - rects->width, rects->height); + rects->width, rects->height, + dst->clip_region); + } } if (status != CAIRO_STATUS_SUCCESS) return _cairo_span_renderer_set_error (abstract_renderer, @@ -1406,12 +1471,12 @@ _cairo_image_surface_check_span_renderer (cairo_operator_t op, cairo_antialias_t antialias, const cairo_composite_rectangles_t *rects) { + return TRUE; (void) op; (void) pattern; (void) abstract_dst; (void) antialias; (void) rects; - return TRUE; } static cairo_span_renderer_t * @@ -1419,22 +1484,25 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op, const cairo_pattern_t *pattern, void *abstract_dst, cairo_antialias_t antialias, - const cairo_composite_rectangles_t *rects) + const cairo_composite_rectangles_t *rects, + cairo_region_t *clip_region) { cairo_image_surface_t *dst = abstract_dst; - cairo_image_surface_span_renderer_t *renderer - = calloc(1, sizeof(*renderer)); + cairo_image_surface_span_renderer_t *renderer = calloc(1, sizeof(*renderer)); cairo_status_t status; int width = rects->width; int height = rects->height; + status = _cairo_image_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + return _cairo_span_renderer_create_in_error (status); + if (renderer == NULL) return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY); renderer->base.destroy = _cairo_image_surface_span_renderer_destroy; renderer->base.finish = _cairo_image_surface_span_renderer_finish; - renderer->base.render_row = - _cairo_image_surface_span_renderer_render_row; + renderer->base.render_row = _cairo_image_surface_span_renderer_render_row; renderer->op = op; renderer->pattern = pattern; renderer->antialias = antialias; @@ -1475,21 +1543,7 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op, return &renderer->base; } -cairo_int_status_t -_cairo_image_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region) -{ - cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface; - - if (! pixman_image_set_clip_region32 (surface->pixman_image, region? ®ion->rgn : NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - surface->has_clip = region != NULL; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t +static cairo_bool_t _cairo_image_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -1500,7 +1554,7 @@ _cairo_image_surface_get_extents (void *abstract_surface, rectangle->width = surface->width; rectangle->height = surface->height; - return CAIRO_STATUS_SUCCESS; + return TRUE; } static void @@ -1512,18 +1566,6 @@ _cairo_image_surface_get_font_options (void *abstract_surface, cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON); } -static cairo_status_t -_cairo_image_surface_reset (void *abstract_surface) -{ - cairo_image_surface_t *surface = abstract_surface; - cairo_status_t status; - - status = _cairo_image_surface_set_clip_region (surface, NULL); - assert (status == CAIRO_STATUS_SUCCESS); - - return CAIRO_STATUS_SUCCESS; -} - /** * _cairo_surface_is_image: * @surface: a #cairo_surface_t @@ -1554,8 +1596,6 @@ const cairo_surface_backend_t _cairo_image_surface_backend = { _cairo_image_surface_check_span_renderer, NULL, /* copy_page */ NULL, /* show_page */ - _cairo_image_surface_set_clip_region, - NULL, /* intersect_clip_path */ _cairo_image_surface_get_extents, NULL, /* old_show_glyphs */ _cairo_image_surface_get_font_options, @@ -1571,8 +1611,6 @@ const cairo_surface_backend_t _cairo_image_surface_backend = { NULL, /* show_glyphs */ NULL, /* snapshot */ NULL, /* is_similar */ - - _cairo_image_surface_reset }; /* A convenience function for when one needs to coerce an image @@ -1600,7 +1638,8 @@ _cairo_image_surface_coerce (cairo_image_surface_t *surface, _cairo_pattern_init_for_surface (&pattern, &surface->base); status = _cairo_surface_paint (&clone->base, CAIRO_OPERATOR_SOURCE, - &pattern.base, NULL); + &pattern.base, + NULL); _cairo_pattern_fini (&pattern.base); if (unlikely (status)) { diff --git a/src/cairo-meta-surface-private.h b/src/cairo-meta-surface-private.h index f0c95c19..edfb20c3 100644 --- a/src/cairo-meta-surface-private.h +++ b/src/cairo-meta-surface-private.h @@ -39,6 +39,7 @@ #include "cairoint.h" #include "cairo-path-fixed-private.h" +#include "cairo-clip-private.h" typedef enum { /* The 5 basic drawing operations. */ @@ -47,15 +48,6 @@ typedef enum { CAIRO_COMMAND_STROKE, CAIRO_COMMAND_FILL, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, - - /* Other junk. For most of these, we should be able to assert that - * they never get called except as part of fallbacks for the 5 - * basic drawing operations (which we implement already so the - * fallbacks should never get triggered). So the plan is to - * eliminate as many of these as possible. */ - - CAIRO_COMMAND_INTERSECT_CLIP_PATH - } cairo_command_type_t; typedef enum { @@ -67,25 +59,23 @@ typedef enum { typedef struct _cairo_command_header { cairo_command_type_t type; cairo_meta_region_type_t region; - cairo_rectangle_int_t extents; + cairo_operator_t op; + cairo_clip_t clip; } cairo_command_header_t; typedef struct _cairo_command_paint { cairo_command_header_t header; - cairo_operator_t op; cairo_pattern_union_t source; } cairo_command_paint_t; typedef struct _cairo_command_mask { cairo_command_header_t header; - cairo_operator_t op; cairo_pattern_union_t source; cairo_pattern_union_t mask; } cairo_command_mask_t; typedef struct _cairo_command_stroke { cairo_command_header_t header; - cairo_operator_t op; cairo_pattern_union_t source; cairo_path_fixed_t path; cairo_stroke_style_t style; @@ -97,7 +87,6 @@ typedef struct _cairo_command_stroke { typedef struct _cairo_command_fill { cairo_command_header_t header; - cairo_operator_t op; cairo_pattern_union_t source; cairo_path_fixed_t path; cairo_fill_rule_t fill_rule; @@ -107,7 +96,6 @@ typedef struct _cairo_command_fill { typedef struct _cairo_command_show_text_glyphs { cairo_command_header_t header; - cairo_operator_t op; cairo_pattern_union_t source; char *utf8; int utf8_len; @@ -119,27 +107,14 @@ typedef struct _cairo_command_show_text_glyphs { cairo_scaled_font_t *scaled_font; } cairo_command_show_text_glyphs_t; -typedef struct _cairo_command_intersect_clip_path { - cairo_command_header_t header; - cairo_path_fixed_t *path_pointer; - cairo_path_fixed_t path; - cairo_fill_rule_t fill_rule; - double tolerance; - cairo_antialias_t antialias; -} cairo_command_intersect_clip_path_t; - typedef union _cairo_command { cairo_command_header_t header; - /* The 5 basic drawing operations. */ cairo_command_paint_t paint; cairo_command_mask_t mask; cairo_command_stroke_t stroke; cairo_command_fill_t fill; cairo_command_show_text_glyphs_t show_text_glyphs; - - /* The other junk. */ - cairo_command_intersect_clip_path_t intersect_clip_path; } cairo_command_t; typedef struct _cairo_meta_surface { @@ -150,14 +125,15 @@ typedef struct _cairo_meta_surface { /* A meta-surface is logically unbounded, but when used as a * source we need to render it to an image, so we need a size at * which to create that image. */ - double width_pixels; - double height_pixels; + cairo_rectangle_t extents_pixels; cairo_rectangle_int_t extents; + cairo_bool_t unbounded; + + cairo_clip_t clip; cairo_array_t commands; cairo_surface_t *commands_owner; - cairo_bool_t is_clipped; int replay_start_idx; } cairo_meta_surface_t; @@ -181,6 +157,11 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface, cairo_surface_t *target, cairo_meta_region_type_t region); +cairo_private cairo_status_t +_cairo_meta_surface_get_bbox (cairo_meta_surface_t *meta, + cairo_box_t *bbox, + const cairo_matrix_t *transform); + cairo_private cairo_bool_t _cairo_surface_is_meta (const cairo_surface_t *surface); diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c index 4fb2722c..f091a59f 100644 --- a/src/cairo-meta-surface.c +++ b/src/cairo-meta-surface.c @@ -50,6 +50,12 @@ * that would have been obtained if the original operations applied to * the meta surface had instead been applied to the target surface. * + * A meta surface is logically unbounded, i.e. it has no implicit constraint + * on the size of the drawing surface. However, in practice this is rarely + * useful as you wish to replay against a particular target surface with + * known bounds. For this case, it is more efficient to specify the target + * extents to the meta surface upon creation. + * * The recording phase of the meta surface is careful to snapshot all * necessary objects (paths, patterns, etc.), in order to achieve * accurate replay. The efficiency of the meta surface could be @@ -58,10 +64,13 @@ * copy-on-write implementation for _cairo_surface_snapshot. */ +/* XXX Rename to recording surface */ + #include "cairoint.h" #include "cairo-analysis-surface-private.h" #include "cairo-meta-surface-private.h" #include "cairo-clip-private.h" +#include "cairo-surface-wrapper-private.h" typedef enum { CAIRO_META_REPLAY, @@ -82,8 +91,8 @@ static const cairo_surface_backend_t cairo_meta_surface_backend; /** * cairo_meta_surface_create: * @content: the content of the meta surface - * @width_pixels: width of the surface, in pixels - * @height_pixels: height of the surface, in pixels + * @extents_pixels: the extents to record in pixels, can be %NULL to record + * unbounded operations. * * Creates a meta-surface which can be used to record all drawing operations * at the highest level (that is, the level of paint, mask, stroke, fill @@ -105,50 +114,45 @@ static const cairo_surface_backend_t cairo_meta_surface_backend; * Since 1.10 **/ cairo_surface_t * -cairo_meta_surface_create (cairo_content_t content, - double width_pixels, - double height_pixels) +cairo_meta_surface_create (cairo_content_t content, + const cairo_rectangle_t *extents) { cairo_meta_surface_t *meta; + cairo_status_t status; meta = malloc (sizeof (cairo_meta_surface_t)); if (unlikely (meta == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - _cairo_surface_init (&meta->base, &cairo_meta_surface_backend, - content); + _cairo_surface_init (&meta->base, &cairo_meta_surface_backend, content); meta->content = content; - meta->width_pixels = width_pixels; - meta->height_pixels = height_pixels; /* unbounded -> 'infinite' extents */ - if (width_pixels < 0) { - meta->extents.x = CAIRO_RECT_INT_MIN; - meta->extents.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; - } else { - meta->extents.x = 0; - if (ceil (width_pixels) > CAIRO_RECT_INT_MAX) - meta->extents.width = CAIRO_RECT_INT_MAX; - else - meta->extents.width = ceil (width_pixels); - } + if (extents != NULL) { + meta->extents_pixels = *extents; - if (height_pixels < 0) { - meta->extents.y = CAIRO_RECT_INT_MIN; - meta->extents.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; + /* XXX check for overflow */ + meta->extents.x = floor (extents->x); + meta->extents.y = floor (extents->y); + meta->extents.width = ceil (extents->x + extents->width) - meta->extents.x; + meta->extents.height = ceil (extents->y + extents->height) - meta->extents.y; + + status = _cairo_clip_init_rectangle (&meta->clip, &meta->extents); + if (unlikely (status)) { + free (meta); + return _cairo_surface_create_in_error (status); + } + + meta->unbounded = FALSE; } else { - meta->extents.y = 0; - if (ceil (height_pixels) > CAIRO_RECT_INT_MAX) - meta->extents.height = CAIRO_RECT_INT_MAX; - else - meta->extents.height = ceil (height_pixels); + meta->unbounded = TRUE; + _cairo_clip_init (&meta->clip); } _cairo_array_init (&meta->commands, sizeof (cairo_command_t *)); meta->commands_owner = NULL; - meta->is_clipped = FALSE; meta->replay_start_idx = 0; return &meta->base; @@ -161,14 +165,17 @@ _cairo_meta_surface_create_similar (void *abstract_surface, int width, int height) { - return cairo_meta_surface_create (content, width, height); + cairo_rectangle_t extents; + extents.x = extents.y = 0; + extents.width = width; + extents.height = height; + return cairo_meta_surface_create (content, &extents); } static cairo_status_t _cairo_meta_surface_finish (void *abstract_surface) { cairo_meta_surface_t *meta = abstract_surface; - cairo_command_t *command; cairo_command_t **elements; int i, num_elements; @@ -180,11 +187,11 @@ _cairo_meta_surface_finish (void *abstract_surface) num_elements = meta->commands.num_elements; elements = _cairo_array_index (&meta->commands, 0); for (i = 0; i < num_elements; i++) { - command = elements[i]; - switch (command->header.type) { + cairo_command_t *command = elements[i]; - /* 5 basic drawing operations */ + _cairo_clip_reset (&command->header.clip); + switch (command->header.type) { case CAIRO_COMMAND_PAINT: _cairo_pattern_fini_snapshot (&command->paint.source.base); free (command); @@ -218,19 +225,13 @@ _cairo_meta_surface_finish (void *abstract_surface) free (command); break; - /* Other junk. */ - case CAIRO_COMMAND_INTERSECT_CLIP_PATH: - if (command->intersect_clip_path.path_pointer) - _cairo_path_fixed_fini (&command->intersect_clip_path.path); - free (command); - break; - default: ASSERT_NOT_REACHED; } } _cairo_array_fini (&meta->commands); + _cairo_clip_reset (&meta->clip); return CAIRO_STATUS_SUCCESS; } @@ -254,8 +255,12 @@ _cairo_meta_surface_acquire_source_image (void *abstract_surface, } image = _cairo_image_surface_create_with_content (surface->content, - ceil (surface->width_pixels), - ceil (surface->height_pixels)); + surface->extents.width, + surface->extents.height); + + cairo_surface_set_device_offset (image, + -surface->extents.x, + -surface->extents.y); status = cairo_meta_surface_replay (&surface->base, image); if (unlikely (status)) { @@ -282,21 +287,30 @@ _cairo_meta_surface_release_source_image (void *abstract_surface, cairo_surface_destroy (&image->base); } -static void -_draw_command_init (cairo_command_header_t *command, - cairo_command_type_t type, - cairo_meta_surface_t *meta) +static cairo_status_t +_command_init (cairo_meta_surface_t *meta, + cairo_command_header_t *command, + cairo_command_type_t type, + cairo_operator_t op, + cairo_clip_t *clip) { + cairo_status_t status = CAIRO_STATUS_SUCCESS; + command->type = type; + command->op = op; command->region = CAIRO_META_REGION_ALL; - command->extents = meta->extents; + _cairo_clip_init_copy (&command->clip, clip); + if (meta->clip.path != NULL) + status = _cairo_clip_apply_clip (&command->clip, &meta->clip); + + return status; } static cairo_int_status_t -_cairo_meta_surface_paint (void *abstract_surface, - cairo_operator_t op, +_cairo_meta_surface_paint (void *abstract_surface, + cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; @@ -306,8 +320,10 @@ _cairo_meta_surface_paint (void *abstract_surface, if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _draw_command_init (&command->header, CAIRO_COMMAND_PAINT, meta); - command->op = op; + status = _command_init (meta, + &command->header, CAIRO_COMMAND_PAINT, op, clip); + if (unlikely (status)) + goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) @@ -320,7 +336,7 @@ _cairo_meta_surface_paint (void *abstract_surface, /* An optimisation that takes care to not replay what was done * before surface is cleared. We don't erase recorded commands * since we may have earlier snapshots of this surface. */ - if (op == CAIRO_OPERATOR_CLEAR && !meta->is_clipped) + if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) meta->replay_start_idx = meta->commands.num_elements; return CAIRO_STATUS_SUCCESS; @@ -337,7 +353,7 @@ _cairo_meta_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; @@ -347,8 +363,10 @@ _cairo_meta_surface_mask (void *abstract_surface, if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _draw_command_init (&command->header, CAIRO_COMMAND_MASK, meta); - command->op = op; + status = _command_init (meta, + &command->header, CAIRO_COMMAND_MASK, op, clip); + if (unlikely (status)) + goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) @@ -383,7 +401,7 @@ _cairo_meta_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; @@ -393,8 +411,10 @@ _cairo_meta_surface_stroke (void *abstract_surface, if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _draw_command_init (&command->header, CAIRO_COMMAND_STROKE, meta); - command->op = op; + status = _command_init (meta, + &command->header, CAIRO_COMMAND_STROKE, op, clip); + if (unlikely (status)) + goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) @@ -438,7 +458,7 @@ _cairo_meta_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; @@ -448,8 +468,10 @@ _cairo_meta_surface_fill (void *abstract_surface, if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _draw_command_init (&command->header, CAIRO_COMMAND_FILL, meta); - command->op = op; + status =_command_init (meta, + &command->header, CAIRO_COMMAND_FILL, op, clip); + if (unlikely (status)) + goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) @@ -496,7 +518,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; @@ -506,8 +528,11 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface, if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _draw_command_init (&command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, meta); - command->op = op; + status = _command_init (meta, + &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, + op, clip); + if (unlikely (status)) + goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) @@ -594,82 +619,31 @@ _cairo_meta_surface_snapshot (void *abstract_other) _cairo_surface_init (&meta->base, &cairo_meta_surface_backend, other->base.content); - meta->width_pixels = other->width_pixels; - meta->height_pixels = other->height_pixels; + meta->extents_pixels = other->extents_pixels; meta->extents = other->extents; + meta->unbounded = other->unbounded; meta->replay_start_idx = other->replay_start_idx; meta->content = other->content; _cairo_array_init_snapshot (&meta->commands, &other->commands); meta->commands_owner = cairo_surface_reference (&other->base); - return &meta->base; -} - -static cairo_int_status_t -_cairo_meta_surface_intersect_clip_path (void *dst, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_meta_surface_t *meta = dst; - cairo_command_intersect_clip_path_t *command; - cairo_status_t status; - - command = malloc (sizeof (cairo_command_intersect_clip_path_t)); - if (unlikely (command == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - command->header.type = CAIRO_COMMAND_INTERSECT_CLIP_PATH; - command->header.region = CAIRO_META_REGION_ALL; - - if (path) { - status = _cairo_path_fixed_init_copy (&command->path, path); - if (unlikely (status)) { - free (command); - return status; - } - command->path_pointer = &command->path; - meta->is_clipped = TRUE; - } else { - command->path_pointer = NULL; - meta->is_clipped = FALSE; - } - command->fill_rule = fill_rule; - command->tolerance = tolerance; - command->antialias = antialias; - - status = _cairo_array_append (&meta->commands, &command); - if (unlikely (status)) { - if (path) - _cairo_path_fixed_fini (&command->path); - free (command); - return status; - } + _cairo_clip_init_copy (&meta->clip, &other->clip); - return CAIRO_STATUS_SUCCESS; + return &meta->base; } -/* Currently, we're using as the "size" of a meta surface the largest - * surface size against which the meta-surface is expected to be - * replayed, (as passed in to cairo_meta_surface_create()). - */ -static cairo_int_status_t +static cairo_bool_t _cairo_meta_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { cairo_meta_surface_t *surface = abstract_surface; - if (surface->width_pixels < 0 || surface->height_pixels < 0) - return CAIRO_INT_STATUS_UNSUPPORTED; - - rectangle->x = 0; - rectangle->y = 0; - rectangle->width = ceil (surface->width_pixels); - rectangle->height = ceil (surface->height_pixels); + if (surface->unbounded) + return FALSE; - return CAIRO_STATUS_SUCCESS; + *rectangle = surface->extents; + return TRUE; } /** @@ -702,8 +676,6 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - NULL, /* set_clip_region */ - _cairo_meta_surface_intersect_clip_path, _cairo_meta_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -726,7 +698,6 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = { _cairo_meta_surface_snapshot, NULL, /* is_similar */ - NULL, /* reset */ NULL, /* fill_stroke */ NULL, /* create_solid_pattern_surface */ NULL, /* can_repaint_solid_pattern_surface */ @@ -735,32 +706,12 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = { _cairo_meta_surface_show_text_glyphs }; -static cairo_path_fixed_t * -_cairo_command_get_path (cairo_command_t *command) -{ - switch (command->header.type) { - case CAIRO_COMMAND_PAINT: - case CAIRO_COMMAND_MASK: - case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: - return NULL; - case CAIRO_COMMAND_STROKE: - return &command->stroke.path; - case CAIRO_COMMAND_FILL: - return &command->fill.path; - case CAIRO_COMMAND_INTERSECT_CLIP_PATH: - return command->intersect_clip_path.path_pointer; - } - - ASSERT_NOT_REACHED; - return NULL; -} - cairo_int_status_t _cairo_meta_surface_get_path (cairo_surface_t *surface, cairo_path_fixed_t *path) { cairo_meta_surface_t *meta; - cairo_command_t *command, **elements; + cairo_command_t **elements; int i, num_elements; cairo_int_status_t status; @@ -773,12 +724,11 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface, num_elements = meta->commands.num_elements; elements = _cairo_array_index (&meta->commands, 0); for (i = meta->replay_start_idx; i < num_elements; i++) { - command = elements[i]; + cairo_command_t *command = elements[i]; switch (command->header.type) { case CAIRO_COMMAND_PAINT: case CAIRO_COMMAND_MASK: - case CAIRO_COMMAND_INTERSECT_CLIP_PATH: status = CAIRO_INT_STATUS_UNSUPPORTED; break; @@ -804,7 +754,9 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface, } case CAIRO_COMMAND_FILL: { - status = _cairo_path_fixed_append (path, &command->fill.path, CAIRO_DIRECTION_FORWARD); + status = _cairo_path_fixed_append (path, + &command->fill.path, CAIRO_DIRECTION_FORWARD, + 0, 0); break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: @@ -827,6 +779,7 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface, return _cairo_surface_set_error (surface, status); } +#define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL) static cairo_status_t _cairo_meta_surface_replay_internal (cairo_surface_t *surface, cairo_surface_t *target, @@ -834,209 +787,155 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, cairo_meta_region_type_t region) { cairo_meta_surface_t *meta; - cairo_command_t *command, **elements; + cairo_command_t **elements; int i, num_elements; - cairo_int_status_t status, status2; - cairo_clip_t clip, *old_clip; - cairo_bool_t has_device_transform = _cairo_surface_has_device_transform (target); - cairo_matrix_t *device_transform = &target->device_transform; - cairo_path_fixed_t path_copy, *dev_path; + cairo_int_status_t status; + cairo_surface_wrapper_t wrapper; - if (surface->status) + if (unlikely (surface->status)) return surface->status; - if (target->status) + if (unlikely (target->status)) return _cairo_surface_set_error (surface, target->status); + _cairo_surface_wrapper_init (&wrapper, target); + meta = (cairo_meta_surface_t *) surface; status = CAIRO_STATUS_SUCCESS; - _cairo_clip_init (&clip, target); - old_clip = _cairo_surface_get_clip (target); - num_elements = meta->commands.num_elements; elements = _cairo_array_index (&meta->commands, 0); for (i = meta->replay_start_idx; i < num_elements; i++) { - command = elements[i]; + cairo_command_t *command = elements[i]; if (type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) { if (command->header.region != region) continue; } - /* For all commands except intersect_clip_path, we have to - * ensure the current clip gets set on the surface. */ - if (command->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) { - status = _cairo_surface_set_clip (target, &clip); - if (unlikely (status)) - break; - } - - dev_path = _cairo_command_get_path (command); - if (dev_path && has_device_transform) { - status = _cairo_path_fixed_init_copy (&path_copy, dev_path); - if (unlikely (status)) - break; - _cairo_path_fixed_transform (&path_copy, device_transform); - dev_path = &path_copy; - } - switch (command->header.type) { case CAIRO_COMMAND_PAINT: - status = _cairo_surface_paint (target, - command->paint.op, - &command->paint.source.base, &command->header.extents); + status = _cairo_surface_wrapper_paint (&wrapper, + command->header.op, + &command->paint.source.base, + _clip (command)); break; + case CAIRO_COMMAND_MASK: - status = _cairo_surface_mask (target, - command->mask.op, - &command->mask.source.base, - &command->mask.mask.base, &command->header.extents); + status = _cairo_surface_wrapper_mask (&wrapper, + command->header.op, + &command->mask.source.base, + &command->mask.mask.base, + _clip (command)); break; + case CAIRO_COMMAND_STROKE: { - cairo_matrix_t dev_ctm = command->stroke.ctm; - cairo_matrix_t dev_ctm_inverse = command->stroke.ctm_inverse; - - if (has_device_transform) { - cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform); - cairo_matrix_multiply (&dev_ctm_inverse, - &target->device_transform_inverse, - &dev_ctm_inverse); - } - - status = _cairo_surface_stroke (target, - command->stroke.op, - &command->stroke.source.base, - dev_path, - &command->stroke.style, - &dev_ctm, - &dev_ctm_inverse, - command->stroke.tolerance, - command->stroke.antialias, &command->header.extents); + status = _cairo_surface_wrapper_stroke (&wrapper, + command->header.op, + &command->stroke.source.base, + &command->stroke.path, + &command->stroke.style, + &command->stroke.ctm, + &command->stroke.ctm_inverse, + command->stroke.tolerance, + command->stroke.antialias, + _clip (command)); break; } case CAIRO_COMMAND_FILL: { cairo_command_t *stroke_command; - if (type != CAIRO_META_CREATE_REGIONS) - stroke_command = (i < num_elements - 1) ? elements[i + 1] : NULL; - else - stroke_command = NULL; + stroke_command = NULL; + if (type != CAIRO_META_CREATE_REGIONS && i < num_elements - 1) + stroke_command = elements[i + 1]; if (stroke_command != NULL && - type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) + type == CAIRO_META_REPLAY && + region != CAIRO_META_REGION_ALL) { if (stroke_command->header.region != region) stroke_command = NULL; } + if (stroke_command != NULL && stroke_command->header.type == CAIRO_COMMAND_STROKE && - _cairo_path_fixed_is_equal (dev_path, _cairo_command_get_path (stroke_command))) { - cairo_matrix_t dev_ctm; - cairo_matrix_t dev_ctm_inverse; - - dev_ctm = stroke_command->stroke.ctm; - dev_ctm_inverse = stroke_command->stroke.ctm_inverse; - - if (has_device_transform) { - cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform); - cairo_matrix_multiply (&dev_ctm_inverse, - &surface->device_transform_inverse, - &dev_ctm_inverse); - } - - status = _cairo_surface_fill_stroke (target, - command->fill.op, - &command->fill.source.base, - command->fill.fill_rule, - command->fill.tolerance, - command->fill.antialias, - dev_path, - stroke_command->stroke.op, - &stroke_command->stroke.source.base, - &stroke_command->stroke.style, - &dev_ctm, - &dev_ctm_inverse, - stroke_command->stroke.tolerance, - stroke_command->stroke.antialias, - &stroke_command->header.extents); + _cairo_path_fixed_is_equal (&command->fill.path, + &stroke_command->stroke.path)) + { + status = _cairo_surface_wrapper_fill_stroke (&wrapper, + command->header.op, + &command->fill.source.base, + command->fill.fill_rule, + command->fill.tolerance, + command->fill.antialias, + &command->fill.path, + stroke_command->header.op, + &stroke_command->stroke.source.base, + &stroke_command->stroke.style, + &stroke_command->stroke.ctm, + &stroke_command->stroke.ctm_inverse, + stroke_command->stroke.tolerance, + stroke_command->stroke.antialias, + _clip (command)); i++; - } else - status = _cairo_surface_fill (target, - command->fill.op, - &command->fill.source.base, - dev_path, - command->fill.fill_rule, - command->fill.tolerance, - command->fill.antialias, &command->header.extents); + } + else + { + status = _cairo_surface_wrapper_fill (&wrapper, + command->header.op, + &command->fill.source.base, + &command->fill.path, + command->fill.fill_rule, + command->fill.tolerance, + command->fill.antialias, + _clip (command)); + } break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: { cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs; - cairo_glyph_t *dev_glyphs; - int i, num_glyphs = command->show_text_glyphs.num_glyphs; + cairo_glyph_t *glyphs_copy; + int num_glyphs = command->show_text_glyphs.num_glyphs; /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed * to modify the glyph array that's passed in. We must always * copy the array before handing it to the backend. */ - dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); - if (unlikely (dev_glyphs == NULL)) { + glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (unlikely (glyphs_copy == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); break; } - if (has_device_transform) { - for (i = 0; i < num_glyphs; i++) { - dev_glyphs[i] = glyphs[i]; - cairo_matrix_transform_point (device_transform, - &dev_glyphs[i].x, - &dev_glyphs[i].y); - } - } else { - memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); - } - - status = _cairo_surface_show_text_glyphs (target, - command->show_text_glyphs.op, - &command->show_text_glyphs.source.base, - command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len, - dev_glyphs, num_glyphs, - command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, - command->show_text_glyphs.cluster_flags, - command->show_text_glyphs.scaled_font, &command->header.extents); - - free (dev_glyphs); + memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + + status = _cairo_surface_wrapper_show_text_glyphs (&wrapper, + command->header.op, + &command->show_text_glyphs.source.base, + command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len, + glyphs_copy, num_glyphs, + command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, + command->show_text_glyphs.cluster_flags, + command->show_text_glyphs.scaled_font, + _clip (command)); + free (glyphs_copy); break; } - case CAIRO_COMMAND_INTERSECT_CLIP_PATH: - /* XXX Meta surface clipping is broken and requires some - * cairo-gstate.c rewriting. Work around it for now. */ - if (dev_path == NULL) - _cairo_clip_reset (&clip); - else - status = _cairo_clip_clip (&clip, dev_path, - command->intersect_clip_path.fill_rule, - command->intersect_clip_path.tolerance, - command->intersect_clip_path.antialias, - target); - break; default: ASSERT_NOT_REACHED; } - if (dev_path == &path_copy) - _cairo_path_fixed_fini (&path_copy); - if (type == CAIRO_META_CREATE_REGIONS) { if (status == CAIRO_STATUS_SUCCESS) { command->header.region = CAIRO_META_REGION_NATIVE; } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) { command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK; status = CAIRO_STATUS_SUCCESS; + } else { + assert (_cairo_status_is_error (status)); } } @@ -1044,10 +943,14 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, break; } - _cairo_clip_reset (&clip); - status2 = _cairo_surface_set_clip (target, old_clip); - if (status == CAIRO_STATUS_SUCCESS) - status = status2; + /* free up any caches */ + for (i = meta->replay_start_idx; i < num_elements; i++) { + cairo_command_t *command = elements[i]; + + _cairo_clip_drop_cache (&command->header.clip); + } + + _cairo_surface_wrapper_fini (&wrapper); return _cairo_surface_set_error (surface, status); } @@ -1104,6 +1007,33 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface, region); } +static cairo_status_t +_meta_surface_get_ink_bbox (cairo_meta_surface_t *surface, + cairo_box_t *bbox, + const cairo_matrix_t *transform) +{ + cairo_surface_t *null_surface; + cairo_surface_t *analysis_surface; + cairo_status_t status; + + null_surface = _cairo_null_surface_create (surface->content); + analysis_surface = _cairo_analysis_surface_create (null_surface); + cairo_surface_destroy (null_surface); + + status = analysis_surface->status; + if (unlikely (status)) + return status; + + if (transform != NULL) + _cairo_analysis_surface_set_ctm (analysis_surface, transform); + + status = cairo_meta_surface_replay (&surface->base, analysis_surface); + _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox); + cairo_surface_destroy (analysis_surface); + + return status; +} + /** * cairo_meta_surface_ink_extents: * @surface: a #cairo_meta_surface_t @@ -1114,7 +1044,7 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface, * * Measures the extents of the operations stored within the meta-surface. * This is useful to compute the required size of an image surface (or - * equivalent) into which to replay the full sequence of drawing operaitions. + * equivalent) into which to replay the full sequence of drawing operations. * * Since: 1.10 **/ @@ -1125,8 +1055,6 @@ cairo_meta_surface_ink_extents (cairo_surface_t *surface, double *width, double *height) { - cairo_surface_t *null_surface; - cairo_surface_t *analysis_surface; cairo_status_t status; cairo_box_t bbox; @@ -1137,17 +1065,11 @@ cairo_meta_surface_ink_extents (cairo_surface_t *surface, goto DONE; } - null_surface = _cairo_null_surface_create (CAIRO_CONTENT_COLOR_ALPHA); - analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1); - cairo_surface_destroy (null_surface); - - status = analysis_surface->status; + status = _meta_surface_get_ink_bbox ((cairo_meta_surface_t *) surface, + &bbox, + NULL); if (unlikely (status)) - goto DONE; - - status = cairo_meta_surface_replay (surface, analysis_surface); - _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox); - cairo_surface_destroy (analysis_surface); + status = _cairo_surface_set_error (surface, status); DONE: if (x0) @@ -1159,3 +1081,19 @@ DONE: if (height) *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y); } + +cairo_status_t +_cairo_meta_surface_get_bbox (cairo_meta_surface_t *surface, + cairo_box_t *bbox, + const cairo_matrix_t *transform) +{ + if (! surface->unbounded) { + _cairo_box_from_rectangle (bbox, &surface->extents); + if (transform != NULL) + _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL); + + return CAIRO_STATUS_SUCCESS; + } + + return _meta_surface_get_ink_bbox (surface, bbox, transform); +} diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c index 82bab3be..3fda0b4f 100644 --- a/src/cairo-os2-surface.c +++ b/src/cairo-os2-surface.c @@ -716,26 +716,18 @@ _cairo_os2_surface_release_dest_image (void *abstract_surface DosReleaseMutexSem (local_os2_surface->hmtx_use_private_fields); } -static cairo_int_status_t +static cairo_bool_t _cairo_os2_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { cairo_os2_surface_t *local_os2_surface; - local_os2_surface = (cairo_os2_surface_t *) abstract_surface; - if ((!local_os2_surface) || - (local_os2_surface->base.backend != &cairo_os2_surface_backend)) - { - /* Invalid parameter (wrong surface)! */ - return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); - } - rectangle->x = 0; rectangle->y = 0; rectangle->width = local_os2_surface->bitmap_info.cx; rectangle->height = local_os2_surface->bitmap_info.cy; - return CAIRO_STATUS_SUCCESS; + return TRUE; } /** @@ -1327,8 +1319,6 @@ static const cairo_surface_backend_t cairo_os2_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - NULL, /* set_clip_region */ - NULL, /* intersect_clip_path */ _cairo_os2_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ diff --git a/src/cairo-paginated-private.h b/src/cairo-paginated-private.h index 5cb2e48b..0841a2b1 100644 --- a/src/cairo-paginated-private.h +++ b/src/cairo-paginated-private.h @@ -149,8 +149,6 @@ struct _cairo_paginated_surface_backend { cairo_private cairo_surface_t * _cairo_paginated_surface_create (cairo_surface_t *target, cairo_content_t content, - int width, - int height, const cairo_paginated_surface_backend_t *backend); cairo_private cairo_surface_t * diff --git a/src/cairo-paginated-surface-private.h b/src/cairo-paginated-surface-private.h index b406cac1..6c130727 100644 --- a/src/cairo-paginated-surface-private.h +++ b/src/cairo-paginated-surface-private.h @@ -48,14 +48,6 @@ typedef struct _cairo_paginated_surface { cairo_content_t content; - /* XXX: These shouldn't actually exist. We inherit this ugliness - * from _cairo_meta_surface_create. The width/height parameters - * from that function also should not exist. The fix that will - * allow us to remove all of these is to fix acquire_source_image - * to pass an interest rectangle. */ - int width; - int height; - /* Paginated-surface specific functions for the target */ const cairo_paginated_surface_backend_t *backend; @@ -66,7 +58,6 @@ typedef struct _cairo_paginated_surface { int page_num; cairo_bool_t page_is_blank; - } cairo_paginated_surface_t; #endif /* CAIRO_PAGINATED_SURFACE_H */ diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c index 033df35a..23443a5d 100644 --- a/src/cairo-paginated-surface.c +++ b/src/cairo-paginated-surface.c @@ -60,17 +60,36 @@ _cairo_paginated_surface_create_similar (void *abstract_surface, int width, int height) { - cairo_paginated_surface_t *surface = abstract_surface; - return cairo_surface_create_similar (surface->target, content, - width, height); + cairo_rectangle_t rect; + rect.x = rect.y = 0.; + rect.width = width; + rect.height = height; + return cairo_meta_surface_create (content, &rect); +} + +static cairo_surface_t * +_create_meta_surface_for_target (cairo_surface_t *target, + cairo_content_t content) +{ + cairo_rectangle_int_t rect; + + if (_cairo_surface_get_extents (target, &rect)) { + cairo_rectangle_t meta_extents; + + meta_extents.x = rect.x; + meta_extents.y = rect.y; + meta_extents.width = rect.width; + meta_extents.height = rect.height; + + return cairo_meta_surface_create (content, &meta_extents); + } else { + return cairo_meta_surface_create (content, NULL); + } } -/* XXX The integer width,height here should be doubles and all uses updated */ cairo_surface_t * _cairo_paginated_surface_create (cairo_surface_t *target, cairo_content_t content, - int width, - int height, const cairo_paginated_surface_backend_t *backend) { cairo_paginated_surface_t *surface; @@ -87,18 +106,15 @@ _cairo_paginated_surface_create (cairo_surface_t *target, /* Override surface->base.type with target's type so we don't leak * evidence of the paginated wrapper out to the user. */ - surface->base.type = cairo_surface_get_type (target); + surface->base.type = target->type; surface->target = cairo_surface_reference (target); surface->content = content; - surface->width = width; - surface->height = height; - surface->backend = backend; - surface->meta = cairo_meta_surface_create (content, width, height); - status = cairo_surface_status (surface->meta); + surface->meta = _create_meta_surface_for_target (target, content); + status = surface->meta->status; if (unlikely (status)) goto FAIL_CLEANUP_SURFACE; @@ -132,31 +148,6 @@ _cairo_paginated_surface_get_target (cairo_surface_t *surface) return paginated_surface->target; } -cairo_status_t -_cairo_paginated_surface_set_size (cairo_surface_t *surface, - int width, - int height) -{ - cairo_paginated_surface_t *paginated_surface; - cairo_status_t status; - - assert (_cairo_surface_is_paginated (surface)); - - paginated_surface = (cairo_paginated_surface_t *) surface; - - paginated_surface->width = width; - paginated_surface->height = height; - - cairo_surface_destroy (paginated_surface->meta); - paginated_surface->meta = cairo_meta_surface_create (paginated_surface->content, - width, height); - status = cairo_surface_status (paginated_surface->meta); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - - return CAIRO_STATUS_SUCCESS; -} - static cairo_status_t _cairo_paginated_surface_finish (void *abstract_surface) { @@ -168,18 +159,11 @@ _cairo_paginated_surface_finish (void *abstract_surface) status = cairo_surface_status (abstract_surface); } - if (status == CAIRO_STATUS_SUCCESS) { - cairo_surface_finish (surface->target); - status = cairo_surface_status (surface->target); - } - - if (status == CAIRO_STATUS_SUCCESS) { - cairo_surface_finish (surface->meta); - status = cairo_surface_status (surface->meta); - } - cairo_surface_destroy (surface->target); + cairo_surface_finish (surface->meta); + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_surface_status (surface->meta); cairo_surface_destroy (surface->meta); return status; @@ -210,13 +194,14 @@ _cairo_paginated_surface_acquire_source_image (void *abstract_surface, void **image_extra) { cairo_paginated_surface_t *surface = abstract_surface; + cairo_bool_t is_bounded; cairo_surface_t *image; cairo_status_t status; cairo_rectangle_int_t extents; - status = _cairo_surface_get_extents (surface->target, &extents); - if (unlikely (status)) - return status; + is_bounded = _cairo_surface_get_extents (surface->target, &extents); + if (! is_bounded) + return CAIRO_INT_STATUS_UNSUPPORTED; image = _cairo_paginated_surface_create_image_surface (surface, extents.width, @@ -248,11 +233,11 @@ _paint_fallback_image (cairo_paginated_surface_t *surface, { double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution; double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution; - cairo_matrix_t matrix; int x, y, width, height; cairo_status_t status; cairo_surface_t *image; cairo_surface_pattern_t pattern; + cairo_clip_t clip; x = rect->x; y = rect->y; @@ -271,15 +256,21 @@ _paint_fallback_image (cairo_paginated_surface_t *surface, goto CLEANUP_IMAGE; _cairo_pattern_init_for_surface (&pattern, image); - cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale); - cairo_pattern_set_matrix (&pattern.base, &matrix); + cairo_matrix_init (&pattern.base.matrix, + x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale); /* the fallback should be rendered at native resolution, so disable * filtering (if possible) to avoid introducing potential artifacts. */ pattern.base.filter = CAIRO_FILTER_NEAREST; + status = _cairo_clip_init_rectangle (&clip, rect); + if (unlikely (status)) + goto CLEANUP_IMAGE; + status = _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, - &pattern.base, NULL); + &pattern.base, &clip); + + _cairo_clip_reset (&clip); _cairo_pattern_fini (&pattern.base); CLEANUP_IMAGE: @@ -295,12 +286,11 @@ _paint_page (cairo_paginated_surface_t *surface) cairo_status_t status; cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback; - if (surface->target->status) + if (unlikely (surface->target->status)) return surface->target->status; - analysis = _cairo_analysis_surface_create (surface->target, - surface->width, surface->height); - if (analysis->status) + analysis = _cairo_analysis_surface_create (surface->target); + if (unlikely (analysis->status)) return _cairo_surface_set_error (surface->target, analysis->status); surface->backend->set_paginated_mode (surface->target, @@ -365,16 +355,19 @@ _paint_page (cairo_paginated_surface_t *surface) } if (has_page_fallback) { - cairo_rectangle_int_t rect; + cairo_rectangle_int_t extents; + cairo_bool_t is_bounded; surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_FALLBACK); - rect.x = 0; - rect.y = 0; - rect.width = surface->width; - rect.height = surface->height; - status = _paint_fallback_image (surface, &rect); + is_bounded = _cairo_surface_get_extents (surface->target, &extents); + if (! is_bounded) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; + } + + status = _paint_fallback_image (surface, &extents); if (unlikely (status)) goto FAIL; } @@ -386,15 +379,6 @@ _paint_page (cairo_paginated_surface_t *surface) surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_FALLBACK); - /* Reset clip region before drawing the fall back images */ - status = _cairo_surface_intersect_clip_path (surface->target, - NULL, - CAIRO_FILL_RULE_WINDING, - CAIRO_GSTATE_TOLERANCE_DEFAULT, - CAIRO_ANTIALIAS_DEFAULT); - if (unlikely (status)) - goto FAIL; - region = _cairo_analysis_surface_get_unsupported (analysis); num_rects = cairo_region_num_rectangles (region); @@ -402,9 +386,7 @@ _paint_page (cairo_paginated_surface_t *surface) cairo_rectangle_int_t rect; cairo_region_get_rectangle (region, i, &rect); - status = _paint_fallback_image (surface, &rect); - if (unlikely (status)) goto FAIL; } @@ -445,7 +427,7 @@ _cairo_paginated_surface_copy_page (void *abstract_surface) surface->page_num++; - /* XXX: It might make sense to add some suport here for calling + /* XXX: It might make sense to add some support here for calling * cairo_surface_copy_page on the target surface. It would be an * optimization for the output, but the interaction with image * fallbacks gets tricky. For now, we just let the target see a @@ -471,20 +453,19 @@ _cairo_paginated_surface_show_page (void *abstract_surface) return status; cairo_surface_show_page (surface->target); - status = cairo_surface_status (surface->target); + status = surface->target->status; if (unlikely (status)) return status; - status = cairo_surface_status (surface->meta); + status = surface->meta->status; if (unlikely (status)) return status; cairo_surface_destroy (surface->meta); - surface->meta = cairo_meta_surface_create (surface->content, - surface->width, - surface->height); - status = cairo_surface_status (surface->meta); + surface->meta = _create_meta_surface_for_target (surface->target, + surface->content); + status = surface->meta->status; if (unlikely (status)) return status; @@ -494,21 +475,7 @@ _cairo_paginated_surface_show_page (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_paginated_surface_intersect_clip_path (void *abstract_surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_paginated_surface_t *surface = abstract_surface; - - return _cairo_surface_intersect_clip_path (surface->meta, - path, fill_rule, - tolerance, antialias); -} - -static cairo_int_status_t +static cairo_bool_t _cairo_paginated_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -530,7 +497,7 @@ static cairo_int_status_t _cairo_paginated_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_paginated_surface_t *surface = abstract_surface; @@ -540,7 +507,7 @@ _cairo_paginated_surface_paint (void *abstract_surface, surface->page_is_blank = FALSE; - return _cairo_surface_paint (surface->meta, op, source, NULL); + return _cairo_surface_paint (surface->meta, op, source, clip); } static cairo_int_status_t @@ -548,11 +515,17 @@ _cairo_paginated_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_paginated_surface_t *surface = abstract_surface; - return _cairo_surface_mask (surface->meta, op, source, mask, NULL); + /* Optimize away erasing of nothing. */ + if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR) + return CAIRO_STATUS_SUCCESS; + + surface->page_is_blank = FALSE; + + return _cairo_surface_mask (surface->meta, op, source, mask, clip); } static cairo_int_status_t @@ -565,7 +538,7 @@ _cairo_paginated_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_paginated_surface_t *surface = abstract_surface; @@ -578,7 +551,8 @@ _cairo_paginated_surface_stroke (void *abstract_surface, return _cairo_surface_stroke (surface->meta, op, source, path, style, ctm, ctm_inverse, - tolerance, antialias, NULL); + tolerance, antialias, + clip); } static cairo_int_status_t @@ -589,7 +563,7 @@ _cairo_paginated_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_paginated_surface_t *surface = abstract_surface; @@ -601,7 +575,8 @@ _cairo_paginated_surface_fill (void *abstract_surface, return _cairo_surface_fill (surface->meta, op, source, path, fill_rule, - tolerance, antialias, NULL); + tolerance, antialias, + clip); } static cairo_bool_t @@ -614,20 +589,19 @@ _cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface) static cairo_int_status_t _cairo_paginated_surface_show_text_glyphs (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const char *utf8, - int utf8_len, - cairo_glyph_t *glyphs, - int num_glyphs, - const cairo_text_cluster_t *clusters, - int num_clusters, - cairo_text_cluster_flags_t cluster_flags, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_paginated_surface_t *surface = abstract_surface; - cairo_int_status_t status; /* Optimize away erasing of nothing. */ if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR) @@ -635,24 +609,13 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface, surface->page_is_blank = FALSE; - /* Since this is a "wrapping" surface, we're calling back into - * _cairo_surface_show_text_glyphs from within a call to the same. - * Since _cairo_surface_show_text_glyphs acquires a mutex, we release - * and re-acquire the mutex around this nested call. - * - * Yes, this is ugly, but we consider it pragmatic as compared to - * adding locking code to all 18 surface-backend-specific - * show_glyphs functions, (which would get less testing and likely - * lead to bugs). - */ - status = _cairo_surface_show_text_glyphs (surface->meta, op, source, - utf8, utf8_len, - glyphs, num_glyphs, - clusters, num_clusters, - cluster_flags, - scaled_font, NULL); - - return status; + return _cairo_surface_show_text_glyphs (surface->meta, op, source, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font, + clip); } static cairo_surface_t * @@ -679,8 +642,6 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = { NULL, /* check_span_renderer */ _cairo_paginated_surface_copy_page, _cairo_paginated_surface_show_page, - NULL, /* set_clip_region */ - _cairo_paginated_surface_intersect_clip_path, _cairo_paginated_surface_get_extents, NULL, /* old_show_glyphs */ _cairo_paginated_surface_get_font_options, @@ -695,7 +656,6 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = { NULL, /* show_glyphs */ _cairo_paginated_surface_snapshot, NULL, /* is_similar */ - NULL, /* reset */ NULL, /* fill_stroke */ NULL, /* create_solid_pattern_surface */ NULL, /* can_repaint_solid_pattern_surface */ diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c index 1fadd84d..1a3cdf06 100644 --- a/src/cairo-path-bounds.c +++ b/src/cairo-path-bounds.c @@ -173,7 +173,7 @@ _cairo_path_bounder_close_path (void *closure) * the control points of the curves, not the flattened path). */ void -_cairo_path_fixed_approximate_clip_extents (cairo_path_fixed_t *path, +_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path, cairo_rectangle_int_t *extents) { cairo_path_bounder_t bounder; @@ -203,7 +203,7 @@ _cairo_path_fixed_approximate_clip_extents (cairo_path_fixed_t *path, * Bezier, but we continue to ignore winding. */ void -_cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path, +_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path, cairo_rectangle_int_t *extents) { cairo_path_bounder_t bounder; @@ -229,9 +229,37 @@ _cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path, _cairo_path_bounder_fini (&bounder); } +void +_cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_rectangle_int_t *extents) +{ + cairo_path_bounder_t bounder; + cairo_status_t status; + + _cairo_path_bounder_init (&bounder); + + status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD, + _cairo_path_bounder_move_to, + _cairo_path_bounder_line_to, + _cairo_path_bounder_close_path, + &bounder, tolerance); + assert (status == CAIRO_STATUS_SUCCESS); + + if (bounder.has_point) { + _cairo_box_round_to_rectangle (&bounder.extents, extents); + } else { + extents->x = extents->y = 0; + extents->width = extents->height = 0; + } + + _cairo_path_bounder_fini (&bounder); +} + /* Adjusts the fill extents (above) by the device-space pen. */ void -_cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path, +_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path, cairo_stroke_style_t *style, const cairo_matrix_t *ctm, cairo_rectangle_int_t *extents) @@ -268,8 +296,37 @@ _cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path, _cairo_path_bounder_fini (&bounder); } +cairo_status_t +_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path, + cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_rectangle_int_t *extents) +{ + cairo_traps_t traps; + cairo_box_t bbox; + cairo_status_t status; + + _cairo_traps_init (&traps); + + status = _cairo_path_fixed_stroke_to_traps (path, + stroke_style, + ctm, + ctm_inverse, + tolerance, + &traps); + + _cairo_traps_extents (&traps, &bbox); + _cairo_traps_fini (&traps); + + _cairo_box_round_to_rectangle (&bbox, extents); + + return status; +} + void -_cairo_path_fixed_bounds (cairo_path_fixed_t *path, +_cairo_path_fixed_bounds (const cairo_path_fixed_t *path, double *x1, double *y1, double *x2, double *y2) { diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index 9569c9e9..123da96e 100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -125,12 +125,12 @@ _cairo_filler_close_path (void *closure) } static cairo_int_status_t -_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path, +_cairo_path_fixed_fill_rectangle (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, cairo_traps_t *traps); cairo_status_t -_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, +_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_traps_t *traps) @@ -138,6 +138,8 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_filler_t filler; + traps->maybe_region = path->maybe_fill_region; + /* Before we do anything else, we use a special-case filler for * a device-axis aligned rectangle if possible. */ status = _cairo_path_fixed_fill_rectangle (path, fill_rule, traps); @@ -181,12 +183,15 @@ BAIL: * this function will return %CAIRO_INT_STATUS_UNSUPPORTED. */ static cairo_int_status_t -_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path, +_cairo_path_fixed_fill_rectangle (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, cairo_traps_t *traps) { cairo_box_t box; + if (! path->is_rectilinear) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (_cairo_path_fixed_is_box (path, &box)) { if (box.p1.x > box.p2.x) { cairo_fixed_t t; diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h index 6bd09f76..1ef7cdda 100644 --- a/src/cairo-path-fixed-private.h +++ b/src/cairo-path-fixed-private.h @@ -81,12 +81,26 @@ struct _cairo_path_fixed { cairo_point_t current_point; unsigned int has_current_point : 1; unsigned int has_curve_to : 1; - unsigned int is_box : 1; - unsigned int is_region : 1; + unsigned int is_rectilinear : 1; + unsigned int maybe_fill_region : 1; + unsigned int is_empty_fill : 1; cairo_path_buf_fixed_t buf; }; + +cairo_private void +_cairo_path_fixed_translate (cairo_path_fixed_t *path, + cairo_fixed_t offx, + cairo_fixed_t offy); + +cairo_private cairo_status_t +_cairo_path_fixed_append (cairo_path_fixed_t *path, + const cairo_path_fixed_t *other, + cairo_direction_t dir, + cairo_fixed_t tx, + cairo_fixed_t ty); + cairo_private unsigned long _cairo_path_fixed_hash (const cairo_path_fixed_t *path); @@ -98,14 +112,14 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a, const cairo_path_fixed_t *b); typedef struct _cairo_path_fixed_iter { - cairo_path_buf_t *buf; + const cairo_path_buf_t *buf; unsigned int n_op; unsigned int n_point; } cairo_path_fixed_iter_t; cairo_private void _cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter, - cairo_path_fixed_t *path); + const cairo_path_fixed_t *path); cairo_private cairo_bool_t _cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter, @@ -115,13 +129,19 @@ cairo_private cairo_bool_t _cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter); static inline cairo_bool_t -_cairo_path_fixed_is_region (cairo_path_fixed_t *path) +_cairo_path_fixed_fill_is_empty (const cairo_path_fixed_t *path) +{ + return path->is_empty_fill; +} + +static inline cairo_bool_t +_cairo_path_fixed_maybe_fill_region (const cairo_path_fixed_t *path) { #if WATCH_PATH - fprintf (stderr, "_cairo_path_fixed_is_region () = %s\n", - path->is_region ? "true" : "false"); + fprintf (stderr, "_cairo_path_fixed_maybe_fill_region () = %s\n", + path->maybe_fill_region ? "true" : "false"); #endif - return path->is_region; + return path->maybe_fill_region; } #endif /* CAIRO_PATH_FIXED_PRIVATE_H */ diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index 0a550399..9819353b 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -96,25 +96,32 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path) path->last_move_point = path->current_point; path->has_current_point = FALSE; path->has_curve_to = FALSE; - path->is_region = TRUE; - path->is_box = TRUE; + path->is_rectilinear = TRUE; + path->maybe_fill_region = TRUE; + path->is_empty_fill = TRUE; } cairo_status_t _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, - cairo_path_fixed_t *other) + const cairo_path_fixed_t *other) { cairo_path_buf_t *buf, *other_buf; unsigned int num_points, num_ops, buf_size; - _cairo_path_fixed_init (path); + VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t))); + + cairo_list_init (&path->buf.base.link); + + path->buf.base.op = path->buf.op; + path->buf.base.points = path->buf.points; path->current_point = other->current_point; - path->has_current_point = other->has_current_point; path->last_move_point = other->last_move_point; + path->has_current_point = other->has_current_point; path->has_curve_to = other->has_curve_to; - path->is_box = other->is_box; - path->is_region = other->is_region; + path->is_rectilinear = other->is_rectilinear; + path->maybe_fill_region = other->maybe_fill_region; + path->is_empty_fill = other->is_empty_fill; path->buf.base.num_ops = other->buf.base.num_ops; path->buf.base.num_points = other->buf.base.num_points; @@ -214,9 +221,10 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a, return TRUE; /* use the flags to quickly differentiate based on contents */ - if (a->has_curve_to != b->has_curve_to || - a->is_region != b->is_region || - a->is_box != b->is_box) + if (a->is_empty_fill != b->is_empty_fill || + a->has_curve_to != b->has_curve_to || + a->maybe_fill_region != b->maybe_fill_region || + a->is_rectilinear != b->is_rectilinear) { return FALSE; } @@ -378,15 +386,16 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path, if (unlikely (status)) return status; - if (path->has_current_point && path->is_box) { + if (path->has_current_point && path->is_rectilinear) { /* a move-to is first an implicit close */ - path->is_box = path->current_point.x == path->last_move_point.x || - path->current_point.y == path->last_move_point.y; - path->is_region &= path->is_box; + path->is_rectilinear = path->current_point.x == path->last_move_point.x || + path->current_point.y == path->last_move_point.y; + path->maybe_fill_region &= path->is_rectilinear; } - if (path->is_region) { - path->is_region = _cairo_fixed_is_integer (x) && - _cairo_fixed_is_integer (y); + if (path->maybe_fill_region) { + path->maybe_fill_region = + _cairo_fixed_is_integer (path->last_move_point.x) && + _cairo_fixed_is_integer (path->last_move_point.y); } } @@ -437,14 +446,18 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path, status = _cairo_path_fixed_move_to (path, point.x, point.y); } else { status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1); - if (path->is_box) { - path->is_box = path->current_point.x == x || - path->current_point.y == y; - path->is_region &= path->is_box; + if (path->is_rectilinear) { + path->is_rectilinear = path->current_point.x == x || + path->current_point.y == y; + path->maybe_fill_region &= path->is_rectilinear; + } + if (path->maybe_fill_region) { + path->maybe_fill_region = _cairo_fixed_is_integer (x) && + _cairo_fixed_is_integer (y); } - if (path->is_region) { - path->is_region = _cairo_fixed_is_integer (x) && - _cairo_fixed_is_integer (y); + if (path->is_empty_fill) { + path->is_empty_fill = path->current_point.x == x && + path->current_point.y == y; } } @@ -495,9 +508,10 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path, path->current_point = point[2]; path->has_current_point = TRUE; + path->is_empty_fill = FALSE; path->has_curve_to = TRUE; - path->is_box = FALSE; - path->is_region = FALSE; + path->is_rectilinear = FALSE; + path->maybe_fill_region = FALSE; return CAIRO_STATUS_SUCCESS; } @@ -732,49 +746,77 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path, return CAIRO_STATUS_SUCCESS; } +typedef struct _cairo_path_fixed_append_closure { + cairo_point_t offset; + cairo_path_fixed_t *path; +} cairo_path_fixed_append_closure_t; + static cairo_status_t -_append_move_to (void *closure, +_append_move_to (void *abstract_closure, const cairo_point_t *point) { - return _cairo_path_fixed_move_to (closure, point->x, point->y); + cairo_path_fixed_append_closure_t *closure = abstract_closure; + + return _cairo_path_fixed_move_to (closure->path, + point->x + closure->offset.x, + point->y + closure->offset.y); } static cairo_status_t -_append_line_to (void *closure, +_append_line_to (void *abstract_closure, const cairo_point_t *point) { - return _cairo_path_fixed_line_to (closure, point->x, point->y); + cairo_path_fixed_append_closure_t *closure = abstract_closure; + + return _cairo_path_fixed_line_to (closure->path, + point->x + closure->offset.x, + point->y + closure->offset.y); } static cairo_status_t -_append_curve_to (void *closure, +_append_curve_to (void *abstract_closure, const cairo_point_t *p0, const cairo_point_t *p1, const cairo_point_t *p2) { - return _cairo_path_fixed_curve_to (closure, - p0->x, p0->y, - p1->x, p1->y, - p2->x, p2->y); + cairo_path_fixed_append_closure_t *closure = abstract_closure; + + return _cairo_path_fixed_curve_to (closure->path, + p0->x + closure->offset.x, + p0->y + closure->offset.y, + p1->x + closure->offset.x, + p1->y + closure->offset.y, + p2->x + closure->offset.x, + p2->y + closure->offset.y); } static cairo_status_t -_append_close_path (void *closure) +_append_close_path (void *abstract_closure) { - return _cairo_path_fixed_close_path (closure); + cairo_path_fixed_append_closure_t *closure = abstract_closure; + + return _cairo_path_fixed_close_path (closure->path); } cairo_status_t -_cairo_path_fixed_append (cairo_path_fixed_t *path, - const cairo_path_fixed_t *other, - cairo_direction_t dir) +_cairo_path_fixed_append (cairo_path_fixed_t *path, + const cairo_path_fixed_t *other, + cairo_direction_t dir, + cairo_fixed_t tx, + cairo_fixed_t ty) { + cairo_path_fixed_append_closure_t closure; + + closure.path = path; + closure.offset.x = tx; + closure.offset.y = ty; + return _cairo_path_fixed_interpret (other, dir, _append_move_to, _append_line_to, _append_curve_to, _append_close_path, - path); + &closure); } static void @@ -787,6 +829,13 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path, cairo_path_buf_t *buf; unsigned int i; + if (path->maybe_fill_region) { + path->maybe_fill_region = _cairo_fixed_is_integer (offx) && + _cairo_fixed_is_integer (offy) && + _cairo_fixed_is_integer (scalex) && + _cairo_fixed_is_integer (scaley); + } + cairo_path_foreach_buf_start (buf, path) { for (i = 0; i < buf->num_points; i++) { if (scalex != CAIRO_FIXED_ONE) @@ -800,6 +849,36 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path, } cairo_path_foreach_buf_end (buf, path); } +void +_cairo_path_fixed_translate (cairo_path_fixed_t *path, + cairo_fixed_t offx, + cairo_fixed_t offy) +{ + cairo_path_buf_t *buf; + unsigned int i; + + if (offx == 0 && offy == 0) + return; + + if (path->maybe_fill_region && + ! (_cairo_fixed_is_integer (offx) && _cairo_fixed_is_integer (offy))) + { + path->maybe_fill_region = FALSE; + } + + path->last_move_point.x += offx; + path->last_move_point.y += offx; + path->current_point.x += offx; + path->current_point.y += offx; + + cairo_path_foreach_buf_start (buf, path) { + for (i = 0; i < buf->num_points; i++) { + buf->points[i].x += offx; + buf->points[i].y += offy; + } + } cairo_path_foreach_buf_end (buf, path); +} + /** * _cairo_path_fixed_transform: * @path: a #cairo_path_fixed_t to be transformed @@ -811,12 +890,14 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path, **/ void _cairo_path_fixed_transform (cairo_path_fixed_t *path, - cairo_matrix_t *matrix) + const cairo_matrix_t *matrix) { cairo_path_buf_t *buf; unsigned int i; double dx, dy; + /* XXX current_point, last_move_to */ + if (matrix->yx == 0.0 && matrix->xy == 0.0) { /* Fast path for the common case of scale+transform */ _cairo_path_fixed_offset_and_scale (path, @@ -827,6 +908,7 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path, return; } + path->maybe_fill_region = FALSE; cairo_path_foreach_buf_start (buf, path) { for (i = 0; i < buf->num_points; i++) { dx = _cairo_fixed_to_double (buf->points[i].x); @@ -841,20 +923,22 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path, } cairo_bool_t -_cairo_path_fixed_is_equal (cairo_path_fixed_t *path, - cairo_path_fixed_t *other) +_cairo_path_fixed_is_equal (const cairo_path_fixed_t *path, + const cairo_path_fixed_t *other) { - cairo_path_buf_t *path_buf, *other_buf; + const cairo_path_buf_t *path_buf, *other_buf; if (path->current_point.x != other->current_point.x || path->current_point.y != other->current_point.y || path->has_current_point != other->has_current_point || path->has_curve_to != other->has_curve_to || - path->is_box != other->is_box || - path->is_region != other->is_region || + path->is_rectilinear != other->is_rectilinear || + path->maybe_fill_region != other->maybe_fill_region || path->last_move_point.x != other->last_move_point.x || path->last_move_point.y != other->last_move_point.y) + { return FALSE; + } other_buf = cairo_path_head (other); cairo_path_foreach_buf_start (path_buf, path) { @@ -970,25 +1054,16 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path, &flattener); } -cairo_bool_t -_cairo_path_fixed_is_empty (cairo_path_fixed_t *path) -{ - if (cairo_path_head (path)->num_ops == 0) - return TRUE; - - return FALSE; -} - /* * Check whether the given path contains a single rectangle. */ cairo_bool_t -_cairo_path_fixed_is_box (cairo_path_fixed_t *path, +_cairo_path_fixed_is_box (const cairo_path_fixed_t *path, cairo_box_t *box) { - cairo_path_buf_t *buf = cairo_path_head (path); + const cairo_path_buf_t *buf = cairo_path_head (path); - if (! path->is_box) + if (! path->is_rectilinear) return FALSE; /* Do we have the right number of ops? */ @@ -1058,12 +1133,12 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path, * </programlisting></informalexample> */ cairo_bool_t -_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path, +_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path, cairo_box_t *box) { - cairo_path_buf_t *buf; + const cairo_path_buf_t *buf; - if (!_cairo_path_fixed_is_box (path, box)) + if (! _cairo_path_fixed_is_box (path, box)) return FALSE; buf = cairo_path_head (path); @@ -1075,7 +1150,7 @@ _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path, void _cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter, - cairo_path_fixed_t *path) + const cairo_path_fixed_t *path) { iter->buf = cairo_path_head (path); iter->n_op = 0; diff --git a/src/cairo-path-in-fill.c b/src/cairo-path-in-fill.c index 24f43ca5..2fa86505 100644 --- a/src/cairo-path-in-fill.c +++ b/src/cairo-path-in-fill.c @@ -38,10 +38,10 @@ typedef struct cairo_in_fill { double tolerance; + cairo_bool_t on_edge; int winding; cairo_fixed_t x, y; - cairo_bool_t on_edge; cairo_bool_t has_current_point; cairo_point_t current_point; @@ -54,12 +54,12 @@ _cairo_in_fill_init (cairo_in_fill_t *in_fill, double x, double y) { + in_fill->on_edge = FALSE; in_fill->winding = 0; in_fill->tolerance = tolerance; in_fill->x = _cairo_fixed_from_double (x); in_fill->y = _cairo_fixed_from_double (y); - in_fill->on_edge = FALSE; in_fill->has_current_point = FALSE; in_fill->current_point.x = 0; @@ -142,7 +142,7 @@ _cairo_in_fill_add_edge (cairo_in_fill_t *in_fill, return; if ((p1->x <= in_fill->x && p2->x <= in_fill->x) || - edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) <= 0) + edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) < 0) { in_fill->winding += dir; } @@ -243,16 +243,19 @@ _cairo_in_fill_close_path (void *closure) return CAIRO_STATUS_SUCCESS; } -void -_cairo_path_fixed_in_fill (cairo_path_fixed_t *path, +cairo_bool_t +_cairo_path_fixed_in_fill (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, double x, - double y, - cairo_bool_t *is_inside) + double y) { cairo_in_fill_t in_fill; cairo_status_t status; + cairo_bool_t is_inside; + + if (path->is_empty_fill) + return FALSE; _cairo_in_fill_init (&in_fill, tolerance, x, y); @@ -268,19 +271,21 @@ _cairo_path_fixed_in_fill (cairo_path_fixed_t *path, _cairo_in_fill_close_path (&in_fill); if (in_fill.on_edge) { - *is_inside = TRUE; + is_inside = TRUE; } else switch (fill_rule) { case CAIRO_FILL_RULE_EVEN_ODD: - *is_inside = in_fill.winding & 1; + is_inside = in_fill.winding & 1; break; case CAIRO_FILL_RULE_WINDING: - *is_inside = in_fill.winding != 0; + is_inside = in_fill.winding != 0; break; default: ASSERT_NOT_REACHED; - *is_inside = FALSE; + is_inside = FALSE; break; } _cairo_in_fill_fini (&in_fill); + + return is_inside; } diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index 79bf09b0..4fa4ce5a 100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -1140,13 +1140,13 @@ _cairo_stroker_close_path (void *closure) } static cairo_int_status_t -_cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path, +_cairo_path_fixed_stroke_rectilinear (const cairo_path_fixed_t *path, cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, cairo_traps_t *traps); cairo_status_t -_cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path, +_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path, cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, @@ -1737,7 +1737,7 @@ _cairo_rectilinear_stroker_close_path (void *closure) } static cairo_int_status_t -_cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path, +_cairo_path_fixed_stroke_rectilinear (const cairo_path_fixed_t *path, cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, cairo_traps_t *traps) @@ -1755,7 +1755,7 @@ _cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path, * UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any * non-rectilinear line_to is encountered. */ - if (path->has_curve_to) + if (! path->is_rectilinear) return CAIRO_INT_STATUS_UNSUPPORTED; if (stroke_style->line_join != CAIRO_LINE_JOIN_MITER) return CAIRO_INT_STATUS_UNSUPPORTED; diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 9fe94ad4..6eabaa40 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -1686,10 +1686,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt pattern, dst)) { - status = _cairo_surface_reset (solid_surface_cache.cache[i].surface); - if (unlikely (status)) - goto UNLOCK; - goto DONE; } @@ -1698,10 +1694,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt pattern, dst)) { - status = _cairo_surface_reset (solid_surface_cache.cache[i].surface); - if (unlikely (status)) - goto UNLOCK; - goto DONE; } } @@ -1717,11 +1709,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt dst)) { /* Reuse the surface instead of evicting */ - - status = _cairo_surface_reset (surface); - if (unlikely (status)) - goto EVICT; - status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern); if (unlikely (status)) goto EVICT; @@ -1738,14 +1725,21 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt if (surface == NULL) { /* Not cached, need to create new */ surface = _cairo_surface_create_solid_pattern_surface (dst, pattern); - if (surface->status) { + if (surface == NULL) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto UNLOCK; + } + if (unlikely (surface->status)) { status = surface->status; goto UNLOCK; } - if (! _cairo_surface_is_similar (surface, dst, pattern->content)) { - /* in the rare event of a substitute surface being returned (e.g. - * malloc failure) don't cache the fallback surface */ + if (unlikely (! _cairo_surface_is_similar (surface, + dst, pattern->content))) + { + /* In the rare event of a substitute surface being returned, + * don't cache the fallback. + */ *out = surface; goto NOCACHE; } @@ -1953,6 +1947,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat double pad; cairo_bool_t is_identity; cairo_bool_t is_empty; + cairo_bool_t is_bounded; cairo_int_status_t status; surface = cairo_surface_reference (pattern->surface); @@ -2010,9 +2005,8 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat cairo_surface_t *src; int w, h; - status = _cairo_surface_get_extents (surface, &extents); - if (unlikely (status)) - goto BAIL; + is_bounded = _cairo_surface_get_extents (surface, &extents); + assert (is_bounded); status = _cairo_surface_clone_similar (dst, surface, content, extents.x, extents.y, @@ -2045,8 +2039,13 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat } cairo_surface_destroy (surface); - surface = cairo_surface_create_similar (dst, dst->content, w, h); - if (surface->status) { + surface = _cairo_surface_create_similar_solid (dst, + dst->content, w, h, + CAIRO_COLOR_TRANSPARENT, + FALSE); + if (surface == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (unlikely (surface->status)) { cairo_surface_destroy (src); return surface->status; } @@ -2092,10 +2091,6 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat attr->extend = CAIRO_EXTEND_REPEAT; } - status = _cairo_surface_get_extents (surface, &extents); - if (unlikely (status)) - goto BAIL; - /* We first transform the rectangle to the coordinate space of the * source surface so that we only need to clone that portion of the * surface that will be read. @@ -2118,36 +2113,38 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat sampled_area.x += tx; sampled_area.y += ty; - if (attr->extend != CAIRO_EXTEND_REPEAT) { - /* Never acquire a larger area than the source itself */ - is_empty = _cairo_rectangle_intersect (&extents, &sampled_area); - } else { - int trim = 0; + if ( _cairo_surface_get_extents (surface, &extents)) { + if (attr->extend != CAIRO_EXTEND_REPEAT) { + /* Never acquire a larger area than the source itself */ + is_empty = _cairo_rectangle_intersect (&extents, &sampled_area); + } else { + int trim = 0; - if (sampled_area.x >= extents.x && - sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width) - { - /* source is horizontally contained within extents, trim */ - extents.x = sampled_area.x; - extents.width = sampled_area.width; - trim |= 0x1; - } + if (sampled_area.x >= extents.x && + sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width) + { + /* source is horizontally contained within extents, trim */ + extents.x = sampled_area.x; + extents.width = sampled_area.width; + trim |= 0x1; + } - if (sampled_area.y >= extents.y && - sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height) - { - /* source is vertically contained within extents, trim */ - extents.y = sampled_area.y; - extents.height = sampled_area.height; - trim |= 0x2; - } + if (sampled_area.y >= extents.y && + sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height) + { + /* source is vertically contained within extents, trim */ + extents.y = sampled_area.y; + extents.height = sampled_area.height; + trim |= 0x2; + } - if (trim == 0x3) { - /* source is wholly contained within extents, drop the REPEAT */ - attr->extend = CAIRO_EXTEND_NONE; - } + if (trim == 0x3) { + /* source is wholly contained within extents, drop the REPEAT */ + attr->extend = CAIRO_EXTEND_NONE; + } - is_empty = extents.width == 0 || extents.height == 0; + is_empty = extents.width == 0 || extents.height == 0; + } } /* XXX can we use is_empty? */ @@ -2237,7 +2234,7 @@ _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern, { cairo_status_t status; - if (pattern->status) { + if (unlikely (pattern->status)) { *surface_out = NULL; return pattern->status; } @@ -2371,9 +2368,9 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src, cairo_int_status_t status; cairo_pattern_union_t src_tmp; - if (src->status) + if (unlikely (src->status)) return src->status; - if (mask && mask->status) + if (unlikely (mask != NULL && mask->status)) return mask->status; /* If src and mask are both solid, then the mask alpha can be @@ -2441,7 +2438,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src, * "infinite" extents, though it would be possible to optimize these * with a little more work. **/ -cairo_status_t +void _cairo_pattern_get_extents (const cairo_pattern_t *pattern, cairo_rectangle_int_t *extents) { @@ -2457,11 +2454,8 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, double x1, y1, x2, y2; double pad; - status = _cairo_surface_get_extents (surface, &surface_extents); - if (status == CAIRO_INT_STATUS_UNSUPPORTED) + if (! _cairo_surface_get_extents (surface, &surface_extents)) goto UNBOUNDED; - if (unlikely (status)) - return status; /* The filter can effectively enlarge the extents of the * pattern, so extend as necessary. @@ -2497,8 +2491,7 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, extents->x = x1; extents->width = x2 - x1; extents->y = y1; extents->height = y2 - y1; - - return CAIRO_STATUS_SUCCESS; + return; } /* XXX: We could optimize gradients with pattern->extend of NONE @@ -2508,12 +2501,7 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, UNBOUNDED: /* unbounded patterns -> 'infinite' extents */ - extents->x = CAIRO_RECT_INT_MIN; - extents->y = CAIRO_RECT_INT_MIN; - extents->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; - extents->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; - - return CAIRO_STATUS_SUCCESS; + _cairo_unbounded_rectangle_init (extents); } @@ -2749,6 +2737,9 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b) if (a->status || b->status) return FALSE; + if (a == b) + return TRUE; + if (a->type != b->type) return FALSE; diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h index 2e7d2445..5c28f70c 100644 --- a/src/cairo-pdf-surface-private.h +++ b/src/cairo-pdf-surface-private.h @@ -45,6 +45,7 @@ #include "cairo-pdf.h" #include "cairo-surface-private.h" +#include "cairo-surface-clipper-private.h" #include "cairo-pdf-operators-private.h" #include "cairo-path-fixed-private.h" @@ -174,6 +175,8 @@ struct _cairo_pdf_surface { cairo_bool_t is_knockout; } group_stream; + cairo_surface_clipper_t clipper; + cairo_pdf_operators_t pdf_operators; cairo_paginated_mode_t paginated_mode; cairo_bool_t select_pattern_gstate_saved; diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 0e5c8403..8cd46723 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -50,6 +50,7 @@ #include "cairo-output-stream-private.h" #include "cairo-paginated-private.h" #include "cairo-scaled-font-subsets-private.h" +#include "cairo-surface-clipper-private.h" #include "cairo-type3-glyph-surface-private.h" #include <time.h> @@ -243,6 +244,34 @@ _cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface, &surface->cairo_to_pdf); } +static cairo_status_t +_cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_pdf_surface_t *surface = cairo_container_of (clipper, + cairo_pdf_surface_t, + clipper); + cairo_int_status_t status; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + if (path == NULL) { + _cairo_output_stream_printf (surface->output, "Q q\n"); + + surface->current_pattern_is_solid_color = FALSE; + _cairo_pdf_operators_reset (&surface->pdf_operators); + + return CAIRO_STATUS_SUCCESS; + } + + return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule); +} + static cairo_surface_t * _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, double width, @@ -313,6 +342,9 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, surface->current_operator = CAIRO_OPERATOR_OVER; surface->header_emitted = FALSE; + _cairo_surface_clipper_init (&surface->clipper, + _cairo_pdf_surface_clipper_intersect_clip_path); + _cairo_pdf_operators_init (&surface->pdf_operators, surface->output, &surface->cairo_to_pdf, @@ -325,7 +357,6 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, surface->paginated_surface = _cairo_paginated_surface_create ( &surface->base, CAIRO_CONTENT_COLOR_ALPHA, - width, height, &cairo_pdf_surface_paginated_backend); status = surface->paginated_surface->status; @@ -572,11 +603,6 @@ cairo_pdf_surface_set_size (cairo_surface_t *surface, _cairo_pdf_surface_set_size_internal (pdf_surface, width_in_points, height_in_points); - status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface, - width_in_points, - height_in_points); - if (unlikely (status)) - status = _cairo_surface_set_error (surface, status); } static void @@ -981,9 +1007,9 @@ _get_jpx_image_info (cairo_surface_t *source, static cairo_int_status_t _get_jpeg_image_info (cairo_surface_t *source, - cairo_image_info_t *info, - const unsigned char **mime_data, - unsigned int *mime_data_length) + cairo_image_info_t *info, + const unsigned char **mime_data, + unsigned int *mime_data_length) { cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, mime_data, mime_data_length); @@ -998,52 +1024,48 @@ _get_source_surface_size (cairo_surface_t *source, int *width, int *height) { - cairo_image_surface_t *image; - void *image_extra; cairo_status_t status; + cairo_rectangle_int_t extents; cairo_image_info_t info; const unsigned char *mime_data; unsigned int mime_data_length; if (_cairo_surface_is_meta (source)) { - cairo_rectangle_int_t extents; + cairo_meta_surface_t *meta_surface = (cairo_meta_surface_t *) source; + cairo_box_t bbox; - status = _cairo_surface_get_extents (source, &extents); + status = _cairo_meta_surface_get_bbox (meta_surface, &bbox, NULL); if (unlikely (status)) return status; + _cairo_box_round_to_rectangle (&bbox, &extents); + *width = extents.width; *height = extents.height; - - return status; + return CAIRO_STATUS_SUCCESS; } status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length); - if (status == CAIRO_STATUS_SUCCESS) { + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { *width = info.width; *height = info.height; - } else if (_cairo_status_is_error (status)) { return status; } status = _get_jpeg_image_info (source, &info, &mime_data, &mime_data_length); - if (status == CAIRO_STATUS_SUCCESS) { + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { *width = info.width; *height = info.height; - } else if (_cairo_status_is_error (status)) { return status; } - status = _cairo_surface_acquire_source_image (source, &image, &image_extra); - if (unlikely (status)) - return status; - - *width = image->width; - *height = image->height; + if (! _cairo_surface_get_extents (source, &extents)) + return CAIRO_INT_STATUS_UNSUPPORTED; - _cairo_surface_release_source_image (source, image, image_extra); + *width = extents.width; + *height = extents.height; - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -1123,7 +1145,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface, static cairo_status_t _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface, const cairo_pattern_t *pattern, - cairo_rectangle_int_t *extents, + cairo_clip_t *clip, cairo_pdf_resource_t *pattern_res, cairo_pdf_resource_t *gstate_res) { @@ -1182,8 +1204,8 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface, pdf_pattern.width = surface->width; pdf_pattern.height = surface->height; - if (extents) { - pdf_pattern.extents = *extents; + if (clip != NULL) { + pdf_pattern.extents = clip->path->extents; } else { pdf_pattern.extents.x = 0; pdf_pattern.extents.y = 0; @@ -1540,15 +1562,6 @@ _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface) return _cairo_output_stream_get_status (surface->output); } -static cairo_surface_t * -_cairo_pdf_surface_create_similar (void *abstract_surface, - cairo_content_t content, - int width, - int height) -{ - return cairo_meta_surface_create (content, width, height); -} - static void _cairo_pdf_source_surface_entry_pluck (void *entry, void *closure) { @@ -1653,6 +1666,8 @@ _cairo_pdf_surface_finish (void *abstract_surface) surface->font_subsets = NULL; } + _cairo_surface_clipper_reset (&surface->clipper); + return status; } @@ -2090,7 +2105,7 @@ _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface, return status; pad_image = &image->base; - if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) { + if (pattern->base.extend == CAIRO_EXTEND_PAD) { cairo_box_t box; cairo_rectangle_int_t rect; cairo_surface_pattern_t pad_pattern; @@ -2121,7 +2136,8 @@ _cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t *surface, 0, 0, 0, 0, rect.width, - rect.height); + rect.height, + NULL); _cairo_pattern_fini (&pad_pattern.base); if (unlikely (status)) goto BAIL; @@ -2173,19 +2189,18 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface, { double old_width, old_height; cairo_paginated_mode_t old_paginated_mode; - cairo_clip_t *old_clip; cairo_rectangle_int_t meta_extents; + cairo_bool_t is_bounded; cairo_status_t status; int alpha = 0; - status = _cairo_surface_get_extents (meta_surface, &meta_extents); - if (unlikely (status)) - return status; + is_bounded = _cairo_surface_get_extents (meta_surface, &meta_extents); + assert (is_bounded); old_width = surface->width; old_height = surface->height; old_paginated_mode = surface->paginated_mode; - old_clip = _cairo_surface_get_clip (&surface->base); + _cairo_pdf_surface_set_size_internal (surface, meta_extents.width, meta_extents.height); @@ -2217,10 +2232,6 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface, if (unlikely (status)) return status; - status = _cairo_surface_set_clip (&surface->base, old_clip); - if (unlikely (status)) - return status; - status = _cairo_pdf_surface_close_content_stream (surface); _cairo_pdf_surface_set_size_internal (surface, @@ -2264,7 +2275,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, int bbox_x, bbox_y; char draw_surface[200]; - if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD && + if (pattern->base.extend == CAIRO_EXTEND_PAD && ! _cairo_surface_is_meta (pattern->surface)) { status = _cairo_pdf_surface_emit_padded_image_surface (surface, @@ -3249,7 +3260,7 @@ _cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface, return CAIRO_STATUS_SUCCESS; status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -3405,7 +3416,7 @@ _cairo_pdf_surface_show_page (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t +static cairo_bool_t _cairo_pdf_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -3421,32 +3432,7 @@ _cairo_pdf_surface_get_extents (void *abstract_surface, rectangle->width = (int) ceil (surface->width); rectangle->height = (int) ceil (surface->height); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_pdf_surface_intersect_clip_path (void *abstract_surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_pdf_surface_t *surface = abstract_surface; - cairo_int_status_t status; - - if (path == NULL) { - status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (unlikely (status)) - return status; - - _cairo_output_stream_printf (surface->output, "Q q\n"); - surface->current_pattern_is_solid_color = FALSE; - _cairo_pdf_operators_reset (&surface->pdf_operators); - - return CAIRO_STATUS_SUCCESS; - } - - return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule); + return TRUE; } static void @@ -5227,7 +5213,7 @@ static cairo_int_status_t _cairo_pdf_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; cairo_status_t status; @@ -5244,17 +5230,21 @@ _cairo_pdf_surface_paint (void *abstract_surface, assert (_cairo_pdf_surface_operation_supported (surface, op, source)); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip, &pattern_res, &gstate_res); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) return CAIRO_STATUS_SUCCESS; if (unlikely (status)) return status; status = _cairo_pdf_surface_select_operator (surface, op); - if (status) + if (unlikely (status)) return status; if (gstate_res.id != 0) { @@ -5292,7 +5282,8 @@ _cairo_pdf_surface_paint (void *abstract_surface, gstate_res.id, group->group_res.id); } else { - status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE); + status = _cairo_pdf_surface_select_pattern (surface, source, + pattern_res, FALSE); if (unlikely (status)) return status; @@ -5313,7 +5304,7 @@ _cairo_pdf_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_smask_group_t *group; @@ -5341,6 +5332,10 @@ _cairo_pdf_surface_mask (void *abstract_surface, assert (_cairo_pdf_surface_operation_supported (surface, op, source)); assert (_cairo_pdf_surface_operation_supported (surface, op, mask)); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + group = _cairo_pdf_surface_create_smask_group (surface); if (unlikely (group == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -5381,7 +5376,7 @@ _cairo_pdf_surface_mask (void *abstract_surface, return status; status = _cairo_pdf_surface_select_operator (surface, op); - if (status) + if (unlikely (status)) return status; _cairo_output_stream_printf (surface->output, @@ -5402,7 +5397,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; cairo_status_t status; @@ -5414,17 +5409,21 @@ _cairo_pdf_surface_stroke (void *abstract_surface, assert (_cairo_pdf_surface_operation_supported (surface, op, source)); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip, &pattern_res, &gstate_res); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) return CAIRO_STATUS_SUCCESS; if (unlikely (status)) return status; status = _cairo_pdf_surface_select_operator (surface, op); - if (status) + if (unlikely (status)) return status; if (gstate_res.id != 0) { @@ -5499,7 +5498,7 @@ _cairo_pdf_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; cairo_status_t status; @@ -5516,17 +5515,21 @@ _cairo_pdf_surface_fill (void *abstract_surface, assert (_cairo_pdf_surface_operation_supported (surface, op, source)); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip, &pattern_res, &gstate_res); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) return CAIRO_STATUS_SUCCESS; if (unlikely (status)) return status; status = _cairo_pdf_surface_select_operator (surface, op); - if (status) + if (unlikely (status)) return status; if (gstate_res.id != 0) { @@ -5604,7 +5607,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; cairo_status_t status; @@ -5632,14 +5635,18 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, if (fill_op != stroke_op) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + status = _cairo_pdf_surface_select_operator (surface, fill_op); - if (status) + if (unlikely (status)) return status; fill_pattern_res.id = 0; gstate_res.id = 0; status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source, - extents, + clip, &fill_pattern_res, &gstate_res); if (unlikely (status)) @@ -5651,7 +5658,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, gstate_res.id = 0; status = _cairo_pdf_surface_add_pdf_pattern (surface, stroke_source, - extents, + clip, &stroke_pattern_res, &gstate_res); if (unlikely (status)) @@ -5705,7 +5712,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; cairo_status_t status; @@ -5717,17 +5724,21 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, assert (_cairo_pdf_surface_operation_supported (surface, op, source)); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip, &pattern_res, &gstate_res); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) return CAIRO_STATUS_SUCCESS; if (unlikely (status)) return status; status = _cairo_pdf_surface_select_operator (surface, op); - if (status) + if (unlikely (status)) return status; if (gstate_res.id != 0) { @@ -5840,7 +5851,7 @@ _cairo_pdf_surface_set_paginated_mode (void *abstract_surface, static const cairo_surface_backend_t cairo_pdf_surface_backend = { CAIRO_SURFACE_TYPE_PDF, - _cairo_pdf_surface_create_similar, + NULL, /* create similar: handled by wrapper */ _cairo_pdf_surface_finish, NULL, /* acquire_source_image */ NULL, /* release_source_image */ @@ -5854,8 +5865,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = { NULL, /* check_span_renderer */ NULL, /* _cairo_pdf_surface_copy_page */ _cairo_pdf_surface_show_page, - NULL, /* set_clip_region */ - _cairo_pdf_surface_intersect_clip_path, _cairo_pdf_surface_get_extents, NULL, /* old_show_glyphs */ _cairo_pdf_surface_get_font_options, @@ -5874,7 +5883,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = { NULL, /* snapshot */ NULL, /* is_compatible */ - NULL, /* reset */ _cairo_pdf_surface_fill_stroke, NULL, /* create_solid_pattern_surface */ NULL, /* can_repaint_solid_pattern_surface */ diff --git a/src/cairo-ps-surface-private.h b/src/cairo-ps-surface-private.h index 8567aff5..e892103b 100644 --- a/src/cairo-ps-surface-private.h +++ b/src/cairo-ps-surface-private.h @@ -44,6 +44,7 @@ #include "cairo-ps.h" #include "cairo-surface-private.h" +#include "cairo-surface-clipper-private.h" #include "cairo-pdf-operators-private.h" #include <time.h> @@ -65,6 +66,7 @@ typedef struct cairo_ps_surface { cairo_content_t content; double width; double height; + cairo_rectangle_int_t page_bbox; int bbox_x1, bbox_y1, bbox_x2, bbox_y2; cairo_matrix_t cairo_to_ps; @@ -97,6 +99,8 @@ typedef struct cairo_ps_surface { cairo_ps_level_t ps_level; cairo_ps_level_t ps_level_used; + cairo_surface_clipper_t clipper; + cairo_pdf_operators_t pdf_operators; cairo_surface_t *paginated_surface; } cairo_ps_surface_t; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index cfe730cb..a577d40f 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -61,6 +61,7 @@ #include "cairo-scaled-font-subsets-private.h" #include "cairo-paginated-private.h" #include "cairo-meta-surface-private.h" +#include "cairo-surface-clipper-private.h" #include "cairo-output-stream-private.h" #include "cairo-type3-glyph-surface-private.h" #include "cairo-image-info-private.h" @@ -73,6 +74,13 @@ #define DEBUG_PS 0 +#if DEBUG_PS +#define DEBUG_FALLBACK(s) \ + fprintf (stderr, "%s::%d -- %s\n", __FUNCTION__, __LINE__, (s)) +#else +#define DEBUG_FALLBACK(s) +#endif + #ifndef HAVE_CTIME_R #define ctime_r(T, BUF) ctime (T) #endif @@ -700,6 +708,74 @@ _cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface) "%%%%EOF\n"); } +static cairo_bool_t +_path_covers_bbox (cairo_ps_surface_t *surface, + cairo_path_fixed_t *path) +{ + cairo_box_t box; + + if (_cairo_path_fixed_is_rectangle (path, &box)) { + cairo_rectangle_int_t rect; + + _cairo_box_round_to_rectangle (&box, &rect); + + /* skip trivial whole-page clips */ + if (_cairo_rectangle_intersect (&rect, &surface->page_bbox)) { + if (rect.x == surface->page_bbox.x && + rect.width == surface->page_bbox.width && + rect.y == surface->page_bbox.y && + rect.height == surface->page_bbox.height) + { + return TRUE; + } + } + } + + return FALSE; +} + +static cairo_status_t +_cairo_ps_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_ps_surface_t *surface = cairo_container_of (clipper, + cairo_ps_surface_t, + clipper); + cairo_output_stream_t *stream = surface->stream; + cairo_status_t status; + + assert (surface->paginated_mode != CAIRO_PAGINATED_MODE_ANALYZE); + +#if DEBUG_PS + _cairo_output_stream_printf (stream, + "%% _cairo_ps_surface_intersect_clip_path\n"); +#endif + + if (path == NULL) { + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (stream, "Q q\n"); + + surface->current_pattern_is_solid_color = FALSE; + _cairo_pdf_operators_reset (&surface->pdf_operators); + + return CAIRO_STATUS_SUCCESS; + } + + if (_path_covers_bbox (surface, path)) + return CAIRO_STATUS_SUCCESS; + + return _cairo_pdf_operators_clip (&surface->pdf_operators, + path, + fill_rule); +} + + static cairo_surface_t * _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, double width, @@ -756,6 +832,9 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, surface->use_string_datasource = FALSE; surface->current_pattern_is_solid_color = FALSE; + _cairo_surface_clipper_init (&surface->clipper, + _cairo_ps_surface_clipper_intersect_clip_path); + _cairo_pdf_operators_init (&surface->pdf_operators, surface->stream, &surface->cairo_to_ps, @@ -771,7 +850,6 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, surface->paginated_surface = _cairo_paginated_surface_create ( &surface->base, CAIRO_CONTENT_COLOR_ALPHA, - width, height, &cairo_ps_surface_paginated_backend); status = surface->paginated_surface->status; if (status == CAIRO_STATUS_SUCCESS) { @@ -1083,11 +1161,6 @@ cairo_ps_surface_set_size (cairo_surface_t *surface, cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, -1, 0, height_in_points); _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators, &ps_surface->cairo_to_ps); - status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface, - width_in_points, - height_in_points); - if (unlikely (status)) - status = _cairo_surface_set_error (surface, status); } /** @@ -1288,15 +1361,6 @@ cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface) } } -static cairo_surface_t * -_cairo_ps_surface_create_similar (void *abstract_surface, - cairo_content_t content, - int width, - int height) -{ - return cairo_meta_surface_create (content, width, height); -} - static cairo_status_t _cairo_ps_surface_finish (void *abstract_surface) { @@ -1346,6 +1410,8 @@ CLEANUP: free (comments[i]); _cairo_array_fini (&surface->dsc_page_setup_comments); + _cairo_surface_clipper_reset (&surface->clipper); + return status; } @@ -1369,8 +1435,11 @@ _cairo_ps_surface_end_page (cairo_ps_surface_t *surface) if (unlikely (status)) return status; - _cairo_output_stream_printf (surface->stream, - "Q\n"); + if (surface->clipper.clip.path != NULL) { + _cairo_output_stream_printf (surface->stream, "Q Q\n"); + _cairo_surface_clipper_reset (&surface->clipper); + } else + _cairo_output_stream_printf (surface->stream, "Q\n"); return CAIRO_STATUS_SUCCESS; } @@ -1448,8 +1517,6 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t static cairo_bool_t surface_pattern_supported (const cairo_surface_pattern_t *pattern) { - cairo_extend_t extend; - if (_cairo_surface_is_meta (pattern->surface)) return TRUE; @@ -1465,24 +1532,7 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern) return FALSE; */ - /* Cast away the const, trusting get_extend not to muck with it. - * And I really wish I had a way to cast away just the const, and - * not potentially coerce this pointer to an incorrect type at the - * same time. :-( - */ - extend = cairo_pattern_get_extend ((cairo_pattern_t*)&pattern->base); - switch (extend) { - case CAIRO_EXTEND_NONE: - case CAIRO_EXTEND_REPEAT: - case CAIRO_EXTEND_REFLECT: - /* There's no point returning FALSE for EXTEND_PAD, as the image - * surface does not currently implement it either */ - case CAIRO_EXTEND_PAD: - return TRUE; - } - - ASSERT_NOT_REACHED; - return FALSE; + return TRUE; } static cairo_bool_t @@ -1567,10 +1617,11 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, } if (! pattern_supported (surface, pattern)) + { return CAIRO_INT_STATUS_UNSUPPORTED; + } - if (!(op == CAIRO_OPERATOR_SOURCE || - op == CAIRO_OPERATOR_OVER)) + if (! (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER)) return CAIRO_INT_STATUS_UNSUPPORTED; if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { @@ -1596,7 +1647,6 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, * render stage and we blend the transparency into the white * background to convert the pattern to opaque. */ - if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; @@ -1606,8 +1656,8 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, if (_cairo_pattern_is_opaque (pattern)) return CAIRO_STATUS_SUCCESS; - else - return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; + + return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; } static cairo_bool_t @@ -1824,7 +1874,8 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface, 0, 0, 0, 0, image->width, - image->height); + image->height, + NULL); if (unlikely (status)) goto fail; @@ -2109,6 +2160,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, data_compressed, data_compressed_size, FALSE); + _cairo_output_stream_printf (surface->stream, "\n"); } else { status = CAIRO_STATUS_SUCCESS; } @@ -2221,31 +2273,31 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface, double old_width, old_height; cairo_matrix_t old_cairo_to_ps; cairo_content_t old_content; - cairo_clip_t *old_clip; - cairo_rectangle_int_t meta_extents; + cairo_box_t bbox; cairo_status_t status; - status = _cairo_surface_get_extents (meta_surface, &meta_extents); - if (unlikely (status)) - return status; - old_content = surface->content; old_width = surface->width; old_height = surface->height; old_cairo_to_ps = surface->cairo_to_ps; - old_clip = _cairo_surface_get_clip (&surface->base); - surface->width = meta_extents.width; - surface->height = meta_extents.height; + + status = + _cairo_meta_surface_get_bbox ((cairo_meta_surface_t *) meta_surface, + &bbox, + NULL); + if (unlikely (status)) + return status; + + /* XXX is this still necessary? */ + surface->width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x); + surface->height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y); + surface->current_pattern_is_solid_color = FALSE; _cairo_pdf_operators_reset (&surface->pdf_operators); cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height); _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators, &surface->cairo_to_ps); - _cairo_output_stream_printf (surface->stream, - " q\n" - " 0 0 %f %f rectclip\n", - surface->width, - surface->height); + _cairo_output_stream_printf (surface->stream, " q\n"); if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) { surface->content = CAIRO_CONTENT_COLOR; @@ -2265,17 +2317,13 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface, if (unlikely (status)) return status; - _cairo_output_stream_printf (surface->stream, - " Q\n"); + _cairo_output_stream_printf (surface->stream, " Q\n"); surface->content = old_content; surface->width = old_width; surface->height = old_height; surface->current_pattern_is_solid_color = FALSE; _cairo_pdf_operators_reset (&surface->pdf_operators); surface->cairo_to_ps = old_cairo_to_ps; - status = _cairo_surface_set_clip (&surface->base, old_clip); - if (unlikely (status)) - return status; _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators, &surface->cairo_to_ps); @@ -2331,11 +2379,11 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, cairo_rectangle_int_t *extents, int *width, int *height, - int *origin_x, - int *origin_y) + int *origin_x, + int *origin_y) { cairo_status_t status; - cairo_surface_t *pad_image; + cairo_surface_t *pad_image; int x = 0; int y = 0; @@ -2343,15 +2391,18 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, surface->image = NULL; if (_cairo_surface_is_meta (pattern->surface)) { - cairo_surface_t *meta_surface = pattern->surface; - cairo_rectangle_int_t pattern_extents; + cairo_meta_surface_t *meta_surface = (cairo_meta_surface_t *) pattern->surface; + cairo_box_t bbox; + cairo_rectangle_int_t extents; - status = _cairo_surface_get_extents (meta_surface, &pattern_extents); + status = _cairo_meta_surface_get_bbox (meta_surface, &bbox, NULL); if (unlikely (status)) return status; - *width = pattern_extents.width; - *height = pattern_extents.height; + _cairo_box_round_to_rectangle (&bbox, &extents); + *width = extents.width; + *height =extents.height; + return CAIRO_STATUS_SUCCESS; } else { status = _cairo_surface_acquire_source_image (pattern->surface, &surface->acquired_image, @@ -2391,7 +2442,8 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, 0, 0, 0, 0, rect.width, - rect.height); + rect.height, + NULL); _cairo_pattern_fini (&pad_pattern.base); if (unlikely (status)) { if (pad_image != &surface->acquired_image->base) @@ -2406,13 +2458,11 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, *height = surface->image->height; *origin_x = x; *origin_y = y; + return CAIRO_STATUS_SUCCESS; } - return CAIRO_STATUS_SUCCESS; - BAIL: _cairo_ps_surface_release_surface (surface, pattern); - return status; } @@ -2428,10 +2478,9 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface, if (_cairo_surface_is_meta (pattern->surface)) { cairo_surface_t *meta_surface = pattern->surface; - status = _cairo_ps_surface_emit_meta_surface (surface, - meta_surface); + status = _cairo_ps_surface_emit_meta_surface (surface, meta_surface); } else { - if (cairo_pattern_get_extend (&pattern->base) != CAIRO_EXTEND_PAD) { + if (pattern->base.extend != CAIRO_EXTEND_PAD) { status = _cairo_ps_surface_emit_jpeg_image (surface, pattern->surface, width, height); if (status != CAIRO_INT_STATUS_UNSUPPORTED) @@ -2540,7 +2589,6 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, int pattern_height = 0; /* squelch bogus compiler warning */ double xstep, ystep; cairo_matrix_t cairo_p2d, ps_p2d; - cairo_rectangle_int_t surface_extents; cairo_bool_t old_use_string_datasource; int origin_x = 0; int origin_y = 0; @@ -2550,12 +2598,6 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, /* cairo_pattern_set_matrix ensures the matrix is invertible */ assert (status == CAIRO_STATUS_SUCCESS); - ps_p2d = surface->cairo_to_ps; - cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d); - cairo_matrix_translate (&ps_p2d, -origin_x, -origin_y); - cairo_matrix_translate (&ps_p2d, 0.0, pattern_height); - cairo_matrix_scale (&ps_p2d, 1.0, -1.0); - status = _cairo_ps_surface_acquire_surface (surface, pattern, extents, @@ -2669,17 +2711,13 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, _cairo_output_stream_printf (surface->stream, ">>\n"); - status = _cairo_surface_get_extents (&surface->base, &surface_extents); - if (unlikely (status)) - return status; - cairo_p2d = pattern->base.matrix; status = cairo_matrix_invert (&cairo_p2d); /* cairo_pattern_set_matrix ensures the matrix is invertible */ assert (status == CAIRO_STATUS_SUCCESS); cairo_matrix_init_identity (&ps_p2d); - cairo_matrix_translate (&ps_p2d, 0.0, surface_extents.height); + cairo_matrix_translate (&ps_p2d, 0.0, surface->height); cairo_matrix_scale (&ps_p2d, 1.0, -1.0); cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d); cairo_matrix_translate (&ps_p2d, 0.0, pattern_height); @@ -3163,43 +3201,7 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_ps_surface_intersect_clip_path (void *abstract_surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_ps_surface_t *surface = abstract_surface; - cairo_output_stream_t *stream = surface->stream; - cairo_status_t status; - - if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return CAIRO_STATUS_SUCCESS; - -#if DEBUG_PS - _cairo_output_stream_printf (stream, - "%% _cairo_ps_surface_intersect_clip_path\n"); -#endif - - if (path == NULL) { - status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (unlikely (status)) - return status; - - _cairo_output_stream_printf (stream, "Q q\n"); - surface->current_pattern_is_solid_color = FALSE; - _cairo_pdf_operators_reset (&surface->pdf_operators); - - return CAIRO_STATUS_SUCCESS; - } - - return _cairo_pdf_operators_clip (&surface->pdf_operators, - path, - fill_rule); -} - -static cairo_int_status_t +static cairo_bool_t _cairo_ps_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -3215,7 +3217,7 @@ _cairo_ps_surface_get_extents (void *abstract_surface, rectangle->width = (int) ceil (surface->width); rectangle->height = (int) ceil (surface->height); - return CAIRO_STATUS_SUCCESS; + return TRUE; } static void @@ -3229,11 +3231,26 @@ _cairo_ps_surface_get_font_options (void *abstract_surface, cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); } +static cairo_bool_t +_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip) +{ + const cairo_rectangle_int_t *clip_extents; + + clip_extents = NULL; + if (clip != NULL) + clip_extents = _cairo_clip_get_extents (clip); + + if (clip_extents != NULL) + return _cairo_rectangle_intersect (extents, clip_extents); + + return TRUE; +} + static cairo_int_status_t _cairo_ps_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *paint_extents) + cairo_clip_t *clip) { cairo_ps_surface_t *surface = abstract_surface; cairo_output_stream_t *stream = surface->stream; @@ -3250,11 +3267,11 @@ _cairo_ps_surface_paint (void *abstract_surface, "%% _cairo_ps_surface_paint\n"); #endif - status = _cairo_surface_get_extents (&surface->base, &extents); - if (unlikely (status)) - return status; + extents = surface->page_bbox; + if (! _rectangle_intersect_clip (&extents, clip)) + return CAIRO_STATUS_SUCCESS; - status = _cairo_pdf_operators_flush (&surface->pdf_operators); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; @@ -3262,28 +3279,25 @@ _cairo_ps_surface_paint (void *abstract_surface, (source->extend == CAIRO_EXTEND_NONE || source->extend == CAIRO_EXTEND_PAD)) { - _cairo_output_stream_printf (stream, "q 0 0 %d %d rectclip\n", - extents.width, - extents.height); - + _cairo_output_stream_printf (stream, "q\n"); status = _cairo_ps_surface_paint_surface (surface, (cairo_surface_pattern_t *) source, - paint_extents, op); + &extents, op); if (unlikely (status)) return status; _cairo_output_stream_printf (stream, "Q\n"); } else { - status = _cairo_ps_surface_emit_pattern (surface, source, paint_extents, op); + status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; if (unlikely (status)) return status; - _cairo_output_stream_printf (stream, "0 0 %d %d rectfill\n", - extents.width, - extents.height); + _cairo_output_stream_printf (stream, "%d %d %d %d rectfill\n", + extents.x, extents.y, + extents.width, extents.height); } return CAIRO_STATUS_SUCCESS; @@ -3299,10 +3313,11 @@ _cairo_ps_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_ps_surface_t *surface = abstract_surface; cairo_int_status_t status; + cairo_rectangle_int_t extents; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_ps_surface_analyze_operation (surface, op, source); @@ -3314,7 +3329,15 @@ _cairo_ps_surface_stroke (void *abstract_surface, "%% _cairo_ps_surface_stroke\n"); #endif - status = _cairo_ps_surface_emit_pattern (surface, source, extents, op); + extents = surface->page_bbox; + if (! _rectangle_intersect_clip (&extents, clip)) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + + status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; @@ -3336,10 +3359,11 @@ _cairo_ps_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_ps_surface_t *surface = abstract_surface; cairo_int_status_t status; + cairo_rectangle_int_t extents; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_ps_surface_analyze_operation (surface, op, source); @@ -3351,14 +3375,22 @@ _cairo_ps_surface_fill (void *abstract_surface, "%% _cairo_ps_surface_fill\n"); #endif + extents = surface->page_bbox; + if (! _rectangle_intersect_clip (&extents, clip)) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + if (source->type == CAIRO_PATTERN_TYPE_SURFACE && (source->extend == CAIRO_EXTEND_NONE || source->extend == CAIRO_EXTEND_PAD)) { - status = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (unlikely (status)) - return status; - _cairo_output_stream_printf (surface->stream, "q\n"); status = _cairo_pdf_operators_clip (&surface->pdf_operators, @@ -3369,14 +3401,14 @@ _cairo_ps_surface_fill (void *abstract_surface, status = _cairo_ps_surface_paint_surface (surface, (cairo_surface_pattern_t *) source, - extents, op); + &extents, op); if (unlikely (status)) return status; _cairo_output_stream_printf (surface->stream, "Q\n"); _cairo_pdf_operators_reset (&surface->pdf_operators); } else { - status = _cairo_ps_surface_emit_pattern (surface, source, extents, op); + status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; @@ -3398,11 +3430,12 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip, + int *remaining_glyphs) { cairo_ps_surface_t *surface = abstract_surface; cairo_status_t status; + cairo_rectangle_int_t extents; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return _cairo_ps_surface_analyze_operation (surface, op, source); @@ -3417,7 +3450,15 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, if (num_glyphs <= 0) return CAIRO_STATUS_SUCCESS; - status = _cairo_ps_surface_emit_pattern (surface, source, extents, op); + extents = surface->page_bbox; + if (! _rectangle_intersect_clip (&extents, clip)) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + + status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; @@ -3439,6 +3480,11 @@ _cairo_ps_surface_set_paginated_mode (void *abstract_surface, cairo_ps_surface_t *surface = abstract_surface; surface->paginated_mode = paginated_mode; + + if (surface->clipper.clip.path != NULL) { + _cairo_output_stream_printf (surface->stream, "Q\n"); + _cairo_surface_clipper_reset (&surface->clipper); + } } static cairo_int_status_t @@ -3462,6 +3508,11 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface, y2 = (int) ceil (surface->height); } + surface->page_bbox.x = x1; + surface->page_bbox.y = y1; + surface->page_bbox.width = x2 - x1; + surface->page_bbox.height = y2 - y1; + _cairo_output_stream_printf (surface->stream, "%%%%Page: %d %d\n", surface->num_pages, @@ -3486,7 +3537,11 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface, _cairo_output_stream_printf (surface->stream, "%%%%EndPageSetup\n" - "q\n"); + "q %d %d %d %d rectclip q\n", + surface->page_bbox.x, + surface->page_bbox.y, + surface->page_bbox.width, + surface->page_bbox.height); if (surface->num_pages == 1) { surface->bbox_x1 = x1; @@ -3517,7 +3572,7 @@ _cairo_ps_surface_supports_fine_grained_fallbacks (void *abstract_surface) static const cairo_surface_backend_t cairo_ps_surface_backend = { CAIRO_SURFACE_TYPE_PS, - _cairo_ps_surface_create_similar, + NULL, /* create similar: handled by wrapper */ _cairo_ps_surface_finish, NULL, /* acquire_source_image */ NULL, /* release_source_image */ @@ -3531,8 +3586,6 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = { NULL, /* check_span_renderer */ NULL, /* cairo_ps_surface_copy_page */ _cairo_ps_surface_show_page, - NULL, /* set_clip_region */ - _cairo_ps_surface_intersect_clip_path, _cairo_ps_surface_get_extents, NULL, /* old_show_glyphs */ _cairo_ps_surface_get_font_options, diff --git a/src/cairo-qt-surface.cpp b/src/cairo-qt-surface.cpp index 70f6d1a7..a0d573da 100644 --- a/src/cairo-qt-surface.cpp +++ b/src/cairo-qt-surface.cpp @@ -39,6 +39,9 @@ #include "cairoint.h" #include "cairo-types-private.h" +#include "cairo-clip-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-region-private.h" #include "cairo-qt.h" @@ -65,6 +68,8 @@ #include <sys/time.h> +#define ENABLE_FAST_FILL 1 /* Enable workaround slow regional Qt paths */ + #if 0 #define D(x) x static const char * @@ -104,14 +109,9 @@ _opstr (cairo_operator_t op) #define DOT_LENGTH 1.0 #define DASH_LENGTH 3.0 -typedef struct { +struct cairo_qt_surface_t { cairo_surface_t base; - bool has_clipping; - // if this is true, calls to intersect_clip_path won't - // update the clip_bounds rect - bool no_update_clip_bounds; - cairo_bool_t supports_porter_duff; #if defined(Q_WS_X11) && CAIRO_HAS_XLIB_XRENDER_SURFACE @@ -131,11 +131,10 @@ typedef struct { QRect window; - - QRect clip_bounds; + cairo_surface_clipper_t clipper; cairo_surface_t *image_equiv; -} cairo_qt_surface_t; +}; /* Will be true if we ever try to create a QPixmap and end * up with one without an alpha channel. @@ -186,6 +185,21 @@ _qpainter_compositionmode_from_cairo_op (cairo_operator_t op) default: case CAIRO_OPERATOR_ADD: case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: ASSERT_NOT_REACHED; } } @@ -211,12 +225,27 @@ _op_is_supported (cairo_qt_surface_t *qs, cairo_operator_t op) case CAIRO_OPERATOR_XOR: return TRUE; + default: + ASSERT_NOT_REACHED; case CAIRO_OPERATOR_ADD: case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: return FALSE; - default: - ASSERT_NOT_REACHED; } } else { return op == CAIRO_OPERATOR_OVER; @@ -458,6 +487,8 @@ _cairo_qt_surface_finish (void *abstract_surface) if (qs->image_equiv) cairo_surface_destroy (qs->image_equiv); + _cairo_surface_clipper_reset (&qs->clipper); + #if defined(Q_WS_X11) && CAIRO_HAS_XLIB_XRENDER_SURFACE if (qs->xlib_equiv) cairo_surface_destroy (qs->xlib_equiv); @@ -655,7 +686,7 @@ _cairo_qt_surface_clone_similar (void *abstract_surface, return (cairo_status_t) CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_int_status_t +static cairo_bool_t _cairo_qt_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *extents) { @@ -666,25 +697,40 @@ _cairo_qt_surface_get_extents (void *abstract_surface, extents->width = qs->window.width(); extents->height = qs->window.height(); - return CAIRO_INT_STATUS_SUCCESS; + return TRUE; } -static cairo_int_status_t -_cairo_qt_surface_intersect_clip_path (void *abstract_surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) +static cairo_status_t +_cairo_qt_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) { - cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; + cairo_qt_surface_t *qs = cairo_container_of (clipper, + cairo_qt_surface_t, + clipper); + QPainterPath qpath; + cairo_status_t status; - D(fprintf(stderr, "q[%p] intersect_clip_path %s\n", abstract_surface, path ? "(path)" : "(clear)")); + // XXX Antialiasing is ignored + status = _cairo_quartz_cairo_path_to_qpainterpath (path, + &qpath, + fill_rule); + if (unlikely (status)) + return status; - if (!qs->p) - return CAIRO_INT_STATUS_UNSUPPORTED; + qs->p->setClipPath (qpath, Qt::IntersectClip); + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_qt_surface_set_clip_region (cairo_qt_surface_t *qs, + cairo_region_t *clip_region) +{ + _cairo_surface_clipper_reset (&qs->clipper); - if (path == NULL) { - //fprintf (stderr, "clip clear\n"); + if (clip_region == NULL) { // How the clip path is reset depends on whether we own p or not if (qs->pixmap || qs->image) { // we own p @@ -693,10 +739,38 @@ _cairo_qt_surface_intersect_clip_path (void *abstract_surface, qs->p->restore (); qs->p->save (); } + } else { + QRegion qr; + int num_rects = cairo_region_num_rectangles (clip_region); + for (int i = 0; i < num_rects; ++i) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (clip_region, i, &rect); - if (!qs->no_update_clip_bounds) { - qs->clip_bounds.setRect(0, 0, 0, 0); - qs->has_clipping = false; + QRect r(rect.x, rect.y, rect.width, rect.height); + qr = qr.unite(r); + } + + qs->p->setClipRegion (qr, Qt::IntersectClip); + } +} + +static cairo_int_status_t +_cairo_qt_surface_set_clip (cairo_qt_surface_t *qs, + cairo_clip_t *clip) +{ + + D(fprintf(stderr, "q[%p] intersect_clip_path %s\n", abstract_surface, path ? "(path)" : "(clear)")); + + if (clip == NULL) { + _cairo_surface_clipper_reset (&qs->clipper); + // How the clip path is reset depends on whether we own p or not + if (qs->pixmap || qs->image) { + // we own p + qs->p->setClipping (false); + } else { + qs->p->restore (); + qs->p->save (); } return CAIRO_INT_STATUS_SUCCESS; @@ -711,125 +785,21 @@ _cairo_qt_surface_intersect_clip_path (void *abstract_surface, // we do a bunch of work here to try to get rectangles or regions // down to Qt for clipping. - QRect clip_bounds; + cairo_region_t *clip_region = NULL; - // First check if it's an integer-aligned single rectangle - cairo_box_t box; - if (_cairo_path_fixed_is_box (path, &box) && - _cairo_fixed_is_integer (box.p1.x) && - _cairo_fixed_is_integer (box.p1.y) && - _cairo_fixed_is_integer (box.p2.x) && - _cairo_fixed_is_integer (box.p2.y)) - { - QRect r(_cairo_fixed_integer_part(box.p1.x), - _cairo_fixed_integer_part(box.p1.y), - _cairo_fixed_integer_part(box.p2.x - box.p1.x), - _cairo_fixed_integer_part(box.p2.y - box.p1.y)); - - r = r.normalized(); - - clip_bounds = r; - - qs->p->setClipRect (r, Qt::IntersectClip); - } else { - // Then if it's not an integer-aligned rectangle, check - // if we can extract a region (a set of rectangles) out. - // We use cairo to convert the path to traps. - - cairo_traps_t traps; - cairo_int_status_t status; - cairo_region_t *region = NULL; - - _cairo_traps_init (&traps); + cairo_int_status_t status; + status = _cairo_clip_get_region (clip, &clip_region); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + // We weren't able to extract a region from the traps. + // Just hand the path down to QPainter. status = (cairo_int_status_t) - _cairo_path_fixed_fill_to_traps (path, - fill_rule, tolerance, &traps); - if (status) { - _cairo_traps_fini (&traps); - return status; - } - - status = _cairo_traps_extract_region (&traps, ®ion); - _cairo_traps_fini (&traps); - - if (_cairo_status_is_error ((cairo_status_t) status)) - return status; - - if (status == CAIRO_INT_STATUS_SUCCESS) { -#if 0 - cairo_box_int_t *boxes; - int n_boxes; - - QRegion qr; - - _cairo_region_get_boxes (®ion, &n_boxes, &boxes); - - for (int i = 0; i < n_boxes; i++) { - QRect r(boxes[i].p1.x, - boxes[i].p1.y, - boxes[i].p2.x - boxes[i].p1.x, - boxes[i].p2.y - boxes[i].p1.y); - - if (i == 0) - clip_bounds = r; - else - clip_bounds = clip_bounds.united(r); - - qr = qr.unite(r); - } - _cairo_region_boxes_fini (®ion, boxes); -#else - int n_boxes; - - QRegion qr; - - n_boxes = cairo_region_num_rectangles (region); - for (int i = 0; i < n_boxes; ++i) { - cairo_rectangle_int_t box; - cairo_region_get_rectangle (region, i, &box); - QRect r(box.x, box.y, box.width, box.height); - - if (0 == i) - clip_bounds = r; - else - clip_bounds = clip_bounds.united(r); - - qr = qr.unite(r); - } -#endif - _cairo_region_fini (region); - - qs->p->setClipRegion (qr, Qt::IntersectClip); - } else { - // We weren't able to extract a region from the traps. - // Just hand the path down to QPainter. - QPainterPath qpath; - cairo_status_t status; - - status = _cairo_quartz_cairo_path_to_qpainterpath (path, - &qpath, - fill_rule); - assert (status == CAIRO_STATUS_SUCCESS); - - clip_bounds = qpath.boundingRect().toAlignedRect(); - - // XXX Antialiasing is ignored - qs->p->setClipPath (qpath, Qt::IntersectClip); - } + _cairo_surface_clipper_set_clip (&qs->clipper, clip); + } else if (status == CAIRO_INT_STATUS_SUCCESS) { + _cairo_qt_surface_set_clip_region (qs, clip_region); + status = CAIRO_INT_STATUS_SUCCESS; } - if (!qs->no_update_clip_bounds) { - clip_bounds = qs->p->worldTransform().mapRect(clip_bounds); - - if (qs->has_clipping) { - qs->clip_bounds = qs->clip_bounds.intersect(clip_bounds); - } else { - qs->clip_bounds = clip_bounds; - qs->has_clipping = true; - } - } - - return CAIRO_INT_STATUS_SUCCESS; + return status; } /** @@ -1156,10 +1126,12 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs, double tolerance = 0.0, cairo_antialias_t antialias = CAIRO_ANTIALIAS_NONE) { +#if ENABLE_FAST_FILL QImage *qsSrc_image = NULL; QPixmap *qsSrc_pixmap = NULL; std::auto_ptr<QImage> qsSrc_image_d; + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t*) source; if (spattern->surface->type == CAIRO_SURFACE_TYPE_QT) { @@ -1190,7 +1162,6 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs, } QMatrix sourceMatrix = _qmatrix_from_cairo_matrix (source->matrix); - cairo_int_status_t status; // We can draw this faster by clipping and calling drawImage/drawPixmap. // Use our own clipping function so that we can get the @@ -1201,14 +1172,29 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs, qs->p->save(); if (path) { - qs->no_update_clip_bounds = true; - status = _cairo_qt_surface_intersect_clip_path (qs, path, fill_rule, tolerance, antialias); - qs->no_update_clip_bounds = false; + cairo_int_status_t status; - if (status != CAIRO_INT_STATUS_SUCCESS) { - qs->p->restore(); - return false; - } + cairo_clip_t clip, old_clip = qs->clipper.clip; + + _cairo_clip_init_copy (&clip, &qs->clipper.clip); + status = (cairo_int_status_t) _cairo_clip_clip (&clip, + path, + fill_rule, + tolerance, + antialias); + if (unlikely (status)) { + qs->p->restore(); + return false; + } + + status = _cairo_qt_surface_set_clip (qs, &clip); + if (unlikely (status)) { + qs->p->restore(); + return false; + } + + _cairo_clip_reset (&clip); + qs->clipper.clip = old_clip; } qs->p->setWorldMatrix (sourceMatrix.inverted(), true); @@ -1242,16 +1228,19 @@ _cairo_qt_fast_fill (cairo_qt_surface_t *qs, qs->p->restore(); return true; +#else + return false; +#endif } static cairo_int_status_t _cairo_qt_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { - Q_UNUSED(extents); cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; + cairo_int_status_t status; D(fprintf(stderr, "q[%p] paint op:%s\n", abstract_surface, _opstr(op))); @@ -1261,6 +1250,10 @@ _cairo_qt_surface_paint (void *abstract_surface, if (! _op_is_supported (qs, op)) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_qt_surface_set_clip (qs, clip); + if (unlikely (status)) + return status; + if (qs->supports_porter_duff) qs->p->setCompositionMode (_qpainter_compositionmode_from_cairo_op (op)); @@ -1283,9 +1276,8 @@ _cairo_qt_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t * extents) + cairo_clip_t *clip) { - Q_UNUSED(extents); cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; D(fprintf(stderr, "q[%p] fill op:%s\n", abstract_surface, _opstr(op))); @@ -1296,6 +1288,10 @@ _cairo_qt_surface_fill (void *abstract_surface, if (! _op_is_supported (qs, op)) return CAIRO_INT_STATUS_UNSUPPORTED; + cairo_int_status_t status = _cairo_qt_surface_set_clip (qs, clip); + if (unlikely (status)) + return status; + if (qs->supports_porter_duff) qs->p->setCompositionMode (_qpainter_compositionmode_from_cairo_op (op)); @@ -1333,9 +1329,8 @@ _cairo_qt_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { - Q_UNUSED(extents); cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; D(fprintf(stderr, "q[%p] stroke op:%s\n", abstract_surface, _opstr(op))); @@ -1346,6 +1341,10 @@ _cairo_qt_surface_stroke (void *abstract_surface, if (! _op_is_supported (qs, op)) return CAIRO_INT_STATUS_UNSUPPORTED; + cairo_int_status_t int_status = _cairo_qt_surface_set_clip (qs, clip); + if (unlikely (int_status)) + return int_status; + QPainterPath qpath; cairo_status_t status; @@ -1387,8 +1386,8 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip, + int *remaining_glyphs) { cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; @@ -1404,37 +1403,6 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface, glyphs[i].y -= qs->redir_offset.y(); } - if (qs->has_clipping != qs->xlib_has_clipping || - qs->clip_bounds != qs->xlib_clip_bounds) - { - cairo_status_t status; - - status = _cairo_surface_reset_clip (qs->xlib_equiv); - assert (status == CAIRO_STATUS_SUCCESS); - - if (qs->has_clipping) { - cairo_region_t region; - cairo_rectangle_int_t rect = { - qs->clip_bounds.x() - qs->redir_offset.x(), - qs->clip_bounds.y() - qs->redir_offset.y(), - qs->clip_bounds.width(), - qs->clip_bounds.height() - }; - - _cairo_region_init_rectangle (®ion, &rect); - status = _cairo_surface_set_clip_region (qs->xlib_equiv, - ®ion, - ++qs->xlib_clip_serial); - _cairo_region_fini (®ion); - - if (status) - return (cairo_int_status_t) status; - } - - qs->xlib_has_clipping = qs->has_clipping; - qs->xlib_clip_bounds = qs->clip_bounds; - } - return (cairo_int_status_t) _cairo_surface_show_text_glyphs (qs->xlib_equiv, op, source, @@ -1443,7 +1411,7 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface, NULL, 0, (cairo_text_cluster_flags_t) 0, scaled_font, - extents); + clip); } #endif @@ -1452,12 +1420,11 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface, static cairo_int_status_t _cairo_qt_surface_mask (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) { - Q_UNUSED(extents); cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; D(fprintf(stderr, "q[%p] mask op:%s\n", abstract_surface, _opstr(op))); @@ -1471,7 +1438,7 @@ _cairo_qt_surface_mask (void *abstract_surface, qs->p->setOpacity (solid_mask->color.alpha); - result = _cairo_qt_surface_paint (abstract_surface, op, source, 0); + result = _cairo_qt_surface_paint (abstract_surface, op, source, clip); qs->p->setOpacity (1.0); @@ -1498,7 +1465,8 @@ _cairo_qt_surface_composite (cairo_operator_t op, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; @@ -1508,6 +1476,8 @@ _cairo_qt_surface_composite (cairo_operator_t op, if (! _op_is_supported (qs, op)) return CAIRO_INT_STATUS_UNSUPPORTED; + _cairo_qt_surface_set_clip_region (qs, clip_region); + D(fprintf(stderr, "q[%p] composite op:%s src:%p [%d %d] dst [%d %d] dim [%d %d]\n", abstract_surface, _opstr(op), (void*)pattern, src_x, src_y, dst_x, dst_y, width, height)); @@ -1618,8 +1588,6 @@ static const cairo_surface_backend_t cairo_qt_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - NULL, /* set_clip_region */ - _cairo_qt_surface_intersect_clip_path, _cairo_qt_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -1636,7 +1604,6 @@ static const cairo_surface_backend_t cairo_qt_surface_backend = { NULL, /* snapshot */ NULL, /* is_similar */ - NULL, /* reset */ NULL, /* fill_stroke */ NULL, /* create_solid_pattern_surface */ NULL, /* can_repaint_solid_pattern_surface */ @@ -1728,6 +1695,10 @@ cairo_qt_surface_create (QPainter *painter) qs->window = painter->window(); + _cairo_surface_clipper_init (&qs->clipper, + _cairo_qt_surface_clipper_intersect_clip_path); + + #if defined(Q_WS_X11) && CAIRO_HAS_XLIB_XRENDER_SURFACE qs->xlib_equiv = _cairo_qt_create_xlib_surface (qs); #endif diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c index dab3dc87..7aa7ffdc 100644 --- a/src/cairo-quartz-image-surface.c +++ b/src/cairo-quartz-image-surface.c @@ -58,9 +58,8 @@ _cairo_quartz_image_surface_create_similar (void *asurface, int height) { cairo_surface_t *result; - cairo_surface_t *isurf = cairo_image_surface_create (_cairo_format_from_content (content), - width, - height); + cairo_surface_t *isurf = + _cairo_image_surface_create_for_content (content, width, height); if (cairo_surface_status(isurf)) return isurf; @@ -108,18 +107,16 @@ _cairo_quartz_image_surface_acquire_dest_image (void *asurface, *image_extra = NULL; return CAIRO_STATUS_SUCCESS; - } -static cairo_int_status_t +static cairo_bool_t _cairo_quartz_image_surface_get_extents (void *asurface, cairo_rectangle_int_t *extents) { cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; *extents = surface->extents; - - return CAIRO_STATUS_SUCCESS; + return TRUE; } /* we assume some drawing happened to the image buffer; make sure it's @@ -168,8 +165,6 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - NULL, /* set_clip_region */ - NULL, /* intersect_clip_path */ _cairo_quartz_image_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -185,7 +180,6 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = { NULL, /* surface_show_glyphs */ NULL, /* snapshot */ NULL, /* is_similar */ - NULL, /* reset */ NULL /* fill_stroke */ }; diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h index 8ba89687..d7e07ac8 100644 --- a/src/cairo-quartz-private.h +++ b/src/cairo-quartz-private.h @@ -42,6 +42,7 @@ #if CAIRO_HAS_QUARTZ_SURFACE #include "cairo-quartz.h" +#include "cairo-surface-clipper-private.h" typedef struct cairo_quartz_surface { cairo_surface_t base; @@ -52,6 +53,7 @@ typedef struct cairo_quartz_surface { void *imageData; cairo_surface_t *imageSurfaceEquiv; + cairo_surface_clipper_t clipper; cairo_rectangle_int_t extents; /* These are stored while drawing operations are in place, set up diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index 892a156d..1db8ba72 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -38,6 +38,7 @@ #include "cairoint.h" #include "cairo-quartz-private.h" +#include "cairo-surface-clipper-private.h" #include <dlfcn.h> @@ -837,7 +838,8 @@ _cairo_surface_to_cgimage (cairo_surface_t *target, } if (stype != CAIRO_SURFACE_TYPE_IMAGE) { - status = _cairo_surface_acquire_source_image (source, &isurf, &image_extra); + status = _cairo_surface_acquire_source_image (source, + &isurf, &image_extra); if (status) return status; } else { @@ -848,12 +850,11 @@ _cairo_surface_to_cgimage (cairo_surface_t *target, *image_out = NULL; } else { cairo_image_surface_t *isurf_snap = NULL; - isurf_snap = (cairo_image_surface_t*) _cairo_surface_snapshot ((cairo_surface_t*) isurf); - if (isurf_snap == NULL) - return CAIRO_STATUS_NO_MEMORY; - if (isurf_snap->base.type != CAIRO_SURFACE_TYPE_IMAGE) - return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + isurf_snap = (cairo_image_surface_t*) + _cairo_surface_snapshot (&isurf->base); + if (isurf_snap->base.status) + return isurf_snap->base.status; image = _cairo_quartz_create_cgimage (isurf_snap->format, isurf_snap->width, @@ -868,10 +869,10 @@ _cairo_surface_to_cgimage (cairo_surface_t *target, *image_out = image; } - if ((cairo_surface_t*) isurf != source) + if (&isurf->base != source) _cairo_surface_release_source_image (source, isurf, image_extra); - return status; + return CAIRO_STATUS_SUCCESS; } /* Generic #cairo_pattern_t -> CGPattern function */ @@ -942,6 +943,7 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t SurfacePatternDrawInfo *info; float rw, rh; cairo_status_t status; + cairo_bool_t is_bounded; cairo_matrix_t m; @@ -952,9 +954,8 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t spattern = (cairo_surface_pattern_t *) apattern; pat_surf = spattern->surface; - status = _cairo_surface_get_extents (pat_surf, &extents); - if (status) - return status; + is_bounded = _cairo_surface_get_extents (pat_surf, &extents); + assert (is_bounded); status = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf, &image); if (status != CAIRO_STATUS_SUCCESS) @@ -1042,9 +1043,7 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface, double x0, y0, w, h; cairo_surface_t *fallback; - cairo_t *fallback_cr; CGImageRef img; - cairo_pattern_t *source_copy; cairo_status_t status; @@ -1070,20 +1069,38 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface, fallback = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, (int) w, (int) h); cairo_surface_set_device_offset (fallback, -x0, -y0); - /* Paint the source onto our temporary */ - fallback_cr = cairo_create (fallback); - cairo_set_operator (fallback_cr, CAIRO_OPERATOR_SOURCE); +#if 0 + { + cairo_t *fallback_cr; + cairo_pattern_t *source_copy; + + /* Paint the source onto our temporary */ + fallback_cr = cairo_create (fallback); + cairo_set_operator (fallback_cr, CAIRO_OPERATOR_SOURCE); - /* Use a copy of the pattern because it is const and could be allocated - * on the stack */ - status = _cairo_pattern_create_copy (&source_copy, source); - cairo_set_source (fallback_cr, source_copy); - cairo_pattern_destroy (source_copy); + /* Use a copy of the pattern because it is const and could be allocated + * on the stack */ + status = _cairo_pattern_create_copy (&source_copy, source); + cairo_set_source (fallback_cr, source_copy); + cairo_pattern_destroy (source_copy); + + cairo_paint (fallback_cr); + cairo_destroy (fallback_cr); + } +#else + { + cairo_pattern_union_t pattern; - cairo_paint (fallback_cr); - cairo_destroy (fallback_cr); + _cairo_pattern_init_static_copy (&pattern, source); + _cairo_pattern_transform (pattern_copy, + &fallback->device_transform_inverse); + status = _cairo_surface_paint (fallback, + CAIRO_OPERATOR_SOURCE, + &pattern.base, NULL); + } +#endif - status = _cairo_surface_to_cgimage ((cairo_surface_t*) surface, fallback, &img); + status = _cairo_surface_to_cgimage (&surface->base, fallback, &img); if (status == CAIRO_STATUS_SUCCESS && img == NULL) return DO_NOTHING; if (status) @@ -1251,6 +1268,7 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface, CGAffineTransform xform; CGRect srcRect; cairo_fixed_t fw, fh; + cairo_bool_t is_bounded; status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img); if (status == CAIRO_STATUS_SUCCESS && img == NULL) @@ -1263,9 +1281,8 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface, cairo_matrix_invert(&m); _cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceTransform); - status = _cairo_surface_get_extents (pat_surf, &extents); - if (status) - return DO_UNSUPPORTED; + is_bounded = _cairo_surface_get_extents (pat_surf, &extents); + assert (is_bounded); if (source->extend == CAIRO_EXTEND_NONE) { surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height); @@ -1485,6 +1502,7 @@ _cairo_quartz_surface_finish (void *abstract_surface) /* Restore our saved gstate that we use to reset clipping */ CGContextRestoreGState (surface->cgContext); + _cairo_surface_clipper_reset (&surface->clipper); CGContextRelease (surface->cgContext); @@ -1700,22 +1718,21 @@ FINISH: return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t +static cairo_bool_t _cairo_quartz_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *extents) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; *extents = surface->extents; - - return CAIRO_STATUS_SUCCESS; + return TRUE; } static cairo_int_status_t _cairo_quartz_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1729,6 +1746,10 @@ _cairo_quartz_surface_paint (void *abstract_surface, if (op == CAIRO_OPERATOR_DEST) return CAIRO_STATUS_SUCCESS; + rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (rv)) + return rv; + CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op)); action = _cairo_quartz_setup_source (surface, source); @@ -1771,7 +1792,7 @@ _cairo_quartz_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1790,7 +1811,7 @@ _cairo_quartz_surface_fill (void *abstract_surface, /* Check whether the path would be a no-op */ /* XXX handle unbounded ops */ - if (_cairo_path_fixed_is_empty(path) || + if (_cairo_path_fixed_fill_is_empty(path) || (_cairo_path_fixed_is_box(path, &box) && box.p1.x == box.p2.x && box.p1.y == box.p2.y)) @@ -1798,6 +1819,10 @@ _cairo_quartz_surface_fill (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } + rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (rv)) + return rv; + CGContextSaveGState (surface->cgContext); CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE)); @@ -1879,7 +1904,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -1896,6 +1921,10 @@ _cairo_quartz_surface_stroke (void *abstract_surface, if (op == CAIRO_OPERATOR_DEST) return CAIRO_STATUS_SUCCESS; + rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (rv)) + return rv; + CGContextSaveGState (surface->cgContext); // Turning antialiasing off used to cause misrendering with @@ -2024,7 +2053,7 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, int num_glyphs, cairo_scaled_font_t *scaled_font, int *remaining_glyphs, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { CGAffineTransform textTransform, ctm; #define STATIC_BUF_SIZE 64 @@ -2055,6 +2084,10 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ) return CAIRO_INT_STATUS_UNSUPPORTED; + rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (rv)) + return rv; + CGContextSaveGState (surface->cgContext); action = _cairo_quartz_setup_source (surface, source); @@ -2239,10 +2272,10 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, cairo_surface_t *pat_surf = mask->surface; cairo_status_t status = CAIRO_STATUS_SUCCESS; CGAffineTransform ctm, mask_matrix; + cairo_bool_t is_bounded; - status = _cairo_surface_get_extents (pat_surf, &mask_extents); - if (status) - return status; + is_bounded = _cairo_surface_get_extents (pat_surf, &mask_extents); + assert (is_bounded); // everything would be masked out, so do nothing if (mask_extents.width == 0 || mask_extents.height == 0) @@ -2347,7 +2380,7 @@ _cairo_quartz_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -2357,6 +2390,10 @@ _cairo_quartz_surface_mask (void *abstract_surface, if (IS_EMPTY(surface)) return CAIRO_STATUS_SUCCESS; + rv = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (rv)) + return rv; + if (mask->type == CAIRO_PATTERN_TYPE_SOLID) { /* This is easy; we just need to paint with the alpha. */ cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask; @@ -2387,14 +2424,15 @@ _cairo_quartz_surface_mask (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_quartz_surface_intersect_clip_path (void *abstract_surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) +static cairo_status_t +_cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) { - cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_quartz_surface_t *surface = + cairo_container_of (clipper, cairo_quartz_surface_t, clipper); quartz_stroke_t stroke; cairo_status_t status; @@ -2455,8 +2493,6 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - NULL, /* set_clip_region */ - _cairo_quartz_surface_intersect_clip_path, _cairo_quartz_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -2477,7 +2513,6 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = { _cairo_quartz_surface_snapshot, NULL, /* is_similar */ - NULL, /* reset */ NULL /* fill_stroke */ }; @@ -2501,6 +2536,9 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext, _cairo_surface_init(&surface->base, &cairo_quartz_surface_backend, content); + _cairo_surface_clipper_init (&surface->clipper, + _cairo_quartz_surface_intersect_clip_path); + /* Save our extents */ surface->extents.x = surface->extents.y = 0; surface->extents.width = width; diff --git a/src/cairo-region-private.h b/src/cairo-region-private.h new file mode 100644 index 00000000..8a10115d --- /dev/null +++ b/src/cairo-region-private.h @@ -0,0 +1,73 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor <otaylor@redhat.com> + * Vladimir Vukicevic <vladimir@pobox.com> + * Søren Sandmann <sandmann@daimi.au.dk> + */ + +#ifndef CAIRO_REGION_PRIVATE_H +#define CAIRO_REGION_PRIVATE_H + +#include "cairo-types-private.h" +#include "cairo-reference-count-private.h" + +#include <pixman.h> + +CAIRO_BEGIN_DECLS + +struct _cairo_region { + cairo_reference_count_t ref_count; + cairo_status_t status; + + pixman_region32_t rgn; +}; + +cairo_private void +_cairo_region_init (cairo_region_t *region); + +cairo_private void +_cairo_region_init_rectangle (cairo_region_t *region, + const cairo_rectangle_int_t *rectangle); + +cairo_private cairo_status_t +_cairo_region_init_rectangles (cairo_region_t *region, + const cairo_rectangle_int_t *rects, + int count); + +cairo_private void +_cairo_region_fini (cairo_region_t *region); + +CAIRO_END_DECLS + +#endif /* CAIRO_REGION_PRIVATE_H */ diff --git a/src/cairo-region.c b/src/cairo-region.c index 6dfa9332..d6fff7f7 100644 --- a/src/cairo-region.c +++ b/src/cairo-region.c @@ -38,7 +38,13 @@ #include "cairoint.h" +#include "cairo-region-private.h" + +/* XXX need to update pixman headers to be const as appropriate */ +#define CONST_CAST (pixman_region32_t *) + static const cairo_region_t _cairo_region_nil = { + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ CAIRO_STATUS_NO_MEMORY, /* status */ }; @@ -82,6 +88,7 @@ _cairo_region_init (cairo_region_t *region) VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t))); region->status = CAIRO_STATUS_SUCCESS; + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 0); pixman_region32_init (®ion->rgn); } @@ -92,6 +99,7 @@ _cairo_region_init_rectangle (cairo_region_t *region, VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t))); region->status = CAIRO_STATUS_SUCCESS; + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 0); pixman_region32_init_rect (®ion->rgn, rectangle->x, rectangle->y, rectangle->width, rectangle->height); @@ -100,6 +108,7 @@ _cairo_region_init_rectangle (cairo_region_t *region, void _cairo_region_fini (cairo_region_t *region) { + assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count)); pixman_region32_fini (®ion->rgn); VG (VALGRIND_MAKE_MEM_NOACCESS (region, sizeof (cairo_region_t))); } @@ -127,6 +136,7 @@ cairo_region_create (void) return (cairo_region_t *) &_cairo_region_nil; region->status = CAIRO_STATUS_SUCCESS; + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1); pixman_region32_init (®ion->rgn); @@ -134,29 +144,23 @@ cairo_region_create (void) } slim_hidden_def (cairo_region_create); -cairo_region_t * -cairo_region_create_rectangles (cairo_rectangle_int_t *rects, - int count) +cairo_status_t +_cairo_region_init_rectangles (cairo_region_t *region, + const cairo_rectangle_int_t *rects, + int count) { pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)]; pixman_box32_t *pboxes = stack_pboxes; - cairo_region_t *region; + cairo_status_t status; int i; - region = _cairo_malloc (sizeof (cairo_region_t)); - - if (!region) - return (cairo_region_t *)&_cairo_region_nil; - - region->status = CAIRO_STATUS_SUCCESS; + status = CAIRO_STATUS_SUCCESS; + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 0); if (count > ARRAY_LENGTH (stack_pboxes)) { pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t)); - - if (unlikely (pboxes == NULL)) { - free (region); - return (cairo_region_t *)&_cairo_region_nil; - } + if (unlikely (pboxes == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); } for (i = 0; i < count; i++) { @@ -166,15 +170,35 @@ cairo_region_create_rectangles (cairo_rectangle_int_t *rects, pboxes[i].y2 = rects[i].y + rects[i].height; } - if (! pixman_region32_init_rects (®ion->rgn, pboxes, count)) { - free (region); - - region = (cairo_region_t *)&_cairo_region_nil; - } + if (! pixman_region32_init_rects (®ion->rgn, pboxes, count)) + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); if (pboxes != stack_pboxes) free (pboxes); + return region->status = status; +} + +cairo_region_t * +cairo_region_create_rectangles (const cairo_rectangle_int_t *rects, + int count) +{ + cairo_region_t *region; + cairo_status_t status; + + region = _cairo_malloc (sizeof (cairo_region_t)); + if (unlikely (region == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_region_t *) &_cairo_region_nil; + } + + status = _cairo_region_init_rectangles (region, rects, count); + if (unlikely (status)) { + cairo_region_destroy (region); + return (cairo_region_t *) &_cairo_region_nil; + } + + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1); return region; } slim_hidden_def (cairo_region_create_rectangles); @@ -199,10 +223,11 @@ cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle) cairo_region_t *region; region = _cairo_malloc (sizeof (cairo_region_t)); - if (region == NULL) + if (unlikely (region == NULL)) return (cairo_region_t *) &_cairo_region_nil; region->status = CAIRO_STATUS_SUCCESS; + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1); pixman_region32_init_rect (®ion->rgn, rectangle->x, rectangle->y, @@ -227,18 +252,20 @@ slim_hidden_def (cairo_region_create_rectangle); * Since: 1.10 **/ cairo_region_t * -cairo_region_copy (cairo_region_t *original) +cairo_region_copy (const cairo_region_t *original) { cairo_region_t *copy; - if (original->status) + if (original != NULL && original->status) return (cairo_region_t *) &_cairo_region_nil; copy = cairo_region_create (); - if (copy->status) + if (unlikely (copy->status)) return copy; - if (! pixman_region32_copy (©->rgn, &original->rgn)) { + if (original != NULL && + ! pixman_region32_copy (©->rgn, CONST_CAST &original->rgn)) + { cairo_region_destroy (copy); return (cairo_region_t *) &_cairo_region_nil; } @@ -248,6 +275,31 @@ cairo_region_copy (cairo_region_t *original) slim_hidden_def (cairo_region_copy); /** + * cairo_region_reference: + * @region: a #cairo_region_t + * + * Increases the reference count on @region by one. This prevents + * @region from being destroyed until a matching call to + * cairo_region_destroy() is made. + * + * Return value: the referenced #cairo_region_t. + * + * Since: 1.10 + **/ +cairo_region_t * +cairo_region_reference (cairo_region_t *region) +{ + if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (®ion->ref_count)) + return NULL; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count)); + + _cairo_reference_count_inc (®ion->ref_count); + return region; +} +slim_hidden_def (cairo_region_reference); + +/** * cairo_region_destroy: * @region: a #cairo_region_t * @@ -260,10 +312,15 @@ slim_hidden_def (cairo_region_copy); void cairo_region_destroy (cairo_region_t *region) { - if (region == (cairo_region_t *) &_cairo_region_nil) + if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (®ion->ref_count)) return; - pixman_region32_fini (®ion->rgn); + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count)); + + if (! _cairo_reference_count_dec_and_test (®ion->ref_count)) + return; + + _cairo_region_fini (region); free (region); } slim_hidden_def (cairo_region_destroy); @@ -279,12 +336,12 @@ slim_hidden_def (cairo_region_destroy); * Since: 1.10 **/ int -cairo_region_num_rectangles (cairo_region_t *region) +cairo_region_num_rectangles (const cairo_region_t *region) { if (region->status) return 0; - return pixman_region32_n_rects (®ion->rgn); + return pixman_region32_n_rects (CONST_CAST ®ion->rgn); } slim_hidden_def (cairo_region_num_rectangles); @@ -299,7 +356,7 @@ slim_hidden_def (cairo_region_num_rectangles); * Since: 1.10 **/ void -cairo_region_get_rectangle (cairo_region_t *region, +cairo_region_get_rectangle (const cairo_region_t *region, int nth, cairo_rectangle_int_t *rectangle) { @@ -311,7 +368,7 @@ cairo_region_get_rectangle (cairo_region_t *region, return; } - pbox = pixman_region32_rectangles (®ion->rgn, NULL) + nth; + pbox = pixman_region32_rectangles (CONST_CAST ®ion->rgn, NULL) + nth; rectangle->x = pbox->x1; rectangle->y = pbox->y1; @@ -330,7 +387,7 @@ slim_hidden_def (cairo_region_get_rectangle); * Since: 1.10 **/ void -cairo_region_get_extents (cairo_region_t *region, +cairo_region_get_extents (const cairo_region_t *region, cairo_rectangle_int_t *extents) { pixman_box32_t *pextents; @@ -341,7 +398,7 @@ cairo_region_get_extents (cairo_region_t *region, return; } - pextents = pixman_region32_extents (®ion->rgn); + pextents = pixman_region32_extents (CONST_CAST ®ion->rgn); extents->x = pextents->x1; extents->y = pextents->y1; @@ -362,7 +419,7 @@ slim_hidden_def (cairo_region_get_extents); * Since: 1.10 **/ cairo_status_t -cairo_region_status (cairo_region_t *region) +cairo_region_status (const cairo_region_t *region) { return region->status; } @@ -564,12 +621,12 @@ slim_hidden_def (cairo_region_union_rectangle); * Since: 1.10 **/ cairo_bool_t -cairo_region_is_empty (cairo_region_t *region) +cairo_region_is_empty (const cairo_region_t *region) { if (region->status) return TRUE; - return ! pixman_region32_not_empty (®ion->rgn); + return ! pixman_region32_not_empty (CONST_CAST ®ion->rgn); } slim_hidden_def (cairo_region_is_empty); @@ -610,7 +667,7 @@ slim_hidden_def (cairo_region_translate); * Since: 1.10 **/ cairo_region_overlap_t -cairo_region_contains_rectangle (cairo_region_t *region, +cairo_region_contains_rectangle (const cairo_region_t *region, const cairo_rectangle_int_t *rectangle) { pixman_box32_t pbox; @@ -624,7 +681,8 @@ cairo_region_contains_rectangle (cairo_region_t *region, pbox.x2 = rectangle->x + rectangle->width; pbox.y2 = rectangle->y + rectangle->height; - poverlap = pixman_region32_contains_rectangle (®ion->rgn, &pbox); + poverlap = pixman_region32_contains_rectangle (CONST_CAST ®ion->rgn, + &pbox); switch (poverlap) { default: case PIXMAN_REGION_OUT: return CAIRO_REGION_OVERLAP_OUT; @@ -647,14 +705,44 @@ slim_hidden_def (cairo_region_contains_rectangle); * Since: 1.10 **/ cairo_bool_t -cairo_region_contains_point (cairo_region_t *region, +cairo_region_contains_point (const cairo_region_t *region, int x, int y) { pixman_box32_t box; - + if (region->status) return FALSE; - return pixman_region32_contains_point (®ion->rgn, x, y, &box); + return pixman_region32_contains_point (CONST_CAST ®ion->rgn, x, y, &box); } slim_hidden_def (cairo_region_contains_point); + +/** + * cairo_region_equal: + * @region_a: a #cairo_region_t + * @region_b: a #cairo_region_t + * + * Compares whether region_a is equivalent to region_b. + * + * Return value: %TRUE if both regions contained the same coverage, + * %FALSE if it is not. + * + * Since: 1.10 + **/ +cairo_bool_t +cairo_region_equal (const cairo_region_t *a, + const cairo_region_t *b) +{ + /* error objects are never equal */ + if ((a != NULL && a->status) || (b != NULL && b->status)) + return FALSE; + + if (a == b) + return TRUE; + + if (a == NULL || b == NULL) + return FALSE; + + return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn); +} +slim_hidden_def (cairo_region_equal); diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index 0510264b..bf5a4f73 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -1969,18 +1969,19 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font, } cairo_status_t -_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, - cairo_operator_t op, +_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, + cairo_operator_t op, const cairo_pattern_t *pattern, - cairo_surface_t *surface, - int source_x, - int source_y, - int dest_x, - int dest_y, - unsigned int width, - unsigned int height, - cairo_glyph_t *glyphs, - int num_glyphs) + cairo_surface_t *surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_region_t *clip_region) { cairo_status_t status; cairo_surface_t *mask = NULL; @@ -2008,7 +2009,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, source_x, source_y, dest_x, dest_y, width, height, - glyphs, num_glyphs, &remaining_glyphs); + glyphs, num_glyphs, + clip_region, + &remaining_glyphs); glyphs += num_glyphs - remaining_glyphs; num_glyphs = remaining_glyphs; if (remaining_glyphs == 0) @@ -2088,7 +2091,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, 0, 0, 0, 0, 0, 0, - width, height); + width, height, + NULL); _cairo_pattern_fini (&mask_pattern.base); @@ -2116,7 +2120,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, 0, 0, x - dest_x, y - dest_y, glyph_surface->width, - glyph_surface->height); + glyph_surface->height, + NULL); _cairo_pattern_fini (&glyph_pattern.base); @@ -2134,7 +2139,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, source_x, source_y, 0, 0, dest_x, dest_y, - width, height); + width, height, + clip_region); _cairo_pattern_fini (&mask_pattern.base); @@ -2148,58 +2154,6 @@ CLEANUP_MASK: return _cairo_scaled_font_set_error (scaled_font, status); } -typedef struct _cairo_scaled_glyph_path_closure { - cairo_point_t offset; - cairo_path_fixed_t *path; -} cairo_scaled_glyph_path_closure_t; - -static cairo_status_t -_scaled_glyph_path_move_to (void *abstract_closure, - const cairo_point_t *point) -{ - cairo_scaled_glyph_path_closure_t *closure = abstract_closure; - - return _cairo_path_fixed_move_to (closure->path, - point->x + closure->offset.x, - point->y + closure->offset.y); -} - -static cairo_status_t -_scaled_glyph_path_line_to (void *abstract_closure, - const cairo_point_t *point) -{ - cairo_scaled_glyph_path_closure_t *closure = abstract_closure; - - return _cairo_path_fixed_line_to (closure->path, - point->x + closure->offset.x, - point->y + closure->offset.y); -} - -static cairo_status_t -_scaled_glyph_path_curve_to (void *abstract_closure, - const cairo_point_t *p0, - const cairo_point_t *p1, - const cairo_point_t *p2) -{ - cairo_scaled_glyph_path_closure_t *closure = abstract_closure; - - return _cairo_path_fixed_curve_to (closure->path, - p0->x + closure->offset.x, - p0->y + closure->offset.y, - p1->x + closure->offset.x, - p1->y + closure->offset.y, - p2->x + closure->offset.x, - p2->y + closure->offset.y); -} - -static cairo_status_t -_scaled_glyph_path_close_path (void *abstract_closure) -{ - cairo_scaled_glyph_path_closure_t *closure = abstract_closure; - - return _cairo_path_fixed_close_path (closure->path); -} - /* Add a single-device-unit rectangle to a path. */ static cairo_status_t _add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y) @@ -2309,14 +2263,13 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, { cairo_status_t status; int i; - cairo_scaled_glyph_path_closure_t closure; + cairo_path_fixed_t glyph_path_static; cairo_path_fixed_t *glyph_path; status = scaled_font->status; if (unlikely (status)) return status; - closure.path = path; _cairo_scaled_font_freeze_cache (scaled_font); for (i = 0; i < num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; @@ -2325,14 +2278,12 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_PATH, &scaled_glyph); - if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_STATUS_SUCCESS) { glyph_path = scaled_glyph->path; - else if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto BAIL; - - /* If the font is incapable of providing a path, then we'll - * have to trace our own from a surface. */ - if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + /* If the font is incapable of providing a path, then we'll + * have to trace our own from a surface. + */ status = _cairo_scaled_glyph_lookup (scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_SURFACE, @@ -2340,31 +2291,22 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, if (unlikely (status)) goto BAIL; - glyph_path = _cairo_path_fixed_create (); - if (unlikely (glyph_path == NULL)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto BAIL; - } - + _cairo_path_fixed_init (&glyph_path_static); + glyph_path = &glyph_path_static; status = _trace_mask_to_path (scaled_glyph->surface, glyph_path); - if (unlikely (status)) { - _cairo_path_fixed_destroy (glyph_path); + if (unlikely (status)) goto BAIL; - } + } else { + goto BAIL; } - closure.offset.x = _cairo_fixed_from_double (glyphs[i].x); - closure.offset.y = _cairo_fixed_from_double (glyphs[i].y); + status = _cairo_path_fixed_append (path, + glyph_path, CAIRO_DIRECTION_FORWARD, + _cairo_fixed_from_double (glyphs[i].x), + _cairo_fixed_from_double (glyphs[i].y)); - status = _cairo_path_fixed_interpret (glyph_path, - CAIRO_DIRECTION_FORWARD, - _scaled_glyph_path_move_to, - _scaled_glyph_path_line_to, - _scaled_glyph_path_curve_to, - _scaled_glyph_path_close_path, - &closure); if (glyph_path != scaled_glyph->path) - _cairo_path_fixed_destroy (glyph_path); + _cairo_path_fixed_fini (glyph_path); if (unlikely (status)) goto BAIL; diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c index 059ef95b..fb1a4f8f 100644 --- a/src/cairo-script-surface.c +++ b/src/cairo-script-surface.c @@ -51,6 +51,10 @@ #include "cairo-list-private.h" #include "cairo-meta-surface-private.h" #include "cairo-output-stream-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-surface-wrapper-private.h" + +#include <ctype.h> #define _cairo_output_stream_puts(S, STR) \ _cairo_output_stream_write ((S), (STR), strlen (STR)) @@ -85,6 +89,7 @@ struct _cairo_script_vmcontext { cairo_list_t deferred; cairo_script_surface_font_private_t *fonts; + cairo_list_t defines; }; struct _cairo_script_surface_font_private { @@ -114,7 +119,10 @@ struct _cairo_script_implicit_context { struct _cairo_script_surface { cairo_surface_t base; + cairo_surface_wrapper_t wrapper; + cairo_script_vmcontext_t *ctx; + cairo_surface_clipper_t clipper; unsigned long id; cairo_list_t operand; @@ -131,7 +139,11 @@ static const cairo_surface_backend_t _cairo_script_surface_backend; static cairo_script_surface_t * _cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx, double width, - double height); + double height, + cairo_surface_t *passthrough); + +static cairo_status_t +_vmcontext_destroy (cairo_script_vmcontext_t *ctx); static void _cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font); @@ -637,9 +649,10 @@ _emit_dash (cairo_script_surface_t *surface, if (num_dashes) { surface->cr.current_style.dash = _cairo_realloc_ab - (surface->cr.current_style.dash, - num_dashes, - sizeof (double)); + (surface->cr.current_style.dash, num_dashes, sizeof (double)); + if (unlikely (surface->cr.current_style.dash == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + memcpy (surface->cr.current_style.dash, dash, sizeof (double) * num_dashes); } else { @@ -833,50 +846,46 @@ static cairo_status_t _emit_meta_surface_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { + cairo_script_implicit_context_t old_cr; cairo_surface_pattern_t *surface_pattern; - cairo_surface_t *source; - cairo_surface_t *null_surface; - cairo_surface_t *analysis_surface; + cairo_meta_surface_t *source; cairo_script_surface_t *similar; cairo_status_t status; cairo_box_t bbox; - int width, height; + cairo_rectangle_int_t rect; surface_pattern = (cairo_surface_pattern_t *) pattern; - source = surface_pattern->surface; + source = (cairo_meta_surface_t *) surface_pattern->surface; /* first measure the extents */ - null_surface = _cairo_null_surface_create (source->content); - analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1); - cairo_surface_destroy (null_surface); - - status = analysis_surface->status; - if (unlikely (status)) - return status; - - status = cairo_meta_surface_replay (source, analysis_surface); - _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox); - cairo_surface_destroy (analysis_surface); + status = _cairo_meta_surface_get_bbox (source, &bbox, NULL); if (unlikely (status)) return status; - width = _cairo_fixed_integer_ceil (bbox.p2.x - bbox.p1.x); - height = _cairo_fixed_integer_ceil (bbox.p2.y - bbox.p1.y); + /* convert to extents so that it matches the public api */ + _cairo_box_round_to_rectangle (&bbox, &rect); similar = _cairo_script_surface_create_internal (surface->ctx, - width, height); + rect.width, + rect.height, + NULL); if (unlikely (similar->base.status)) return similar->base.status; + cairo_surface_set_device_offset (&similar->base, -rect.x, -rect.y); _get_target (surface); _cairo_output_stream_printf (surface->ctx->stream, - "%u %u //%s similar dup context\n", - width, height, + "%d %d //%s similar dup context\n", + rect.width, rect.height, _content_to_string (source->content)); target_push (similar); - status = cairo_meta_surface_replay (source, &similar->base); + old_cr = surface->cr; + _cairo_script_implicit_context_init (&surface->cr); + status = cairo_meta_surface_replay (&source->base, &similar->base); + surface->cr = old_cr; + if (unlikely (status)) { cairo_surface_destroy (&similar->base); return status; @@ -1048,6 +1057,23 @@ _emit_png_surface (cairo_script_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +struct def { + cairo_script_vmcontext_t *ctx; + cairo_user_data_array_t *user_data; + unsigned int tag; + cairo_list_t link; +}; + +static void +_undef (void *data) +{ + struct def *def = data; + + cairo_list_del (&def->link); + _cairo_output_stream_printf (def->ctx->stream, "/s%u undef ", def->tag); + free (def); +} + static cairo_status_t _emit_image_surface (cairo_script_surface_t *surface, cairo_image_surface_t *image) @@ -1057,12 +1083,23 @@ _emit_image_surface (cairo_script_surface_t *surface, cairo_status_t status, status2; const uint8_t *mime_data; unsigned int mime_data_length; + struct def *tag; + + if (_cairo_user_data_array_get_data (&image->base.user_data, + (cairo_user_data_key_t *) surface->ctx)) + { + _cairo_output_stream_printf (surface->ctx->stream, + "s%u pattern ", + image->base.unique_id); + return CAIRO_STATUS_SUCCESS; + } status = _emit_png_surface (surface, image); if (_cairo_status_is_error (status)) { return status; } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) { cairo_image_surface_t *clone; + uint32_t len; if (image->format == CAIRO_FORMAT_INVALID) { clone = @@ -1078,14 +1115,34 @@ _emit_image_surface (cairo_script_surface_t *surface, "/width %d " "/height %d " "/format //%s " - "/source <~", + "/source ", clone->width, clone->height, _format_to_string (clone->format)); - if (clone->width * clone->height > 8) { + switch (clone->format) { + case CAIRO_FORMAT_A1: + len = (clone->width + 7)/8; + break; + case CAIRO_FORMAT_A8: + len = clone->width; + break; + case CAIRO_FORMAT_RGB24: + len = clone->width * 3; + break; + case CAIRO_FORMAT_ARGB32: + len = clone->width * 4; + break; + } + len *= clone->height; + + if (len > 24) { + _cairo_output_stream_puts (surface->ctx->stream, "<|"); + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); - zlib_stream = _cairo_deflate_stream_create (base85_stream); + _cairo_output_stream_write (base85_stream, &len, sizeof (len)); + + zlib_stream = _cairo_deflate_stream_create (base85_stream); status = _write_image_surface (zlib_stream, clone); status2 = _cairo_output_stream_destroy (zlib_stream); @@ -1096,23 +1153,42 @@ _emit_image_surface (cairo_script_surface_t *surface, status = status2; if (unlikely (status)) return status; - - _cairo_output_stream_puts (surface->ctx->stream, - " /deflate filter >> image "); } else { + _cairo_output_stream_puts (surface->ctx->stream, "<~"); + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); status = _write_image_surface (base85_stream, clone); status2 = _cairo_output_stream_destroy (base85_stream); if (status == CAIRO_STATUS_SUCCESS) status = status2; - - _cairo_output_stream_puts (surface->ctx->stream, - " >> image "); + if (unlikely (status)) + return status; } + _cairo_output_stream_puts (surface->ctx->stream, " >> image "); cairo_surface_destroy (&clone->base); } + tag = malloc (sizeof (*tag)); + if (unlikely (tag == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + tag->ctx = surface->ctx; + tag->tag = image->base.unique_id; + tag->user_data = &image->base.user_data; + cairo_list_add (&tag->link, &surface->ctx->defines); + status = _cairo_user_data_array_set_data (&image->base.user_data, + (cairo_user_data_key_t *) surface->ctx, + tag, _undef); + if (unlikely (status)) { + free (tag); + return status; + } + + _cairo_output_stream_printf (surface->ctx->stream, + "dup /s%u exch def ", + image->base.unique_id); + cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JPEG, &mime_data, &mime_data_length); if (mime_data != NULL) { @@ -1126,14 +1202,28 @@ _emit_image_surface (cairo_script_surface_t *surface, if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, - " set-mime-data\n"); + _cairo_output_stream_puts (surface->ctx->stream, " set-mime-data\n"); } - _cairo_output_stream_puts (surface->ctx->stream, - "pattern"); + cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JP2, + &mime_data, &mime_data_length); + if (mime_data != NULL) { + _cairo_output_stream_printf (surface->ctx->stream, + "\n (%s) <~", + CAIRO_MIME_TYPE_JP2); - return status; + base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); + status = _cairo_output_stream_destroy (base85_stream); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (surface->ctx->stream, " set-mime-data\n"); + } + + _cairo_output_stream_puts (surface->ctx->stream, "pattern"); + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -1141,22 +1231,17 @@ _emit_image_surface_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { cairo_surface_pattern_t *surface_pattern; - cairo_surface_t *source; cairo_image_surface_t *image; - void *image_extra; cairo_status_t status; + /* XXX keeping a copy is nasty, but we want to hook into the surface's + * lifetime. Using a snapshot is a convenient method. + */ surface_pattern = (cairo_surface_pattern_t *) pattern; - source = surface_pattern->surface; - - /* XXX snapshot-cow */ - status = _cairo_surface_acquire_source_image (source, &image, &image_extra); - if (unlikely (status)) - return status; - + image = (cairo_image_surface_t *) + _cairo_surface_snapshot (surface_pattern->surface); status = _emit_image_surface (surface, image); - - _cairo_surface_release_source_image (source, image, image_extra); + cairo_surface_destroy (&image->base); return status; } @@ -1249,6 +1334,9 @@ _emit_pattern (cairo_script_surface_t *surface, _extend_to_string (pattern->extend)); } + if (need_newline) + _cairo_output_stream_puts (surface->ctx->stream, "\n "); + return CAIRO_STATUS_SUCCESS; } @@ -1414,13 +1502,21 @@ _emit_path (cairo_script_surface_t *surface, } static cairo_status_t -_emit_matrix (cairo_script_surface_t *surface, - const cairo_matrix_t *ctm, - cairo_bool_t *matrix_updated) +_emit_scaling_matrix (cairo_script_surface_t *surface, + const cairo_matrix_t *ctm, + cairo_bool_t *matrix_updated) { + cairo_matrix_t current, ctm_scaling; + assert (target_is_active (surface)); - if (memcmp (&surface->cr.current_ctm, ctm, sizeof (cairo_matrix_t)) == 0) + current = surface->cr.current_ctm; + current.x0 = current.y0 = 0; + + ctm_scaling = *ctm; + ctm_scaling.x0 = ctm_scaling.y0 = 0; + + if (memcmp (¤t, &ctm_scaling, sizeof (cairo_matrix_t)) == 0) return CAIRO_STATUS_SUCCESS; *matrix_updated = TRUE; @@ -1475,11 +1571,11 @@ _cairo_script_surface_create_similar (void *abstract_surface, int width, int height) { - cairo_script_surface_t *surface, *other; + cairo_script_surface_t *surface, *other = abstract_surface; + cairo_surface_t *passthrough = NULL; cairo_script_vmcontext_t *ctx; cairo_status_t status; - other = abstract_surface; ctx = other->ctx; if (other->id == (unsigned long) -1) { @@ -1490,8 +1586,20 @@ _cairo_script_surface_create_similar (void *abstract_surface, target_push (other); } - surface = _cairo_script_surface_create_internal (ctx, width, height); - if (surface->base.status) + if (_cairo_surface_wrapper_is_active (&other->wrapper)) { + passthrough = + _cairo_surface_wrapper_create_similar (&other->wrapper, + content, width, height); + if (unlikely (passthrough->status)) + return passthrough; + } + + surface = _cairo_script_surface_create_internal (ctx, + width, height, + passthrough); + cairo_surface_destroy (passthrough); + + if (unlikely (surface->base.status)) return &surface->base; status = _bitmap_next_id (&ctx->surface_id, @@ -1527,6 +1635,16 @@ _vmcontext_destroy (cairo_script_vmcontext_t *ctx) _cairo_script_surface_scaled_font_fini (font->parent); } + while (! cairo_list_is_empty (&ctx->defines)) { + struct def *def = cairo_list_first_entry (&ctx->defines, + struct def, link); + + status = _cairo_user_data_array_set_data (def->user_data, + (cairo_user_data_key_t *) ctx, + NULL, NULL); + assert (status == CAIRO_STATUS_SUCCESS); + } + status = _cairo_output_stream_destroy (ctx->stream); free (ctx); @@ -1535,13 +1653,49 @@ _vmcontext_destroy (cairo_script_vmcontext_t *ctx) } static cairo_status_t +_cairo_script_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_script_surface_t *surface = abstract_surface; + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_acquire_source_image (&surface->wrapper, + image_out, + image_extra); + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static void +_cairo_script_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_script_surface_t *surface = abstract_surface; + + assert (_cairo_surface_wrapper_is_active (&surface->wrapper)); + _cairo_surface_wrapper_release_source_image (&surface->wrapper, + image, + image_extra); +} + +static cairo_status_t _cairo_script_surface_finish (void *abstract_surface) { cairo_script_surface_t *surface = abstract_surface; cairo_status_t status = CAIRO_STATUS_SUCCESS, status2; + _cairo_surface_wrapper_fini (&surface->wrapper); + + if (surface->cr.current_style.dash != NULL) { + free (surface->cr.current_style.dash); + surface->cr.current_style.dash = NULL; + } _cairo_pattern_fini (&surface->cr.current_source.base); _cairo_path_fixed_fini (&surface->cr.current_path); + _cairo_surface_clipper_reset (&surface->clipper); if (surface->id != (unsigned long) -1) { if (! surface->ctx->active) { @@ -1622,16 +1776,19 @@ _cairo_script_surface_show_page (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_script_surface_intersect_clip_path (void *abstract_surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_script_surface_t *surface = abstract_surface; +static cairo_status_t +_cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_script_surface_t *surface = cairo_container_of (clipper, + cairo_script_surface_t, + clipper); cairo_bool_t matrix_updated = FALSE; cairo_status_t status; + cairo_box_t box; status = _emit_context (surface); if (unlikely (status)) @@ -1645,6 +1802,18 @@ _cairo_script_surface_intersect_clip_path (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } + /* skip the trivial clip covering the surface extents */ + if (surface->width >=0 && surface->height >= 0 && + _cairo_path_fixed_is_rectangle (path, &box)) + { + if (box.p1.x <= 0 && box.p1.y <= 0 && + box.p2.x - box.p1.x >= _cairo_fixed_from_double (surface->width) && + box.p2.y - box.p1.y >= _cairo_fixed_from_double (surface->height)) + { + return CAIRO_STATUS_SUCCESS; + } + } + status = _emit_identity (surface, &matrix_updated); if (unlikely (status)) return status; @@ -1653,13 +1822,17 @@ _cairo_script_surface_intersect_clip_path (void *abstract_surface, if (unlikely (status)) return status; - status = _emit_tolerance (surface, tolerance, matrix_updated); - if (unlikely (status)) - return status; + if (! path->is_rectilinear) { + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + return status; + } - status = _emit_antialias (surface, antialias); - if (unlikely (status)) - return status; + if (! path->maybe_fill_region) { + status = _emit_antialias (surface, antialias); + if (unlikely (status)) + return status; + } status = _emit_path (surface, path); if (unlikely (status)) @@ -1721,18 +1894,18 @@ static cairo_int_status_t _cairo_script_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_status_t status; ctx_active (surface->ctx); - status = _emit_context (surface); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _emit_operator (surface, op); + status = _emit_context (surface); if (unlikely (status)) return status; @@ -1740,10 +1913,20 @@ _cairo_script_surface_paint (void *abstract_surface, if (unlikely (status)) return status; + status = _emit_operator (surface, op); + if (unlikely (status)) + return status; + _cairo_output_stream_puts (surface->ctx->stream, "paint\n"); ctx_inactive (surface->ctx); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_paint (&surface->wrapper, + op, source, clip); + } + return CAIRO_STATUS_SUCCESS; } @@ -1752,18 +1935,18 @@ _cairo_script_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_status_t status; ctx_active (surface->ctx); - status = _emit_context (surface); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _emit_operator (surface, op); + status = _emit_context (surface); if (unlikely (status)) return status; @@ -1771,14 +1954,30 @@ _cairo_script_surface_mask (void *abstract_surface, if (unlikely (status)) return status; - status = _emit_pattern (surface, mask); + status = _emit_operator (surface, op); if (unlikely (status)) return status; + if (_cairo_pattern_equal (source, mask)) { + _cairo_output_stream_puts (surface->ctx->stream, "/source get"); + } else { + status = _emit_pattern (surface, mask); + if (unlikely (status)) + return status; + } + + assert (surface->cr.current_operator == op); + _cairo_output_stream_puts (surface->ctx->stream, " mask\n"); ctx_inactive (surface->ctx); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_mask (&surface->wrapper, + op, source, mask, clip); + } + return CAIRO_STATUS_SUCCESS; } @@ -1792,7 +1991,7 @@ _cairo_script_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_bool_t matrix_updated = FALSE; @@ -1800,6 +1999,10 @@ _cairo_script_surface_stroke (void *abstract_surface, ctx_active (surface->ctx); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + status = _emit_context (surface); if (unlikely (status)) return status; @@ -1816,7 +2019,7 @@ _cairo_script_surface_stroke (void *abstract_surface, if (unlikely (status)) return status; - status = _emit_matrix (surface, ctm, &matrix_updated); + status = _emit_scaling_matrix (surface, ctm, &matrix_updated); if (unlikely (status)) return status; @@ -1828,9 +2031,11 @@ _cairo_script_surface_stroke (void *abstract_surface, if (unlikely (status)) return status; - status = _emit_tolerance (surface, tolerance, matrix_updated); - if (unlikely (status)) - return status; + if (! path->is_rectilinear) { + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + return status; + } status = _emit_antialias (surface, antialias); if (unlikely (status)) @@ -1839,6 +2044,16 @@ _cairo_script_surface_stroke (void *abstract_surface, _cairo_output_stream_puts (surface->ctx->stream, "stroke+\n"); ctx_inactive (surface->ctx); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_stroke (&surface->wrapper, + op, source, path, + style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + } + return CAIRO_STATUS_SUCCESS; } @@ -1850,7 +2065,7 @@ _cairo_script_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_bool_t matrix_updated = FALSE; @@ -1858,11 +2073,11 @@ _cairo_script_surface_fill (void *abstract_surface, ctx_active (surface->ctx); - status = _emit_context (surface); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _emit_operator (surface, op); + status = _emit_context (surface); if (unlikely (status)) return status; @@ -1878,21 +2093,39 @@ _cairo_script_surface_fill (void *abstract_surface, if (unlikely (status)) return status; - status = _emit_tolerance (surface, tolerance, matrix_updated); - if (unlikely (status)) - return status; + if (! path->is_rectilinear) { + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + return status; + } - status = _emit_antialias (surface, antialias); + if (! path->maybe_fill_region) { + status = _emit_antialias (surface, antialias); + if (unlikely (status)) + return status; + } + + status = _emit_path (surface, path); if (unlikely (status)) return status; - status = _emit_path (surface, path); + status = _emit_operator (surface, op); if (unlikely (status)) return status; _cairo_output_stream_puts (surface->ctx->stream, "fill+\n"); ctx_inactive (surface->ctx); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_fill (&surface->wrapper, + op, source, path, + fill_rule, + tolerance, + antialias, + clip); + } + return CAIRO_STATUS_SUCCESS; } @@ -2024,6 +2257,7 @@ _emit_type42_font (cairo_script_surface_t *surface, cairo_status_t status, status2; unsigned long size; unsigned int load_flags; + uint32_t len; uint8_t *buf; backend = scaled_font->backend; @@ -2049,13 +2283,15 @@ _emit_type42_font (cairo_script_surface_t *surface, _cairo_output_stream_printf (surface->ctx->stream, "<< " "/type 42 " - "/size %lu " "/index 0 " "/flags %d " - "/source <~", - size, load_flags); + "/source <|", + load_flags); base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + len = size; + _cairo_output_stream_write (base85_stream, &len, sizeof (len)); + zlib_stream = _cairo_deflate_stream_create (base85_stream); _cairo_output_stream_write (zlib_stream, buf, size); @@ -2071,7 +2307,6 @@ _emit_type42_font (cairo_script_surface_t *surface, font_private = scaled_font->surface_private; _cairo_output_stream_printf (surface->ctx->stream, - " /deflate filter" " >> font dup /f%lu exch def set-font-face\n", font_private->id); @@ -2146,7 +2381,7 @@ _emit_scaled_font (cairo_script_surface_t *surface, cairo_script_surface_font_private_t *font_private; cairo_scaled_font_get_ctm (scaled_font, &matrix); - status = _emit_matrix (surface, &matrix, &matrix_updated); + status = _emit_scaling_matrix (surface, &matrix, &matrix_updated); if (unlikely (status)) return status; @@ -2268,7 +2503,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) { _cairo_output_stream_printf (surface->ctx->stream, - " [%f %f %f %f %f %f] set-matrix\n", + "\n [%f %f %f %f %f %f] set-matrix\n", scaled_font->font_matrix.xx, scaled_font->font_matrix.yx, scaled_font->font_matrix.xy, @@ -2390,6 +2625,65 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface, return status; } +static void +_emit_string_literal (cairo_script_surface_t *surface, + const char *utf8, int len) +{ + char c; + const char *end; + + _cairo_output_stream_puts (surface->ctx->stream, "("); + + if (utf8 == NULL) { + end = utf8; + } else { + if (len < 0) + len = strlen (utf8); + end = utf8 + len; + } + + while (utf8 < end) { + switch ((c = *utf8++)) { + case '\n': + c = 'n'; + goto ESCAPED_CHAR; + case '\r': + c = 'r'; + goto ESCAPED_CHAR; + case '\t': + c = 't'; + goto ESCAPED_CHAR; + case '\b': + c = 'b'; + goto ESCAPED_CHAR; + case '\f': + c = 'f'; + goto ESCAPED_CHAR; + case '\\': + case '(': + case ')': +ESCAPED_CHAR: + _cairo_output_stream_printf (surface->ctx->stream, "\\%c", c); + break; + default: + if (isprint (c) || isspace (c)) { + _cairo_output_stream_printf (surface->ctx->stream, "%c", c); + } else { + int octal = 0; + while (c) { + octal *= 10; + octal += c&7; + c /= 8; + } + _cairo_output_stream_printf (surface->ctx->stream, + "\\%03d", octal); + } + break; + } + } + _cairo_output_stream_puts (surface->ctx->stream, ")"); +} + static cairo_int_status_t _cairo_script_surface_show_text_glyphs (void *abstract_surface, cairo_operator_t op, @@ -2402,7 +2696,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t backward, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; cairo_script_surface_font_private_t *font_private; @@ -2415,11 +2709,11 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, ctx_active (surface->ctx); - status = _emit_context (surface); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _emit_operator (surface, op); + status = _emit_context (surface); if (unlikely (status)) return status; @@ -2431,6 +2725,10 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, if (unlikely (status)) return status; + status = _emit_operator (surface, op); + if (unlikely (status)) + return status; + status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs); if (unlikely (status)) return status; @@ -2439,9 +2737,8 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, /* [cx cy [glyphs]] show_glyphs */ if (utf8 != NULL && clusters != NULL) { - _cairo_output_stream_printf (surface->ctx->stream, - "(%s) ", - utf8); + _emit_string_literal (surface, utf8, utf8_len); + _cairo_output_stream_puts (surface->ctx->stream, " "); } matrix = surface->cr.current_ctm; @@ -2597,24 +2894,41 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, } ctx_inactive (surface->ctx); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)){ + return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper, + op, source, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + backward, + scaled_font, + clip); + } + return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t +static cairo_bool_t _cairo_script_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { cairo_script_surface_t *surface = abstract_surface; + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_get_extents (&surface->wrapper, + rectangle); + } + if (surface->width < 0 || surface->height < 0) - return CAIRO_INT_STATUS_UNSUPPORTED; + return FALSE; rectangle->x = 0; rectangle->y = 0; rectangle->width = surface->width; rectangle->height = surface->height; - return CAIRO_STATUS_SUCCESS; + return TRUE; } static const cairo_surface_backend_t @@ -2622,8 +2936,8 @@ _cairo_script_surface_backend = { CAIRO_SURFACE_TYPE_SCRIPT, _cairo_script_surface_create_similar, _cairo_script_surface_finish, - NULL, //_cairo_script_surface_acquire_source_image, - NULL, //_cairo_script_surface_release_source_image, + _cairo_script_surface_acquire_source_image, + _cairo_script_surface_release_source_image, NULL, /* acquire_dest_image */ NULL, /* release_dest_image */ NULL, /* clone_similar */ @@ -2634,8 +2948,6 @@ _cairo_script_surface_backend = { NULL, /* check_span_renderer */ _cairo_script_surface_copy_page, _cairo_script_surface_show_page, - NULL, /* set_clip_region */ - _cairo_script_surface_intersect_clip_path, _cairo_script_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -2651,10 +2963,10 @@ _cairo_script_surface_backend = { _cairo_script_surface_fill, NULL, - NULL, //_cairo_script_surface_snapshot, + NULL, /* _cairo_script_surface_snapshot, */ NULL, /* is_similar */ - NULL, /* reset */ + /* XXX need fill-stroke for passthrough */ NULL, /* fill_stroke */ NULL, /* create_solid_pattern_surface */ NULL, /* can_repaint_solid_pattern_surface */ @@ -2686,6 +2998,8 @@ _cairo_script_vmcontext_create (cairo_output_stream_t *stream) ctx->stream = stream; ctx->mode = CAIRO_SCRIPT_MODE_ASCII; + cairo_list_init (&ctx->defines); + return ctx; } @@ -2711,7 +3025,8 @@ _cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr) static cairo_script_surface_t * _cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx, double width, - double height) + double height, + cairo_surface_t *passthrough) { cairo_script_surface_t *surface; @@ -2726,6 +3041,11 @@ _cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx, &_cairo_script_surface_backend, CAIRO_CONTENT_COLOR_ALPHA); + _cairo_surface_wrapper_init (&surface->wrapper, passthrough); + + _cairo_surface_clipper_init (&surface->clipper, + _cairo_script_surface_clipper_intersect_clip_path); + surface->ctx = ctx; ctx->ref++; @@ -2755,7 +3075,7 @@ cairo_script_surface_create (const char *filename, surface = _cairo_script_surface_create_internal - (_cairo_script_vmcontext_create (stream), width, height); + (_cairo_script_vmcontext_create (stream), width, height, NULL); if (surface->base.status) return &surface->base; @@ -2776,7 +3096,64 @@ cairo_script_surface_create_for_stream (cairo_write_func_t write_func, return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream)); return &_cairo_script_surface_create_internal - (_cairo_script_vmcontext_create (stream), width, height)->base; + (_cairo_script_vmcontext_create (stream), width, height, NULL)->base; +} + +cairo_surface_t * +cairo_script_surface_create_for_target (cairo_surface_t *target, + cairo_write_func_t write_func, + void *closure) +{ + cairo_output_stream_t *stream; + cairo_script_surface_t *surface; + cairo_rectangle_int_t extents; + + if (unlikely (target->status)) + return _cairo_surface_create_in_error (target->status); + + stream = _cairo_output_stream_create (write_func, NULL, closure); + if (_cairo_output_stream_get_status (stream)) + return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream)); + + if (! _cairo_surface_get_extents (target, &extents)) + extents.width = extents.height = -1; + + surface = _cairo_script_surface_create_internal + (_cairo_script_vmcontext_create (stream), + extents.width, extents.height, + target); + if (unlikely (surface->base.status)) + return &surface->base; + + _cairo_output_stream_puts (surface->ctx->stream, "%!CairoScript\n"); + return &surface->base; +} + +void +cairo_script_surface_write_comment (cairo_surface_t *abstract_surface, + const char *comment, + int len) +{ + cairo_script_surface_t *surface; + cairo_status_t status_ignored; + + if (! _cairo_surface_is_script (abstract_surface)) { + status_ignored = _cairo_surface_set_error (abstract_surface, + CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return; + } + + if (abstract_surface->status) + return; + + surface = (cairo_script_surface_t *) abstract_surface; + + if (len < 0) + len = strlen (comment); + + _cairo_output_stream_puts (surface->ctx->stream, "% "); + _cairo_output_stream_write (surface->ctx->stream, comment, len); + _cairo_output_stream_puts (surface->ctx->stream, "\n"); } void diff --git a/src/cairo-script.h b/src/cairo-script.h index 9c428e3b..397080bc 100644 --- a/src/cairo-script.h +++ b/src/cairo-script.h @@ -53,6 +53,16 @@ cairo_script_surface_create_for_stream (cairo_write_func_t write_func, double width, double height); +cairo_public cairo_surface_t * +cairo_script_surface_create_for_target (cairo_surface_t *surface, + cairo_write_func_t write_func, + void *closure); + +cairo_public void +cairo_script_surface_write_comment (cairo_surface_t *abstract_surface, + const char *comment, + int len); + typedef enum { CAIRO_SCRIPT_MODE_BINARY, CAIRO_SCRIPT_MODE_ASCII diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h index c285f949..c706b22a 100644 --- a/src/cairo-spans-private.h +++ b/src/cairo-spans-private.h @@ -132,13 +132,14 @@ _cairo_span_renderer_set_error (void *abstract_renderer, cairo_status_t error); cairo_private cairo_status_t -_cairo_path_fixed_fill_using_spans ( - cairo_operator_t op, - const cairo_pattern_t *pattern, - cairo_path_fixed_t *path, - cairo_surface_t *dst, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_composite_rectangles_t *rects); +_cairo_path_fixed_fill_using_spans (cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_path_fixed_t *path, + cairo_surface_t *dst, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects, + cairo_region_t *clip_region); + #endif /* CAIRO_SPANS_PRIVATE_H */ diff --git a/src/cairo-spans.c b/src/cairo-spans.c index cf8f7677..48396b54 100644 --- a/src/cairo-spans.c +++ b/src/cairo-spans.c @@ -149,19 +149,19 @@ _create_scan_converter (cairo_fill_rule_t fill_rule, } cairo_status_t -_cairo_path_fixed_fill_using_spans ( - cairo_operator_t op, - const cairo_pattern_t *pattern, - cairo_path_fixed_t *path, - cairo_surface_t *dst, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, - const cairo_composite_rectangles_t *rects) +_cairo_path_fixed_fill_using_spans (cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_path_fixed_t *path, + cairo_surface_t *dst, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects, + cairo_region_t *clip_region) { cairo_status_t status; cairo_span_renderer_t *renderer = _cairo_surface_create_span_renderer ( - op, pattern, dst, antialias, rects); + op, pattern, dst, antialias, rects, clip_region); cairo_scan_converter_t *converter = _create_scan_converter ( fill_rule, antialias, rects); diff --git a/src/cairo-stroke-style.c b/src/cairo-stroke-style.c index 9ab91e53..38518838 100644 --- a/src/cairo-stroke-style.c +++ b/src/cairo-stroke-style.c @@ -110,13 +110,13 @@ _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style, style_expansion = M_SQRT1_2; if (style->line_join == CAIRO_LINE_JOIN_MITER && - style_expansion < style->miter_limit) + style_expansion < M_SQRT2 * style->miter_limit) { - style_expansion = style->miter_limit; + style_expansion = M_SQRT2 * style->miter_limit; } style_expansion *= style->line_width; - *dx = style_expansion * (fabs (ctm->xx) + fabs (ctm->xy)); - *dy = style_expansion * (fabs (ctm->yy) + fabs (ctm->yx)); + *dx = style_expansion * hypot (ctm->xx, ctm->xy); + *dy = style_expansion * hypot (ctm->yy, ctm->yx); } diff --git a/src/cairo-surface-clipper-private.h b/src/cairo-surface-clipper-private.h new file mode 100644 index 00000000..f3d9de18 --- /dev/null +++ b/src/cairo-surface-clipper-private.h @@ -0,0 +1,72 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.u> + */ + +#ifndef CAIRO_SURFACE_CLIPPER_PRIVATE_H +#define CAIRO_SURFACE_CLIPPER_PRIVATE_H + +#include "cairo-types-private.h" +#include "cairo-clip-private.h" + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_surface_clipper cairo_surface_clipper_t; + +typedef cairo_status_t +(*cairo_surface_clipper_intersect_clip_path_func_t) (cairo_surface_clipper_t *, + cairo_path_fixed_t *, + cairo_fill_rule_t, + double, + cairo_antialias_t); +struct _cairo_surface_clipper { + cairo_clip_t clip; + cairo_bool_t is_clipped; + cairo_surface_clipper_intersect_clip_path_func_t intersect_clip_path; +}; + +cairo_private cairo_status_t +_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper, + cairo_clip_t *clip); + +cairo_private void +_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper, + cairo_surface_clipper_intersect_clip_path_func_t intersect); + +cairo_private void +_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper); + +CAIRO_END_DECLS + +#endif /* CAIRO_SURFACE_CLIPPER_PRIVATE_H */ diff --git a/src/cairo-surface-clipper.c b/src/cairo-surface-clipper.c new file mode 100644 index 00000000..d536f0cb --- /dev/null +++ b/src/cairo-surface-clipper.c @@ -0,0 +1,138 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairoint.h" + +#include "cairo-surface-clipper-private.h" + +/* A collection of routines to facilitate vector surface clipping */ + +static cairo_status_t +_cairo_surface_clipper_intersect_clip_path_recursive (cairo_surface_clipper_t *clipper, + cairo_clip_path_t *clip_path) +{ + cairo_status_t status; + + if (clip_path->prev != NULL) { + status = + _cairo_surface_clipper_intersect_clip_path_recursive (clipper, + clip_path->prev); + if (unlikely (status)) + return status; + } + + return clipper->intersect_clip_path (clipper, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias); +} + +cairo_status_t +_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_bool_t clear; + + /* XXX as we cache a reference to the path, and compare every time, + * we may in future need to install a notification if the clip->path + * is every modified (e.g. cairo_clip_translate). + */ + + if (clip == NULL && clipper->clip.path == NULL) + return CAIRO_STATUS_SUCCESS; + + if (clip != NULL && clip->path == clipper->clip.path) + return CAIRO_STATUS_SUCCESS; + + if (clip != NULL && clipper->clip.path != NULL && + _cairo_path_fixed_equal (&clip->path->path, &clipper->clip.path->path)) + { + return CAIRO_STATUS_SUCCESS; + } + + /* all clipped out state should never propagate this far */ + assert (clip == NULL || clip->path != NULL); + + /* Check whether this clip is a continuation of the previous. + * If not, we have to remove the current clip and rebuild. + */ + clear = clip == NULL || clip->path->prev != clipper->clip.path; + + _cairo_clip_reset (&clipper->clip); + _cairo_clip_init_copy (&clipper->clip, clip); + + if (clear) { + clipper->is_clipped = FALSE; + status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0); + if (unlikely (status)) + return status; + + if (clip != NULL && clip->path != NULL) { + status = + _cairo_surface_clipper_intersect_clip_path_recursive (clipper, + clip->path); + clipper->is_clipped = TRUE; + } + } else { + cairo_clip_path_t *path = clip->path; + + clipper->is_clipped = TRUE; + status = clipper->intersect_clip_path (clipper, + &path->path, + path->fill_rule, + path->tolerance, + path->antialias); + } + + return status; +} + +void +_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper, + cairo_surface_clipper_intersect_clip_path_func_t func) +{ + _cairo_clip_init (&clipper->clip); + clipper->is_clipped = FALSE; + clipper->intersect_clip_path = func; +} + +void +_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper) +{ + _cairo_clip_reset (&clipper->clip); + clipper->is_clipped = FALSE; +} diff --git a/src/cairo-surface-fallback-private.h b/src/cairo-surface-fallback-private.h index cd181780..236b7459 100644 --- a/src/cairo-surface-fallback-private.h +++ b/src/cairo-surface-fallback-private.h @@ -44,13 +44,15 @@ cairo_private cairo_status_t _cairo_surface_fallback_paint (cairo_surface_t *surface, cairo_operator_t op, - const cairo_pattern_t *source); + const cairo_pattern_t *source, + cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fallback_mask (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask); + const cairo_pattern_t *mask, + cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fallback_stroke (cairo_surface_t *surface, @@ -61,7 +63,8 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias); + cairo_antialias_t antialias, + cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fallback_fill (cairo_surface_t *surface, @@ -70,7 +73,8 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias); + cairo_antialias_t antialias, + cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, @@ -78,7 +82,8 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, - cairo_scaled_font_t *scaled_font); + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip); cairo_private cairo_surface_t * _cairo_surface_fallback_snapshot (cairo_surface_t *surface); @@ -95,7 +100,8 @@ _cairo_surface_fallback_composite (cairo_operator_t op, int dst_x, int dst_y, unsigned int width, - unsigned int height); + unsigned int height, + cairo_region_t *clip_region); cairo_private cairo_status_t _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface, @@ -116,7 +122,8 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int num_traps); + int num_traps, + cairo_region_t *clip_region); cairo_private cairo_status_t _cairo_surface_fallback_clone_similar (cairo_surface_t *surface, diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index 830c1b3d..9867eea8 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -40,6 +40,7 @@ #include "cairo-surface-fallback-private.h" #include "cairo-clip-private.h" +#include "cairo-region-private.h" typedef struct { cairo_surface_t *dst; @@ -82,13 +83,13 @@ _fallback_init (fallback_state_t *state, if (unlikely (status)) return status; + /* XXX: This NULL value tucked away in state->image is a rather * ugly interface. Cleaner would be to push the * CAIRO_INT_STATUS_NOTHING_TO_DO value down into * _cairo_surface_acquire_dest_image and its backend * counterparts. */ - if (state->image == NULL) - return CAIRO_INT_STATUS_NOTHING_TO_DO; + assert (state->image != NULL); return CAIRO_STATUS_SUCCESS; } @@ -101,46 +102,85 @@ _fallback_fini (fallback_state_t *state) state->image_extra); } -typedef cairo_status_t (*cairo_draw_func_t) (void *closure, - cairo_operator_t op, - const cairo_pattern_t *src, - cairo_surface_t *dst, - int dst_x, - int dst_y, - const cairo_rectangle_int_t *extents); +typedef cairo_status_t +(*cairo_draw_func_t) (void *closure, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region); static cairo_status_t _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern, cairo_clip_t *clip, - cairo_draw_func_t draw_func, + cairo_draw_func_t draw_func, void *draw_closure, cairo_surface_t *dst, const cairo_rectangle_int_t *extents) { cairo_surface_t *mask; + cairo_region_t *clip_region = NULL; + cairo_solid_pattern_t solid; cairo_status_t status; + cairo_bool_t clip_surface = FALSE; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + assert (! _cairo_status_is_error (status)); + + clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; + + if (clip_region && cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; + } - mask = cairo_surface_create_similar (dst, - CAIRO_CONTENT_ALPHA, - extents->width, - extents->height); - if (mask->status) + /* We need to use solid here, because to use CAIRO_OPERATOR_SOURCE with + * a mask (as called via _cairo_surface_mask) triggers assertion failures. + */ + mask = _cairo_surface_create_similar_solid (dst, + CAIRO_CONTENT_ALPHA, + extents->width, + extents->height, + CAIRO_COLOR_TRANSPARENT, + TRUE); + if (unlikely (mask->status)) return mask->status; - status = (*draw_func) (draw_closure, CAIRO_OPERATOR_ADD, - NULL, mask, - extents->x, extents->y, - extents); + _cairo_pattern_init_solid (&solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_ALPHA); + status = draw_func (draw_closure, CAIRO_OPERATOR_ADD, + &solid.base, mask, + extents->x, extents->y, + extents, + clip_region); if (unlikely (status)) goto CLEANUP_SURFACE; - if (clip && clip->surface) - status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN, - mask, - extents->x, extents->y, - extents); - if (unlikely (status)) - goto CLEANUP_SURFACE; + if (clip_surface) { + cairo_surface_pattern_t pattern; + cairo_surface_t *surface; + + surface = _cairo_clip_get_surface (clip, mask); + _cairo_pattern_init_for_surface (&pattern, surface); + cairo_surface_destroy (surface); + + status = _cairo_surface_composite (CAIRO_OPERATOR_IN, + &pattern.base, + NULL, + mask, + extents->x - clip->path->extents.x, + extents->y - clip->path->extents.y, + 0, 0, + 0, 0, + extents->width, extents->height, + NULL); + + _cairo_pattern_fini (&pattern.base); + + if (unlikely (status)) + goto CLEANUP_SURFACE; + } _cairo_pattern_init_for_surface (mask_pattern, mask); @@ -169,17 +209,17 @@ _clip_and_composite_with_mask (cairo_clip_t *clip, clip, draw_func, draw_closure, dst, extents); - if (unlikely (status)) - return status; - - status = _cairo_surface_composite (op, - src, &mask_pattern.base, dst, - extents->x, extents->y, - 0, 0, - extents->x, extents->y, - extents->width, extents->height); - - _cairo_pattern_fini (&mask_pattern.base); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _cairo_surface_composite (op, + src, &mask_pattern.base, dst, + extents->x, extents->y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height, + NULL); + + _cairo_pattern_fini (&mask_pattern.base); + } return status; } @@ -197,77 +237,95 @@ _clip_and_composite_combine (cairo_clip_t *clip, const cairo_rectangle_int_t *extents) { cairo_surface_t *intermediate; - cairo_surface_pattern_t dst_pattern; - cairo_surface_pattern_t intermediate_pattern; + cairo_surface_pattern_t pattern; + cairo_surface_pattern_t clip_pattern; + cairo_surface_t *clip_surface; cairo_status_t status; /* We'd be better off here creating a surface identical in format * to dst, but we have no way of getting that information. * A CAIRO_CONTENT_CLONE or something might be useful. - * cairo_surface_create_similar() also unnecessarily clears the surface. */ - intermediate = cairo_surface_create_similar (dst, - CAIRO_CONTENT_COLOR_ALPHA, - extents->width, - extents->height); - if (intermediate->status) + intermediate = + _cairo_surface_create_similar_scratch (dst, + CAIRO_CONTENT_COLOR_ALPHA, + extents->width, + extents->height); + if (intermediate == NULL) { + intermediate = + _cairo_image_surface_create_with_content (CAIRO_CONTENT_COLOR_ALPHA, + extents->width, + extents->width); + } + if (unlikely (intermediate->status)) return intermediate->status; - /* Initialize the intermediate surface from the destination surface - */ - _cairo_pattern_init_for_surface (&dst_pattern, dst); - + /* Initialize the intermediate surface from the destination surface */ + _cairo_pattern_init_for_surface (&pattern, dst); status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, - &dst_pattern.base, NULL, intermediate, + &pattern.base, NULL, intermediate, extents->x, extents->y, 0, 0, 0, 0, - extents->width, extents->height); - - _cairo_pattern_fini (&dst_pattern.base); - + extents->width, extents->height, + NULL); + _cairo_pattern_fini (&pattern.base); if (unlikely (status)) goto CLEANUP_SURFACE; status = (*draw_func) (draw_closure, op, src, intermediate, extents->x, extents->y, - extents); + extents, + NULL); if (unlikely (status)) goto CLEANUP_SURFACE; - /* Combine that with the clip - */ - status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_IN, - intermediate, - extents->x, extents->y, - extents); - if (unlikely (status)) + assert (clip->path != NULL); + clip_surface = _cairo_clip_get_surface (clip, dst); + if (unlikely (clip_surface->status)) goto CLEANUP_SURFACE; - /* Punch the clip out of the destination - */ - status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_OUT, - dst, - 0, 0, - extents); + _cairo_pattern_init_for_surface (&clip_pattern, clip_surface); + cairo_surface_destroy (clip_surface); + + /* Combine that with the clip */ + status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_IN, + &clip_pattern.base, NULL, intermediate, + extents->x - clip->path->extents.x, + extents->y - clip->path->extents.y, + 0, 0, + 0, 0, + extents->width, extents->height, + NULL); if (unlikely (status)) goto CLEANUP_SURFACE; - /* Now add the two results together - */ - _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); + /* Punch the clip out of the destination */ + status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT, + &clip_pattern.base, NULL, dst, + extents->x - clip->path->extents.x, + extents->y - clip->path->extents.y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height, + NULL); + if (unlikely (status)) + goto CLEANUP_SURFACE; + /* Now add the two results together */ + _cairo_pattern_init_for_surface (&pattern, intermediate); status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, - &intermediate_pattern.base, NULL, dst, + &pattern.base, NULL, dst, 0, 0, 0, 0, extents->x, extents->y, - extents->width, extents->height); - - _cairo_pattern_fini (&intermediate_pattern.base); + extents->width, extents->height, + NULL); + _cairo_pattern_fini (&pattern.base); CLEANUP_SURFACE: + _cairo_pattern_fini (&clip_pattern.base); cairo_surface_destroy (intermediate); return status; @@ -285,10 +343,10 @@ _clip_and_composite_source (cairo_clip_t *clip, const cairo_rectangle_int_t *extents) { cairo_surface_pattern_t mask_pattern; + cairo_region_t *clip_region = NULL; cairo_status_t status; - /* Create a surface that is mask IN clip - */ + /* Create a surface that is mask IN clip */ status = _create_composite_mask_pattern (&mask_pattern, clip, draw_func, draw_closure, @@ -296,26 +354,35 @@ _clip_and_composite_source (cairo_clip_t *clip, if (unlikely (status)) return status; - /* Compute dest' = dest OUT (mask IN clip) - */ + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + assert (! _cairo_status_is_error (status)); + + /* a solitary clip rectangle is already accommodated by extents */ + if (clip_region && cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; + } + + /* Compute dest' = dest OUT (mask IN clip) */ status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT, &mask_pattern.base, NULL, dst, 0, 0, 0, 0, extents->x, extents->y, - extents->width, extents->height); + extents->width, extents->height, + clip_region); if (unlikely (status)) goto CLEANUP_MASK_PATTERN; - /* Now compute (src IN (mask IN clip)) ADD dest' - */ + /* Now compute (src IN (mask IN clip)) ADD dest' */ status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, src, &mask_pattern.base, dst, extents->x, extents->y, 0, 0, extents->x, extents->y, - extents->width, extents->height); + extents->width, extents->height, + clip_region); CLEANUP_MASK_PATTERN: _cairo_pattern_fini (&mask_pattern.base); @@ -372,30 +439,45 @@ _clip_and_composite (cairo_clip_t *clip, op = CAIRO_OPERATOR_DEST_OUT; } - if ((clip && clip->surface) || op == CAIRO_OPERATOR_SOURCE) - { - if (op == CAIRO_OPERATOR_SOURCE) - status = _clip_and_composite_source (clip, - src, - draw_func, draw_closure, - dst, extents); - else if (_cairo_operator_bounded_by_mask (op)) - status = _clip_and_composite_with_mask (clip, op, - src, - draw_func, draw_closure, - dst, extents); - else - status = _clip_and_composite_combine (clip, op, - src, - draw_func, draw_closure, - dst, extents); - } - else - { - status = (*draw_func) (draw_closure, op, - src, dst, - 0, 0, - extents); + if (op == CAIRO_OPERATOR_SOURCE) { + status = _clip_and_composite_source (clip, + src, + draw_func, draw_closure, + dst, extents); + } else { + cairo_bool_t clip_surface = FALSE; + cairo_region_t *clip_region = NULL; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + assert (! _cairo_status_is_error (status)); + + clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (clip_surface) { + if (_cairo_operator_bounded_by_mask (op)) { + status = _clip_and_composite_with_mask (clip, op, + src, + draw_func, draw_closure, + dst, extents); + } else { + status = _clip_and_composite_combine (clip, op, + src, + draw_func, draw_closure, + dst, extents); + } + } else { + /* a solitary clip rectangle is already accommodated by extents */ + if (clip_region && cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; + + status = draw_func (draw_closure, op, + src, dst, + 0, 0, + extents, + clip_region); + } } return status; @@ -409,59 +491,51 @@ _composite_trap_region (cairo_clip_t *clip, cairo_operator_t op, cairo_surface_t *dst, cairo_region_t *trap_region, - cairo_rectangle_int_t *extents) + const cairo_rectangle_int_t *extents) { cairo_status_t status; cairo_solid_pattern_t solid_pattern; - cairo_surface_pattern_t mask; - int num_rects = cairo_region_num_rectangles (trap_region); - unsigned int clip_serial; - cairo_surface_t *clip_surface = clip ? clip->surface : NULL; + cairo_surface_pattern_t mask_pattern; + cairo_pattern_t *mask = NULL; + int mask_x = 0, mask_y =0; + + if (clip != NULL) { + cairo_surface_t *clip_surface = NULL; + const cairo_rectangle_int_t *clip_extents; + + clip_surface = _cairo_clip_get_surface (clip, dst); + if (unlikely (clip_surface->status)) + return clip_surface->status; + + if (op == CAIRO_OPERATOR_CLEAR) { + _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE, + CAIRO_CONTENT_COLOR); + src = &solid_pattern.base; + op = CAIRO_OPERATOR_DEST_OUT; + } - if (num_rects == 0) - return CAIRO_STATUS_SUCCESS; + _cairo_pattern_init_for_surface (&mask_pattern, clip_surface); + cairo_surface_destroy (clip_surface); - if (clip_surface && op == CAIRO_OPERATOR_CLEAR) { - _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - src = &solid_pattern.base; - op = CAIRO_OPERATOR_DEST_OUT; + clip_extents = _cairo_clip_get_extents (clip); + mask_x = extents->x - clip_extents->x; + mask_y = extents->y - clip_extents->y; + mask = &mask_pattern.base; } - if (num_rects > 1) { - if (_cairo_surface_get_clip_mode (dst) != CAIRO_CLIP_MODE_REGION) - return CAIRO_INT_STATUS_UNSUPPORTED; - - clip_serial = _cairo_surface_allocate_clip_serial (dst); - status = _cairo_surface_set_clip_region (dst, - trap_region, - clip_serial); - if (unlikely (status)) - return status; - } + /* reduce a solitary clipping region to the extents */ + if (cairo_region_num_rectangles (trap_region) == 1) + trap_region = NULL; - if (clip_surface) - _cairo_pattern_init_for_surface (&mask, clip_surface); - - status = _cairo_surface_composite (op, - src, - clip_surface ? &mask.base : NULL, - dst, + status = _cairo_surface_composite (op, src, mask, dst, extents->x, extents->y, - extents->x - (clip_surface ? clip->surface_rect.x : 0), - extents->y - (clip_surface ? clip->surface_rect.y : 0), + mask_x, mask_y, extents->x, extents->y, - extents->width, extents->height); - - /* Restore the original clip if we modified it temporarily. */ - if (num_rects > 1) { - cairo_status_t status2 = _cairo_surface_set_clip (dst, clip); - if (status == CAIRO_STATUS_SUCCESS) - status = status2; - } + extents->width, extents->height, + trap_region); - if (clip_surface) - _cairo_pattern_fini (&mask.base); + if (mask != NULL) + _cairo_pattern_fini (mask); return status; } @@ -478,183 +552,211 @@ _composite_traps_draw_func (void *closure, cairo_surface_t *dst, int dst_x, int dst_y, - const cairo_rectangle_int_t *extents) + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) { cairo_composite_traps_info_t *info = closure; - cairo_solid_pattern_t pattern; if (dst_x != 0 || dst_y != 0) _cairo_traps_translate (info->traps, - dst_x, - dst_y); - if (src == NULL) { - _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - src = &pattern.base; - } - return _cairo_surface_composite_trapezoids (op, src, dst, info->antialias, extents->x, extents->y, extents->x - dst_x, extents->y - dst_y, extents->width, extents->height, info->traps->traps, - info->traps->num_traps); + info->traps->num_traps, + clip_region); } -/* Warning: This call modifies the coordinates of traps */ +enum { + HAS_CLEAR_REGION = 0x1, +}; + static cairo_status_t -_clip_and_composite_trapezoids (const cairo_pattern_t *src, - cairo_operator_t op, - cairo_surface_t *dst, - cairo_traps_t *traps, - cairo_clip_t *clip, - cairo_antialias_t antialias) +_clip_and_composite_region (const cairo_pattern_t *src, + cairo_operator_t op, + cairo_surface_t *dst, + cairo_region_t *trap_region, + cairo_antialias_t antialias, + cairo_clip_t *clip, + cairo_rectangle_int_t *extents) { + cairo_region_t clear_region; + cairo_bool_t clip_surface = FALSE; + unsigned int has_region = 0; cairo_status_t status; - cairo_region_t *trap_region = NULL; - cairo_region_t *clear_region = NULL; - cairo_rectangle_int_t extents; - cairo_composite_traps_info_t traps_info; - if (_cairo_operator_bounded_by_mask (op) && traps->num_traps == 0) - return CAIRO_STATUS_SUCCESS; + if (clip != NULL) { + cairo_region_t *clip_region; - status = _cairo_surface_get_extents (dst, &extents); - if (unlikely (status)) - return status; + status = _cairo_clip_get_region (clip, &clip_region); + assert (! _cairo_status_is_error (status)); - status = _cairo_traps_extract_region (traps, &trap_region); - if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; + } if (_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_int_t trap_extents; - if (trap_region) { - status = _cairo_clip_intersect_to_region (clip, trap_region); + cairo_region_get_extents (trap_region, &trap_extents); + if (! _cairo_rectangle_intersect (extents, &trap_extents)) + return CAIRO_STATUS_SUCCESS; + } else { + if (! clip_surface) { + /* If we optimize drawing with an unbounded operator to + * _cairo_surface_fill_rectangles() or to drawing with a + * clip region, then we have an additional region to clear. + */ + _cairo_region_init_rectangle (&clear_region, extents); + status = cairo_region_subtract (&clear_region, trap_region); if (unlikely (status)) - goto out; + return status; - cairo_region_get_extents (trap_region, &trap_extents); - } else { - cairo_box_t trap_box; - _cairo_traps_extents (traps, &trap_box); - _cairo_box_round_to_rectangle (&trap_box, &trap_extents); + if (! cairo_region_is_empty (&clear_region)) + has_region |= HAS_CLEAR_REGION; } + } - if (! _cairo_rectangle_intersect (&extents, &trap_extents)) { - status = CAIRO_STATUS_SUCCESS; - goto out; - } + if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) && + ! clip_surface) + { + const cairo_color_t *color; - status = _cairo_clip_intersect_to_rectangle (clip, &extents); - if (unlikely (status)) - goto out; + if (op == CAIRO_OPERATOR_CLEAR) + color = CAIRO_COLOR_TRANSPARENT; + else + color = &((cairo_solid_pattern_t *)src)->color; + + /* Solid rectangles special case */ + status = _cairo_surface_fill_region (dst, op, color, trap_region); } else { - cairo_surface_t *clip_surface = clip ? clip->surface : NULL; + /* For a simple rectangle, we can just use composite(), for more + * rectangles, we have to set a clip region. The cost of rasterizing + * trapezoids is pretty high for most backends currently, so it's + * worthwhile even if a region is needed. + * + * If we have a clip surface, we set it as the mask; this only works + * for bounded operators other than SOURCE; for unbounded operators, + * clip and mask cannot be interchanged. For SOURCE, the operator + * as implemented by the backends is different in its handling + * of the mask then what we want. + * + * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has + * more than rectangle and the destination doesn't support clip + * regions. In that case, we fall through. + */ + status = _composite_trap_region (clip_surface ? clip : NULL, + src, op, dst, + trap_region, extents); + } - if (trap_region && !clip_surface) { - /* If we optimize drawing with an unbounded operator to - * _cairo_surface_fill_rectangles() or to drawing with a - * clip region, then we have an additional region to clear. - */ - clear_region = cairo_region_create_rectangle (&extents); + if (has_region & HAS_CLEAR_REGION) { + if (status == CAIRO_STATUS_SUCCESS) { + status = _cairo_surface_fill_region (dst, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &clear_region); + } + _cairo_region_fini (&clear_region); + } - status = cairo_region_status (clear_region); - if (unlikely (status)) - goto out; + return status; +} - status = _cairo_clip_intersect_to_region (clip, clear_region); - if (unlikely (status)) - goto out; +/* Warning: This call modifies the coordinates of traps */ +static cairo_status_t +_clip_and_composite_trapezoids (const cairo_pattern_t *src, + cairo_operator_t op, + cairo_surface_t *dst, + cairo_traps_t *traps, + cairo_antialias_t antialias, + cairo_clip_t *clip, + cairo_rectangle_int_t *extents) +{ + cairo_composite_traps_info_t traps_info; + cairo_region_t *clip_region = NULL; + cairo_bool_t clip_surface = FALSE; + cairo_status_t status; - cairo_region_get_extents (clear_region, &extents); + if (_cairo_operator_bounded_by_mask (op) && traps->num_traps == 0) + return CAIRO_STATUS_SUCCESS; - status = cairo_region_subtract (clear_region, trap_region); - if (unlikely (status)) - goto out; - - if (cairo_region_is_empty (clear_region)) { - cairo_region_destroy (clear_region); - clear_region = NULL; - } - } else { - status = _cairo_clip_intersect_to_rectangle (clip, &extents); - } - } + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + if (unlikely (_cairo_status_is_error (status))) + return status; - if (unlikely (status)) - goto out; + /* The all-clipped state should not have been propagated this far. */ + assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO); + clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; + } - if (trap_region) { - cairo_surface_t *clip_surface = clip ? clip->surface : NULL; + /* Use a fast path if the trapezoids consist of a simple region, + * but we can only do this if we do not have a clip surface, or can + * substitute the mask with the clip. + */ + if (! clip_surface || + (_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE)) + { + cairo_region_t *trap_region = NULL; - if ((src->type == CAIRO_PATTERN_TYPE_SOLID || - op == CAIRO_OPERATOR_CLEAR) && !clip_surface) { - const cairo_color_t *color; + status = _cairo_traps_extract_region (traps, &trap_region); + if (unlikely (_cairo_status_is_error (status))) + return status; - if (op == CAIRO_OPERATOR_CLEAR) { - color = CAIRO_COLOR_TRANSPARENT; - } else { - color = &((cairo_solid_pattern_t *)src)->color; - } + if (trap_region != NULL) { + status = cairo_region_intersect_rectangle (trap_region, extents); + if (unlikely (status)) { + cairo_region_destroy (trap_region); + return status; + } - /* Solid rectangles special case */ - status = _cairo_surface_fill_region (dst, op, color, trap_region); + if (clip_region != NULL) { + status = cairo_region_intersect (trap_region, clip_region); + if (unlikely (status)) { + cairo_region_destroy (trap_region); + return status; + } + } - if (!status && clear_region) { - status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, - CAIRO_COLOR_TRANSPARENT, - clear_region); + if (cairo_region_is_empty (trap_region) && + _cairo_operator_bounded_by_mask (op)) + { + cairo_region_destroy (trap_region); + return CAIRO_STATUS_SUCCESS; } - goto out; - } + status = _clip_and_composite_region (src, op, dst, + trap_region, + antialias, + clip, extents); + cairo_region_destroy (trap_region); - if ((_cairo_operator_bounded_by_mask (op) && - op != CAIRO_OPERATOR_SOURCE) || !clip_surface) { - /* For a simple rectangle, we can just use composite(), for more - * rectangles, we have to set a clip region. The cost of rasterizing - * trapezoids is pretty high for most backends currently, so it's - * worthwhile even if a region is needed. - * - * If we have a clip surface, we set it as the mask; this only works - * for bounded operators other than SOURCE; for unbounded operators, - * clip and mask cannot be interchanged. For SOURCE, the operator - * as implemented by the backends is different in its handling - * of the mask then what we want. - * - * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has - * more than rectangle and the destination doesn't support clip - * regions. In that case, we fall through. - */ - status = _composite_trap_region (clip, src, op, dst, - trap_region, &extents); - - if (status != CAIRO_INT_STATUS_UNSUPPORTED) { - if (!status && clear_region) - status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, - CAIRO_COLOR_TRANSPARENT, - clear_region); - goto out; - } - } + if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED)) + return status; + } } - traps_info.traps = traps; - traps_info.antialias = antialias; - - status = _clip_and_composite (clip, op, src, - _composite_traps_draw_func, - &traps_info, dst, &extents); + /* Otherwise we need to render the trapezoids to a mask and composite + * in the usual fashion. + */ + if (_cairo_operator_bounded_by_mask (op)) { + cairo_rectangle_int_t trap_extents; + cairo_box_t trap_box; -out: - if (trap_region) - cairo_region_destroy (trap_region); - if (clear_region) - cairo_region_destroy (clear_region); + _cairo_traps_extents (traps, &trap_box); + _cairo_box_round_to_rectangle (&trap_box, &trap_extents); + if (! _cairo_rectangle_intersect (extents, &trap_extents)) + return CAIRO_STATUS_SUCCESS; + } - return status; + traps_info.traps = traps; + traps_info.antialias = antialias; + return _clip_and_composite (clip, op, src, + _composite_traps_draw_func, + &traps_info, dst, extents); } typedef struct { @@ -671,11 +773,11 @@ _composite_spans_fill_func (void *closure, cairo_surface_t *dst, int dst_x, int dst_y, - const cairo_rectangle_int_t *extents) + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) { cairo_composite_rectangles_t rects; cairo_composite_spans_fill_info_t *info = closure; - cairo_solid_pattern_t pattern; _cairo_composite_rectangles_init ( &rects, extents->x, extents->y, @@ -687,60 +789,60 @@ _composite_spans_fill_func (void *closure, rects.dst.x -= dst_x; rects.dst.y -= dst_y; - /* We're called without a source pattern from - * _create_composite_mask_pattern(). */ - if (src == NULL) { - _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - src = &pattern.base; + return _cairo_path_fixed_fill_using_spans (op, src, info->path, dst, + info->fill_rule, + info->tolerance, + info->antialias, + &rects, + clip_region); +} + +static cairo_bool_t +_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip) +{ + if (clip != NULL) { + const cairo_rectangle_int_t *clip_extents; + + clip_extents = _cairo_clip_get_extents (clip); + if (clip_extents != NULL) + return _cairo_rectangle_intersect (extents, clip_extents); } - return _cairo_path_fixed_fill_using_spans ( - op, src, info->path, dst, - info->fill_rule, info->tolerance, info->antialias, - &rects); + return ! _cairo_rectangle_empty (extents); } cairo_status_t _cairo_surface_fallback_paint (cairo_surface_t *surface, cairo_operator_t op, - const cairo_pattern_t *source) + const cairo_pattern_t *source, + cairo_clip_t *clip) { cairo_status_t status; cairo_rectangle_int_t extents; cairo_box_t box; cairo_traps_t traps; + cairo_bool_t is_bounded; - status = _cairo_surface_get_extents (surface, &extents); - if (unlikely (status)) - return status; + is_bounded = _cairo_surface_get_extents (surface, &extents); + assert (is_bounded || clip); if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; - status = _cairo_pattern_get_extents (source, &source_extents); - if (unlikely (status)) - return status; - + _cairo_pattern_get_extents (source, &source_extents); if (! _cairo_rectangle_intersect (&extents, &source_extents)) return CAIRO_STATUS_SUCCESS; } - status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (unlikely (status)) - return status; + if (! _rectangle_intersect_clip (&extents, clip)) + return CAIRO_STATUS_SUCCESS; _cairo_box_from_rectangle (&box, &extents); _cairo_traps_init_box (&traps, &box); - - status = _clip_and_composite_trapezoids (source, - op, - surface, - &traps, - surface->clip, - CAIRO_ANTIALIAS_NONE); - + status = _clip_and_composite_trapezoids (source, op, surface, + &traps, CAIRO_ANTIALIAS_NONE, + clip, &extents); _cairo_traps_fini (&traps); return status; @@ -753,69 +855,67 @@ _cairo_surface_mask_draw_func (void *closure, cairo_surface_t *dst, int dst_x, int dst_y, - const cairo_rectangle_int_t *extents) + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) { cairo_pattern_t *mask = closure; - if (src) + if (src) { return _cairo_surface_composite (op, src, mask, dst, extents->x, extents->y, extents->x, extents->y, extents->x - dst_x, extents->y - dst_y, - extents->width, extents->height); - else + extents->width, extents->height, + clip_region); + } else { return _cairo_surface_composite (op, mask, NULL, dst, extents->x, extents->y, 0, 0, /* unused */ extents->x - dst_x, extents->y - dst_y, - extents->width, extents->height); + extents->width, extents->height, + clip_region); + } } + cairo_status_t _cairo_surface_fallback_mask (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_pattern_t *mask) + const cairo_pattern_t *mask, + cairo_clip_t *clip) { - cairo_status_t status; - cairo_rectangle_int_t extents, source_extents, mask_extents; + cairo_rectangle_int_t extents; + cairo_bool_t is_bounded; - status = _cairo_surface_get_extents (surface, &extents); - if (unlikely (status)) - return status; + is_bounded = _cairo_surface_get_extents (surface, &extents); + assert (is_bounded || clip); if (_cairo_operator_bounded_by_source (op)) { - status = _cairo_pattern_get_extents (source, &source_extents); - if (unlikely (status)) - return status; + cairo_rectangle_int_t source_extents; + _cairo_pattern_get_extents (source, &source_extents); if (! _cairo_rectangle_intersect (&extents, &source_extents)) return CAIRO_STATUS_SUCCESS; } if (_cairo_operator_bounded_by_mask (op)) { - status = _cairo_pattern_get_extents (mask, &mask_extents); - if (unlikely (status)) - return status; + cairo_rectangle_int_t mask_extents; + _cairo_pattern_get_extents (mask, &mask_extents); if (! _cairo_rectangle_intersect (&extents, &mask_extents)) return CAIRO_STATUS_SUCCESS; } - status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (unlikely (status)) - return status; - - status = _clip_and_composite (surface->clip, op, - source, - _cairo_surface_mask_draw_func, - (void *) mask, - surface, - &extents); + if (! _rectangle_intersect_clip (&extents, clip)) + return CAIRO_STATUS_SUCCESS; - return status; + return _clip_and_composite (clip, op, source, + _cairo_surface_mask_draw_func, + (void *) mask, + surface, &extents); } cairo_status_t @@ -827,32 +927,27 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, cairo_matrix_t *ctm, cairo_matrix_t *ctm_inverse, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_clip_t *clip) { cairo_status_t status; cairo_traps_t traps; cairo_box_t box; cairo_rectangle_int_t extents; + cairo_bool_t is_bounded; - status = _cairo_surface_get_extents (surface, &extents); - if (unlikely (status)) - return status; + is_bounded = _cairo_surface_get_extents (surface, &extents); + assert (is_bounded || clip); if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; - status = _cairo_pattern_get_extents (source, &source_extents); - if (unlikely (status)) - return status; + _cairo_pattern_get_extents (source, &source_extents); if (! _cairo_rectangle_intersect (&extents, &source_extents)) return CAIRO_STATUS_SUCCESS; } - status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (unlikely (status)) - return status; - - if (extents.width == 0 || extents.height == 0) + if (! _rectangle_intersect_clip (&extents, clip)) return CAIRO_STATUS_SUCCESS; _cairo_box_from_rectangle (&box, &extents); @@ -868,14 +963,10 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, if (unlikely (status)) goto FAIL; - status = _clip_and_composite_trapezoids (source, - op, - surface, - &traps, - surface->clip, - antialias); - -FAIL: + status = _clip_and_composite_trapezoids (source, op, + surface, &traps, antialias, + clip, &extents); + FAIL: _cairo_traps_fini (&traps); return status; @@ -888,35 +979,41 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, - cairo_antialias_t antialias) + cairo_antialias_t antialias, + cairo_clip_t *clip) { cairo_status_t status; cairo_traps_t traps; cairo_box_t box; cairo_rectangle_int_t extents; + cairo_bool_t is_bounded; - status = _cairo_surface_get_extents (surface, &extents); - if (unlikely (status)) - return status; + is_bounded = _cairo_surface_get_extents (surface, &extents); + assert (is_bounded || clip); if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; - status = _cairo_pattern_get_extents (source, &source_extents); - if (unlikely (status)) - return status; - + _cairo_pattern_get_extents (source, &source_extents); if (! _cairo_rectangle_intersect (&extents, &source_extents)) return CAIRO_STATUS_SUCCESS; } - status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (unlikely (status)) - return status; - - if (extents.width == 0 || extents.height == 0) + if (! _rectangle_intersect_clip (&extents, clip)) return CAIRO_STATUS_SUCCESS; + /* XXX future direction: + status = _cairo_path_fixed_fill_to_region (path, fill_rule, ®ion); + if (status != CAIRO_STATUS_INT_UNSUPPORTED) { + if (unlikely (status)) + return status; + + status = _clip_and_composite_region (); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + */ + /* Ask if the surface would like to render this combination of * op/source/dst/antialias with spans or not, but don't actually * make a renderer yet. We'll try to hit the region optimisations @@ -927,9 +1024,7 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, /* TODO: The region filling code should be lifted from * _clip_and_composite_trapezoids() and given first priority * explicitly before deciding between spans and trapezoids. */ - if (antialias != CAIRO_ANTIALIAS_NONE && - !_cairo_path_fixed_is_box (path, &box) && - !_cairo_path_fixed_is_region (path) && + if (antialias != CAIRO_ANTIALIAS_NONE && ! path->is_rectilinear && _cairo_surface_check_span_renderer ( op, source, surface, antialias, NULL)) { @@ -948,12 +1043,11 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; } - return _clip_and_composite ( - surface->clip, op, source, - _composite_spans_fill_func, - &info, - surface, - &extents); + return _clip_and_composite (clip, op, source, + _composite_spans_fill_func, + &info, + surface, + &extents); } /* Fall back to trapezoid fills. */ @@ -965,18 +1059,13 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, fill_rule, tolerance, &traps); - if (unlikely (status)) { - _cairo_traps_fini (&traps); - return status; - } - - status = _clip_and_composite_trapezoids (source, - op, - surface, - &traps, - surface->clip, - antialias); + if (unlikely (status)) + goto FAIL; + status = _clip_and_composite_trapezoids (source, op, surface, + &traps, antialias, + clip, &extents); + FAIL: _cairo_traps_fini (&traps); return status; @@ -995,10 +1084,10 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure cairo_surface_t *dst, int dst_x, int dst_y, - const cairo_rectangle_int_t *extents) + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) { cairo_show_glyphs_info_t *glyph_info = closure; - cairo_solid_pattern_t pattern; cairo_status_t status; /* Modifying the glyph array is fine because we know that this function @@ -1008,19 +1097,12 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure if (dst_x != 0 || dst_y != 0) { int i; - for (i = 0; i < glyph_info->num_glyphs; ++i) - { + for (i = 0; i < glyph_info->num_glyphs; ++i) { ((cairo_glyph_t *) glyph_info->glyphs)[i].x -= dst_x; ((cairo_glyph_t *) glyph_info->glyphs)[i].y -= dst_y; } } - if (src == NULL) { - _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - src = &pattern.base; - } - status = _cairo_surface_old_show_glyphs (glyph_info->font, op, src, dst, extents->x, extents->y, @@ -1029,7 +1111,8 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure extents->width, extents->height, glyph_info->glyphs, - glyph_info->num_glyphs); + glyph_info->num_glyphs, + clip_region); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -1041,7 +1124,8 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure extents->y - dst_y, extents->width, extents->height, glyph_info->glyphs, - glyph_info->num_glyphs); + glyph_info->num_glyphs, + clip_region); } cairo_status_t @@ -1050,15 +1134,16 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, - cairo_scaled_font_t *scaled_font) + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip) { cairo_status_t status; cairo_rectangle_int_t extents; cairo_show_glyphs_info_t glyph_info; + cairo_bool_t is_bounded; - status = _cairo_surface_get_extents (surface, &extents); - if (unlikely (status)) - return status; + is_bounded = _cairo_surface_get_extents (surface, &extents); + assert (is_bounded || clip); if (_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_int_t glyph_extents; @@ -1074,23 +1159,18 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; } - status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); - if (unlikely (status)) - return status; + if (! _rectangle_intersect_clip (&extents, clip)) + return CAIRO_STATUS_SUCCESS; glyph_info.font = scaled_font; glyph_info.glyphs = glyphs; glyph_info.num_glyphs = num_glyphs; - status = _clip_and_composite (surface->clip, - op, - source, - _cairo_surface_old_show_glyphs_draw_func, - &glyph_info, - surface, - &extents); - - return status; + return _clip_and_composite (clip, op, source, + _cairo_surface_old_show_glyphs_draw_func, + &glyph_info, + surface, + &extents); } cairo_surface_t * @@ -1124,15 +1204,10 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface) } _cairo_pattern_init_for_surface (&pattern, &image->base); - status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, - &pattern.base, - NULL, - snapshot, - 0, 0, - 0, 0, - 0, 0, - image->width, - image->height); + status = _cairo_surface_paint (snapshot, + CAIRO_OPERATOR_SOURCE, + &pattern.base, + NULL); _cairo_pattern_fini (&pattern.base); _cairo_surface_release_source_image (surface, image, image_extra); if (unlikely (status)) { @@ -1155,15 +1230,17 @@ _cairo_surface_fallback_composite (cairo_operator_t op, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { fallback_state_t state; + cairo_region_t *fallback_region = NULL; cairo_status_t status; status = _fallback_init (&state, dst, dst_x, dst_y, width, height); if (unlikely (status)) { if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; + status = CAIRO_STATUS_SUCCESS; return status; } @@ -1172,12 +1249,29 @@ _cairo_surface_fallback_composite (cairo_operator_t op, * _cairo_surface_composite so that we get the correct device * offset handling. */ + + if (clip_region != NULL && (state.image_rect.x || state.image_rect.y)) { + fallback_region = cairo_region_copy (clip_region); + status = fallback_region->status; + if (unlikely (status)) + goto FAIL; + + cairo_region_translate (fallback_region, + -state.image_rect.x, + -state.image_rect.y); + clip_region = fallback_region; + } + status = _cairo_surface_composite (op, src, mask, &state.image->base, src_x, src_y, mask_x, mask_y, dst_x - state.image_rect.x, dst_y - state.image_rect.y, - width, height); + width, height, + clip_region); + FAIL: + if (fallback_region != NULL) + cairo_region_destroy (fallback_region); _fallback_fini (&state); return status; @@ -1224,7 +1318,7 @@ _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface, status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1); if (unlikely (status)) { if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; + status = CAIRO_STATUS_SUCCESS; return status; } @@ -1271,16 +1365,18 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int num_traps) + int num_traps, + cairo_region_t *clip_region) { fallback_state_t state; + cairo_region_t *fallback_region = NULL; cairo_trapezoid_t *offset_traps = NULL; cairo_status_t status; status = _fallback_init (&state, dst, dst_x, dst_y, width, height); if (unlikely (status)) { if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; + status = CAIRO_STATUS_SUCCESS; return status; } @@ -1288,15 +1384,28 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op, if (state.image_rect.x != 0 || state.image_rect.y != 0) { offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t)); - if (!offset_traps) { + if (offset_traps == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto DONE; + goto FAIL; } _cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps, - state.image_rect.x, - state.image_rect.y, 1.0, 1.0); traps = offset_traps; + + /* similarly we need to adjust the region */ + if (clip_region != NULL) { + fallback_region = cairo_region_copy (clip_region); + status = fallback_region->status; + if (unlikely (status)) + goto FAIL; + + cairo_region_translate (fallback_region, + -state.image_rect.x, + -state.image_rect.y); + clip_region = fallback_region; + } } status = _cairo_surface_composite_trapezoids (op, pattern, @@ -1306,11 +1415,14 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op, dst_x - state.image_rect.x, dst_y - state.image_rect.y, width, height, - traps, num_traps); - if (offset_traps) + traps, num_traps, + clip_region); + if (offset_traps != NULL) free (offset_traps); - DONE: + FAIL: + if (fallback_region != NULL) + cairo_region_destroy (fallback_region); _fallback_fini (&state); return status; @@ -1335,7 +1447,9 @@ _cairo_surface_fallback_clone_similar (cairo_surface_t *surface, new_surface = _cairo_surface_create_similar_scratch (surface, src->content & content, width, height); - if (new_surface->status) + if (new_surface == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (unlikely (new_surface->status)) return new_surface->status; /* We have to copy these here, so that the coordinate spaces are correct */ @@ -1348,7 +1462,8 @@ _cairo_surface_fallback_clone_similar (cairo_surface_t *surface, status = _cairo_surface_paint (new_surface, CAIRO_OPERATOR_SOURCE, - &pattern.base, NULL); + &pattern.base, + NULL); _cairo_pattern_fini (&pattern.base); if (unlikely (status)) { diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h index c25b6dc8..5c80d43f 100644 --- a/src/cairo-surface-private.h +++ b/src/cairo-surface-private.h @@ -42,6 +42,7 @@ #include "cairo-types-private.h" #include "cairo-reference-count-private.h" +#include "cairo-clip-private.h" typedef void (*cairo_surface_func_t) (cairo_surface_t *); @@ -77,24 +78,6 @@ struct _cairo_surface { double x_fallback_resolution; double y_fallback_resolution; - cairo_clip_t *clip; - - /* - * Each time a clip region is modified, it gets the next value in this - * sequence. This means that clip regions for this surface are uniquely - * identified and updates to the clip can be readily identified - */ - unsigned int next_clip_serial; - /* - * The serial number of the current clip. This is set when - * the surface clipping is set. The gstate can then cheaply - * check whether the surface clipping is already correct before - * performing a rendering operation. - * - * The special value '0' is reserved for the unclipped case. - */ - unsigned int current_clip_serial; - /* A "snapshot" surface is immutable. See _cairo_surface_snapshot. */ cairo_surface_t *snapshot_of; cairo_surface_func_t snapshot_detach; diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h new file mode 100644 index 00000000..5ebcb860 --- /dev/null +++ b/src/cairo-surface-wrapper-private.h @@ -0,0 +1,156 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.u> + */ + +#ifndef CAIRO_SURFACE_WRAPPER_PRIVATE_H +#define CAIRO_SURFACE_WRAPPER_PRIVATE_H + +#include "cairo-types-private.h" + +CAIRO_BEGIN_DECLS + +struct _cairo_surface_wrapper { + cairo_surface_t *target; + + /* any other information? */ +}; + +cairo_private void +_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper, + cairo_surface_t *target); + +cairo_private void +_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper); + +cairo_private cairo_status_t +_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper, + cairo_image_surface_t **image_out, + void **image_extra); + +cairo_private void +_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper, + cairo_image_surface_t *image, + void *image_extra); + + +cairo_private cairo_status_t +_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *stroke_style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, + cairo_operator_t fill_op, + const cairo_pattern_t *fill_source, + cairo_fill_rule_t fill_rule, + double fill_tolerance, + cairo_antialias_t fill_antialias, + cairo_path_fixed_t *path, + cairo_operator_t stroke_op, + const cairo_pattern_t *stroke_source, + cairo_stroke_style_t *stroke_style, + cairo_matrix_t *stroke_ctm, + cairo_matrix_t *stroke_ctm_inverse, + double stroke_tolerance, + cairo_antialias_t stroke_antialias, + cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip); + +cairo_private cairo_surface_t * +_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper, + cairo_content_t content, + int width, + int height); +cairo_private cairo_bool_t +_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper, + cairo_rectangle_int_t *extents); + +cairo_private cairo_bool_t +_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper); + +static inline cairo_bool_t +_cairo_surface_wrapper_is_active (cairo_surface_wrapper_t *wrapper) +{ + return wrapper->target != (cairo_surface_t *) 0; +} + +CAIRO_END_DECLS + +#endif /* CAIRO_SURFACE_WRAPPER_PRIVATE_H */ diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c new file mode 100644 index 00000000..b21a32da --- /dev/null +++ b/src/cairo-surface-wrapper.c @@ -0,0 +1,449 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * Copyright © 2007 Adrian Johnson + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairoint.h" + +#include "cairo-surface-wrapper-private.h" + +/* A collection of routines to facilitate surface wrapping */ + +static cairo_bool_t +_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper, + cairo_matrix_t *matrix) +{ + if (_cairo_matrix_is_identity (&wrapper->target->device_transform)) + return FALSE; + + *matrix = wrapper->target->device_transform; + return TRUE; +} + +cairo_status_t +_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper, + cairo_image_surface_t **image_out, + void **image_extra) +{ + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + return _cairo_surface_acquire_source_image (wrapper->target, + image_out, image_extra); +} + +void +_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper, + cairo_image_surface_t *image, + void *image_extra) +{ + _cairo_surface_release_source_image (wrapper->target, image, image_extra); +} + +cairo_status_t +_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_matrix_t device_transform; + cairo_clip_t clip_copy, *dev_clip = clip; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + if (clip != NULL && + _cairo_surface_wrapper_needs_device_transform (wrapper, + &device_transform)) + { + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, + &device_transform); + if (unlikely (status)) + goto FINISH; + + dev_clip = &clip_copy; + } + + status = _cairo_surface_paint (wrapper->target, op, source, dev_clip); + + FINISH: + if (dev_clip != clip) + _cairo_clip_reset (dev_clip); + return status; +} + +cairo_status_t +_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_matrix_t device_transform; + cairo_clip_t clip_copy, *dev_clip = clip; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + if (clip != NULL && + _cairo_surface_wrapper_needs_device_transform (wrapper, + &device_transform)) + { + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, + &device_transform); + if (unlikely (status)) + goto FINISH; + + dev_clip = &clip_copy; + } + + status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip); + + FINISH: + if (dev_clip != clip) + _cairo_clip_reset (dev_clip); + return status; +} + +cairo_status_t +_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *stroke_style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_matrix_t device_transform; + cairo_path_fixed_t path_copy, *dev_path = path; + cairo_clip_t clip_copy, *dev_clip = clip; + cairo_matrix_t dev_ctm = *ctm; + cairo_matrix_t dev_ctm_inverse = *ctm_inverse; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_surface_wrapper_needs_device_transform (wrapper, + &device_transform)) + { + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); + if (unlikely (status)) + goto FINISH; + + _cairo_path_fixed_transform (&path_copy, &device_transform); + dev_path = &path_copy; + + if (clip != NULL) { + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, + &device_transform); + if (unlikely (status)) + goto FINISH; + + dev_clip = &clip_copy; + } + + cairo_matrix_multiply (&dev_ctm, &dev_ctm, &device_transform); + status = cairo_matrix_invert (&device_transform); + assert (status == CAIRO_STATUS_SUCCESS); + cairo_matrix_multiply (&dev_ctm_inverse, + &device_transform, + &dev_ctm_inverse); + } + + status = _cairo_surface_stroke (wrapper->target, op, source, + dev_path, stroke_style, + &dev_ctm, &dev_ctm_inverse, + tolerance, antialias, + dev_clip); + + FINISH: + if (dev_path != path) + _cairo_path_fixed_fini (dev_path); + if (dev_clip != clip) + _cairo_clip_reset (dev_clip); + return status; +} + +cairo_status_t +_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, + cairo_operator_t fill_op, + const cairo_pattern_t *fill_source, + cairo_fill_rule_t fill_rule, + double fill_tolerance, + cairo_antialias_t fill_antialias, + cairo_path_fixed_t *path, + cairo_operator_t stroke_op, + const cairo_pattern_t *stroke_source, + cairo_stroke_style_t *stroke_style, + cairo_matrix_t *stroke_ctm, + cairo_matrix_t *stroke_ctm_inverse, + double stroke_tolerance, + cairo_antialias_t stroke_antialias, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_matrix_t device_transform; + cairo_path_fixed_t path_copy, *dev_path = path; + cairo_clip_t clip_copy, *dev_clip = clip; + cairo_matrix_t dev_ctm = *stroke_ctm; + cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_surface_wrapper_needs_device_transform (wrapper, + &device_transform)) + { + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); + if (unlikely (status)) + goto FINISH; + + _cairo_path_fixed_transform (&path_copy, &device_transform); + dev_path = &path_copy; + + if (clip != NULL) { + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, + &device_transform); + if (unlikely (status)) + goto FINISH; + + dev_clip = &clip_copy; + } + + cairo_matrix_multiply (&dev_ctm, &dev_ctm, &device_transform); + status = cairo_matrix_invert (&device_transform); + assert (status == CAIRO_STATUS_SUCCESS); + cairo_matrix_multiply (&dev_ctm_inverse, + &device_transform, + &dev_ctm_inverse); + } + + status = _cairo_surface_fill_stroke (wrapper->target, + fill_op, fill_source, fill_rule, + fill_tolerance, fill_antialias, + dev_path, + stroke_op, stroke_source, + stroke_style, + &dev_ctm, &dev_ctm_inverse, + stroke_tolerance, stroke_antialias, + dev_clip); + + FINISH: + if (dev_path != path) + _cairo_path_fixed_fini (dev_path); + if (dev_clip != clip) + _cairo_clip_reset (dev_clip); + return status; +} + +cairo_status_t +_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_matrix_t device_transform; + cairo_path_fixed_t path_copy, *dev_path = path; + cairo_clip_t clip_copy, *dev_clip = clip; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_surface_wrapper_needs_device_transform (wrapper, + &device_transform)) + { + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); + if (unlikely (status)) + goto FINISH; + + _cairo_path_fixed_transform (&path_copy, &device_transform); + dev_path = &path_copy; + + if (clip != NULL) { + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, + &device_transform); + if (unlikely (status)) + goto FINISH; + + dev_clip = &clip_copy; + } + } + + status = _cairo_surface_fill (wrapper->target, op, source, + dev_path, fill_rule, + tolerance, antialias, + dev_clip); + + FINISH: + if (dev_path != path) + _cairo_path_fixed_fini (dev_path); + if (dev_clip != clip) + _cairo_clip_reset (dev_clip); + return status; +} + +cairo_status_t +_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_matrix_t device_transform; + cairo_clip_t clip_copy, *dev_clip = clip; + cairo_glyph_t *dev_glyphs = glyphs; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + if (glyphs == NULL || num_glyphs == 0) + return CAIRO_STATUS_SUCCESS; + + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_surface_wrapper_needs_device_transform (wrapper, + &device_transform)) + { + int i; + + if (clip != NULL) { + dev_clip = &clip_copy; + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, + &device_transform); + if (unlikely (status)) + goto FINISH; + } + + dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (dev_glyphs == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto FINISH; + } + + for (i = 0; i < num_glyphs; i++) { + dev_glyphs[i] = glyphs[i]; + cairo_matrix_transform_point (&device_transform, + &dev_glyphs[i].x, + &dev_glyphs[i].y); + } + } + + status = _cairo_surface_show_text_glyphs (wrapper->target, op, source, + utf8, utf8_len, + dev_glyphs, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font, + dev_clip); + FINISH: + if (dev_clip != clip) + _cairo_clip_reset (dev_clip); + if (dev_glyphs != glyphs) + free (dev_glyphs); + return status; +} + +cairo_surface_t * +_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper, + cairo_content_t content, + int width, + int height) +{ + return _cairo_surface_create_similar_solid (wrapper->target, + content, width, height, + CAIRO_COLOR_TRANSPARENT, + TRUE); +} + +cairo_bool_t +_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper, + cairo_rectangle_int_t *extents) +{ + return _cairo_surface_get_extents (wrapper->target, extents); +} + +cairo_bool_t +_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper) +{ + return cairo_surface_has_show_text_glyphs (wrapper->target); +} + +void +_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper, + cairo_surface_t *target) +{ + wrapper->target = cairo_surface_reference (target); +} + +void +_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper) +{ + cairo_surface_destroy (wrapper->target); +} diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 16e84921..f656ed5f 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -41,6 +41,7 @@ #include "cairo-surface-fallback-private.h" #include "cairo-clip-private.h" #include "cairo-meta-surface-private.h" +#include "cairo-region-private.h" #define DEFINE_NIL_SURFACE(status, name) \ const cairo_surface_t name = { \ @@ -59,9 +60,6 @@ const cairo_surface_t name = { \ 0.0, /* y_resolution */ \ 0.0, /* x_fallback_resolution */ \ 0.0, /* y_fallback_resolution */ \ - NULL, /* clip */ \ - 0, /* next_clip_serial */ \ - 0, /* current_clip_serial */ \ NULL, /* snapshot_of */ \ NULL, /* snapshot_detach */ \ { 0, /* size */ \ @@ -77,8 +75,11 @@ const cairo_surface_t name = { \ } /* font_options */ \ } +/* XXX error object! */ + static DEFINE_NIL_SURFACE(CAIRO_STATUS_NO_MEMORY, _cairo_surface_nil); static DEFINE_NIL_SURFACE(CAIRO_STATUS_SURFACE_TYPE_MISMATCH, _cairo_surface_nil_surface_type_mismatch); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STATUS, _cairo_surface_nil_invalid_status); static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_CONTENT, _cairo_surface_nil_invalid_content); static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_FORMAT, _cairo_surface_nil_invalid_format); static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_VISUAL, _cairo_surface_nil_invalid_visual); @@ -89,7 +90,7 @@ static DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_err static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STRIDE, _cairo_surface_nil_invalid_stride); static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_SIZE, _cairo_surface_nil_invalid_size); -static cairo_status_t +static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t **pattern, cairo_surface_t *destination, cairo_pattern_t *pattern_copy); @@ -361,53 +362,48 @@ _cairo_surface_init (cairo_surface_t *surface, surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT; surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT; - surface->clip = NULL; - surface->next_clip_serial = 0; - surface->current_clip_serial = 0; - _cairo_array_init (&surface->snapshots, sizeof (cairo_surface_t *)); surface->snapshot_of = NULL; surface->has_font_options = FALSE; } +static void +_cairo_surface_copy_similar_properties (cairo_surface_t *surface, + cairo_surface_t *other) +{ + if (other->has_font_options || other->backend != surface->backend) { + cairo_font_options_t options; + + cairo_surface_get_font_options (other, &options); + _cairo_surface_set_font_options (surface, &options); + } + + cairo_surface_set_fallback_resolution (surface, + other->x_fallback_resolution, + other->y_fallback_resolution); +} + cairo_surface_t * _cairo_surface_create_similar_scratch (cairo_surface_t *other, cairo_content_t content, int width, int height) { - cairo_surface_t *surface = NULL; + cairo_surface_t *surface; - if (other->status) + if (unlikely (other->status)) return _cairo_surface_create_in_error (other->status); - if (other->backend->create_similar) { - surface = other->backend->create_similar (other, content, width, height); - if (surface != NULL && surface->status) - return surface; - } - - if (surface == NULL) { - surface = - cairo_image_surface_create (_cairo_format_from_content (content), - width, height); - } + if (other->backend->create_similar == NULL) + return NULL; - /* If any error occurred, then return the nil surface we received. */ - if (unlikely (surface->status)) + surface = other->backend->create_similar (other, + content, width, height); + if (surface == NULL || surface->status) return surface; - if (other->has_font_options || other->backend != surface->backend) { - cairo_font_options_t options; - - cairo_surface_get_font_options (other, &options); - _cairo_surface_set_font_options (surface, &options); - } - - cairo_surface_set_fallback_resolution (surface, - other->x_fallback_resolution, - other->y_fallback_resolution); + _cairo_surface_copy_similar_properties (surface, other); return surface; } @@ -443,46 +439,46 @@ cairo_surface_create_similar (cairo_surface_t *other, int width, int height) { - if (other->status) + if (unlikely (other->status)) return _cairo_surface_create_in_error (other->status); - if (! CAIRO_CONTENT_VALID (content)) + if (unlikely (! CAIRO_CONTENT_VALID (content))) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); - return _cairo_surface_create_similar_solid (other, content, - width, height, - CAIRO_COLOR_TRANSPARENT); + return _cairo_surface_create_similar_solid (other, + content, width, height, + CAIRO_COLOR_TRANSPARENT, + TRUE); } -slim_hidden_def (cairo_surface_create_similar); cairo_surface_t * _cairo_surface_create_similar_solid (cairo_surface_t *other, cairo_content_t content, int width, int height, - const cairo_color_t *color) + const cairo_color_t *color, + cairo_bool_t allow_fallback) { cairo_status_t status; cairo_surface_t *surface; - cairo_solid_pattern_t solid_pattern; + cairo_solid_pattern_t pattern; surface = _cairo_surface_create_similar_scratch (other, content, width, height); - if (surface->status) + if (surface == NULL && allow_fallback) + surface = _cairo_image_surface_create_with_content (content, + width, height); + if (surface == NULL || surface->status) return surface; - _cairo_pattern_init_solid (&solid_pattern, color, content); - + _cairo_pattern_init_solid (&pattern, color, content); status = _cairo_surface_paint (surface, color == CAIRO_COLOR_TRANSPARENT ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE, - &solid_pattern.base, NULL); - - _cairo_pattern_fini (&solid_pattern.base); - + &pattern.base, NULL); if (unlikely (status)) { cairo_surface_destroy (surface); - return _cairo_surface_create_in_error (status); + surface = _cairo_surface_create_in_error (status); } return surface; @@ -504,7 +500,8 @@ _cairo_surface_create_solid_pattern_surface (cairo_surface_t *other, return _cairo_surface_create_similar_solid (other, solid_pattern->content, 1, 1, - &solid_pattern->color); + &solid_pattern->color, + FALSE); } cairo_int_status_t @@ -532,17 +529,6 @@ _cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other, NULL); } -cairo_clip_mode_t -_cairo_surface_get_clip_mode (cairo_surface_t *surface) -{ - if (surface->backend->intersect_clip_path != NULL) - return CAIRO_CLIP_MODE_PATH; - else if (surface->backend->set_clip_region != NULL) - return CAIRO_CLIP_MODE_REGION; - else - return CAIRO_CLIP_MODE_MASK; -} - /** * cairo_surface_reference: * @surface: a #cairo_surface_t @@ -605,36 +591,6 @@ cairo_surface_destroy (cairo_surface_t *surface) slim_hidden_def(cairo_surface_destroy); /** - * _cairo_surface_reset: - * @surface: a #cairo_surface_t - * - * Resets the surface back to defaults such that it may be reused in lieu - * of creating a new surface. - **/ -cairo_status_t -_cairo_surface_reset (cairo_surface_t *surface) -{ - if (surface == NULL || - CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) - return CAIRO_STATUS_SUCCESS; - - assert (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count) == 1); - - _cairo_user_data_array_fini (&surface->user_data); - _cairo_user_data_array_fini (&surface->mime_data); - - if (surface->backend->reset != NULL) { - cairo_status_t status = surface->backend->reset (surface); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - } - - _cairo_surface_init (surface, surface->backend, surface->content); - - return CAIRO_STATUS_SUCCESS; -} - -/** * cairo_surface_get_reference_count: * @surface: a #cairo_surface_t * @@ -1078,14 +1034,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, * call mark_dirty()). */ assert (! _cairo_surface_has_snapshots (surface)); - /* Always reset the clip here, to avoid having external calls to - * clip manipulation functions of the underlying device clip result - * in a desync between the cairo clip and the backend clip, due to - * the clip caching. - */ - surface->current_clip_serial = -1; - - if (surface->backend->mark_dirty_rectangle) { + if (surface->backend->mark_dirty_rectangle != NULL) { /* XXX: FRAGILE: We're ignoring the scaling component of * device_transform here. I don't know what the right thing to * do would actually be if there were some scaling here, but @@ -1478,13 +1427,17 @@ _cairo_meta_surface_clone_similar (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; } - if (width*height*8 < meta->extents.width*meta->extents.height) { - similar = cairo_surface_create_similar (surface, - src->content & content, - width, height); - status = similar->status; - if (unlikely (status)) - return status; + if (meta->unbounded || + width*height*8 < meta->extents.width*meta->extents.height) + { + /* XXX use _solid to perform an initial CLEAR? */ + similar = _cairo_surface_create_similar_scratch (surface, + src->content & content, + width, height); + if (similar == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (unlikely (similar->status)) + return similar->status; cairo_surface_set_device_offset (similar, -src_x, -src_y); @@ -1493,15 +1446,15 @@ _cairo_meta_surface_clone_similar (cairo_surface_t *surface, cairo_surface_destroy (similar); return status; } - } else { - similar = cairo_surface_create_similar (surface, - src->content & content, - meta->extents.width, - meta->extents.height); - status = similar->status; - if (unlikely (status)) - return status; + similar = _cairo_surface_create_similar_scratch (surface, + src->content & content, + meta->extents.width, + meta->extents.height); + if (similar == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (unlikely (similar->status)) + return similar->status; status = cairo_meta_surface_replay (src, similar); if (unlikely (status)) { @@ -1567,7 +1520,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, if (unlikely (surface->finished)) return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); - if (surface->backend->clone_similar) { + if (surface->backend->clone_similar != NULL) { status = surface->backend->clone_similar (surface, src, content, src_x, src_y, @@ -1575,7 +1528,6 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, clone_offset_x, clone_offset_y, clone_out); - if (status == CAIRO_INT_STATUS_UNSUPPORTED) { if (_cairo_surface_is_image (src)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1620,7 +1572,6 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, clone_out); } - /* We should never get UNSUPPORTED here, so if we have an error, bail. */ if (unlikely (status)) return status; @@ -1762,11 +1713,12 @@ _cairo_surface_composite (cairo_operator_t op, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_int_status_t status; - if (dst->status) + if (unlikely (dst->status)) return dst->status; assert (_cairo_surface_is_writable (dst)); @@ -1784,7 +1736,8 @@ _cairo_surface_composite (cairo_operator_t op, src_x, src_y, mask_x, mask_y, dst_x, dst_y, - width, height); + width, height, + clip_region); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return _cairo_surface_set_error (dst, status); } @@ -1795,7 +1748,8 @@ _cairo_surface_composite (cairo_operator_t op, src_x, src_y, mask_x, mask_y, dst_x, dst_y, - width, height)); + width, height, + clip_region)); } /** @@ -1883,8 +1837,8 @@ _cairo_surface_fill_region (cairo_surface_t *surface, for (i = 0; i < num_rects; i++) cairo_region_get_rectangle (region, i, &rects[i]); - status = _cairo_surface_fill_rectangles (surface, op, - color, rects, num_rects); + status = _cairo_surface_fill_rectangles (surface, + op, color, rects, num_rects); if (rects != stack_rects) free (rects); @@ -1926,14 +1880,16 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; if (surface->backend->fill_rectangles) { - status = surface->backend->fill_rectangles (surface, op, color, + status = surface->backend->fill_rectangles (surface, + op, color, rects, num_rects); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return _cairo_surface_set_error (surface, status); } return _cairo_surface_set_error (surface, - _cairo_surface_fallback_fill_rectangles (surface, op, color, + _cairo_surface_fallback_fill_rectangles (surface, + op, color, rects, num_rects)); } @@ -1941,34 +1897,32 @@ cairo_status_t _cairo_surface_paint (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_pattern_union_t dev_source; - if (surface->status) + if (unlikely (surface->status)) return surface->status; + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + _cairo_surface_begin_modification (surface); - status = _cairo_surface_copy_pattern_for_destination (&source, - surface, - &dev_source.base); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); + _cairo_surface_copy_pattern_for_destination (&source, + surface, + &dev_source.base); - if (surface->backend->paint) { - status = surface->backend->paint (surface, op, source, extents); + if (surface->backend->paint != NULL) { + status = surface->backend->paint (surface, op, source, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto FINISH; } - status = _cairo_surface_fallback_paint (surface, op, source); + status = _cairo_surface_fallback_paint (surface, op, source, clip); FINISH: - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); - return _cairo_surface_set_error (surface, status); } @@ -1977,45 +1931,34 @@ _cairo_surface_mask (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_pattern_union_t dev_source; cairo_pattern_union_t dev_mask; - if (surface->status) + if (unlikely (surface->status)) return surface->status; - _cairo_surface_begin_modification (surface); + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; - status = _cairo_surface_copy_pattern_for_destination (&source, - surface, - &dev_source.base); - if (unlikely (status)) - goto FINISH; + _cairo_surface_begin_modification (surface); - status = _cairo_surface_copy_pattern_for_destination (&mask, - surface, - &dev_mask.base); - if (unlikely (status)) - goto CLEANUP_SOURCE; + _cairo_surface_copy_pattern_for_destination (&source, surface, + &dev_source.base); + _cairo_surface_copy_pattern_for_destination (&mask, surface, + &dev_mask.base); - if (surface->backend->mask) { - status = surface->backend->mask (surface, op, source, mask, extents); + if (surface->backend->mask != NULL) { + status = surface->backend->mask (surface, op, source, mask, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto CLEANUP_MASK; + goto FINISH; } - status = _cairo_surface_fallback_mask (surface, op, source, mask); + status = _cairo_surface_fallback_mask (surface, op, source, mask, clip); - CLEANUP_MASK: - if (mask == &dev_mask.base) - _cairo_pattern_fini (&dev_mask.base); - CLEANUP_SOURCE: - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); FINISH: - return _cairo_surface_set_error (surface, status); } @@ -2034,13 +1977,16 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; - if (surface->status) + if (unlikely (surface->status)) return surface->status; + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + _cairo_surface_begin_modification (surface); if (surface->backend->fill_stroke) { @@ -2049,21 +1995,10 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, cairo_matrix_t dev_ctm = *stroke_ctm; cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse; - status = _cairo_surface_copy_pattern_for_destination (&stroke_source, - surface, - &dev_stroke_source.base); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - - status = _cairo_surface_copy_pattern_for_destination (&fill_source, - surface, - &dev_fill_source.base); - if (unlikely (status)) { - if (stroke_source == &dev_stroke_source.base) - _cairo_pattern_fini (&dev_stroke_source.base); - - return _cairo_surface_set_error (surface, status); - } + _cairo_surface_copy_pattern_for_destination (&stroke_source, surface, + &dev_stroke_source.base); + _cairo_surface_copy_pattern_for_destination (&fill_source, surface, + &dev_fill_source.base); status = surface->backend->fill_stroke (surface, fill_op, fill_source, fill_rule, @@ -2073,26 +2008,22 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, stroke_style, &dev_ctm, &dev_ctm_inverse, stroke_tolerance, stroke_antialias, - extents); - - if (stroke_source == &dev_stroke_source.base) - _cairo_pattern_fini (&dev_stroke_source.base); - - if (fill_source == &dev_fill_source.base) - _cairo_pattern_fini (&dev_fill_source.base); + clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return _cairo_surface_set_error (surface, status); } status = _cairo_surface_fill (surface, fill_op, fill_source, path, - fill_rule, fill_tolerance, fill_antialias, NULL); + fill_rule, fill_tolerance, fill_antialias, + clip); if (unlikely (status)) return _cairo_surface_set_error (surface, status); status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path, stroke_style, stroke_ctm, stroke_ctm_inverse, - stroke_tolerance, stroke_antialias, NULL); + stroke_tolerance, stroke_antialias, + clip); if (unlikely (status)) return _cairo_surface_set_error (surface, status); @@ -2109,31 +2040,28 @@ _cairo_surface_stroke (cairo_surface_t *surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_pattern_union_t dev_source; - cairo_path_fixed_t *dev_path = path; - cairo_path_fixed_t real_dev_path; - cairo_matrix_t dev_ctm = *ctm; - cairo_matrix_t dev_ctm_inverse = *ctm_inverse; - if (surface->status) + if (unlikely (surface->status)) return surface->status; + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + _cairo_surface_begin_modification (surface); - status = _cairo_surface_copy_pattern_for_destination (&source, - surface, - &dev_source.base); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); + _cairo_surface_copy_pattern_for_destination (&source, surface, + &dev_source.base); - if (surface->backend->stroke) { + if (surface->backend->stroke != NULL) { status = surface->backend->stroke (surface, op, source, path, stroke_style, - &dev_ctm, &dev_ctm_inverse, - tolerance, antialias, extents); + ctm, ctm_inverse, + tolerance, antialias, + clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto FINISH; @@ -2141,16 +2069,11 @@ _cairo_surface_stroke (cairo_surface_t *surface, status = _cairo_surface_fallback_stroke (surface, op, source, path, stroke_style, - &dev_ctm, &dev_ctm_inverse, - tolerance, antialias); + ctm, ctm_inverse, + tolerance, antialias, + clip); FINISH: - if (dev_path == &real_dev_path) - _cairo_path_fixed_fini (&real_dev_path); - - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); - return _cairo_surface_set_error (surface, status); } @@ -2162,26 +2085,26 @@ _cairo_surface_fill (cairo_surface_t *surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_pattern_union_t dev_source; - if (surface->status) + if (unlikely (surface->status)) return surface->status; - _cairo_surface_begin_modification (surface); + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; - status = _cairo_surface_copy_pattern_for_destination (&source, - surface, - &dev_source.base); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); + _cairo_surface_begin_modification (surface); - if (surface->backend->fill) { + _cairo_surface_copy_pattern_for_destination (&source, surface, + &dev_source.base); + if (surface->backend->fill != NULL) { status = surface->backend->fill (surface, op, source, path, fill_rule, - tolerance, antialias, extents); + tolerance, antialias, + clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto FINISH; @@ -2189,12 +2112,10 @@ _cairo_surface_fill (cairo_surface_t *surface, status = _cairo_surface_fallback_fill (surface, op, source, path, fill_rule, - tolerance, antialias); + tolerance, antialias, + clip); FINISH: - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); - return _cairo_surface_set_error (surface, status); } @@ -2210,7 +2131,8 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int num_traps) + int num_traps, + cairo_region_t *clip_region) { cairo_int_status_t status; @@ -2231,7 +2153,8 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, src_x, src_y, dst_x, dst_y, width, height, - traps, num_traps); + traps, num_traps, + clip_region); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return _cairo_surface_set_error (dst, status); } @@ -2242,56 +2165,58 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, src_x, src_y, dst_x, dst_y, width, height, - traps, num_traps)); + traps, num_traps, + clip_region)); } cairo_span_renderer_t * -_cairo_surface_create_span_renderer (cairo_operator_t op, - const cairo_pattern_t *pattern, +_cairo_surface_create_span_renderer (cairo_operator_t op, + const cairo_pattern_t *pattern, cairo_surface_t *dst, - cairo_antialias_t antialias, - const cairo_composite_rectangles_t *rects) + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects, + cairo_region_t *clip_region) { assert (dst->snapshot_of == NULL); - if (dst->status) + if (unlikely (dst->status)) return _cairo_span_renderer_create_in_error (dst->status); - if (dst->finished) + if (unlikely (dst->finished)) return _cairo_span_renderer_create_in_error (CAIRO_STATUS_SURFACE_FINISHED); if (dst->backend->create_span_renderer) { return dst->backend->create_span_renderer (op, pattern, dst, antialias, - rects); + rects, + clip_region); } ASSERT_NOT_REACHED; return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED); } cairo_bool_t -_cairo_surface_check_span_renderer (cairo_operator_t op, +_cairo_surface_check_span_renderer (cairo_operator_t op, const cairo_pattern_t *pattern, cairo_surface_t *dst, - cairo_antialias_t antialias, + cairo_antialias_t antialias, const cairo_composite_rectangles_t *rects) { cairo_int_status_t status; assert (dst->snapshot_of == NULL); - if (dst->status) + if (unlikely (dst->status)) return FALSE; - if (dst->finished) { + if (unlikely (dst->finished)) { status = _cairo_surface_set_error (dst, CAIRO_STATUS_SURFACE_FINISHED); return FALSE; } if (dst->backend->check_span_renderer) { - return dst->backend->check_span_renderer (op, - pattern, dst, + return dst->backend->check_span_renderer (op, pattern, dst, antialias, rects); } @@ -2375,329 +2300,6 @@ cairo_surface_show_page (cairo_surface_t *surface) slim_hidden_def (cairo_surface_show_page); /** - * _cairo_surface_get_current_clip_serial: - * @surface: the #cairo_surface_t to return the serial number for - * - * This space left intentionally blank. - * - * Returns: the serial number associated with the current - * clip in the surface. All gstate functions must - * verify that the correct clip is set in the surface before - * invoking any surface drawing function. - */ -unsigned int -_cairo_surface_get_current_clip_serial (cairo_surface_t *surface) -{ - return surface->current_clip_serial; -} - -/** - * _cairo_surface_allocate_clip_serial: - * @surface: the #cairo_surface_t to allocate a serial number from - * - * Each surface has a separate set of clipping serial numbers, and - * this function allocates one from the specified surface. As zero is - * reserved for the special no-clipping case, this function will not - * return that except for an in-error surface, (ie. surface->status != - * %CAIRO_STATUS_SUCCESS). - */ -unsigned int -_cairo_surface_allocate_clip_serial (cairo_surface_t *surface) -{ - unsigned int serial; - - if (surface->status) - return 0; - - if ((serial = ++(surface->next_clip_serial)) == 0) - serial = ++(surface->next_clip_serial); - return serial; -} - -/** - * _cairo_surface_reset_clip: - * @surface: the #cairo_surface_t to reset the clip on - * - * This function sets the clipping for the surface to - * None, which is to say that drawing is entirely - * unclipped. It also sets the clip serial number - * to zero. - */ -cairo_status_t -_cairo_surface_reset_clip (cairo_surface_t *surface) -{ - cairo_status_t status; - - if (surface->status) - return surface->status; - - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); - - surface->current_clip_serial = 0; - - if (surface->backend->intersect_clip_path) { - status = surface->backend->intersect_clip_path (surface, - NULL, - CAIRO_FILL_RULE_WINDING, - 0, - CAIRO_ANTIALIAS_DEFAULT); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - } - - if (surface->backend->set_clip_region != NULL) { - status = surface->backend->set_clip_region (surface, NULL); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - } - - return CAIRO_STATUS_SUCCESS; -} - -/** - * _cairo_surface_set_clip_region: - * @surface: the #cairo_surface_t to reset the clip on - * @region: the #cairo_region_t to use for clipping - * @serial: the clip serial number associated with the region - * - * This function sets the clipping for the surface to - * the specified region and sets the surface clipping - * serial number to the associated serial number. - */ -cairo_status_t -_cairo_surface_set_clip_region (cairo_surface_t *surface, - cairo_region_t *region, - unsigned int serial) -{ - cairo_status_t status; - - if (surface->status) - return surface->status; - - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); - - assert (surface->backend->set_clip_region != NULL); - - status = surface->backend->set_clip_region (surface, region); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - - surface->current_clip_serial = serial; - - return CAIRO_STATUS_SUCCESS; -} - -cairo_int_status_t -_cairo_surface_intersect_clip_path (cairo_surface_t *surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_path_fixed_t *dev_path = path; - cairo_status_t status; - - if (surface->status) - return surface->status; - - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); - - assert (surface->backend->intersect_clip_path != NULL); - - status = surface->backend->intersect_clip_path (surface, - dev_path, - fill_rule, - tolerance, - antialias); - - return _cairo_surface_set_error (surface, status); -} - -static cairo_status_t -_cairo_surface_set_clip_path_recursive (cairo_surface_t *surface, - cairo_clip_path_t *clip_path) -{ - cairo_status_t status; - - if (surface->status) - return surface->status; - - if (clip_path == NULL) - return CAIRO_STATUS_SUCCESS; - - status = _cairo_surface_set_clip_path_recursive (surface, clip_path->prev); - if (unlikely (status)) - return status; - - return _cairo_surface_intersect_clip_path (surface, - &clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - clip_path->antialias); -} - -/** - * _cairo_surface_set_clip_path: - * @surface: the #cairo_surface_t to set the clip on - * @clip_path: the clip path to set - * @serial: the clip serial number associated with the clip path - * - * Sets the given clipping path for the surface and assigns the - * clipping serial to the surface. - **/ -static cairo_status_t -_cairo_surface_set_clip_path (cairo_surface_t *surface, - cairo_clip_path_t *clip_path, - unsigned int serial) -{ - cairo_status_t status; - - if (surface->status) - return surface->status; - - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); - - assert (surface->backend->intersect_clip_path != NULL); - - status = surface->backend->intersect_clip_path (surface, - NULL, - CAIRO_FILL_RULE_WINDING, - 0, - CAIRO_ANTIALIAS_DEFAULT); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - - status = _cairo_surface_set_clip_path_recursive (surface, clip_path); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - - surface->current_clip_serial = serial; - - return CAIRO_STATUS_SUCCESS; -} - - -/** - * _cairo_surface_set_empty_clip_path: - * @surface: the #cairo_surface_t to set the clip on - * @serial: the clip serial number associated with the clip path - * - * Create an empty clip path, one that represents the entire surface clipped - * out, and assigns the given clipping serial to the surface. - **/ -static cairo_status_t -_cairo_surface_set_empty_clip_path (cairo_surface_t *surface, - unsigned int serial) -{ - cairo_path_fixed_t path; - cairo_status_t status; - - if (surface->status) - return surface->status; - - _cairo_path_fixed_init (&path); - - status = surface->backend->intersect_clip_path (surface, - &path, - CAIRO_FILL_RULE_WINDING, - 0, - CAIRO_ANTIALIAS_DEFAULT); - - if (status == CAIRO_STATUS_SUCCESS) - surface->current_clip_serial = serial; - - _cairo_path_fixed_fini (&path); - - return _cairo_surface_set_error (surface, status); -} - -/** - * _cairo_surface_set_empty_clip_region: - * @surface: the #cairo_surface_t to set the clip on - * @serial: the clip serial number associated with the clip path - * - * Create an empty clip region, one that represents the entire surface clipped - * out, and assigns the given clipping serial to the surface. - **/ -static cairo_status_t -_cairo_surface_set_empty_clip_region (cairo_surface_t *surface, - unsigned int serial) -{ - cairo_region_t *region; - cairo_status_t status; - - if (surface->status) - return surface->status; - - region = cairo_region_create (); - status = region->status; - - if (status == CAIRO_STATUS_SUCCESS) - status = _cairo_surface_set_clip_region (surface, region, serial); - - cairo_region_destroy (region); - - return _cairo_surface_set_error (surface, status); -} - -cairo_clip_t * -_cairo_surface_get_clip (cairo_surface_t *surface) -{ - return surface->clip; -} - -cairo_status_t -_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip) -{ - unsigned int serial = 0; - - if (surface->status) - return surface->status; - - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); - - if (clip) { - serial = clip->serial; - if (serial == 0) - clip = NULL; - } - - surface->clip = clip; - - if (serial == _cairo_surface_get_current_clip_serial (surface)) - return CAIRO_STATUS_SUCCESS; - - if (clip) { - if (clip->all_clipped) { - if (surface->backend->intersect_clip_path != NULL) - return _cairo_surface_set_empty_clip_path (surface, - clip->serial); - - if (surface->backend->set_clip_region != NULL) - return _cairo_surface_set_empty_clip_region (surface, - clip->serial); - } else { - if (clip->path) - return _cairo_surface_set_clip_path (surface, - clip->path, - clip->serial); - - if (clip->region) - return _cairo_surface_set_clip_region (surface, - clip->region, - clip->serial); - } - } - - return _cairo_surface_reset_clip (surface); -} - -/** * _cairo_surface_get_extents: * @surface: the #cairo_surface_t to fetch extents for * @@ -2721,31 +2323,22 @@ _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip) * This behavior would have to be changed is we ever exported a public * variant of this function. */ -cairo_int_status_t +cairo_bool_t _cairo_surface_get_extents (cairo_surface_t *surface, cairo_rectangle_int_t *extents) { - cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + cairo_bool_t bounded = FALSE; - if (surface->status) - return surface->status; + if (unlikely (surface->status || surface->finished)) + return TRUE; - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); + if (surface->backend->get_extents != NULL) + bounded = surface->backend->get_extents (surface, extents); - if (surface->backend->get_extents) { - status = _cairo_surface_set_error (surface, - surface->backend->get_extents (surface, extents)); - } + if (! bounded) + _cairo_unbounded_rectangle_init (extents); - if (status == CAIRO_INT_STATUS_UNSUPPORTED) { - extents->x = CAIRO_RECT_INT_MIN; - extents->y = CAIRO_RECT_INT_MIN; - extents->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; - extents->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; - } - - return status; + return bounded; } /** @@ -2817,25 +2410,25 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_scaled_font_t *dev_scaled_font = scaled_font; cairo_pattern_union_t dev_source; - if (surface->status) + if (unlikely (surface->status)) return surface->status; if (num_glyphs == 0 && utf8_len == 0) return CAIRO_STATUS_SUCCESS; + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + _cairo_surface_begin_modification (surface); - status = _cairo_surface_copy_pattern_for_destination (&source, - surface, - &dev_source.base); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); + _cairo_surface_copy_pattern_for_destination (&source, surface, + &dev_source.base); if (_cairo_surface_has_device_transform (surface) && ! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL)) @@ -2853,12 +2446,8 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, &font_options); } status = cairo_scaled_font_status (dev_scaled_font); - if (unlikely (status)) { - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); - + if (unlikely (status)) return _cairo_surface_set_error (surface, status); - } status = CAIRO_INT_STATUS_UNSUPPORTED; @@ -2867,21 +2456,25 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, if (clusters) { /* A real show_text_glyphs call. Try show_text_glyphs backend * method first */ - if (surface->backend->show_text_glyphs) { + if (surface->backend->show_text_glyphs != NULL) { status = surface->backend->show_text_glyphs (surface, op, source, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - dev_scaled_font, extents); + dev_scaled_font, + clip); } - if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->backend->show_glyphs) { + if (status == CAIRO_INT_STATUS_UNSUPPORTED && + surface->backend->show_glyphs) + { int remaining_glyphs = num_glyphs; status = surface->backend->show_glyphs (surface, op, source, glyphs, num_glyphs, dev_scaled_font, - &remaining_glyphs, extents); + clip, + &remaining_glyphs); glyphs += num_glyphs - remaining_glyphs; num_glyphs = remaining_glyphs; if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0) @@ -2889,18 +2482,19 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, } } else { /* A mere show_glyphs call. Try show_glyphs backend method first */ - if (surface->backend->show_glyphs) { + if (surface->backend->show_glyphs != NULL) { int remaining_glyphs = num_glyphs; status = surface->backend->show_glyphs (surface, op, source, glyphs, num_glyphs, dev_scaled_font, - &remaining_glyphs, extents); + clip, + &remaining_glyphs); glyphs += num_glyphs - remaining_glyphs; num_glyphs = remaining_glyphs; if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0) status = CAIRO_STATUS_SUCCESS; - } else if (surface->backend->show_text_glyphs) { + } else if (surface->backend->show_text_glyphs != NULL) { /* Intentionally only try show_text_glyphs method for show_glyphs * calls if backend does not have show_glyphs. If backend has * both methods implemented, we don't fallback from show_glyphs to @@ -2914,22 +2508,22 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - dev_scaled_font, extents); + dev_scaled_font, + clip); } } - if (status == CAIRO_INT_STATUS_UNSUPPORTED) + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { status = _cairo_surface_fallback_show_glyphs (surface, op, source, glyphs, num_glyphs, - dev_scaled_font); + dev_scaled_font, + clip); + } if (dev_scaled_font != scaled_font) cairo_scaled_font_destroy (dev_scaled_font); - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); - return _cairo_surface_set_error (surface, status); } @@ -2950,7 +2544,8 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, unsigned int width, unsigned int height, cairo_glyph_t *glyphs, - int num_glyphs) + int num_glyphs, + cairo_region_t *clip_region) { cairo_status_t status; @@ -2965,7 +2560,8 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, source_x, source_y, dest_x, dest_y, width, height, - glyphs, num_glyphs); + glyphs, num_glyphs, + clip_region); } else status = CAIRO_INT_STATUS_UNSUPPORTED; @@ -2979,7 +2575,8 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_rectangle_int_t dst_rectangle; cairo_region_t clear_region; @@ -2995,12 +2592,18 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst, _cairo_region_init_rectangle (&clear_region, &dst_rectangle); - if (src_rectangle) { + if (clip_region != NULL) { + status = cairo_region_intersect (&clear_region, clip_region); + if (unlikely (status)) + goto CLEANUP_REGIONS; + } + + if (src_rectangle != NULL) { if (! _cairo_rectangle_intersect (&dst_rectangle, src_rectangle)) goto EMPTY; } - if (mask_rectangle) { + if (mask_rectangle != NULL) { if (! _cairo_rectangle_intersect (&dst_rectangle, mask_rectangle)) goto EMPTY; } @@ -3011,7 +2614,7 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst, goto CLEANUP_REGIONS; EMPTY: - status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_SOURCE, + status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, &clear_region); @@ -3060,13 +2663,14 @@ _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_rectangle_int_t src_tmp, mask_tmp; cairo_rectangle_int_t *src_rectangle = NULL; cairo_rectangle_int_t *mask_rectangle = NULL; - if (dst->status) + if (unlikely (dst->status)) return dst->status; assert (_cairo_surface_is_writable (dst)); @@ -3098,7 +2702,8 @@ _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, } return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle, - dst_x, dst_y, width, height); + dst_x, dst_y, width, height, + clip_region); } /** @@ -3138,7 +2743,8 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_rectangle_int_t src_tmp, mask_tmp; cairo_rectangle_int_t *src_rectangle = NULL; @@ -3171,7 +2777,8 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, mask_rectangle = &mask_tmp; return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle, - dst_x, dst_y, width, height); + dst_x, dst_y, width, height, + clip_region); } /** @@ -3183,26 +2790,19 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, * Copies the given pattern, taking into account device scale and offsets * of the destination surface. */ -static cairo_status_t +static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t **pattern, cairo_surface_t *destination, cairo_pattern_t *pattern_copy) { - cairo_status_t status; - if (! _cairo_surface_has_device_transform (destination)) - return CAIRO_STATUS_SUCCESS; - - status = _cairo_pattern_init_copy (pattern_copy, *pattern); - if (unlikely (status)) - return status; + return; + _cairo_pattern_init_static_copy (pattern_copy, *pattern); _cairo_pattern_transform (pattern_copy, &destination->device_transform_inverse); - *pattern = pattern_copy; - return CAIRO_STATUS_SUCCESS; } /** @@ -3235,6 +2835,8 @@ _cairo_surface_create_in_error (cairo_status_t status) return (cairo_surface_t *) &_cairo_surface_nil; case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: return (cairo_surface_t *) &_cairo_surface_nil_surface_type_mismatch; + case CAIRO_STATUS_INVALID_STATUS: + return (cairo_surface_t *) &_cairo_surface_nil_invalid_status; case CAIRO_STATUS_INVALID_CONTENT: return (cairo_surface_t *) &_cairo_surface_nil_invalid_content; case CAIRO_STATUS_INVALID_FORMAT: @@ -3261,7 +2863,6 @@ _cairo_surface_create_in_error (cairo_status_t status) case CAIRO_STATUS_INVALID_POP_GROUP: case CAIRO_STATUS_NO_CURRENT_POINT: case CAIRO_STATUS_INVALID_MATRIX: - case CAIRO_STATUS_INVALID_STATUS: case CAIRO_STATUS_NULL_POINTER: case CAIRO_STATUS_INVALID_STRING: case CAIRO_STATUS_INVALID_PATH_DATA: diff --git a/src/cairo-svg-surface-private.h b/src/cairo-svg-surface-private.h index e7cd4db8..64efe7f2 100644 --- a/src/cairo-svg-surface-private.h +++ b/src/cairo-svg-surface-private.h @@ -44,6 +44,7 @@ #include "cairo-svg.h" #include "cairo-surface-private.h" +#include "cairo-surface-clipper-private.h" typedef struct cairo_svg_document cairo_svg_document_t; @@ -52,8 +53,6 @@ typedef struct cairo_svg_surface { cairo_content_t content; - unsigned int id; - double width; double height; @@ -62,6 +61,7 @@ typedef struct cairo_svg_surface { cairo_output_stream_t *xml_node; cairo_array_t page_set; + cairo_surface_clipper_t clipper; unsigned int clip_level; unsigned int base_clip; cairo_bool_t is_base_clip_emitted; diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index 3a6b62df..08e4cfcb 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -49,6 +49,7 @@ #include "cairo-path-fixed-private.h" #include "cairo-paginated-private.h" #include "cairo-scaled-font-subsets-private.h" +#include "cairo-surface-clipper-private.h" #include "cairo-svg-surface-private.h" typedef struct cairo_svg_page cairo_svg_page_t; @@ -63,6 +64,11 @@ static const cairo_svg_version_t _cairo_svg_versions[] = #define CAIRO_SVG_VERSION_LAST ARRAY_LENGTH (_cairo_svg_versions) +static void +_cairo_svg_surface_emit_path (cairo_output_stream_t *output, + cairo_path_fixed_t *path, + cairo_matrix_t *ctm_inverse); + static cairo_bool_t _cairo_svg_version_has_page_set_support (cairo_svg_version_t version) { @@ -99,7 +105,6 @@ struct cairo_svg_document { cairo_output_stream_t *xml_node_defs; cairo_output_stream_t *xml_node_glyphs; - unsigned int surface_id; unsigned int linear_pattern_id; unsigned int radial_pattern_id; unsigned int pattern_id; @@ -109,18 +114,11 @@ struct cairo_svg_document { cairo_bool_t alpha_filter; - cairo_array_t meta_snapshots; - cairo_svg_version_t svg_version; cairo_scaled_font_subsets_t *font_subsets; }; -typedef struct { - unsigned int id; - cairo_meta_surface_t *meta; -} cairo_meta_snapshot_t; - static cairo_status_t _cairo_svg_document_create (cairo_output_stream_t *stream, double width, @@ -278,8 +276,8 @@ _extract_svg_surface (cairo_surface_t *surface, * Since: 1.2 **/ void -cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface, - cairo_svg_version_t version) +cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface, + cairo_svg_version_t version) { cairo_svg_surface_t *surface = NULL; /* hide compiler warning */ cairo_status_t status; @@ -306,7 +304,7 @@ cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface, **/ void cairo_svg_get_versions (cairo_svg_version_t const **versions, - int *num_versions) + int *num_versions) { if (versions != NULL) *versions = _cairo_svg_versions; @@ -336,6 +334,73 @@ cairo_svg_version_to_string (cairo_svg_version_t version) return _cairo_svg_version_strings[version]; } +static cairo_bool_t +_cliprect_covers_surface (cairo_svg_surface_t *surface, + cairo_path_fixed_t *path) +{ + cairo_box_t box; + + if (_cairo_path_fixed_is_rectangle (path, &box)) { + if (box.p1.x <= 0 && + box.p1.y <= 0 && + _cairo_fixed_to_double (box.p2.x) >= surface->width && + _cairo_fixed_to_double (box.p2.y) >= surface->height) + { + return TRUE; + } + } + + return FALSE; +} + +static cairo_status_t +_cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_svg_surface_t *surface = cairo_container_of (clipper, + cairo_svg_surface_t, + clipper); + cairo_svg_document_t *document = surface->document; + unsigned int i; + + if (path == NULL) { + for (i = 0; i < surface->clip_level; i++) + _cairo_output_stream_printf (surface->xml_node, "</g>\n"); + + surface->clip_level = 0; + return CAIRO_STATUS_SUCCESS; + } + + /* skip trivial whole-page clips */ + if (_cliprect_covers_surface (surface, path)) + return CAIRO_STATUS_SUCCESS; + + _cairo_output_stream_printf (document->xml_node_defs, + "<clipPath id=\"clip%d\">\n" + " <path ", + document->clip_id); + _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL); + + _cairo_output_stream_printf (document->xml_node_defs, + "/>\n" + "</clipPath>\n"); + + _cairo_output_stream_printf (surface->xml_node, + "<g clip-path=\"url(#clip%d)\" " + "clip-rule=\"%s\">\n", + document->clip_id, + fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? + "evenodd" : "nonzero"); + + document->clip_id++; + surface->clip_level++; + + return CAIRO_STATUS_SUCCESS; +} + static cairo_surface_t * _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, cairo_content_t content, @@ -359,8 +424,9 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, surface->document = _cairo_svg_document_reference (document); surface->clip_level = 0; + _cairo_surface_clipper_init (&surface->clipper, + _cairo_svg_surface_clipper_intersect_clip_path); - surface->id = document->surface_id++; surface->base_clip = document->clip_id++; surface->is_base_clip_emitted = FALSE; @@ -388,8 +454,6 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, paginated = _cairo_paginated_surface_create (&surface->base, surface->content, - surface->width, - surface->height, &cairo_svg_surface_paginated_backend); status = paginated->status; if (status == CAIRO_STATUS_SUCCESS) { @@ -457,7 +521,7 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface) return NULL; } - page.surface_id = surface->id; + page.surface_id = surface->base.unique_id; page.clip_level = surface->clip_level; page.xml_node = surface->xml_node; @@ -468,11 +532,13 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface) surface->xml_node = stream; surface->clip_level = 0; - for (i = 0; i < page.clip_level; i++) _cairo_output_stream_printf (page.xml_node, "</g>\n"); - return _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1); + _cairo_surface_clipper_reset (&surface->clipper); + + return _cairo_array_index (&surface->page_set, + surface->page_set.num_elements - 1); } static cairo_int_status_t @@ -486,7 +552,6 @@ _cairo_svg_surface_copy_page (void *abstract_surface) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_memory_stream_copy (page->xml_node, surface->xml_node); - surface->clip_level = page->clip_level; return CAIRO_STATUS_SUCCESS; } @@ -596,7 +661,7 @@ _cairo_svg_path_close_path (void *closure) return CAIRO_STATUS_SUCCESS; } -static cairo_status_t +static void _cairo_svg_surface_emit_path (cairo_output_stream_t *output, cairo_path_fixed_t *path, cairo_matrix_t *ctm_inverse) @@ -615,12 +680,9 @@ _cairo_svg_surface_emit_path (cairo_output_stream_t *output, _cairo_svg_path_curve_to, _cairo_svg_path_close_path, &info); - if (unlikely (status)) - return status; + assert (status == CAIRO_STATUS_SUCCESS); _cairo_output_stream_printf (output, "\""); - - return status; } static cairo_int_status_t @@ -642,9 +704,8 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document, _cairo_output_stream_printf (document->xml_node_glyphs, "<path style=\"stroke:none;\" "); - status = _cairo_svg_surface_emit_path (document->xml_node_glyphs, scaled_glyph->path, NULL); - if (unlikely (status)) - return status; + _cairo_svg_surface_emit_path (document->xml_node_glyphs, + scaled_glyph->path, NULL); _cairo_output_stream_printf (document->xml_node_glyphs, "/>\n"); @@ -847,22 +908,7 @@ _cairo_svg_surface_operation_supported (cairo_svg_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *pattern) { - if (_cairo_svg_surface_analyze_operation (surface, op, pattern) - != CAIRO_INT_STATUS_UNSUPPORTED) - { - return TRUE; - } else { - return FALSE; - } -} - -static cairo_surface_t * -_cairo_svg_surface_create_similar (void *abstract_src, - cairo_content_t content, - int width, - int height) -{ - return cairo_meta_surface_create (content, width, height); + return _cairo_svg_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED; } static cairo_status_t @@ -893,6 +939,8 @@ _cairo_svg_surface_finish (void *abstract_surface) } _cairo_array_fini (&surface->page_set); + _cairo_surface_clipper_reset (&surface->clipper); + status2 = _cairo_svg_document_destroy (document); if (status == CAIRO_STATUS_SUCCESS) status = status2; @@ -900,6 +948,7 @@ _cairo_svg_surface_finish (void *abstract_surface) return status; } + static void _cairo_svg_surface_emit_alpha_filter (cairo_svg_document_t *document) { @@ -1120,112 +1169,139 @@ _cairo_svg_surface_emit_operator_for_style (cairo_output_stream_t *output, } static cairo_status_t -_cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output, - cairo_svg_surface_t *svg_surface, - cairo_operator_t op, - cairo_surface_pattern_t *pattern, - int pattern_id, - const cairo_matrix_t *parent_matrix, - const char *extra_attributes) +_cairo_svg_surface_emit_surface (cairo_svg_document_t *document, + cairo_surface_t *surface) { cairo_rectangle_int_t extents; + cairo_bool_t is_bounded; cairo_status_t status; - cairo_matrix_t p2u; - status = _cairo_surface_get_extents (pattern->surface, &extents); + if (_cairo_user_data_array_get_data (&surface->user_data, + (cairo_user_data_key_t *) document)) + { + return CAIRO_STATUS_SUCCESS; + } + + is_bounded = _cairo_surface_get_extents (surface, &extents); + assert (is_bounded); + + _cairo_output_stream_printf (document->xml_node_defs, + "<image id=\"image%d\" width=\"%d\" height=\"%d\"", + surface->unique_id, + extents.width, extents.height); + + _cairo_output_stream_printf (document->xml_node_defs, " xlink:href=\""); + + status = _cairo_surface_base64_encode (surface, + document->xml_node_defs); if (unlikely (status)) return status; + _cairo_output_stream_printf (document->xml_node_defs, "\"/>\n"); + + /* and tag it */ + return _cairo_user_data_array_set_data (&surface->user_data, + (cairo_user_data_key_t *) document, + document, NULL); +} + +static cairo_status_t +_cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output, + cairo_svg_surface_t *svg_surface, + cairo_operator_t op, + cairo_surface_pattern_t *pattern, + int pattern_id, + const cairo_matrix_t *parent_matrix, + const char *extra_attributes) +{ + cairo_status_t status; + cairo_matrix_t p2u; + p2u = pattern->base.matrix; status = cairo_matrix_invert (&p2u); /* cairo_pattern_set_matrix ensures the matrix is invertible */ assert (status == CAIRO_STATUS_SUCCESS); + status = _cairo_svg_surface_emit_surface (svg_surface->document, + pattern->surface); + if (unlikely (status)) + return status; + if (pattern_id != invalid_pattern_id) { + cairo_rectangle_int_t extents; + cairo_bool_t is_bounded; + + is_bounded = _cairo_surface_get_extents (pattern->surface, &extents); + assert (is_bounded); + _cairo_output_stream_printf (output, "<pattern id=\"pattern%d\" " "patternUnits=\"userSpaceOnUse\" " - "width=\"%d\" height=\"%d\"", + "width=\"%d\" height=\"%d\" ", pattern_id, extents.width, extents.height); - _cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix); - _cairo_output_stream_printf (output, ">\n"); + _cairo_svg_surface_emit_transform (output, + " patternTransform", + &p2u, parent_matrix); + _cairo_output_stream_printf (output, ">\n "); } _cairo_output_stream_printf (output, - " <image width=\"%d\" height=\"%d\"", - extents.width, extents.height); + "<use xlink:href=\"#image%d\"", + pattern->surface->unique_id); + if (extra_attributes) + _cairo_output_stream_printf (output, " %s", extra_attributes); if (pattern_id == invalid_pattern_id) { _cairo_svg_surface_emit_operator (output, svg_surface, op); - _cairo_svg_surface_emit_transform (output, " transform", &p2u, parent_matrix); + _cairo_svg_surface_emit_transform (output, + " transform", + &p2u, parent_matrix); } + _cairo_output_stream_printf (output, "/>\n"); - if (extra_attributes) - _cairo_output_stream_printf (output, " %s", extra_attributes); - - _cairo_output_stream_printf (output, " xlink:href=\""); - - status = _cairo_surface_base64_encode (pattern->surface, output); - - _cairo_output_stream_printf (output, "\"/>\n"); if (pattern_id != invalid_pattern_id) _cairo_output_stream_printf (output, "</pattern>\n"); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, - cairo_meta_surface_t *surface, - int *id) + cairo_meta_surface_t *source) { cairo_status_t status; cairo_surface_t *paginated_surface; cairo_svg_surface_t *svg_surface; - cairo_meta_snapshot_t new_snapshot; cairo_array_t *page_set; cairo_output_stream_t *contents; - cairo_meta_surface_t *meta; - cairo_meta_snapshot_t *snapshot; - unsigned int num_elements; - unsigned int i; - /* search in already emitted meta snapshots */ - num_elements = document->meta_snapshots.num_elements; - for (i = 0; i < num_elements; i++) { - snapshot = _cairo_array_index (&document->meta_snapshots, i); - meta = snapshot->meta; - if (meta->commands.num_elements == surface->commands.num_elements && - _cairo_array_index (&meta->commands, 0) == _cairo_array_index (&surface->commands, 0)) { - *id = snapshot->id; - return CAIRO_STATUS_SUCCESS; - } + if (_cairo_user_data_array_get_data (&source->base.user_data, + (cairo_user_data_key_t *) document)) + { + return CAIRO_STATUS_SUCCESS; } - meta = (cairo_meta_surface_t *) _cairo_surface_snapshot (&surface->base); - if (unlikely (meta->base.status)) - return meta->base.status; - paginated_surface = _cairo_svg_surface_create_for_document (document, - meta->content, - meta->width_pixels, - meta->height_pixels); - if (paginated_surface->status) { - cairo_surface_destroy (&meta->base); + source->content, + source->extents_pixels.width, + source->extents_pixels.height); + if (unlikely (paginated_surface->status)) return paginated_surface->status; - } - svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface); + svg_surface = (cairo_svg_surface_t *) + _cairo_paginated_surface_get_target (paginated_surface); cairo_surface_set_fallback_resolution (paginated_surface, document->owner->x_fallback_resolution, document->owner->y_fallback_resolution); + cairo_surface_set_device_offset (&svg_surface->base, + -source->extents_pixels.x, + -source->extents_pixels.y); - status = cairo_meta_surface_replay (&meta->base, paginated_surface); + status = cairo_meta_surface_replay (&source->base, paginated_surface); if (unlikely (status)) { - cairo_surface_destroy (&meta->base); cairo_surface_destroy (paginated_surface); return status; } @@ -1233,21 +1309,11 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, cairo_surface_show_page (paginated_surface); status = cairo_surface_status (paginated_surface); if (unlikely (status)) { - cairo_surface_destroy (&meta->base); - cairo_surface_destroy (paginated_surface); - return status; - } - - new_snapshot.meta = meta; - new_snapshot.id = svg_surface->id; - status = _cairo_array_append (&document->meta_snapshots, &new_snapshot); - if (unlikely (status)) { - cairo_surface_destroy (&meta->base); cairo_surface_destroy (paginated_surface); return status; } - if (!svg_surface->is_base_clip_emitted) { + if (! svg_surface->is_base_clip_emitted) { svg_surface->is_base_clip_emitted = TRUE; _cairo_output_stream_printf (document->xml_node_defs, "<clipPath id=\"clip%d\">\n" @@ -1258,19 +1324,19 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, svg_surface->height); } - if (meta->content == CAIRO_CONTENT_ALPHA) { + if (source->content == CAIRO_CONTENT_ALPHA) { _cairo_svg_surface_emit_alpha_filter (document); _cairo_output_stream_printf (document->xml_node_defs, "<g id=\"surface%d\" " "clip-path=\"url(#clip%d)\" " "filter=\"url(#alpha)\">\n", - svg_surface->id, + source->base.unique_id, svg_surface->base_clip); } else { _cairo_output_stream_printf (document->xml_node_defs, "<g id=\"surface%d\" " "clip-path=\"url(#clip%d)\">\n", - svg_surface->id, + source->base.unique_id, svg_surface->base_clip); } @@ -1293,19 +1359,16 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document, _cairo_output_stream_printf (document->xml_node_defs, "</g>\n"); - *id = new_snapshot.id; - status = cairo_surface_status (paginated_surface); cairo_surface_destroy (paginated_surface); - /* FIXME: cairo_paginated_surface doesn't take a ref to the - * passed in target surface so we can't call destroy here. - * cairo_paginated_surface should be fixed, but for now just - * work around it. */ - - /* cairo_surface_destroy (svg_surface); */ + if (unlikely (status)) + return status; - return status; + /* and tag it */ + return _cairo_user_data_array_set_data (&source->base.user_data, + (cairo_user_data_key_t *) document, + document, NULL); } static cairo_status_t @@ -1321,7 +1384,6 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output, cairo_meta_surface_t *meta_surface; cairo_matrix_t p2u; cairo_status_t status; - int id = 0; p2u = pattern->base.matrix; status = cairo_matrix_invert (&p2u); @@ -1329,8 +1391,7 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output, assert (status == CAIRO_STATUS_SUCCESS); meta_surface = (cairo_meta_surface_t *) pattern->surface; - - status = _cairo_svg_surface_emit_meta_surface (document, meta_surface, &id); + status = _cairo_svg_surface_emit_meta_surface (document, meta_surface); if (unlikely (status)) return status; @@ -1340,15 +1401,15 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output, "patternUnits=\"userSpaceOnUse\" " "width=\"%d\" height=\"%d\"", pattern_id, - (int) ceil (meta_surface->width_pixels), - (int) ceil (meta_surface->height_pixels)); + meta_surface->extents.width, + meta_surface->extents.height); _cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix); _cairo_output_stream_printf (output, ">\n"); } _cairo_output_stream_printf (output, "<use xlink:href=\"#surface%d\"", - id); + meta_surface->base.unique_id); if (pattern_id == invalid_pattern_id) { _cairo_svg_surface_emit_operator (output, surface, op); @@ -1377,12 +1438,18 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output, { if (_cairo_surface_is_meta (pattern->surface)) { - return _cairo_svg_surface_emit_composite_meta_pattern (output, surface, op, pattern, - pattern_id, parent_matrix, extra_attributes); + return _cairo_svg_surface_emit_composite_meta_pattern (output, surface, + op, pattern, + pattern_id, + parent_matrix, + extra_attributes); } - return _cairo_svg_surface_emit_composite_image_pattern (output, surface, op, pattern, - pattern_id, parent_matrix, extra_attributes); + return _cairo_svg_surface_emit_composite_surface_pattern (output, surface, + op, pattern, + pattern_id, + parent_matrix, + extra_attributes); } static cairo_status_t @@ -1716,7 +1783,9 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, document->radial_pattern_id, x1, y1, x1, y1, r1); - _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix); + _cairo_svg_surface_emit_transform (document->xml_node_defs, + "gradientTransform", + &p2u, parent_matrix); _cairo_output_stream_printf (document->xml_node_defs, ">\n"); if (extend == CAIRO_EXTEND_NONE || n_stops < 1) @@ -1981,11 +2050,15 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface, cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_svg_surface_t *surface = abstract_surface; cairo_status_t status; + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + _cairo_output_stream_printf (surface->xml_node, "<path style=\""); status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op, fill_source, fill_rule, stroke_ctm_inverse); @@ -1999,9 +2072,7 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface, _cairo_output_stream_printf (surface->xml_node, "\" "); - status = _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse); - if (unlikely (status)) - return status; + _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse); _cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm, NULL); _cairo_output_stream_printf (surface->xml_node, "/>\n"); @@ -2017,7 +2088,7 @@ _cairo_svg_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_svg_surface_t *surface = abstract_surface; cairo_status_t status; @@ -2027,6 +2098,10 @@ _cairo_svg_surface_fill (void *abstract_surface, assert (_cairo_svg_surface_operation_supported (surface, op, source)); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + _cairo_output_stream_printf (surface->xml_node, "<path style=\" stroke:none;"); status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL); if (unlikely (status)) @@ -2034,16 +2109,14 @@ _cairo_svg_surface_fill (void *abstract_surface, _cairo_output_stream_printf (surface->xml_node, "\" "); - status = _cairo_svg_surface_emit_path (surface->xml_node, path, NULL); - if (unlikely (status)) - return status; + _cairo_svg_surface_emit_path (surface->xml_node, path, NULL); _cairo_output_stream_printf (surface->xml_node, "/>\n"); return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t +static cairo_bool_t _cairo_svg_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -2053,13 +2126,13 @@ _cairo_svg_surface_get_extents (void *abstract_surface, rectangle->y = 0; /* XXX: The conversion to integers here is pretty bogus, (not to - * mention the aribitray limitation of width to a short(!). We + * mention the arbitrary limitation of width to a short(!). We * may need to come up with a better interface for get_size. */ rectangle->width = (int) ceil (surface->width); rectangle->height = (int) ceil (surface->height); - return CAIRO_STATUS_SUCCESS; + return TRUE; } static cairo_status_t @@ -2106,52 +2179,63 @@ static cairo_int_status_t _cairo_svg_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_svg_surface_t *surface = abstract_surface; - if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _cairo_svg_surface_analyze_operation (surface, op, source); - - assert (_cairo_svg_surface_operation_supported (surface, op, source)); - /* Emulation of clear and source operators, when no clipping region * is defined. We just delete existing content of surface root node, * and exit early if operator is clear. - * XXX: optimization of SOURCE operator doesn't work, since analyze - * above always return FALSE. In order to make it work, we need a way - * to know if there's an active clipping path. - * Optimization of CLEAR works because of a test in paginated surface, - * and an optimization in meta surface. */ - if (surface->clip_level == 0 && op == CAIRO_OPERATOR_CLEAR) { - status = _cairo_output_stream_destroy (surface->xml_node); - if (unlikely (status)) { - surface->xml_node = NULL; - return status; - } + */ + if ((op == CAIRO_OPERATOR_CLEAR || op == CAIRO_OPERATOR_SOURCE) && + clip == NULL) + { + switch (surface->paginated_mode) { + case CAIRO_PAGINATED_MODE_FALLBACK: + ASSERT_NOT_REACHED; + case CAIRO_PAGINATED_MODE_ANALYZE: + return CAIRO_STATUS_SUCCESS; - surface->xml_node = _cairo_memory_stream_create (); - if (_cairo_output_stream_get_status (surface->xml_node)) { + case CAIRO_PAGINATED_MODE_RENDER: status = _cairo_output_stream_destroy (surface->xml_node); - surface->xml_node = NULL; - return status; - } + if (unlikely (status)) { + surface->xml_node = NULL; + return status; + } - if (op == CAIRO_OPERATOR_CLEAR) { - if (surface->content == CAIRO_CONTENT_COLOR) { - _cairo_output_stream_printf (surface->xml_node, - "<rect " - "width=\"%f\" height=\"%f\" " - "style=\"opacity:1;" - "stroke:none;" - "fill:rgb(0,0,0);\"/>\n", - surface->width, surface->height); + surface->xml_node = _cairo_memory_stream_create (); + if (_cairo_output_stream_get_status (surface->xml_node)) { + status = _cairo_output_stream_destroy (surface->xml_node); + surface->xml_node = NULL; + return status; } - return CAIRO_STATUS_SUCCESS; + + if (op == CAIRO_OPERATOR_CLEAR) { + if (surface->content == CAIRO_CONTENT_COLOR) { + _cairo_output_stream_printf (surface->xml_node, + "<rect " + "width=\"%f\" height=\"%f\" " + "style=\"opacity:1;" + "stroke:none;" + "fill:rgb(0,0,0);\"/>\n", + surface->width, surface->height); + } + return CAIRO_STATUS_SUCCESS; + } + break; } + } else { + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) + return _cairo_svg_surface_analyze_operation (surface, op, source); + + assert (_cairo_svg_surface_operation_supported (surface, op, source)); } + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + return _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, 0, NULL); } @@ -2161,7 +2245,7 @@ _cairo_svg_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_svg_surface_t *surface = abstract_surface; @@ -2189,6 +2273,10 @@ _cairo_svg_surface_mask (void *abstract_surface, assert (_cairo_svg_surface_operation_supported (surface, op, source)); assert (_cairo_svg_surface_operation_supported (surface, CAIRO_OPERATOR_OVER, mask)); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) { const cairo_surface_pattern_t *surface_pattern = (const cairo_surface_pattern_t*) mask; cairo_content_t content = cairo_surface_get_content (surface_pattern->surface); @@ -2249,7 +2337,7 @@ _cairo_svg_surface_stroke (void *abstract_dst, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_svg_surface_t *surface = abstract_dst; cairo_status_t status; @@ -2259,6 +2347,10 @@ _cairo_svg_surface_stroke (void *abstract_dst, assert (_cairo_svg_surface_operation_supported (surface, op, source)); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + _cairo_output_stream_printf (surface->xml_node, "<path style=\"fill:none;"); status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, op, source, stroke_style, ctm_inverse); @@ -2267,9 +2359,7 @@ _cairo_svg_surface_stroke (void *abstract_dst, _cairo_output_stream_printf (surface->xml_node, "\" "); - status = _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse); - if (unlikely (status)) - return status; + _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse); _cairo_svg_surface_emit_transform (surface->xml_node, " transform", ctm, NULL); _cairo_output_stream_printf (surface->xml_node, "/>\n"); @@ -2284,8 +2374,8 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip, + int *remaining_glyphs) { cairo_svg_surface_t *surface = abstract_surface; cairo_svg_document_t *document = surface->document; @@ -2302,6 +2392,10 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, if (num_glyphs <= 0) return CAIRO_STATUS_SUCCESS; + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + /* FIXME it's probably possible to apply a pattern of a gradient to * a group of symbols, but I don't know how yet. Gradients or patterns * are translated by x and y properties of use element. */ @@ -2349,7 +2443,9 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface, FALLBACK: _cairo_path_fixed_init (&path); - status = _cairo_scaled_font_glyph_path (scaled_font,(cairo_glyph_t *) glyphs, num_glyphs, &path); + status = _cairo_scaled_font_glyph_path (scaled_font, + (cairo_glyph_t *) glyphs, + num_glyphs, &path); if (unlikely (status)) { _cairo_path_fixed_fini (&path); @@ -2357,58 +2453,15 @@ FALLBACK: } status = _cairo_svg_surface_fill (abstract_surface, op, pattern, - &path, CAIRO_FILL_RULE_WINDING, 0.0, CAIRO_ANTIALIAS_SUBPIXEL, NULL); + &path, CAIRO_FILL_RULE_WINDING, + 0.0, CAIRO_ANTIALIAS_SUBPIXEL, + clip); _cairo_path_fixed_fini (&path); return status; } -static cairo_int_status_t -_cairo_svg_surface_intersect_clip_path (void *dst, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_svg_surface_t *surface = dst; - cairo_svg_document_t *document = surface->document; - cairo_status_t status; - unsigned int i; - - if (path == NULL) { - for (i = 0; i < surface->clip_level; i++) - _cairo_output_stream_printf (surface->xml_node, "</g>\n"); - - surface->clip_level = 0; - return CAIRO_STATUS_SUCCESS; - } - - _cairo_output_stream_printf (document->xml_node_defs, - "<clipPath id=\"clip%d\">\n" - " <path ", - document->clip_id); - status = _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL); - if (unlikely (status)) - return status; - - _cairo_output_stream_printf (document->xml_node_defs, - "/>\n" - "</clipPath>\n"); - - _cairo_output_stream_printf (surface->xml_node, - "<g clip-path=\"url(#clip%d)\" " - "clip-rule=\"%s\">\n", - document->clip_id, - fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? - "evenodd" : "nonzero"); - - document->clip_id++; - surface->clip_level++; - - return CAIRO_STATUS_SUCCESS; -} - static void _cairo_svg_surface_get_font_options (void *abstract_surface, cairo_font_options_t *options) @@ -2422,7 +2475,7 @@ _cairo_svg_surface_get_font_options (void *abstract_surface, static const cairo_surface_backend_t cairo_svg_surface_backend = { CAIRO_SURFACE_TYPE_SVG, - _cairo_svg_surface_create_similar, + NULL, /* create_similar: handled by wrapper */ _cairo_svg_surface_finish, NULL, /* acquire_source_image */ NULL, /* release_source_image */ @@ -2436,8 +2489,6 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = { NULL, /* check_span_renderer */ _cairo_svg_surface_copy_page, _cairo_svg_surface_show_page, - NULL, /* set_clip_region */ - _cairo_svg_surface_intersect_clip_path, _cairo_svg_surface_get_extents, NULL, /* _cairo_svg_surface_old_show_glyphs, */ _cairo_svg_surface_get_font_options, @@ -2452,7 +2503,6 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = { _cairo_svg_surface_show_glyphs, NULL, /* snapshot */ NULL, /* is_similar */ - NULL, /* reset */ _cairo_svg_surface_fill_stroke }; @@ -2487,7 +2537,6 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream, document->width = width; document->height = height; - document->surface_id = 0; document->linear_pattern_id = 0; document->radial_pattern_id = 0; document->pattern_id = 0; @@ -2507,9 +2556,6 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream, document->alpha_filter = FALSE; - _cairo_array_init (&document->meta_snapshots, - sizeof (cairo_meta_snapshot_t)); - document->svg_version = version; *document_out = document; @@ -2560,7 +2606,6 @@ _cairo_svg_document_finish (cairo_svg_document_t *document) { cairo_status_t status, status2; cairo_output_stream_t *output = document->output_stream; - cairo_meta_snapshot_t *snapshot; cairo_svg_page_t *page; unsigned int i; @@ -2662,16 +2707,6 @@ _cairo_svg_document_finish (cairo_svg_document_t *document) if (status == CAIRO_STATUS_SUCCESS) status = status2; - for (i = 0; i < document->meta_snapshots.num_elements; i++) { - snapshot = _cairo_array_index (&document->meta_snapshots, i); - cairo_surface_finish (&snapshot->meta->base); - status2 = cairo_surface_status (&snapshot->meta->base); - cairo_surface_destroy (&snapshot->meta->base); - if (status == CAIRO_STATUS_SUCCESS) - status = status2; - } - _cairo_array_fini (&document->meta_snapshots); - document->finished = TRUE; return status; diff --git a/src/cairo-traps.c b/src/cairo-traps.c index d8464cc8..343d77fd 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -39,6 +39,8 @@ #include "cairoint.h" +#include "cairo-region-private.h" + /* private functions */ static int @@ -51,6 +53,8 @@ _cairo_traps_init (cairo_traps_t *traps) traps->status = CAIRO_STATUS_SUCCESS; + traps->maybe_region = 1; + traps->num_traps = 0; traps->traps_size = ARRAY_LENGTH (traps->traps_embedded); @@ -83,6 +87,8 @@ _cairo_traps_clear (cairo_traps_t *traps) { traps->status = CAIRO_STATUS_SUCCESS; + traps->maybe_region = 1; + traps->num_traps = 0; traps->extents.p1.x = traps->extents.p1.y = INT32_MAX; traps->extents.p2.x = traps->extents.p2.y = INT32_MIN; @@ -616,14 +622,18 @@ _cairo_traps_extents (const cairo_traps_t *traps, * or %CAIRO_STATUS_NO_MEMORY **/ cairo_int_status_t -_cairo_traps_extract_region (const cairo_traps_t *traps, - cairo_region_t **region) +_cairo_traps_extract_region (cairo_traps_t *traps, + cairo_region_t **region) { cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)]; cairo_rectangle_int_t *rects = stack_rects; cairo_int_status_t status; int i, rect_count; + /* we only treat this a hint... */ + if (! traps->maybe_region) + return CAIRO_INT_STATUS_UNSUPPORTED; + for (i = 0; i < traps->num_traps; i++) { if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x || traps->traps[i].right.p1.x != traps->traps[i].right.p2.x || @@ -632,6 +642,7 @@ _cairo_traps_extract_region (const cairo_traps_t *traps, ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) || ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x)) { + traps->maybe_region = FALSE; return CAIRO_INT_STATUS_UNSUPPORTED; } } @@ -655,7 +666,7 @@ _cairo_traps_extract_region (const cairo_traps_t *traps, */ if (x1 == x2 || y1 == y2) continue; - + rects[rect_count].x = x1; rects[rect_count].y = y1; rects[rect_count].width = x2 - x1; @@ -663,18 +674,13 @@ _cairo_traps_extract_region (const cairo_traps_t *traps, rect_count++; } - + *region = cairo_region_create_rectangles (rects, rect_count); - status = cairo_region_status (*region); + status = (*region)->status; if (rects != stack_rects) free (rects); - if (unlikely (status)) { - cairo_region_destroy (*region); - *region = NULL; - } - return status; } diff --git a/src/cairo-type3-glyph-surface-private.h b/src/cairo-type3-glyph-surface-private.h index 33314ae9..0b0010bc 100644 --- a/src/cairo-type3-glyph-surface-private.h +++ b/src/cairo-type3-glyph-surface-private.h @@ -42,6 +42,7 @@ #if CAIRO_HAS_FONT_SUBSET #include "cairo-surface-private.h" +#include "cairo-surface-clipper-private.h" #include "cairo-pdf-operators-private.h" typedef cairo_status_t (*cairo_type3_glyph_surface_emit_image_t) (cairo_image_surface_t *image, @@ -55,16 +56,18 @@ typedef struct cairo_type3_glyph_surface { cairo_pdf_operators_t pdf_operators; cairo_matrix_t cairo_to_pdf; cairo_type3_glyph_surface_emit_image_t emit_image; + + cairo_surface_clipper_t clipper; } cairo_type3_glyph_surface_t; cairo_private cairo_surface_t * -_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font, +_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font, cairo_output_stream_t *stream, cairo_type3_glyph_surface_emit_image_t emit_image, - cairo_scaled_font_subsets_t *font_subsets); + cairo_scaled_font_subsets_t *font_subsets); cairo_private void -_cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract_surface, +_cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract_surface, cairo_pdf_operators_use_font_subset_t use_font_subset, void *closure); diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c index 6e725960..f55b12ac 100644 --- a/src/cairo-type3-glyph-surface.c +++ b/src/cairo-type3-glyph-surface.c @@ -42,9 +42,31 @@ #include "cairo-output-stream-private.h" #include "cairo-meta-surface-private.h" #include "cairo-analysis-surface-private.h" +#include "cairo-surface-clipper-private.h" static const cairo_surface_backend_t cairo_type3_glyph_surface_backend; +static cairo_status_t +_cairo_type3_glyph_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_type3_glyph_surface_t *surface = cairo_container_of (clipper, + cairo_type3_glyph_surface_t, + clipper); + + if (path == NULL) { + _cairo_output_stream_printf (surface->stream, "Q q\n"); + return CAIRO_STATUS_SUCCESS; + } + + return _cairo_pdf_operators_clip (&surface->pdf_operators, + path, + fill_rule); +} + cairo_surface_t * _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font, cairo_output_stream_t *stream, @@ -81,6 +103,9 @@ _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font, &surface->cairo_to_pdf, font_subsets); + _cairo_surface_clipper_init (&surface->clipper, + _cairo_type3_glyph_surface_clipper_intersect_clip_path); + return &surface->base; } @@ -156,29 +181,10 @@ _cairo_type3_glyph_surface_finish (void *abstract_surface) } static cairo_int_status_t -_cairo_type3_glyph_surface_intersect_clip_path (void *abstract_surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_type3_glyph_surface_t *surface = abstract_surface; - - if (path == NULL) { - _cairo_output_stream_printf (surface->stream, "Q q\n"); - return CAIRO_STATUS_SUCCESS; - } - - return _cairo_pdf_operators_clip (&surface->pdf_operators, - path, - fill_rule); -} - -static cairo_int_status_t _cairo_type3_glyph_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_type3_glyph_surface_t *surface = abstract_surface; const cairo_surface_pattern_t *pattern; @@ -189,8 +195,13 @@ _cairo_type3_glyph_surface_paint (void *abstract_surface, if (source->type != CAIRO_PATTERN_TYPE_SURFACE) return CAIRO_INT_STATUS_IMAGE_FALLBACK; + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + pattern = (const cairo_surface_pattern_t *) source; - status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra); + status = _cairo_surface_acquire_source_image (pattern->surface, + &image, &image_extra); if (unlikely (status)) goto fail; @@ -209,9 +220,11 @@ _cairo_type3_glyph_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { - return _cairo_type3_glyph_surface_paint (abstract_surface, op, mask, extents); + return _cairo_type3_glyph_surface_paint (abstract_surface, + op, mask, + clip); } static cairo_int_status_t @@ -224,9 +237,14 @@ _cairo_type3_glyph_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_type3_glyph_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; return _cairo_pdf_operators_stroke (&surface->pdf_operators, path, @@ -243,16 +261,18 @@ _cairo_type3_glyph_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_int_status_t status; - status = _cairo_pdf_operators_fill (&surface->pdf_operators, - path, - fill_rule); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; - return status; + return _cairo_pdf_operators_fill (&surface->pdf_operators, + path, + fill_rule); } static cairo_int_status_t @@ -262,8 +282,8 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip, + int *remaining_glyphs) { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -271,8 +291,14 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface, cairo_matrix_t new_ctm, ctm_inverse; int i; - for (i = 0; i < num_glyphs; i++) - cairo_matrix_transform_point (&surface->cairo_to_pdf, &glyphs[i].x, &glyphs[i].y); + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + + for (i = 0; i < num_glyphs; i++) { + cairo_matrix_transform_point (&surface->cairo_to_pdf, + &glyphs[i].x, &glyphs[i].y); + } /* We require the matrix to be invertable. */ ctm_inverse = scaled_font->ctm; @@ -316,8 +342,6 @@ static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = { NULL, /* check_span_renderer */ NULL, /* cairo_type3_glyph_surface_copy_page */ NULL, /* _cairo_type3_glyph_surface_show_page */ - NULL, /* set_clip_region */ - _cairo_type3_glyph_surface_intersect_clip_path, NULL, /* _cairo_type3_glyph_surface_get_extents */ NULL, /* old_show_glyphs */ NULL, /* _cairo_type3_glyph_surface_get_font_options */ diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h index 2ed3264b..a68fe500 100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -41,6 +41,7 @@ #include "cairo.h" #include "cairo-fixed-type-private.h" +#include "cairo-list-private.h" #include "cairo-reference-count-private.h" typedef struct _cairo_array cairo_array_t; @@ -63,6 +64,7 @@ typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t; typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t; typedef struct _cairo_solid_pattern cairo_solid_pattern_t; typedef struct _cairo_surface_backend cairo_surface_backend_t; +typedef struct _cairo_surface_wrapper cairo_surface_wrapper_t; typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t; typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t; @@ -167,6 +169,7 @@ typedef enum _cairo_internal_surface_type { CAIRO_INTERNAL_SURFACE_TYPE_TEST_META, CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED, + CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING, CAIRO_INTERNAL_SURFACE_TYPE_NULL, CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH } cairo_internal_surface_type_t; @@ -237,12 +240,6 @@ typedef enum _cairo_direction { CAIRO_DIRECTION_REVERSE } cairo_direction_t; -typedef enum _cairo_clip_mode { - CAIRO_CLIP_MODE_PATH, - CAIRO_CLIP_MODE_REGION, - CAIRO_CLIP_MODE_MASK -} cairo_clip_mode_t; - typedef struct _cairo_edge { cairo_line_t edge; int dir; diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c index 1adfd7d6..42e8bae2 100644 --- a/src/cairo-user-font.c +++ b/src/cairo-user-font.c @@ -85,7 +85,7 @@ _cairo_user_scaled_font_create_meta_context (cairo_user_scaled_font_t *scaled_fo CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_ALPHA; - meta_surface = cairo_meta_surface_create (content, -1, -1); + meta_surface = cairo_meta_surface_create (content, NULL); cr = cairo_create (meta_surface); cairo_surface_destroy (meta_surface); @@ -114,11 +114,11 @@ _cairo_user_scaled_glyph_init (void *abstract_font, cr = _cairo_user_scaled_font_create_meta_context (scaled_font); - if (face->scaled_font_methods.render_glyph) + if (face->scaled_font_methods.render_glyph) { status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font, _cairo_scaled_glyph_index(scaled_glyph), cr, &extents); - else + } else status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; if (status == CAIRO_STATUS_SUCCESS) @@ -141,27 +141,16 @@ _cairo_user_scaled_glyph_init (void *abstract_font, /* set metrics */ if (extents.width == 0.) { - /* Compute extents.x/y/width/height from meta_surface, in font space */ - cairo_box_t bbox; double x1, y1, x2, y2; double x_scale, y_scale; - cairo_surface_t *null_surface; - cairo_surface_t *analysis_surface; - - null_surface = _cairo_null_surface_create (cairo_surface_get_content (meta_surface)); - analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1); - cairo_surface_destroy (null_surface); - status = analysis_surface->status; - if (unlikely (status)) - return status; - - _cairo_analysis_surface_set_ctm (analysis_surface, - &scaled_font->extent_scale); - status = cairo_meta_surface_replay (meta_surface, analysis_surface); - _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox); - cairo_surface_destroy (analysis_surface); + /* Compute extents.x/y/width/height from meta_surface, + * in font space. + */ + status = _cairo_meta_surface_get_bbox ((cairo_meta_surface_t *) meta_surface, + &bbox, + &scaled_font->extent_scale); if (unlikely (status)) return status; @@ -231,7 +220,6 @@ _cairo_user_scaled_glyph_init (void *abstract_font, return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_meta_surface_get_path (meta_surface, path); - if (unlikely (status)) { _cairo_path_fixed_destroy (path); return status; diff --git a/src/cairo-vg-surface.c b/src/cairo-vg-surface.c index de3d0c6f..232450d5 100644 --- a/src/cairo-vg-surface.c +++ b/src/cairo-vg-surface.c @@ -40,6 +40,7 @@ #include "cairo-path-fixed-private.h" #include "cairo-meta-surface-private.h" +#include "cairo-surface-clipper-private.h" #include "cairo-cache-private.h" #include <pixman.h> @@ -94,7 +95,7 @@ struct _cairo_vg_surface { cairo_cache_entry_t snapshot_cache_entry; - cairo_bool_t clipped; + cairo_surface_clipper_t clipper; unsigned long target_id; }; @@ -397,21 +398,21 @@ _vg_surface_create_similar (void *abstract_surface, return cairo_vg_surface_create (surface->context, content, width, height); } -static cairo_int_status_t -_vg_surface_intersect_clip_path (void *abstract_surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) +static cairo_status_t +_vg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) { - cairo_vg_surface_t *surface = abstract_surface; + cairo_vg_surface_t *surface = cairo_container_of (clipper, + cairo_vg_surface_t, + clipper); cairo_vg_surface_t *mask; - cairo_rectangle_int_t extents, clip_extents; cairo_solid_pattern_t white; cairo_status_t status; if (path == NULL) { - surface->clipped = FALSE; vgMask (VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, surface->width, surface->height); vgSeti (VG_MASKING, VG_FALSE); @@ -419,16 +420,6 @@ _vg_surface_intersect_clip_path (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } - extents.x = extents.y = 0; - extents.width = surface->width; - extents.height = surface->height; - _cairo_path_fixed_approximate_clip_extents (path, &clip_extents); - if (! _cairo_rectangle_intersect (&clip_extents, &extents)) - surface->clipped = TRUE; - - if (surface->clipped) - return CAIRO_STATUS_SUCCESS; - mask = (cairo_vg_surface_t *) _vg_surface_create_similar (surface, CAIRO_CONTENT_ALPHA, surface->width, surface->height); @@ -456,7 +447,7 @@ _vg_surface_intersect_clip_path (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t +static cairo_bool_t _vg_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *extents) { @@ -467,7 +458,7 @@ _vg_surface_get_extents (void *abstract_surface, extents->width = surface->width; extents->height = surface->height; - return CAIRO_STATUS_SUCCESS; + return TRUE; } #define MAX_SEG 16 /* max number of knots to upload in a batch */ @@ -589,7 +580,7 @@ _vg_close_path (void *closure) static void _vg_path_from_cairo (vg_path_t *vg_path, - cairo_path_fixed_t *path) + const cairo_path_fixed_t *path) { cairo_status_t status; @@ -805,7 +796,7 @@ _vg_setup_linear_source (cairo_vg_context_t *context, static cairo_status_t _vg_setup_radial_source (cairo_vg_context_t *context, - cairo_radial_pattern_t *rpat) + const cairo_radial_pattern_t *rpat) { VGfloat radial[5]; @@ -832,7 +823,7 @@ _vg_setup_radial_source (cairo_vg_context_t *context, static cairo_status_t _vg_setup_solid_source (cairo_vg_context_t *context, - cairo_solid_pattern_t *spat) + const cairo_solid_pattern_t *spat) { VGfloat color[] = { spat->color.red, @@ -960,7 +951,7 @@ _vg_surface_remove_from_cache (cairo_surface_t *abstract_surface) static cairo_status_t _vg_setup_surface_source (cairo_vg_context_t *context, - cairo_surface_pattern_t *spat) + const cairo_surface_pattern_t *spat) { cairo_surface_t *snapshot; cairo_vg_surface_t *clone; @@ -1077,7 +1068,7 @@ _vg_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_vg_surface_t *surface = abstract_surface; cairo_vg_context_t *context; @@ -1086,9 +1077,6 @@ _vg_surface_stroke (void *abstract_surface, VGfloat strokeTransform[9]; vg_path_t vg_path; - if (surface->clipped) - return CAIRO_STATUS_SUCCESS; - if (! _vg_is_supported_operator (op)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1105,6 +1093,12 @@ _vg_surface_stroke (void *abstract_surface, return status; } + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) { + _vg_context_unlock (context); + return status; + } + vg_path.path = vgCreatePath (VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0, @@ -1148,16 +1142,13 @@ _vg_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_vg_surface_t *surface = abstract_surface; cairo_vg_context_t *context; cairo_status_t status; vg_path_t vg_path; - if (surface->clipped) - return CAIRO_STATUS_SUCCESS; - if (op == CAIRO_OPERATOR_DEST) return CAIRO_STATUS_SUCCESS; @@ -1177,6 +1168,12 @@ _vg_surface_fill (void *abstract_surface, return status; } + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) { + _vg_context_unlock (context); + return status; + } + vg_path.path = vgCreatePath (VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, @@ -1208,15 +1205,12 @@ static cairo_int_status_t _vg_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_vg_surface_t *surface = abstract_surface; cairo_vg_context_t *context; cairo_status_t status; - if (surface->clipped) - return CAIRO_STATUS_SUCCESS; - if (op == CAIRO_OPERATOR_DEST) return CAIRO_STATUS_SUCCESS; @@ -1236,6 +1230,12 @@ _vg_surface_paint (void *abstract_surface, return status; } + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) { + _vg_context_unlock (context); + return status; + } + vgSeti (VG_BLEND_MODE, _vg_operator (op)); vgSetPaint (context->paint, VG_FILL_PATH); @@ -1273,14 +1273,11 @@ _vg_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_vg_surface_t *surface = abstract_surface; cairo_status_t status; - if (surface->clipped) - return CAIRO_STATUS_SUCCESS; - if (! _vg_is_supported_operator (op)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1291,7 +1288,7 @@ _vg_surface_mask (void *abstract_surface, double alpha = context->alpha; context->alpha = solid->color.alpha; - status = _vg_surface_paint (abstract_surface, op, source, extents); + status = _vg_surface_paint (abstract_surface, op, source, clip); context->alpha = alpha; _vg_context_unlock (context); @@ -1312,14 +1309,14 @@ _vg_surface_get_font_options (void *abstract_surface, } static cairo_int_status_t -_vg_surface_show_glyphs (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents) +_vg_surface_show_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip, + int *remaining_glyphs) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_path_fixed_t path; @@ -1342,7 +1339,7 @@ _vg_surface_show_glyphs (void *abstract_surface, CAIRO_FILL_RULE_WINDING, CAIRO_GSTATE_TOLERANCE_DEFAULT, CAIRO_ANTIALIAS_SUBPIXEL, - extents); + clip); BAIL: _cairo_path_fixed_fini (&path); return status; @@ -1510,12 +1507,6 @@ _vg_surface_release_dest_image (void *abstract_surface, cairo_vg_surface_t *surface = abstract_surface; cairo_bool_t needs_unpremultiply; - /* XXX clipping is incorrect - * We can either composite through the current clip mask using fill, - * or what for the clipping overhaul patches, due to land any time - * soon now... - */ - _vg_format_to_pixman (surface->format, &needs_unpremultiply); if (needs_unpremultiply) { unpremultiply_argb (image->data, @@ -1545,6 +1536,8 @@ _vg_surface_finish (void *abstract_surface) surface->snapshot_cache_entry.hash = 0; } + _cairo_surface_clipper_reset (&surface->clipper); + if (surface->own_image) vgDestroyImage (surface->image); @@ -1561,20 +1554,21 @@ static const cairo_surface_backend_t cairo_vg_surface_backend = { CAIRO_SURFACE_TYPE_VG, _vg_surface_create_similar, _vg_surface_finish, + _vg_surface_acquire_source_image, _vg_surface_release_source_image, _vg_surface_acquire_dest_image, _vg_surface_release_dest_image, + NULL, /* clone_similar */ NULL, /* composite */ NULL, /* fill_rectangles */ NULL, /* composite_trapezoids */ NULL, /* create_span_renderer */ NULL, /* check_span_renderer */ + NULL, /* copy_page */ NULL, /* show_page */ - NULL, /* set_clip_region */ - _vg_surface_intersect_clip_path, _vg_surface_get_extents, NULL, /* old_show_glyphs */ _vg_surface_get_font_options, /* get_font_options */ @@ -1591,7 +1585,6 @@ static const cairo_surface_backend_t cairo_vg_surface_backend = { NULL, /* snapshot */ NULL, /* is_similar */ - NULL, /* reset */ }; static cairo_surface_t * @@ -1617,15 +1610,14 @@ _vg_surface_create_internal (cairo_vg_context_t *context, surface->width = width; surface->height = height; - surface->clipped = FALSE; + + _cairo_surface_clipper_init (&surface->clipper, + _vg_surface_clipper_intersect_clip_path); surface->snapshot_cache_entry.hash = 0; surface->target_id = 0; - /* Force an initial "clip", that resets the mask */ - _vg_surface_intersect_clip_path (surface, NULL, 0, 0.0, 0); - CHECK_VG_ERRORS(); return &surface->base; } diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c index e62e8816..2f1127c2 100644 --- a/src/cairo-win32-font.c +++ b/src/cairo-win32-font.c @@ -1360,6 +1360,7 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font, unsigned int height, cairo_glyph_t *glyphs, int num_glyphs, + cairo_region_t *clip_region, int *remaining_glyphs) { cairo_win32_scaled_font_t *scaled_font = abstract_font; @@ -1381,15 +1382,17 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font, */ COLORREF new_color; + status = _cairo_win32_surface_set_clip_region (surface, clip_region); + if (unlikely (status)) + return status; + new_color = RGB (((int)solid_pattern->color.red_short) >> 8, ((int)solid_pattern->color.green_short) >> 8, ((int)solid_pattern->color.blue_short) >> 8); - status = _draw_glyphs_on_surface (surface, scaled_font, new_color, - 0, 0, - glyphs, num_glyphs); - - return status; + return _draw_glyphs_on_surface (surface, scaled_font, new_color, + 0, 0, + glyphs, num_glyphs); } else { /* Otherwise, we need to draw using software fallbacks. We create a mask * surface by drawing the the glyphs onto a DIB, black-on-white then @@ -1458,7 +1461,8 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font, source_x, source_y, 0, 0, dest_x, dest_y, - width, height); + width, height, + clip_region); _cairo_pattern_fini (&mask.base); diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c index 9025bfa7..17a7b39c 100644 --- a/src/cairo-win32-printing-surface.c +++ b/src/cairo-win32-printing-surface.c @@ -53,6 +53,7 @@ #include "cairo-meta-surface-private.h" #include "cairo-scaled-font-subsets-private.h" #include "cairo-image-info-private.h" +#include "cairo-surface-clipper-private.h" #include <windows.h> @@ -128,7 +129,7 @@ analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern) cairo_image_surface_t *image; void *image_extra; cairo_int_status_t status; - int x, y; + cairo_image_transparency_t transparency; status = _cairo_surface_acquire_source_image (pattern->surface, &image, @@ -136,38 +137,20 @@ analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern) if (status) return status; - if (image->base.status) - return image->base.status; - - if (image->format == CAIRO_FORMAT_RGB24) { + transparency = _cairo_image_analyze_transparency (image); + switch (transparency) { + case CAIRO_IMAGE_UNKNOWN: + ASSERT_NOT_REACHED; + case CAIRO_IMAGE_IS_OPAQUE: status = CAIRO_STATUS_SUCCESS; - goto RELEASE_SOURCE; - } + break; - if (image->format != CAIRO_FORMAT_ARGB32) { - /* If the surface does not support the image format, assume - * that it does have alpha. The image will be converted to - * rgb24 when the surface blends the image into the page - * color to remove the transparency. */ + case CAIRO_IMAGE_HAS_BILEVEL_ALPHA: + case CAIRO_IMAGE_HAS_ALPHA: status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; - goto RELEASE_SOURCE; - } - - for (y = 0; y < image->height; y++) { - int a; - uint32_t *pixel = (uint32_t *) (image->data + y * image->stride); - - for (x = 0; x < image->width; x++, pixel++) { - a = (*pixel & 0xff000000) >> 24; - if (a != 255) { - status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; - goto RELEASE_SOURCE; - } - } + break; } - status = CAIRO_STATUS_SUCCESS; -RELEASE_SOURCE: _cairo_surface_release_source_image (pattern->surface, image, image_extra); return status; @@ -176,8 +159,6 @@ RELEASE_SOURCE: static cairo_bool_t surface_pattern_supported (const cairo_surface_pattern_t *pattern) { - cairo_extend_t extend; - if (_cairo_surface_is_meta (pattern->surface)) return TRUE; @@ -187,19 +168,7 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern) return FALSE; } - extend = cairo_pattern_get_extend ((cairo_pattern_t*)&pattern->base); - switch (extend) { - case CAIRO_EXTEND_NONE: - case CAIRO_EXTEND_REPEAT: - case CAIRO_EXTEND_REFLECT: - /* There's no point returning FALSE for EXTEND_PAD, as the image - * surface does not currently implement it either */ - case CAIRO_EXTEND_PAD: - return TRUE; - } - - ASSERT_NOT_REACHED; - return FALSE; + return TRUE; } static cairo_bool_t @@ -390,7 +359,8 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa XFORM xform; int x_tile, y_tile, left, right, top, bottom; RECT clip; - cairo_surface_t *meta_surface = pattern->surface; + cairo_meta_surface_t *meta_surface = (cairo_meta_surface_t *) pattern->surface; + cairo_box_t bbox; extend = cairo_pattern_get_extend (&pattern->base); @@ -406,7 +376,7 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa SaveDC (surface->dc); _cairo_matrix_to_win32_xform (&p2d, &xform); - status = _cairo_surface_get_extents (meta_surface, &meta_extents); + status = _cairo_meta_surface_get_bbox (meta_surface, &bbox, NULL); if (status) return status; @@ -415,10 +385,10 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa return status; if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) { - left = (int) floor((double)clip.left/meta_extents.width); - right = (int) ceil((double)clip.right/meta_extents.width); - top = (int) floor((double)clip.top/meta_extents.height); - bottom = (int) ceil((double)clip.bottom/meta_extents.height); + left = (int) floor (clip.left / _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x)); + right = (int) ceil (clip.right / _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x)); + top = (int) floor (clip.top / _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y)); + bottom = (int) ceil (clip.bottom / _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y)); } else { left = 0; right = 1; @@ -427,7 +397,7 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa } old_content = surface->content; - if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) { + if (meta_surface->base.content == CAIRO_CONTENT_COLOR) { cairo_pattern_t *source; cairo_solid_pattern_t black; @@ -490,7 +460,8 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa SelectClipPath (surface->dc, RGN_AND); SaveDC (surface->dc); /* Allow clip path to be reset during replay */ - status = _cairo_meta_surface_replay_region (meta_surface, &surface->base, + status = _cairo_meta_surface_replay_region (&meta_surface->base, + &surface->base, CAIRO_META_REGION_NATIVE); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); /* Restore both the clip save and our earlier path SaveDC */ @@ -594,7 +565,6 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf cairo_extend_t extend; cairo_image_surface_t *image; void *image_extra; - cairo_surface_t *opaque_surface; cairo_image_surface_t *opaque_image = NULL; BITMAPINFO bi; cairo_matrix_t m; @@ -651,13 +621,15 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf &mime_size, &mime_info); } - if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) + if (_cairo_status_is_error (status)) return status; use_mime = (status == CAIRO_STATUS_SUCCESS); if (!use_mime && image->format != CAIRO_FORMAT_RGB24) { - cairo_surface_pattern_t opaque_pattern; + cairo_surface_t *opaque_surface; + cairo_surface_pattern_t image_pattern; + cairo_solid_pattern_t background_pattern; opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, image->width, @@ -667,36 +639,27 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf goto CLEANUP_OPAQUE_IMAGE; } - _cairo_pattern_init_for_surface (&opaque_pattern, &image->base); - - status = _cairo_surface_fill_rectangle (opaque_surface, - CAIRO_OPERATOR_SOURCE, - background_color, - 0, 0, - image->width, image->height); - if (status) { - _cairo_pattern_fini (&opaque_pattern.base); + _cairo_pattern_init_solid (&background_pattern, + background_color, + CAIRO_CONTENT_COLOR); + status = _cairo_surface_paint (opaque_surface, + CAIRO_OPERATOR_SOURCE, + &background_pattern.base, + NULL); + if (status) goto CLEANUP_OPAQUE_IMAGE; - } - status = _cairo_surface_composite (CAIRO_OPERATOR_OVER, - &opaque_pattern.base, - NULL, - opaque_surface, - 0, 0, - 0, 0, - 0, 0, - image->width, - image->height); - if (status) { - _cairo_pattern_fini (&opaque_pattern.base); + _cairo_pattern_init_for_surface (&image_pattern, &image->base); + status = _cairo_surface_paint (opaque_surface, + CAIRO_OPERATOR_OVER, + &image_pattern.base, + NULL); + _cairo_pattern_fini (&image_pattern.base); + if (status) goto CLEANUP_OPAQUE_IMAGE; - } - _cairo_pattern_fini (&opaque_pattern.base); opaque_image = (cairo_image_surface_t *) opaque_surface; } else { - opaque_surface = &image->base; opaque_image = image; } @@ -767,7 +730,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf CLEANUP_OPAQUE_IMAGE: if (opaque_image != image) - cairo_surface_destroy (opaque_surface); + cairo_surface_destroy (&opaque_image->base); CLEANUP_IMAGE: _cairo_surface_release_source_image (pattern->surface, image, image_extra); @@ -1085,17 +1048,15 @@ _cairo_win32_printing_surface_emit_path (cairo_win32_surface_t *surface, cairo_path_fixed_t *path) { win32_path_info_t path_info; - cairo_status_t status; path_info.surface = surface; - status = _cairo_path_fixed_interpret (path, - CAIRO_DIRECTION_FORWARD, - _cairo_win32_printing_surface_path_move_to, - _cairo_win32_printing_surface_path_line_to, - _cairo_win32_printing_surface_path_curve_to, - _cairo_win32_printing_surface_path_close_path, - &path_info); - return status; + return _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cairo_win32_printing_surface_path_move_to, + _cairo_win32_printing_surface_path_line_to, + _cairo_win32_printing_surface_path_curve_to, + _cairo_win32_printing_surface_path_close_path, + &path_info); } static cairo_int_status_t @@ -1109,14 +1070,16 @@ _cairo_win32_printing_surface_show_page (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_win32_printing_surface_intersect_clip_path (void *abstract_surface, +static cairo_status_t +_cairo_win32_printing_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { - cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_surface_t *surface = cairo_container_of (clipper, + cairo_win32_surface_t, + clipper); cairo_status_t status; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) @@ -1164,10 +1127,15 @@ static cairo_int_status_t _cairo_win32_printing_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_win32_surface_t *surface = abstract_surface; cairo_solid_pattern_t clear; + cairo_status_t status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (status) + return status; if (op == CAIRO_OPERATOR_CLEAR) { _cairo_win32_printing_surface_init_clear_color (surface, &clear); @@ -1242,7 +1210,7 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface, cairo_matrix_t *stroke_ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_win32_surface_t *surface = abstract_surface; cairo_int_status_t status; @@ -1258,6 +1226,10 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface, cairo_matrix_t mat; double scale; + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (status) + return status; + if (op == CAIRO_OPERATOR_CLEAR) { _cairo_win32_printing_surface_init_clear_color (surface, &clear); source = (cairo_pattern_t*) &clear; @@ -1364,12 +1336,16 @@ _cairo_win32_printing_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_win32_surface_t *surface = abstract_surface; cairo_int_status_t status; cairo_solid_pattern_t clear; + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (status) + return status; + if (op == CAIRO_OPERATOR_CLEAR) { _cairo_win32_printing_surface_init_clear_color (surface, &clear); source = (cairo_pattern_t*) &clear; @@ -1423,8 +1399,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip, + int *remaining_glyphs) { cairo_win32_surface_t *surface = abstract_surface; cairo_status_t status = CAIRO_STATUS_SUCCESS; @@ -1435,6 +1411,10 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac cairo_bool_t old_has_ctm; cairo_solid_pattern_t clear; + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (status) + return status; + if (op == CAIRO_OPERATOR_CLEAR) { _cairo_win32_printing_surface_init_clear_color (surface, &clear); source = (cairo_pattern_t*) &clear; @@ -1547,8 +1527,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac status = _cairo_win32_surface_show_glyphs (surface, op, source, glyphs, num_glyphs, scaled_font, - remaining_glyphs, - extents); + clip, + remaining_glyphs); if (surface->has_ctm) cairo_scaled_font_destroy (scaled_font); @@ -1607,7 +1587,12 @@ _cairo_win32_printing_surface_create_similar (void *abstract_surface, int width, int height) { - return cairo_meta_surface_create (content, width, height); + cairo_rectangle_t extents; + + extents.x = extents.y = 0; + extents.width = width; + extents.height = height; + return cairo_meta_surface_create (content, &extents); } static cairo_int_status_t @@ -1698,6 +1683,9 @@ cairo_win32_printing_surface_create (HDC hdc) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } + _cairo_surface_clipper_init (&surface->clipper, + _cairo_win32_printing_surface_clipper_intersect_clip_path); + surface->image = NULL; surface->format = CAIRO_FORMAT_RGB24; surface->content = CAIRO_CONTENT_COLOR_ALPHA; @@ -1725,13 +1713,12 @@ cairo_win32_printing_surface_create (HDC hdc) _cairo_win32_printing_surface_init_ps_mode (surface); _cairo_win32_printing_surface_init_image_support (surface); - _cairo_surface_init (&surface->base, &cairo_win32_printing_surface_backend, + _cairo_surface_init (&surface->base, + &cairo_win32_printing_surface_backend, CAIRO_CONTENT_COLOR_ALPHA); paginated = _cairo_paginated_surface_create (&surface->base, CAIRO_CONTENT_COLOR_ALPHA, - surface->extents.width, - surface->extents.height, &cairo_win32_surface_paginated_backend); /* paginated keeps the only reference to surface now, drop ours */ @@ -1762,8 +1749,6 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ _cairo_win32_printing_surface_show_page, - NULL, /* set_clip_region */ - _cairo_win32_printing_surface_intersect_clip_path, _cairo_win32_surface_get_extents, NULL, /* old_show_glyphs */ _cairo_win32_printing_surface_get_font_options, @@ -1779,7 +1764,6 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = { _cairo_win32_printing_surface_show_glyphs, NULL, /* snapshot */ NULL, /* is_similar */ - NULL, /* reset */ NULL, /* fill_stroke */ }; diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h index 40ed20ef..c1040e83 100644 --- a/src/cairo-win32-private.h +++ b/src/cairo-win32-private.h @@ -38,6 +38,7 @@ #include "cairo-win32.h" #include "cairoint.h" +#include "cairo-surface-clipper-private.h" #ifndef SHADEBLENDCAPS #define SHADEBLENDCAPS 120 @@ -81,6 +82,10 @@ typedef struct _cairo_win32_surface { cairo_rectangle_int_t clip_rect; HRGN initial_clip_rgn; cairo_bool_t had_simple_clip; + cairo_region_t *clip_region; + + /* For path clipping to the printing-surface */ + cairo_surface_clipper_t clipper; /* Surface DC flags */ uint32_t flags; @@ -137,13 +142,17 @@ _cairo_surface_is_win32_printing (cairo_surface_t *surface); cairo_status_t _cairo_win32_surface_finish (void *abstract_surface); -cairo_int_status_t +cairo_bool_t _cairo_win32_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle); uint32_t _cairo_win32_flags_for_dc (HDC dc); +cairo_status_t +_cairo_win32_surface_set_clip_region (void *abstract_surface, + cairo_region_t *region); + cairo_int_status_t _cairo_win32_surface_show_glyphs (void *surface, cairo_operator_t op, @@ -151,8 +160,8 @@ _cairo_win32_surface_show_glyphs (void *surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip, + int *remaining_glyphs); cairo_surface_t * _cairo_win32_surface_create_similar (void *abstract_src, diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c index 5bbc8f86..12219e95 100644 --- a/src/cairo-win32-surface.c +++ b/src/cairo-win32-surface.c @@ -468,7 +468,8 @@ _cairo_win32_surface_clone_similar (void *abstract_surface, src_x, src_y, 0, 0, 0, 0, - width, height); + width, height, + NULL); _cairo_pattern_fini (&pattern.base); @@ -693,6 +694,91 @@ _cairo_win32_surface_release_dest_image (void *abstract_surfa cairo_surface_destroy ((cairo_surface_t *)local); } +cairo_status_t +_cairo_win32_surface_set_clip_region (void *abstract_surface, + cairo_region_t *region) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (surface->clip_region == region) + return CAIRO_STATUS_SUCCESS; + + cairo_region_destroy (surface->clip_region); + surface->clip_region = cairo_region_reference (region); + + /* The semantics we want is that any clip set by cairo combines + * is intersected with the clip on device context that the + * surface was created for. To implement this, we need to + * save the original clip when first setting a clip on surface. + */ + + /* Clear any clip set by cairo, return to the original first */ + status = _cairo_win32_restore_initial_clip (surface); + + /* Then combine any new region with it */ + if (region) { + cairo_rectangle_int_t extents; + int num_rects; + RGNDATA *data; + size_t data_size; + RECT *rects; + int i; + HRGN gdi_region; + + /* Create a GDI region for the cairo region */ + + cairo_region_get_extents (region, &extents); + num_rects = cairo_region_num_rectangles (region); + /* XXX see notes in _cairo_win32_save_initial_clip -- + * this code will interact badly with a HDC which had an initial + * world transform -- we should probably manually transform the + * region rects, because SelectClipRgn takes device units, not + * logical units (unlike IntersectClipRect). + */ + + data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT); + data = malloc (data_size); + if (!data) + return _cairo_error(CAIRO_STATUS_NO_MEMORY); + rects = (RECT *)data->Buffer; + + data->rdh.dwSize = sizeof (RGNDATAHEADER); + data->rdh.iType = RDH_RECTANGLES; + data->rdh.nCount = num_rects; + data->rdh.nRgnSize = num_rects * sizeof (RECT); + data->rdh.rcBound.left = extents.x; + data->rdh.rcBound.top = extents.y; + data->rdh.rcBound.right = extents.x + extents.width; + data->rdh.rcBound.bottom = extents.y + extents.height; + + for (i = 0; i < num_rects; i++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (region, i, &rect); + + rects[i].left = rect.x; + rects[i].top = rect.y; + rects[i].right = rect.x + rect.width; + rects[i].bottom = rect.y + rect.height; + } + + gdi_region = ExtCreateRegion (NULL, data_size, data); + free (data); + + if (!gdi_region) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + /* AND the new region into our DC */ + if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR) + status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region"); + + DeleteObject (gdi_region); + } + + return status; +} + #if !defined(AC_SRC_OVER) #define AC_SRC_OVER 0x00 #pragma pack(1) @@ -889,7 +975,8 @@ _cairo_win32_surface_composite (cairo_operator_t op, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_win32_surface_t *dst = abstract_dst; cairo_win32_surface_t *src; @@ -1030,7 +1117,7 @@ _cairo_win32_surface_composite (cairo_operator_t op, fflush (stderr); #endif - /* If the src recangle doesn't wholly lie within the src extents, + /* If the src rectangle doesn't wholly lie within the src extents, * fudge things. We really need to do fixup on the unpainted * region -- e.g. the SOURCE operator is broken for areas outside * of the extents, because it won't clear that area to transparent @@ -1150,6 +1237,10 @@ _cairo_win32_surface_composite (cairo_operator_t op, fflush (stderr); #endif + status = _cairo_win32_surface_set_clip_region (dst, clip_region); + if (status) + return status; + /* If we need to repeat, we turn the repeated blit into * a bunch of piece-by-piece blits. */ @@ -1283,7 +1374,8 @@ UNSUPPORTED: src_x, src_y, mask_x, mask_y, dst_x, dst_y, - width, height); + width, height, + clip_region); } return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1387,6 +1479,10 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface, if (surface->format != CAIRO_FORMAT_RGB24) return CAIRO_INT_STATUS_UNSUPPORTED; + status = _cairo_win32_surface_set_clip_region (surface, NULL); + if (status) + return status; + /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all * surfaces with alpha.) */ @@ -1432,133 +1528,20 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface, return status; } -static cairo_int_status_t -_cairo_win32_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region) -{ - cairo_win32_surface_t *surface = abstract_surface; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - - /* If we are in-memory, then we set the clip on the image surface - * as well as on the underlying GDI surface. - */ - if (surface->image) { - unsigned int serial; - - serial = _cairo_surface_allocate_clip_serial (surface->image); - status = _cairo_surface_set_clip_region (surface->image, region, serial); - if (status) - return status; - } - - /* The semantics we want is that any clip set by cairo combines - * is intersected with the clip on device context that the - * surface was created for. To implement this, we need to - * save the original clip when first setting a clip on surface. - */ - - /* Clear any clip set by cairo, return to the original first */ - status = _cairo_win32_restore_initial_clip (surface); - - /* Then combine any new region with it */ - if (region) { - cairo_rectangle_int_t extents; - int num_rects; - RGNDATA *data; - size_t data_size; - RECT *rects; - int i; - HRGN gdi_region; - cairo_rectangle_int_t rect0; - - /* Create a GDI region for the cairo region */ - - cairo_region_get_extents (region, &extents); - num_rects = cairo_region_num_rectangles (region); - - if (num_rects == 1) - cairo_region_get_rectangle (region, 0, &rect0); - - if (num_rects == 1 && - rect0.x == 0 && - rect0.y == 0 && - rect0.width == surface->extents.width && - rect0.width == surface->extents.height) - { - gdi_region = NULL; - - SelectClipRgn (surface->dc, NULL); - IntersectClipRect (surface->dc, - rect0.x, - rect0.y, - rect0.x + rect0.width, - rect0.y + rect0.height); - } else { - /* XXX see notes in _cairo_win32_save_initial_clip -- - * this code will interact badly with a HDC which had an initial - * world transform -- we should probably manually transform the - * region rects, because SelectClipRgn takes device units, not - * logical units (unlike IntersectClipRect). - */ - - data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT); - data = malloc (data_size); - if (!data) - return _cairo_error(CAIRO_STATUS_NO_MEMORY); - rects = (RECT *)data->Buffer; - - data->rdh.dwSize = sizeof (RGNDATAHEADER); - data->rdh.iType = RDH_RECTANGLES; - data->rdh.nCount = num_rects; - data->rdh.nRgnSize = num_rects * sizeof (RECT); - data->rdh.rcBound.left = extents.x; - data->rdh.rcBound.top = extents.y; - data->rdh.rcBound.right = extents.x + extents.width; - data->rdh.rcBound.bottom = extents.y + extents.height; - - for (i = 0; i < num_rects; i++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (region, i, &rect); - - rects[i].left = rect.x; - rects[i].top = rect.y; - rects[i].right = rect.x + rect.width; - rects[i].bottom = rect.y + rect.height; - } - - gdi_region = ExtCreateRegion (NULL, data_size, data); - free (data); - - if (!gdi_region) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - /* AND the new region into our DC */ - if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR) - status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region"); - - DeleteObject (gdi_region); - } - } - - return status; -} - -cairo_int_status_t +cairo_bool_t _cairo_win32_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { cairo_win32_surface_t *surface = abstract_surface; *rectangle = surface->extents; - - return CAIRO_STATUS_SUCCESS; + return TRUE; } static cairo_status_t _cairo_win32_surface_flush (void *abstract_surface) { - return _cairo_surface_reset_clip (abstract_surface); + return _cairo_win32_surface_set_clip_region (abstract_surface, NULL); } #define STACK_GLYPH_SIZE 256 @@ -1570,8 +1553,8 @@ _cairo_win32_surface_show_glyphs (void *surface, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip, + int *remaining_glyphs) { #if CAIRO_HAS_WIN32_FONT cairo_win32_surface_t *dst = surface; @@ -1611,11 +1594,19 @@ _cairo_win32_surface_show_glyphs (void *surface, /* If we have a fallback mask clip set on the dst, we have * to go through the fallback path, but only if we're not * doing this for printing */ - if (dst->base.clip && - !(dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) && - (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION || - dst->base.clip->surface != NULL)) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (clip != NULL) { + if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) == 0) { + cairo_region_t *clip_region; + cairo_status_t status; + + status = _cairo_clip_get_region (clip, &clip_region); + assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO); + if (status) + return status; + + _cairo_win32_surface_set_clip_region (surface, clip_region); + } + } solid_pattern = (cairo_solid_pattern_t *)source; color = RGB(((int)solid_pattern->color.red_short) >> 8, @@ -1957,19 +1948,6 @@ _cairo_win32_surface_is_similar (void *surface_a, return a->dc == b->dc; } -static cairo_status_t -_cairo_win32_surface_reset (void *abstract_surface) -{ - cairo_win32_surface_t *surface = abstract_surface; - cairo_status_t status; - - status = _cairo_win32_surface_set_clip_region (surface, NULL); - if (status) - return status; - - return CAIRO_STATUS_SUCCESS; -} - typedef struct _cairo_win32_surface_span_renderer { cairo_span_renderer_t base; @@ -1979,6 +1957,7 @@ typedef struct _cairo_win32_surface_span_renderer { cairo_image_surface_t *mask; cairo_win32_surface_t *dst; + cairo_region_t *clip_region; cairo_composite_rectangles_t composite_rectangles; } cairo_win32_surface_span_renderer_t; @@ -2031,18 +2010,20 @@ _cairo_win32_surface_span_renderer_finish (void *abstract_renderer) rects->src.y, 0, 0, /* mask.x, mask.y */ rects->dst.x, rects->dst.y, - rects->width, rects->height); + rects->width, rects->height, + renderer->clip_region); } else { /* otherwise go through the fallback_composite path which * will do the appropriate surface acquisition */ status = _cairo_surface_fallback_composite ( renderer->op, - renderer->pattern, mask_pattern, dst, + renderer->pattern, mask_pattern, &dst->base, rects->src.x, rects->src.y, 0, 0, /* mask.x, mask.y */ rects->dst.x, rects->dst.y, - rects->width, rects->height); + rects->width, rects->height, + renderer->clip_region); } cairo_pattern_destroy (mask_pattern); @@ -2073,15 +2054,16 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op, const cairo_pattern_t *pattern, void *abstract_dst, cairo_antialias_t antialias, - const cairo_composite_rectangles_t *rects) + const cairo_composite_rectangles_t *rects, + cairo_region_t *clip_region) { cairo_win32_surface_t *dst = abstract_dst; - cairo_win32_surface_span_renderer_t *renderer - = calloc(1, sizeof(*renderer)); + cairo_win32_surface_span_renderer_t *renderer; cairo_status_t status; int width = rects->width; int height = rects->height; + renderer = calloc(1, sizeof(*renderer)); if (renderer == NULL) return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY); @@ -2093,6 +2075,7 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op, renderer->pattern = pattern; renderer->antialias = antialias; renderer->dst = dst; + renderer->clip_region = clip_region; renderer->composite_rectangles = *rects; @@ -2128,8 +2111,6 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = { _cairo_win32_surface_check_span_renderer, NULL, /* copy_page */ NULL, /* show_page */ - _cairo_win32_surface_set_clip_region, - NULL, /* intersect_clip_path */ _cairo_win32_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -2146,8 +2127,6 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = { NULL, /* snapshot */ _cairo_win32_surface_is_similar, - - _cairo_win32_surface_reset }; /* Notes: diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index a7340cf9..0650f8f6 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -75,6 +75,7 @@ typedef struct cairo_xcb_surface { cairo_bool_t have_clip_rects; xcb_rectangle_t *clip_rects; int num_clip_rects; + cairo_region_t *clip_region; xcb_render_picture_t src_picture, dst_picture; xcb_render_pictforminfo_t xrender_format; @@ -166,6 +167,93 @@ _xcb_render_format_to_content (xcb_render_pictforminfo_t *xrender_format) return CAIRO_CONTENT_COLOR; } +static void +_cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface) +{ + if (surface->have_clip_rects) + xcb_set_clip_rectangles(surface->dpy, XCB_CLIP_ORDERING_YX_SORTED, surface->gc, + 0, 0, + surface->num_clip_rects, + surface->clip_rects ); +} + +static void +_cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface) +{ + if (surface->have_clip_rects) + xcb_render_set_picture_clip_rectangles (surface->dpy, surface->dst_picture, + 0, 0, + surface->num_clip_rects, + surface->clip_rects); +} + +static cairo_status_t +_cairo_xcb_surface_set_clip_region (void *abstract_surface, + cairo_region_t *region) +{ + cairo_xcb_surface_t *surface = abstract_surface; + + if (region == surface->clip_region) + return CAIRO_STATUS_SUCCESS; + + cairo_region_destroy (surface->clip_region); + region = cairo_region_reference (region); + + if (surface->clip_rects) { + free (surface->clip_rects); + surface->clip_rects = NULL; + } + + surface->have_clip_rects = FALSE; + surface->num_clip_rects = 0; + + if (region == NULL) { + uint32_t none[] = { XCB_NONE }; + if (surface->gc) + xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none); + + if (surface->xrender_format.id != XCB_NONE && surface->dst_picture) + xcb_render_change_picture (surface->dpy, surface->dst_picture, + XCB_RENDER_CP_CLIP_MASK, none); + } else { + xcb_rectangle_t *rects = NULL; + int n_rects, i; + + n_rects = cairo_region_num_rectangles (region); + + if (n_rects > 0) { + rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t)); + if (rects == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else { + rects = NULL; + } + + for (i = 0; i < n_rects; i++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (region, i, &rect); + + rects[i].x = rect.x; + rects[i].y = rect.y; + rects[i].width = rect.width; + rects[i].height = rect.height; + } + + surface->have_clip_rects = TRUE; + surface->clip_rects = rects; + surface->num_clip_rects = n_rects; + + if (surface->gc) + _cairo_xcb_surface_set_gc_clip_rects (surface); + + if (surface->dst_picture) + _cairo_xcb_surface_set_picture_clip_rects (surface); + } + + return CAIRO_STATUS_SUCCESS; +} + static cairo_surface_t * _cairo_xcb_surface_create_similar (void *abstract_src, cairo_content_t content, @@ -223,6 +311,7 @@ _cairo_xcb_surface_finish (void *abstract_surface) xcb_free_gc (surface->dpy, surface->gc); free (surface->clip_rects); + cairo_region_destroy (surface->clip_region); surface->dpy = NULL; @@ -476,26 +565,6 @@ _cairo_xcb_surface_ensure_src_picture (cairo_xcb_surface_t *surface) } static void -_cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface) -{ - if (surface->have_clip_rects) - xcb_render_set_picture_clip_rectangles (surface->dpy, surface->dst_picture, - 0, 0, - surface->num_clip_rects, - surface->clip_rects); -} - -static void -_cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface) -{ - if (surface->have_clip_rects) - xcb_set_clip_rectangles(surface->dpy, XCB_CLIP_ORDERING_YX_SORTED, surface->gc, - 0, 0, - surface->num_clip_rects, - surface->clip_rects ); -} - -static void _cairo_xcb_surface_ensure_dst_picture (cairo_xcb_surface_t *surface) { if (!surface->dst_picture) { @@ -1124,7 +1193,8 @@ _cairo_xcb_surface_composite (cairo_operator_t op, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_surface_attributes_t src_attr, mask_attr; cairo_xcb_surface_t *dst = abstract_dst; @@ -1163,6 +1233,10 @@ _cairo_xcb_surface_composite (cairo_operator_t op, goto BAIL; } + status = _cairo_xcb_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + goto BAIL; + status = _cairo_xcb_surface_set_attributes (src, &src_attr); if (status) goto BAIL; @@ -1257,7 +1331,8 @@ _cairo_xcb_surface_composite (cairo_operator_t op, mask ? mask->height : 0, src_x, src_y, mask_x, mask_y, - dst_x, dst_y, width, height); + dst_x, dst_y, width, height, + clip_region); BAIL: if (mask) @@ -1279,6 +1354,7 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface, xcb_render_color_t render_color; xcb_rectangle_t static_xrects[16]; xcb_rectangle_t *xrects = static_xrects; + cairo_status_t status; int i; if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) @@ -1289,6 +1365,9 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface, render_color.blue = color->blue_short; render_color.alpha = color->alpha_short; + status = _cairo_xcb_surface_set_clip_region (surface, NULL); + assert (status == CAIRO_STATUS_SUCCESS); + if (num_rects > ARRAY_LENGTH(static_xrects)) { xrects = _cairo_malloc_ab (num_rects, sizeof(xcb_rectangle_t)); if (xrects == NULL) @@ -1415,7 +1494,8 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int num_traps) + int num_traps, + cairo_region_t *clip_region) { cairo_surface_attributes_t attributes; cairo_xcb_surface_t *dst = abstract_dst; @@ -1475,6 +1555,11 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op, render_src_y = src_y + render_reference_y - dst_y; _cairo_xcb_surface_ensure_dst_picture (dst); + + status = _cairo_xcb_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + goto BAIL; + status = _cairo_xcb_surface_set_attributes (src, &attributes); if (status) goto BAIL; @@ -1516,7 +1601,8 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op, width, height, src_x, src_y, 0, 0, - dst_x, dst_y, width, height); + dst_x, dst_y, width, height, + clip_region); } else { xcb_render_trapezoid_t xtraps_stack[16]; @@ -1562,68 +1648,7 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op, return status; } -static cairo_int_status_t -_cairo_xcb_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region) -{ - cairo_xcb_surface_t *surface = abstract_surface; - - if (surface->clip_rects) { - free (surface->clip_rects); - surface->clip_rects = NULL; - } - - surface->have_clip_rects = FALSE; - surface->num_clip_rects = 0; - - if (region == NULL) { - uint32_t none[] = { XCB_NONE }; - if (surface->gc) - xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none); - - if (surface->xrender_format.id != XCB_NONE && surface->dst_picture) - xcb_render_change_picture (surface->dpy, surface->dst_picture, - XCB_RENDER_CP_CLIP_MASK, none); - } else { - xcb_rectangle_t *rects = NULL; - int n_rects, i; - - n_rects = cairo_region_num_rectangles (region); - - if (n_rects > 0) { - rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t)); - if (rects == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } else { - rects = NULL; - } - - for (i = 0; i < n_rects; i++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (region, i, &rect); - - rects[i].x = rect.x; - rects[i].y = rect.y; - rects[i].width = rect.width; - rects[i].height = rect.height; - } - - surface->have_clip_rects = TRUE; - surface->clip_rects = rects; - surface->num_clip_rects = n_rects; - - if (surface->gc) - _cairo_xcb_surface_set_gc_clip_rects (surface); - - if (surface->dst_picture) - _cairo_xcb_surface_set_picture_clip_rects (surface); - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t +static cairo_bool_t _cairo_xcb_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -1635,7 +1660,7 @@ _cairo_xcb_surface_get_extents (void *abstract_surface, rectangle->width = surface->width; rectangle->height = surface->height; - return CAIRO_STATUS_SUCCESS; + return TRUE; } /* XXX: _cairo_xcb_surface_get_font_options */ @@ -1654,8 +1679,8 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip, + int *remaining_glyphs); static cairo_bool_t _cairo_xcb_surface_is_similar (void *surface_a, @@ -1682,40 +1707,29 @@ _cairo_xcb_surface_is_similar (void *surface_a, return a->xrender_format.id == xrender_format->id; } -static cairo_status_t -_cairo_xcb_surface_reset (void *abstract_surface) -{ - cairo_xcb_surface_t *surface = abstract_surface; - cairo_status_t status; - - status = _cairo_xcb_surface_set_clip_region (surface, NULL); - if (status) - return status; - - return CAIRO_STATUS_SUCCESS; -} - - /* XXX: move this to the bottom of the file, XCB and Xlib */ static const cairo_surface_backend_t cairo_xcb_surface_backend = { CAIRO_SURFACE_TYPE_XCB, + _cairo_xcb_surface_create_similar, _cairo_xcb_surface_finish, _cairo_xcb_surface_acquire_source_image, _cairo_xcb_surface_release_source_image, + _cairo_xcb_surface_acquire_dest_image, _cairo_xcb_surface_release_dest_image, + _cairo_xcb_surface_clone_similar, _cairo_xcb_surface_composite, _cairo_xcb_surface_fill_rectangles, _cairo_xcb_surface_composite_trapezoids, NULL, /* create_span_renderer */ NULL, /* check_span_renderer */ + NULL, /* copy_page */ NULL, /* show_page */ - _cairo_xcb_surface_set_clip_region, - NULL, /* intersect_clip_path */ + _cairo_xcb_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -1733,8 +1747,6 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = { _cairo_xcb_surface_snapshot, _cairo_xcb_surface_is_similar, - - _cairo_xcb_surface_reset }; /** @@ -1853,8 +1865,9 @@ _cairo_xcb_surface_create_internal (xcb_connection_t *dpy, surface->have_clip_rects = FALSE; surface->clip_rects = NULL; surface->num_clip_rects = 0; + surface->clip_region = NULL; - return (cairo_surface_t *) surface; + return &surface->base; } static xcb_screen_t * @@ -2463,8 +2476,8 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip, + int *remaining_glyphs) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_xcb_surface_t *dst = abstract_dst; @@ -2474,6 +2487,7 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst, cairo_xcb_surface_t *src = NULL; cairo_solid_pattern_t solid_pattern; + cairo_region_t *clip_region = NULL; if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -2497,10 +2511,12 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst, * fallback clip masking, we have to go through the full * fallback path. */ - if (dst->base.clip && - (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION || - dst->base.clip->surface != NULL)) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO); + if (status) + return status; + } operation = _categorize_composite_operation (dst, op, src_pattern, TRUE); if (operation == DO_UNSUPPORTED) @@ -2564,6 +2580,10 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst, goto BAIL; } + status = _cairo_xcb_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + goto BAIL; + status = _cairo_xcb_surface_set_attributes (src, &attributes); if (status) goto BAIL; diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h index 164fe15f..53701e24 100644 --- a/src/cairo-xlib-surface-private.h +++ b/src/cairo-xlib-surface-private.h @@ -85,11 +85,11 @@ struct _cairo_xlib_surface { Picture dst_picture, src_picture; unsigned int clip_dirty; - cairo_bool_t have_clip_rects; cairo_bool_t gc_has_clip_rects; XRectangle embedded_clip_rects[8]; XRectangle *clip_rects; int num_clip_rects; + cairo_region_t *clip_region; XRenderPictFormat *xrender_format; cairo_filter_t filter; diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 1aae2885..647e61fb 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -45,11 +45,25 @@ #include "cairo-xlib-surface-private.h" #include "cairo-clip-private.h" #include "cairo-scaled-font-private.h" +#include "cairo-region-private.h" #include <X11/Xutil.h> /* for XDestroyImage */ #define XLIB_COORD_MAX 32767 +#define DEBUG 0 + +#if DEBUG +#define UNSUPPORTED(reason) ({ \ + fprintf (stderr, \ + "cairo-xlib: hit unsupported operation %s(), line %d: %s\n", \ + __FUNCTION__, __LINE__, reason); \ + CAIRO_INT_STATUS_UNSUPPORTED; \ +}) +#else +#define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED +#endif + /* Xlib doesn't define a typedef, so define one ourselves */ typedef int (*cairo_xlib_error_func_t) (Display *display, XErrorEvent *event); @@ -65,7 +79,8 @@ _cairo_xlib_surface_create_internal (Display *dpy, int depth); static cairo_status_t -_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface); +_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface, + cairo_bool_t set_clip); static void _cairo_xlib_surface_maybe_put_gc (cairo_xlib_surface_t *surface); @@ -89,8 +104,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip, + int *remaining_glyphs); /* XXX temporarily used by cairo-qt-surface.c */ slim_hidden_proto (cairo_xlib_surface_create); @@ -135,12 +150,68 @@ static const XTransform identity = { { #if RENDER_MAJOR > 0 || RENDER_MINOR >= 11 #define CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR(surface, op) \ - (CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS (surface) ? (op) <= CAIRO_OPERATOR_HSL_LUMINOSITY : (op) <= CAIRO_OPERATOR_SATURATE) + (((op) <= CAIRO_OPERATOR_SATURATE) ? TRUE : (CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS (surface) ? (op) <= CAIRO_OPERATOR_HSL_LUMINOSITY : FALSE)) #else #define CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR(surface, op) \ ((op) <= CAIRO_OPERATOR_SATURATE) #endif +static cairo_status_t +_cairo_xlib_surface_set_clip_region (cairo_xlib_surface_t *surface, + cairo_region_t *region) +{ + cairo_bool_t had_clip_rects = surface->clip_region != NULL; + + if (had_clip_rects == FALSE && region == NULL) + return CAIRO_STATUS_SUCCESS; + + if (surface->clip_region == region) + return CAIRO_STATUS_SUCCESS; + + if (cairo_region_equal (surface->clip_region, region)) + return CAIRO_STATUS_SUCCESS; + + cairo_region_destroy (surface->clip_region); + surface->clip_region = cairo_region_reference (region); + + if (surface->clip_rects != surface->embedded_clip_rects) { + free (surface->clip_rects); + surface->clip_rects = surface->embedded_clip_rects; + } + surface->num_clip_rects = 0; + + if (region != NULL) { + XRectangle *rects = NULL; + int n_rects, i; + + n_rects = cairo_region_num_rectangles (region); + if (n_rects > ARRAY_LENGTH (surface->embedded_clip_rects)) { + rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle)); + if (unlikely (rects == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else { + rects = surface->embedded_clip_rects; + } + + for (i = 0; i < n_rects; i++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (region, i, &rect); + + rects[i].x = rect.x; + rects[i].y = rect.y; + rects[i].width = rect.width; + rects[i].height = rect.height; + } + + surface->clip_rects = rects; + surface->num_clip_rects = n_rects; + } + + surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL; + return CAIRO_STATUS_SUCCESS; +} + static cairo_surface_t * _cairo_xlib_surface_create_similar_with_format (void *abstract_src, cairo_format_t format, @@ -178,7 +249,7 @@ _cairo_xlib_surface_create_similar_with_format (void *abstract_src, xrender_format, width, height, xrender_format->depth); - if (surface->base.status) { + if (unlikely (surface->base.status)) { XFreePixmap (dpy, pix); return &surface->base; } @@ -256,7 +327,7 @@ _cairo_xlib_surface_create_similar (void *abstract_src, xrender_format, width, height, xrender_format->depth); - if (surface->base.status != CAIRO_STATUS_SUCCESS) { + if (unlikely (surface->base.status)) { XFreePixmap (src->dpy, pix); return &surface->base; } @@ -280,9 +351,7 @@ _cairo_xlib_surface_finish (void *abstract_surface) status2 = _cairo_xlib_display_queue_resource (display, XRenderFreePicture, surface->dst_picture); - if (status2 == CAIRO_STATUS_SUCCESS) - surface->dst_picture = None; - else if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_STATUS_SUCCESS) status = status2; } @@ -290,19 +359,14 @@ _cairo_xlib_surface_finish (void *abstract_surface) status2 = _cairo_xlib_display_queue_resource (display, XRenderFreePicture, surface->src_picture); - if (status2 == CAIRO_STATUS_SUCCESS) - surface->src_picture = None; - else if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_STATUS_SUCCESS) status = status2; } status2 = _cairo_xlib_display_queue_resource (display, (cairo_xlib_notify_resource_func) XFreePixmap, surface->drawable); - if (status2 == CAIRO_STATUS_SUCCESS) { - surface->owns_pixmap = FALSE; - surface->drawable = None; - } else if (status == CAIRO_STATUS_SUCCESS) + if (status == CAIRO_STATUS_SUCCESS) status = status2; } else { if (surface->dst_picture != None) @@ -332,6 +396,7 @@ _cairo_xlib_surface_finish (void *abstract_surface) _cairo_xlib_display_destroy (surface->display); } + cairo_region_destroy (surface->clip_region); surface->dpy = NULL; return status; @@ -667,8 +732,7 @@ _get_image_surface (cairo_xlib_surface_t *surface, ximage = NULL; } - if (!ximage) { - + if (ximage == NULL) { /* XGetImage from a window is dangerous because it can * produce errors if the window is unmapped or partially * outside the screen. We could check for errors and @@ -677,7 +741,7 @@ _get_image_surface (cairo_xlib_surface_t *surface, */ Pixmap pixmap; - status = _cairo_xlib_surface_ensure_gc (surface); + status = _cairo_xlib_surface_ensure_gc (surface, FALSE); if (unlikely (status)) return status; @@ -700,7 +764,7 @@ _get_image_surface (cairo_xlib_surface_t *surface, XFreePixmap (surface->dpy, pixmap); } - if (!ximage) + if (ximage == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_xlib_surface_maybe_put_gc (surface); @@ -714,10 +778,14 @@ _get_image_surface (cairo_xlib_surface_t *surface, xlib_masks.green_mask = surface->g_mask; xlib_masks.blue_mask = surface->b_mask; - if (_pixman_format_from_masks (&xlib_masks, &pixman_format) && - xlib_masks.bpp >= 24 && - ximage->bitmap_unit == 32 && - ximage->bitmap_pad == 32) + /* We can't use pixman to simply write to image if: + * (a) the pixels are not appropriately aligned, + * (b) pixman does not the pixel format, or + * (c) if the image is palettized and we need to convert. + */ + if (ximage->bitmap_unit == 32 && ximage->bitmap_pad == 32 && + _pixman_format_from_masks (&xlib_masks, &pixman_format) && + (surface->visual == NULL || surface->visual->class == TrueColor)) { image = (cairo_image_surface_t*) _cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data, @@ -861,7 +929,7 @@ _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface) static void _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface) { - if (surface->have_clip_rects) { + if (surface->clip_region != NULL) { XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture, 0, 0, surface->clip_rects, @@ -879,8 +947,8 @@ _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface) static void _cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface) { - surface->gc_has_clip_rects = surface->have_clip_rects; - if (surface->have_clip_rects) { + surface->gc_has_clip_rects = surface->clip_region != NULL; + if (surface->clip_region != NULL) { XSetClipRectangles(surface->dpy, surface->gc, 0, 0, surface->clip_rects, @@ -906,7 +974,8 @@ _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface) } static cairo_status_t -_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface) +_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface, + cairo_bool_t set_clip) { if (surface->gc == NULL) { @@ -916,10 +985,22 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface) &surface->clip_dirty); if (unlikely (surface->gc == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + surface->gc_has_clip_rects = + surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC; } - if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC) - _cairo_xlib_surface_set_gc_clip_rects (surface); + if (set_clip) { + if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC) + _cairo_xlib_surface_set_gc_clip_rects (surface); + } else { + if (surface->gc_has_clip_rects) { + surface->gc_has_clip_rects = FALSE; + XSetClipMask (surface->dpy, surface->gc, None); + + surface->clip_dirty |= CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC; + } + } return CAIRO_STATUS_SUCCESS; } @@ -928,7 +1009,6 @@ static void _cairo_xlib_surface_maybe_put_gc (cairo_xlib_surface_t *surface) { /* return the GC back to the common pool if clean */ - if (surface->gc_has_clip_rects) return; @@ -984,7 +1064,9 @@ _draw_image_surface (cairo_xlib_surface_t *surface, ret = XInitImage (&ximage); assert (ret != 0); - } else { + } + else + { unsigned int stride, rowstride; int x, y, x0, y0, x_off, y_off; uint32_t in_pixel, out_pixel, *row; @@ -1089,13 +1171,14 @@ _draw_image_surface (cairo_xlib_surface_t *surface, } } - status = _cairo_xlib_surface_ensure_gc (surface); + /* XXX set clip? */ + status = _cairo_xlib_surface_ensure_gc (surface, FALSE); if (unlikely (status)) goto BAIL; - XPutImage(surface->dpy, surface->drawable, surface->gc, - &ximage, src_x, src_y, dst_x, dst_y, - width, height); + XPutImage (surface->dpy, surface->drawable, surface->gc, + &ximage, src_x, src_y, dst_x, dst_y, + width, height); _cairo_xlib_surface_maybe_put_gc (surface); @@ -1103,7 +1186,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface, if (own_data) free (ximage.data); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -1197,11 +1280,11 @@ _cairo_xlib_surface_release_dest_image (void *abstract_surfac * screen. Both core and Render drawing require this * when using multiple drawables in an operation. */ -static cairo_bool_t +static inline cairo_bool_t _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst, cairo_xlib_surface_t *src) { - return dst->dpy == src->dpy && dst->screen == src->screen; + return dst->screen_info == src->screen_info; } static cairo_status_t @@ -1237,7 +1320,7 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface, cairo_format_t format; if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) - return CAIRO_INT_STATUS_UNSUPPORTED; + return UNSUPPORTED ("roi too large for xlib"); format = image_src->format; if (format == CAIRO_FORMAT_INVALID || @@ -1250,9 +1333,9 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface, format, width, height); if (clone == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; + return UNSUPPORTED ("unhandled image format, no similar surface"); - if (clone->base.status) + if (unlikely (clone->base.status)) return clone->base.status; status = _draw_image_surface (clone, image_src, @@ -1299,9 +1382,6 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac if (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other)) return NULL; - if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) - return NULL; - image = (cairo_image_surface_t *) _cairo_image_surface_create_with_content (solid_pattern->content, width, height); @@ -1327,7 +1407,8 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac status = _cairo_surface_paint (&image->base, CAIRO_OPERATOR_SOURCE, - &solid_pattern->base, NULL); + &solid_pattern->base, + NULL); if (unlikely (status)) goto BAIL; @@ -1361,7 +1442,6 @@ _cairo_xlib_surface_can_repaint_solid_pattern_surface (void *abstract_surface, return CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other); } - static cairo_status_t _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface, cairo_matrix_t *matrix, @@ -1380,8 +1460,8 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface, if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0) return CAIRO_STATUS_SUCCESS; - if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (! CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) + return UNSUPPORTED ("XRender does not support picture transforms"); XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform); surface->xtransform = xtransform; @@ -1398,12 +1478,11 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface, if (surface->filter == filter) return CAIRO_STATUS_SUCCESS; - if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) - { + if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) { if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) return CAIRO_STATUS_SUCCESS; - return CAIRO_INT_STATUS_UNSUPPORTED; + return UNSUPPORTED ("XRender does not support filter"); } switch (filter) { @@ -1463,6 +1542,7 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, double yc) { cairo_int_status_t status; + int repeat; _cairo_xlib_surface_ensure_src_picture (surface); @@ -1473,24 +1553,28 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, switch (attributes->extend) { case CAIRO_EXTEND_NONE: - _cairo_xlib_surface_set_repeat (surface, RepeatNone); + repeat = RepeatNone; break; case CAIRO_EXTEND_REPEAT: - _cairo_xlib_surface_set_repeat (surface, RepeatNormal); + repeat = RepeatNormal; break; case CAIRO_EXTEND_REFLECT: if (surface->buggy_pad_reflect) - return CAIRO_INT_STATUS_UNSUPPORTED; - _cairo_xlib_surface_set_repeat (surface, RepeatReflect); + return UNSUPPORTED ("buggy reflect"); + + repeat = RepeatReflect; break; case CAIRO_EXTEND_PAD: if (surface->buggy_pad_reflect) - return CAIRO_INT_STATUS_UNSUPPORTED; - _cairo_xlib_surface_set_repeat (surface, RepeatPad); + return UNSUPPORTED ("buggy reflect"); + + repeat = RepeatPad; break; default: + ASSERT_NOT_REACHED; return CAIRO_INT_STATUS_UNSUPPORTED; } + _cairo_xlib_surface_set_repeat (surface, repeat); status = _cairo_xlib_surface_set_filter (surface, attributes->filter); if (unlikely (status)) @@ -1508,7 +1592,7 @@ _surfaces_compatible (cairo_xlib_surface_t *dst, cairo_xlib_surface_t *src) { /* same screen */ - if (!_cairo_xlib_surface_same_screen (dst, src)) + if (! _cairo_xlib_surface_same_screen (dst, src)) return FALSE; /* same depth (for core) */ @@ -1538,7 +1622,6 @@ _surface_has_alpha (cairo_xlib_surface_t *surface) else return FALSE; } else { - /* In the no-render case, we never have alpha */ return FALSE; } @@ -1601,7 +1684,7 @@ _categorize_composite_operation (cairo_xlib_surface_t *dst, if (!CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR (dst, op)) return DO_UNSUPPORTED; - if (!dst->buggy_repeat) + if (! dst->buggy_repeat) return DO_RENDER; if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE) @@ -1665,9 +1748,6 @@ _recategorize_composite_operation (cairo_xlib_surface_t *dst, _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL); cairo_bool_t needs_alpha_composite; - if (! _cairo_surface_is_xlib (&src->base)) - return DO_UNSUPPORTED; - needs_alpha_composite = _operator_needs_alpha_composite (op, _surface_has_alpha (dst), @@ -1810,7 +1890,8 @@ _cairo_xlib_surface_composite (cairo_operator_t op, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_surface_attributes_t src_attr, mask_attr; cairo_xlib_surface_t *dst = abstract_dst; @@ -1823,12 +1904,13 @@ _cairo_xlib_surface_composite (cairo_operator_t op, cairo_bool_t needs_alpha_composite; cairo_content_t src_content; - _cairo_xlib_display_notify (dst->display); + if (mask_pattern != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) + return UNSUPPORTED ("no support for masks"); operation = _categorize_composite_operation (dst, op, src_pattern, mask_pattern != NULL); if (operation == DO_UNSUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; + return UNSUPPORTED ("unsupported operation"); needs_alpha_composite = _operator_needs_alpha_composite (op, @@ -1838,6 +1920,8 @@ _cairo_xlib_surface_composite (cairo_operator_t op, if (! needs_alpha_composite) src_content &= ~CAIRO_CONTENT_ALPHA; + _cairo_xlib_display_notify (dst->display); + status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern, &dst->base, src_content, @@ -1854,25 +1938,25 @@ _cairo_xlib_surface_composite (cairo_operator_t op, return status; /* check for fallback surfaces that we cannot handle ... */ - if (!_cairo_surface_is_xlib (&src->base)) { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto BAIL; - } - if (mask != NULL && - (! _cairo_surface_is_xlib (&mask->base) || - ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))) - { - status = CAIRO_INT_STATUS_UNSUPPORTED; + assert (_cairo_surface_is_xlib (&src->base)); + assert (mask == NULL || _cairo_surface_is_xlib (&mask->base)); + + if (mask != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (mask)) { + status = UNSUPPORTED ("unsupported mask"); goto BAIL; } operation = _recategorize_composite_operation (dst, op, src, &src_attr, mask_pattern != NULL); if (operation == DO_UNSUPPORTED) { - status = CAIRO_INT_STATUS_UNSUPPORTED; + status = UNSUPPORTED ("unsupported operation"); goto BAIL; } + status = _cairo_xlib_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + goto BAIL; + switch (operation) { case DO_RENDER: @@ -1917,7 +2001,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, break; case DO_XCOPYAREA: - status = _cairo_xlib_surface_ensure_gc (dst); + status = _cairo_xlib_surface_ensure_gc (dst, TRUE); if (unlikely (status)) goto BAIL; @@ -1947,7 +2031,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, * _recategorize_composite_operation. */ - status = _cairo_xlib_surface_ensure_gc (dst); + status = _cairo_xlib_surface_ensure_gc (dst, TRUE); if (unlikely (status)) goto BAIL; is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix, @@ -1979,7 +2063,8 @@ _cairo_xlib_surface_composite (cairo_operator_t op, mask ? mask->height : 0, src_x, src_y, mask_x, mask_y, - dst_x, dst_y, width, height); + dst_x, dst_y, width, height, + clip_region); BAIL: if (mask) @@ -2004,7 +2089,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface, _cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR); - status = _cairo_xlib_surface_ensure_gc (surface); + status = _cairo_xlib_surface_ensure_gc (surface, FALSE); if (unlikely (status)) return status; @@ -2019,10 +2104,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface, if (unlikely (status)) return status; - if (! _cairo_surface_is_xlib (solid_surface)) { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto BAIL; - } + assert (_cairo_surface_is_xlib (solid_surface)); XSetTSOrigin (surface->dpy, surface->gc, - (surface->base.device_transform.x0 + attrs.x_offset), @@ -2039,10 +2121,9 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface, _cairo_xlib_surface_maybe_put_gc (surface); - BAIL: _cairo_pattern_release_surface (&solid.base, solid_surface, &attrs); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -2054,6 +2135,7 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, { cairo_xlib_surface_t *surface = abstract_surface; XRenderColor render_color; + cairo_status_t status; int i; _cairo_xlib_display_notify (surface->display); @@ -2070,7 +2152,7 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, rects, num_rects); } - return CAIRO_INT_STATUS_UNSUPPORTED; + return UNSUPPORTED ("no support for FillRectangles with this op"); } render_color.red = color->red_short; @@ -2078,6 +2160,9 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, render_color.blue = color->blue_short; render_color.alpha = color->alpha_short; + status = _cairo_xlib_surface_set_clip_region (surface, NULL); + assert (status == CAIRO_STATUS_SUCCESS); + _cairo_xlib_surface_ensure_dst_picture (surface); if (num_rects == 1) { /* Take advantage of the protocol compaction that libXrender performs @@ -2245,7 +2330,8 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int num_traps) + int num_traps, + cairo_region_t *clip_region) { cairo_surface_attributes_t attributes; cairo_xlib_surface_t *dst = abstract_dst; @@ -2258,12 +2344,12 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, _cairo_xlib_display_notify (dst->display); - if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (! CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) + return UNSUPPORTED ("XRender does not support CompositeTrapezoids"); operation = _categorize_composite_operation (dst, op, pattern, TRUE); if (operation == DO_UNSUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; + return UNSUPPORTED ("unsupported operation"); status = _cairo_pattern_acquire_surface (pattern, &dst->base, CAIRO_CONTENT_COLOR_ALPHA, @@ -2279,7 +2365,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE); if (operation == DO_UNSUPPORTED) { - status = CAIRO_INT_STATUS_UNSUPPORTED; + status = UNSUPPORTED ("unsupported operation"); goto BAIL; } @@ -2310,7 +2396,12 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, render_src_x = src_x + render_reference_x - dst_x; render_src_y = src_y + render_reference_y - dst_y; + status = _cairo_xlib_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + goto BAIL; + _cairo_xlib_surface_ensure_dst_picture (dst); + status = _cairo_xlib_surface_set_attributes (src, &attributes, dst_x + width / 2., dst_y + height / 2.); @@ -2353,7 +2444,8 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, width, height, src_x, src_y, 0, 0, - dst_x, dst_y, width, height); + dst_x, dst_y, width, height, + clip_region); } else { XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)]; @@ -2399,115 +2491,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, return status; } -static cairo_region_t * -_surface_maybe_clip_region (cairo_xlib_surface_t *surface, - cairo_region_t *clip, - cairo_region_t *bounded) -{ - cairo_rectangle_int_t rect; - - cairo_region_get_extents (clip, &rect); - if (rect.x >= 0 && - rect.y >= 0 && - rect.x + rect.width <= surface->width && - rect.y + rect.height <= surface->height) - { - return clip; - } - - rect.x = rect.y = 0; - rect.width = surface->width; - rect.height = surface->height; - _cairo_region_init_rectangle (bounded, &rect); - - bounded->status = cairo_region_intersect (bounded, clip); - - return bounded; -} - -static cairo_int_status_t -_cairo_xlib_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region) -{ - cairo_xlib_surface_t *surface = abstract_surface; - cairo_bool_t had_clip_rects = surface->have_clip_rects; - - if (had_clip_rects == FALSE && region == NULL) - return CAIRO_STATUS_SUCCESS; - - if (surface->clip_rects != surface->embedded_clip_rects) { - free (surface->clip_rects); - surface->clip_rects = surface->embedded_clip_rects; - } - - surface->have_clip_rects = FALSE; - surface->num_clip_rects = 0; - - if (region != NULL) { - XRectangle *rects = NULL; - int n_rects, i; - cairo_region_t bounded; - - /* Intersect the region with the bounds of the surface. This - * is necessary so we don't wrap around when we convert cairo's - * 32 bit region into 16 bit rectangles. - */ - region = _surface_maybe_clip_region (surface, region, &bounded); - if (unlikely (region->status)) - return region->status; - - n_rects = cairo_region_num_rectangles (region); - if (n_rects > ARRAY_LENGTH (surface->embedded_clip_rects)) { - rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle)); - if (unlikely (rects == NULL)) { - if (unlikely (region == &bounded)) - _cairo_region_fini (&bounded); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - } else { - rects = surface->embedded_clip_rects; - } - - for (i = 0; i < n_rects; i++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (region, i, &rect); - - rects[i].x = rect.x; - rects[i].y = rect.y; - rects[i].width = rect.width; - rects[i].height = rect.height; - } - - if (unlikely (region == &bounded)) - _cairo_region_fini (&bounded); - - surface->have_clip_rects = TRUE; - surface->clip_rects = rects; - surface->num_clip_rects = n_rects; - - /* Discard the trivial clip rectangle that covers the entire surface */ - if (n_rects == 1 && - rects[0].x == 0 && - rects[0].y == 0 && - rects[0].width == surface->width && - rects[0].height == surface->height) - { - surface->have_clip_rects = FALSE; - surface->num_clip_rects = 0; - - if (! had_clip_rects) - goto DONE; - } - } - - surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL; - DONE: - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t +static cairo_bool_t _cairo_xlib_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -2519,7 +2503,7 @@ _cairo_xlib_surface_get_extents (void *abstract_surface, rectangle->width = surface->width; rectangle->height = surface->height; - return CAIRO_STATUS_SUCCESS; + return TRUE; } static void @@ -2547,7 +2531,7 @@ _cairo_xlib_surface_is_similar (void *surface_a, cairo_xlib_surface_t *b = surface_b; XRenderPictFormat *xrender_format = b->xrender_format; - if (!_cairo_xlib_surface_same_screen (a, b)) + if (! _cairo_xlib_surface_same_screen (a, b)) return FALSE; /* now inspect the content to check that a is similar to b */ @@ -2566,19 +2550,6 @@ _cairo_xlib_surface_is_similar (void *surface_a, return a->xrender_format == xrender_format; } -static cairo_status_t -_cairo_xlib_surface_reset (void *abstract_surface) -{ - cairo_xlib_surface_t *surface = abstract_surface; - cairo_status_t status; - - status = _cairo_xlib_surface_set_clip_region (surface, NULL); - if (unlikely (status)) - return status; - - return CAIRO_STATUS_SUCCESS; -} - static const cairo_surface_backend_t cairo_xlib_surface_backend = { CAIRO_SURFACE_TYPE_XLIB, _cairo_xlib_surface_create_similar, @@ -2595,8 +2566,6 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - _cairo_xlib_surface_set_clip_region, - NULL, /* intersect_clip_path */ _cairo_xlib_surface_get_extents, NULL, /* old_show_glyphs */ _cairo_xlib_surface_get_font_options, @@ -2612,10 +2581,10 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = { _cairo_xlib_surface_show_glyphs, _cairo_xlib_surface_snapshot, - _cairo_xlib_surface_is_similar, - _cairo_xlib_surface_reset, + NULL, /* fill_stroke */ + _cairo_xlib_surface_create_solid_pattern_surface, _cairo_xlib_surface_can_repaint_solid_pattern_surface }; @@ -2771,7 +2740,7 @@ _cairo_xlib_surface_create_internal (Display *dpy, surface->height = height; surface->buggy_repeat = screen_info->display->buggy_repeat; - if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) { + if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) { /* so we can use the XTile fallback */ surface->buggy_repeat = TRUE; } @@ -2787,7 +2756,7 @@ _cairo_xlib_surface_create_internal (Display *dpy, surface->repeat = FALSE; surface->xtransform = identity; - surface->have_clip_rects = FALSE; + surface->clip_region = NULL; surface->gc_has_clip_rects = FALSE; surface->clip_rects = surface->embedded_clip_rects; surface->num_clip_rects = 0; @@ -2833,23 +2802,25 @@ _cairo_xlib_surface_create_internal (Display *dpy, static Screen * _cairo_xlib_screen_from_visual (Display *dpy, Visual *visual) { - int s; - int d; - int v; - Screen *screen; - Depth *depth; + int s, d, v; for (s = 0; s < ScreenCount (dpy); s++) { + Screen *screen; + screen = ScreenOfDisplay (dpy, s); if (visual == DefaultVisualOfScreen (screen)) return screen; + for (d = 0; d < screen->ndepths; d++) { + Depth *depth; + depth = &screen->depths[d]; for (v = 0; v < depth->nvisuals; v++) if (visual == &depth->visuals[v]) return screen; } } + return NULL; } @@ -3624,7 +3595,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, sz_xGlyphInfo - 8; if (len >= max_request_size) - return CAIRO_INT_STATUS_UNSUPPORTED; + return UNSUPPORTED ("glyph too large for XRequest"); } /* If the glyph surface has zero height or width, we create @@ -3975,7 +3946,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); - if (status != CAIRO_STATUS_SUCCESS) + if (unlikely (status)) return status; this_x = _cairo_lround (glyphs[i].d.x); @@ -4055,7 +4026,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst, status = _emit_glyphs_chunk (dst, glyphs, i, scaled_font, op, src, attributes, num_elts, old_width, glyphset_info); - if (status != CAIRO_STATUS_SUCCESS) + if (unlikely (status)) return status; glyphs += i; @@ -4094,13 +4065,14 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst, request_size += width; } - if (num_elts) + if (num_elts) { status = _emit_glyphs_chunk (dst, glyphs, i, scaled_font, op, src, attributes, num_elts, width, glyphset_info); + } *remaining_glyphs = num_glyphs - i; - if (*remaining_glyphs && status == CAIRO_STATUS_SUCCESS) + if (*remaining_glyphs != 0 && status == CAIRO_STATUS_SUCCESS) status = CAIRO_INT_STATUS_UNSUPPORTED; return status; @@ -4130,8 +4102,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip, + int *remaining_glyphs) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_xlib_surface_t *dst = (cairo_xlib_surface_t*) abstract_dst; @@ -4139,16 +4111,17 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, composite_operation_t operation; cairo_surface_attributes_t attributes; cairo_xlib_surface_t *src = NULL; + cairo_region_t *clip_region = NULL; cairo_solid_pattern_t solid_pattern; if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; + return UNSUPPORTED ("XRender does not support CompositeText"); /* Just let unbounded operators go through the fallback code * instead of trying to do the fixups here */ - if (!_cairo_operator_bounded_by_mask (op)) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (! _cairo_operator_bounded_by_mask (op)) + return UNSUPPORTED ("unsupported unbounded op"); /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs -- * the solid source seems to be multiplied by the glyph mask, and @@ -4156,25 +4129,33 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, * including the fully transparent "background" of the rectangular * glyph surface. */ if (op == CAIRO_OPERATOR_SOURCE && - !CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11)) - return CAIRO_INT_STATUS_UNSUPPORTED; + ! CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11)) + { + return UNSUPPORTED ("known bug in Render"); + } /* We can only use our code if we either have no clip or * have a real native clip region set. If we're using * fallback clip masking, we have to go through the full * fallback path. */ - if (dst->base.clip && - (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION || - dst->base.clip->surface != NULL)) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO); + if (status) + return status; + } operation = _categorize_composite_operation (dst, op, src_pattern, TRUE); if (operation == DO_UNSUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; + return UNSUPPORTED ("unsupported op"); if (! _cairo_xlib_surface_owns_font (dst, scaled_font)) - return CAIRO_INT_STATUS_UNSUPPORTED; + return UNSUPPORTED ("unowned font"); + + status = _cairo_xlib_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + return status; /* After passing all those tests, we're now committed to rendering * these glyphs or to fail trying. We first upload any glyphs to @@ -4213,6 +4194,14 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, if (unlikely (status)) goto BAIL0; + if (clip != NULL) { + if (! _cairo_rectangle_intersect (&glyph_extents, + _cairo_clip_get_extents (clip))) + { + goto BAIL0; + } + } + status = _cairo_pattern_acquire_surface (src_pattern, &dst->base, CAIRO_CONTENT_COLOR_ALPHA, glyph_extents.x, glyph_extents.y, @@ -4229,7 +4218,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE); if (operation == DO_UNSUPPORTED) { - status = CAIRO_INT_STATUS_UNSUPPORTED; + status = UNSUPPORTED ("unsupported op"); goto BAIL1; } @@ -4247,15 +4236,14 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, src, &attributes, remaining_glyphs); - } else - status = CAIRO_INT_STATUS_UNSUPPORTED; + } else { + status = UNSUPPORTED ("unowned font"); + } _cairo_scaled_font_thaw_cache (scaled_font); BAIL1: if (src) _cairo_pattern_release_surface (src_pattern, &src->base, &attributes); - if (src_pattern == &solid_pattern.base) - _cairo_pattern_fini (&solid_pattern.base); BAIL0: _cairo_xlib_display_notify (dst->display); diff --git a/src/cairo.c b/src/cairo.c index 3e590496..2470b0d6 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -44,6 +44,10 @@ #define CAIRO_TOLERANCE_MINIMUM _cairo_fixed_to_double(1) +#if !defined(INFINITY) +#define INFINITY HUGE_VAL +#endif + static const cairo_t _cairo_nil = { CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ CAIRO_STATUS_NO_MEMORY, /* status */ @@ -57,7 +61,8 @@ static const cairo_t _cairo_nil = { FALSE, /* has_current_point */ FALSE, /* has_curve_to */ FALSE, /* is_box */ - FALSE, /* is_region */ + FALSE, /* maybe_fill_region */ + TRUE, /* is_empty_fill */ {{{NULL,NULL}}} /* link */ }} }; @@ -496,25 +501,28 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content) { cairo_status_t status; cairo_rectangle_int_t extents; + const cairo_rectangle_int_t *clip_extents; cairo_surface_t *parent_surface, *group_surface = NULL; + cairo_bool_t is_empty; if (unlikely (cr->status)) return; parent_surface = _cairo_gstate_get_target (cr->gstate); - /* Get the extents that we'll use in creating our new group surface */ - status = _cairo_surface_get_extents (parent_surface, &extents); - if (unlikely (status)) - goto bail; - status = _cairo_clip_intersect_to_rectangle (_cairo_gstate_get_clip (cr->gstate), &extents); - if (unlikely (status)) - goto bail; - group_surface = cairo_surface_create_similar (parent_surface, - content, - extents.width, - extents.height); - status = cairo_surface_status (group_surface); + /* Get the extents that we'll use in creating our new group surface */ + is_empty = _cairo_surface_get_extents (parent_surface, &extents); + clip_extents = _cairo_clip_get_extents (_cairo_gstate_get_clip (cr->gstate)); + if (clip_extents != NULL) + is_empty = _cairo_rectangle_intersect (&extents, clip_extents); + + group_surface = _cairo_surface_create_similar_solid (parent_surface, + content, + extents.width, + extents.height, + CAIRO_COLOR_TRANSPARENT, + TRUE); + status = group_surface->status; if (unlikely (status)) goto bail; @@ -2340,7 +2348,7 @@ cairo_in_stroke (cairo_t *cr, double x, double y) cairo_bool_t inside = FALSE; if (unlikely (cr->status)) - return 0; + return FALSE; status = _cairo_gstate_in_stroke (cr->gstate, cr->path, @@ -2370,16 +2378,10 @@ cairo_in_stroke (cairo_t *cr, double x, double y) cairo_bool_t cairo_in_fill (cairo_t *cr, double x, double y) { - cairo_bool_t inside; - if (unlikely (cr->status)) - return 0; - - _cairo_gstate_in_fill (cr->gstate, - cr->path, - x, y, &inside); + return FALSE; - return inside; + return _cairo_gstate_in_fill (cr->gstate, cr->path, x, y); } /** @@ -2600,8 +2602,6 @@ cairo_clip_extents (cairo_t *cr, double *x1, double *y1, double *x2, double *y2) { - cairo_status_t status; - if (unlikely (cr->status)) { if (x1) *x1 = 0.0; @@ -2615,9 +2615,38 @@ cairo_clip_extents (cairo_t *cr, return; } - status = _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2); - if (unlikely (status)) - _cairo_set_error (cr, status); + if (! _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2)) { + *x1 = -INFINITY; + *y1 = -INFINITY; + *x2 = +INFINITY; + *y2 = +INFINITY; + } +} + +/** + * cairo_in_clip: + * @cr: a cairo context + * @x: X coordinate of the point to test + * @y: Y coordinate of the point to test + * + * Tests whether the given point is inside the area that would be + * visible through the current clip, i.e. the area that would be filled by + * a cairo_paint() operation. + * + * See cairo_clip(), and cairo_clip_preserve(). + * + * Return value: A non-zero value if the point is inside, or zero if + * outside. + * + * Since: 1.10 + **/ +cairo_bool_t +cairo_in_clip (cairo_t *cr, double x, double y) +{ + if (unlikely (cr->status)) + return FALSE; + + return _cairo_gstate_in_clip (cr->gstate, x, y); } static cairo_rectangle_list_t * diff --git a/src/cairo.h b/src/cairo.h index bd4eb661..4e930604 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -788,6 +788,9 @@ cairo_in_stroke (cairo_t *cr, double x, double y); cairo_public cairo_bool_t cairo_in_fill (cairo_t *cr, double x, double y); +cairo_public cairo_bool_t +cairo_in_clip (cairo_t *cr, double x, double y); + /* Rectangular extents */ cairo_public void cairo_stroke_extents (cairo_t *cr, @@ -2169,8 +2172,7 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, cairo_public cairo_surface_t * cairo_meta_surface_create (cairo_content_t content, - double width_pixels, - double height_pixels); + const cairo_rectangle_t *extents); cairo_public void cairo_meta_surface_ink_extents (cairo_surface_t *surface, @@ -2451,39 +2453,45 @@ cairo_public cairo_region_t * cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle); cairo_public cairo_region_t * -cairo_region_create_rectangles (cairo_rectangle_int_t *rects, +cairo_region_create_rectangles (const cairo_rectangle_int_t *rects, int count); cairo_public cairo_region_t * -cairo_region_copy (cairo_region_t *original); +cairo_region_copy (const cairo_region_t *original); + +cairo_public cairo_region_t * +cairo_region_reference (cairo_region_t *); cairo_public void cairo_region_destroy (cairo_region_t *region); +cairo_public cairo_bool_t +cairo_region_equal (const cairo_region_t *a, const cairo_region_t *b); + cairo_public cairo_status_t -cairo_region_status (cairo_region_t *region); +cairo_region_status (const cairo_region_t *region); cairo_public void -cairo_region_get_extents (cairo_region_t *region, +cairo_region_get_extents (const cairo_region_t *region, cairo_rectangle_int_t *extents); cairo_public int -cairo_region_num_rectangles (cairo_region_t *region); +cairo_region_num_rectangles (const cairo_region_t *region); cairo_public void -cairo_region_get_rectangle (cairo_region_t *region, +cairo_region_get_rectangle (const cairo_region_t *region, int nth_rectangle, cairo_rectangle_int_t *rectangle); cairo_public cairo_bool_t -cairo_region_is_empty (cairo_region_t *region); +cairo_region_is_empty (const cairo_region_t *region); cairo_public cairo_region_overlap_t -cairo_region_contains_rectangle (cairo_region_t *region, +cairo_region_contains_rectangle (const cairo_region_t *region, const cairo_rectangle_int_t *rectangle); cairo_public cairo_bool_t -cairo_region_contains_point (cairo_region_t *region, int x, int y); +cairo_region_contains_point (const cairo_region_t *region, int x, int y); cairo_public void cairo_region_translate (cairo_region_t *region, int dx, int dy); diff --git a/src/cairoint.h b/src/cairoint.h index cb30f6de..5782f071 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -125,7 +125,7 @@ _cairo_win32_tmpfile (void); #define STRINGIFY(macro_or_string) STRINGIFY_ARG (macro_or_string) #define STRINGIFY_ARG(contents) #contents -#ifdef __GNUC__ +#if defined (__GNUC__) #define cairo_container_of(ptr, type, member) ({ \ const __typeof__ (((type *) 0)->member) *mptr__ = (ptr); \ (type *) ((char *) mptr__ - offsetof (type, member)); \ @@ -252,6 +252,15 @@ cairo_private void _cairo_box_round_to_rectangle (const cairo_box_t *box, cairo_rectangle_int_t *rectangle); +static inline void +_cairo_unbounded_rectangle_init (cairo_rectangle_int_t *rect) +{ + rect->x = CAIRO_RECT_INT_MIN; + rect->y = CAIRO_RECT_INT_MIN; + rect->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; + rect->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; +} + cairo_private cairo_bool_t _cairo_rectangle_intersect (cairo_rectangle_int_t *dst, const cairo_rectangle_int_t *src); @@ -489,6 +498,7 @@ struct _cairo_scaled_font_backend { unsigned int height, cairo_glyph_t *glyphs, int num_glyphs, + cairo_region_t *clip_region, int *remaining_glyphs); cairo_warn cairo_int_status_t @@ -615,6 +625,7 @@ struct _cairo_surface_backend { int *clone_offset_y, cairo_surface_t **clone_out); + /* XXX remove to a separate cairo_surface_compositor_t */ /* XXX: dst should be the first argument for consistency */ cairo_warn cairo_int_status_t (*composite) (cairo_operator_t op, @@ -628,7 +639,8 @@ struct _cairo_surface_backend { int dst_x, int dst_y, unsigned int width, - unsigned int height); + unsigned int height, + cairo_region_t *clip_region); cairo_warn cairo_int_status_t (*fill_rectangles) (void *surface, @@ -650,14 +662,16 @@ struct _cairo_surface_backend { unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int num_traps); + int num_traps, + cairo_region_t *region); cairo_warn cairo_span_renderer_t * (*create_span_renderer) (cairo_operator_t op, const cairo_pattern_t *pattern, void *dst, cairo_antialias_t antialias, - const cairo_composite_rectangles_t *rects); + const cairo_composite_rectangles_t *rects, + cairo_region_t *clip_region); cairo_warn cairo_bool_t (*check_span_renderer) (cairo_operator_t op, @@ -672,59 +686,15 @@ struct _cairo_surface_backend { cairo_warn cairo_int_status_t (*show_page) (void *surface); - /* Set given region as the clip region for the surface, replacing - * any previously set clip region. Passing in a NULL region will - * clear the surface clip region. - * - * The surface is expected to store the clip region and clip all - * following drawing operations against it until the clip region - * is cleared of replaced by another clip region. - * - * Cairo will call this function whenever a clip path can be - * represented as a device pixel aligned set of rectangles. When - * this is not possible, cairo will use mask surfaces for - * clipping. - */ - cairo_warn cairo_int_status_t - (*set_clip_region) (void *surface, - cairo_region_t *region); - - /* Intersect the given path against the clip path currently set in - * the surface, using the given fill_rule and tolerance, and set - * the result as the new clipping path for the surface. Passing - * in a NULL path will clear the surface clipping path. - * - * The surface is expected to store the resulting clip path and - * clip all following drawing operations against it until the clip - * path cleared or intersected with a new path. - * - * If a surface implements this function, set_clip_region() will - * never be called and should not be implemented. If this - * function is not implemented cairo will use set_clip_region() - * (if available) and mask surfaces for clipping. - */ - cairo_warn cairo_int_status_t - (*intersect_clip_path) (void *dst, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias); - /* Get the extents of the current surface. For many surface types * this will be as simple as { x=0, y=0, width=surface->width, * height=surface->height}. * - * This function need not take account of any clipping from - * set_clip_region since the generic version of set_clip_region - * saves those, and the generic get_clip_extents will only call - * into the specific surface->get_extents if there is no current - * clip. - * * If this function is not implemented, or if it returns - * %CAIRO_INT_STATUS_UNSUPPORTED, the surface is considered to be - * boundless and inifnite bounds are used for it. + * FALSE the surface is considered to be + * boundless and infinite bounds are used for it. */ - cairo_warn cairo_int_status_t + cairo_warn cairo_bool_t (*get_extents) (void *surface, cairo_rectangle_int_t *extents); @@ -745,7 +715,8 @@ struct _cairo_surface_backend { unsigned int width, unsigned int height, cairo_glyph_t *glyphs, - int num_glyphs); + int num_glyphs, + cairo_region_t *clip_region); void (*get_font_options) (void *surface, @@ -775,14 +746,14 @@ struct _cairo_surface_backend { (*paint) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); cairo_warn cairo_int_status_t (*mask) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); cairo_warn cairo_int_status_t (*stroke) (void *surface, @@ -794,7 +765,7 @@ struct _cairo_surface_backend { cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); cairo_warn cairo_int_status_t (*fill) (void *surface, @@ -804,7 +775,7 @@ struct _cairo_surface_backend { cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); cairo_warn cairo_int_status_t (*show_glyphs) (void *surface, @@ -813,8 +784,8 @@ struct _cairo_surface_backend { cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip, + int *remaining_glyphs); cairo_surface_t * (*snapshot) (void *surface); @@ -824,9 +795,6 @@ struct _cairo_surface_backend { void *surface_b, cairo_content_t content); - cairo_warn cairo_status_t - (*reset) (void *surface); - cairo_warn cairo_int_status_t (*fill_stroke) (void *surface, cairo_operator_t fill_op, @@ -842,7 +810,7 @@ struct _cairo_surface_backend { cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); cairo_surface_t * (*create_solid_pattern_surface) @@ -869,7 +837,7 @@ struct _cairo_surface_backend { int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); }; #include "cairo-surface-private.h" @@ -887,9 +855,9 @@ struct _cairo_image_surface { int depth; pixman_image_t *pixman_image; + cairo_region_t *clip_region; unsigned owns_data : 1; - unsigned has_clip : 1; unsigned transparency : 2; }; @@ -983,6 +951,8 @@ typedef struct _cairo_traps { cairo_box_t extents; + unsigned int maybe_region : 1; /* hint: 0 implies that it cannot be */ + int num_traps; int traps_size; cairo_trapezoid_t *traps; @@ -1245,12 +1215,16 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate, double y, cairo_bool_t *inside_ret); -cairo_private void +cairo_private cairo_bool_t _cairo_gstate_in_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path, double x, - double y, - cairo_bool_t *inside_ret); + double y); + +cairo_private cairo_bool_t +_cairo_gstate_in_clip (cairo_gstate_t *gstate, + double x, + double y); cairo_private cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path); @@ -1258,12 +1232,12 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path); cairo_private cairo_status_t _cairo_gstate_reset_clip (cairo_gstate_t *gstate); -cairo_private cairo_status_t +cairo_private cairo_bool_t _cairo_gstate_clip_extents (cairo_gstate_t *gstate, double *x1, double *y1, - double *x2, - double *y2); + double *x2, + double *y2); cairo_private cairo_rectangle_list_t* _cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate); @@ -1480,19 +1454,19 @@ cairo_private void _cairo_intern_string_reset_static_data (void); /* cairo-path-fixed.c */ +cairo_private cairo_path_fixed_t * +_cairo_path_fixed_create (void); + cairo_private void _cairo_path_fixed_init (cairo_path_fixed_t *path); cairo_private cairo_status_t _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, - cairo_path_fixed_t *other); + const cairo_path_fixed_t *other); cairo_private cairo_bool_t -_cairo_path_fixed_is_equal (cairo_path_fixed_t *path, - cairo_path_fixed_t *other); - -cairo_private cairo_path_fixed_t * -_cairo_path_fixed_create (void); +_cairo_path_fixed_is_equal (const cairo_path_fixed_t *path, + const cairo_path_fixed_t *other); cairo_private void _cairo_path_fixed_fini (cairo_path_fixed_t *path); @@ -1578,64 +1552,69 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path, void *closure, double tolerance); -cairo_private cairo_status_t -_cairo_path_fixed_append (cairo_path_fixed_t *path, - const cairo_path_fixed_t *other, - cairo_direction_t dir); - cairo_private void -_cairo_path_fixed_approximate_clip_extents (cairo_path_fixed_t *path, +_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path, cairo_rectangle_int_t *extents); cairo_private void -_cairo_path_fixed_approximate_fill_extents (cairo_path_fixed_t *path, +_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path, cairo_rectangle_int_t *extents); cairo_private void -_cairo_path_fixed_approximate_stroke_extents (cairo_path_fixed_t *path, +_cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_rectangle_int_t *extents); + +cairo_private void +_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path, cairo_stroke_style_t *style, const cairo_matrix_t *ctm, cairo_rectangle_int_t *extents); +cairo_private cairo_status_t +_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path, + cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_rectangle_int_t *extents); + cairo_private void -_cairo_path_fixed_bounds (cairo_path_fixed_t *path, +_cairo_path_fixed_bounds (const cairo_path_fixed_t *path, double *x1, double *y1, double *x2, double *y2); cairo_private void _cairo_path_fixed_transform (cairo_path_fixed_t *path, - cairo_matrix_t *matrix); - -cairo_private cairo_bool_t -_cairo_path_fixed_is_empty (cairo_path_fixed_t *path); + const cairo_matrix_t *matrix); cairo_private cairo_bool_t -_cairo_path_fixed_is_box (cairo_path_fixed_t *path, +_cairo_path_fixed_is_box (const cairo_path_fixed_t *path, cairo_box_t *box); cairo_private cairo_bool_t -_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path, +_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path, cairo_box_t *box); /* cairo-path-in-fill.c */ -cairo_private void -_cairo_path_fixed_in_fill (cairo_path_fixed_t *path, +cairo_private cairo_bool_t +_cairo_path_fixed_in_fill (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, double x, - double y, - cairo_bool_t *is_inside); + double y); /* cairo-path-fill.c */ cairo_private cairo_status_t -_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, +_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_traps_t *traps); /* cairo-path-stroke.c */ cairo_private cairo_status_t -_cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path, +_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path, cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, @@ -1707,7 +1686,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, unsigned int width, unsigned int height, cairo_glyph_t *glyphs, - int num_glyphs); + int num_glyphs, + cairo_region_t *clip_region); cairo_private cairo_status_t _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, @@ -1789,11 +1769,12 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other, int height); cairo_private cairo_surface_t * -_cairo_surface_create_similar_solid (cairo_surface_t *other, - cairo_content_t content, - int width, - int height, - const cairo_color_t *color); +_cairo_surface_create_similar_solid (cairo_surface_t *other, + cairo_content_t content, + int width, + int height, + const cairo_color_t *color, + cairo_bool_t allow_fallback); cairo_private cairo_surface_t * _cairo_surface_create_solid_pattern_surface (cairo_surface_t *other, @@ -1813,22 +1794,20 @@ cairo_private void _cairo_surface_set_font_options (cairo_surface_t *surface, cairo_font_options_t *options); -cairo_private cairo_clip_mode_t -_cairo_surface_get_clip_mode (cairo_surface_t *surface); - cairo_private cairo_status_t _cairo_surface_composite (cairo_operator_t op, const cairo_pattern_t *src, const cairo_pattern_t *mask, cairo_surface_t *dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height); + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, + cairo_region_t *clip_region); cairo_private cairo_status_t _cairo_surface_fill_rectangle (cairo_surface_t *surface, @@ -1856,14 +1835,14 @@ cairo_private cairo_status_t _cairo_surface_paint (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_mask (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fill_stroke (cairo_surface_t *surface, @@ -1880,7 +1859,7 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_stroke (cairo_surface_t *surface, @@ -1892,7 +1871,7 @@ _cairo_surface_stroke (cairo_surface_t *surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_fill (cairo_surface_t *surface, @@ -1902,7 +1881,7 @@ _cairo_surface_fill (cairo_surface_t *surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_show_text_glyphs (cairo_surface_t *surface, @@ -1916,7 +1895,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t op, @@ -1930,23 +1909,23 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int ntraps); + int ntraps, + cairo_region_t *clip_region); cairo_private cairo_span_renderer_t * -_cairo_surface_create_span_renderer ( - cairo_operator_t op, - const cairo_pattern_t *pattern, - cairo_surface_t *dst, - cairo_antialias_t antialias, - const cairo_composite_rectangles_t *rects); +_cairo_surface_create_span_renderer (cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_surface_t *dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects, + cairo_region_t *clip_region); cairo_private cairo_bool_t -_cairo_surface_check_span_renderer ( - cairo_operator_t op, - const cairo_pattern_t *pattern, - cairo_surface_t *dst, - cairo_antialias_t antialias, - const cairo_composite_rectangles_t *rects); +_cairo_surface_check_span_renderer (cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_surface_t *dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects); cairo_private cairo_status_t _cairo_surface_acquire_source_image (cairo_surface_t *surface, @@ -2005,37 +1984,7 @@ _cairo_surface_is_similar (cairo_surface_t *surface_a, cairo_surface_t *surface_b, cairo_content_t content); -cairo_private cairo_status_t -_cairo_surface_reset (cairo_surface_t *surface); - -cairo_private unsigned int -_cairo_surface_get_current_clip_serial (cairo_surface_t *surface); - -cairo_private unsigned int -_cairo_surface_allocate_clip_serial (cairo_surface_t *surface); - -cairo_private cairo_status_t -_cairo_surface_reset_clip (cairo_surface_t *surface); - -cairo_private cairo_status_t -_cairo_surface_set_clip_region (cairo_surface_t *surface, - cairo_region_t *region, - unsigned int serial); - -cairo_private cairo_int_status_t -_cairo_surface_intersect_clip_path (cairo_surface_t *surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias); - -cairo_private cairo_clip_t * -_cairo_surface_get_clip (cairo_surface_t *surface); - -cairo_private cairo_status_t -_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip); - -cairo_private cairo_int_status_t +cairo_private cairo_bool_t _cairo_surface_get_extents (cairo_surface_t *surface, cairo_rectangle_int_t *extents); @@ -2051,7 +2000,8 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, unsigned int width, unsigned int height, cairo_glyph_t *glyphs, - int num_glyphs); + int num_glyphs, + cairo_region_t *clip_region); cairo_private cairo_status_t _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, @@ -2068,7 +2018,8 @@ _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, int dst_x, int dst_y, unsigned int width, - unsigned int height); + unsigned int height, + cairo_region_t *clip_region); cairo_private cairo_status_t _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, @@ -2084,7 +2035,8 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, int dst_x, int dst_y, unsigned int width, - unsigned int height); + unsigned int height, + cairo_region_t *clip_region); cairo_private cairo_bool_t _cairo_surface_is_opaque (const cairo_surface_t *surface); @@ -2193,19 +2145,6 @@ _cairo_image_surface_create_for_data_with_content (unsigned char *data, cairo_private void _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface); -/* XXX: It's a nasty kludge that this appears here. Backend functions - * like this should really be static. But we're doing this to work - * around some general defects in the backend clipping interfaces, - * (see some notes in test-paginated-surface.c). - * - * I want to fix the real defects, but it's "hard" as they touch many - * backends, so doing that will require synchronizing several backend - * maintainers. - */ -cairo_private cairo_int_status_t -_cairo_image_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region); - cairo_private cairo_image_surface_t * _cairo_image_surface_coerce (cairo_image_surface_t *surface, cairo_format_t format); @@ -2439,8 +2378,8 @@ _cairo_traps_extents (const cairo_traps_t *traps, cairo_box_t *extents); cairo_private cairo_int_status_t -_cairo_traps_extract_region (const cairo_traps_t *tr, - cairo_region_t **region); +_cairo_traps_extract_region (cairo_traps_t *traps, + cairo_region_t **region); cairo_private cairo_status_t _cairo_traps_path (const cairo_traps_t *traps, @@ -2560,7 +2499,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src, cairo_surface_attributes_t *src_attributes, cairo_surface_attributes_t *mask_attributes); -cairo_private cairo_status_t +cairo_private void _cairo_pattern_get_extents (const cairo_pattern_t *pattern, cairo_rectangle_int_t *extents); @@ -2577,23 +2516,8 @@ _cairo_pattern_equal (const cairo_pattern_t *a, cairo_private void _cairo_pattern_reset_static_data (void); -/* cairo-region.c */ - -struct _cairo_region { - cairo_status_t status; - - pixman_region32_t rgn; -}; - -cairo_private void -_cairo_region_init (cairo_region_t *region); - -cairo_private void -_cairo_region_init_rectangle (cairo_region_t *region, - const cairo_rectangle_int_t *rectangle); - cairo_private void -_cairo_region_fini (cairo_region_t *region); +_cairo_clip_reset_static_data (void); /* cairo-unicode.c */ @@ -2725,7 +2649,6 @@ slim_hidden_proto (cairo_status); slim_hidden_proto (cairo_stroke); slim_hidden_proto (cairo_stroke_preserve); slim_hidden_proto (cairo_surface_copy_page); -slim_hidden_proto (cairo_surface_create_similar); slim_hidden_proto (cairo_surface_destroy); slim_hidden_proto (cairo_surface_finish); slim_hidden_proto (cairo_surface_flush); @@ -2760,7 +2683,9 @@ slim_hidden_proto (cairo_region_create); slim_hidden_proto (cairo_region_create_rectangle); slim_hidden_proto (cairo_region_create_rectangles); slim_hidden_proto (cairo_region_copy); +slim_hidden_proto (cairo_region_reference); slim_hidden_proto (cairo_region_destroy); +slim_hidden_proto (cairo_region_equal); slim_hidden_proto (cairo_region_status); slim_hidden_proto (cairo_region_get_extents); slim_hidden_proto (cairo_region_num_rectangles); diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c index 2a7f1489..f331cf25 100644 --- a/src/test-fallback-surface.c +++ b/src/test-fallback-surface.c @@ -194,7 +194,7 @@ _test_fallback_surface_clone_similar (void *abstract_surface, return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_int_status_t +static cairo_bool_t _test_fallback_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -219,8 +219,6 @@ static const cairo_surface_backend_t test_fallback_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - NULL, /* set_clip_region */ - NULL, /* intersect_clip_path */ _test_fallback_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ diff --git a/src/test-fallback16-surface.c b/src/test-fallback16-surface.c index 07c06105..5f6bee4a 100644 --- a/src/test-fallback16-surface.c +++ b/src/test-fallback16-surface.c @@ -193,7 +193,7 @@ _test_fallback16_surface_clone_similar (void *abstract_surface, } } -static cairo_int_status_t +static cairo_bool_t _test_fallback16_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -218,8 +218,6 @@ static const cairo_surface_backend_t test_fallback16_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - NULL, /* set_clip_region */ - NULL, /* intersect_clip_path */ _test_fallback16_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ diff --git a/src/test-null-surface.c b/src/test-null-surface.c index 2c71f853..59761a39 100644 --- a/src/test-null-surface.c +++ b/src/test-null-surface.c @@ -50,26 +50,17 @@ _return_success (void) /* These typedefs are just to silence the compiler... */ typedef cairo_int_status_t -(*_set_clip_region_func) (void *surface, - cairo_region_t *region); -typedef cairo_int_status_t -(*_intersect_clip_path_func) (void *dst, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias); -typedef cairo_int_status_t (*_paint_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); typedef cairo_int_status_t (*_mask_func) (void *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); typedef cairo_int_status_t (*_stroke_func) (void *surface, @@ -81,7 +72,7 @@ typedef cairo_int_status_t cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); typedef cairo_int_status_t (*_fill_func) (void *surface, @@ -91,7 +82,7 @@ typedef cairo_int_status_t cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); typedef cairo_int_status_t (*_show_glyphs_func) (void *surface, @@ -100,8 +91,8 @@ typedef cairo_int_status_t cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, - int *remaining_glyphs, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip, + int *remaining_glyphs); typedef cairo_int_status_t (*_show_text_glyphs_func) (void *surface, @@ -115,7 +106,7 @@ typedef cairo_int_status_t int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents); + cairo_clip_t *clip); static cairo_surface_t * _cairo_null_surface_create_similar (void *other, @@ -125,16 +116,11 @@ _cairo_null_surface_create_similar (void *other, return _cairo_test_null_surface_create (content); } -static cairo_int_status_t +static cairo_bool_t _cairo_null_surface_get_extents (void *surface, cairo_rectangle_int_t *extents) { - extents->x = 0; - extents->y = 0; - extents->width = 0; - extents->height = 0; - - return CAIRO_STATUS_SUCCESS; + return FALSE; } static cairo_bool_t @@ -160,8 +146,6 @@ static const cairo_surface_backend_t null_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - (_set_clip_region_func) _return_success, /* set_clip_region */ - (_intersect_clip_path_func) _return_success, /* intersect_clip_path */ _cairo_null_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -176,7 +160,6 @@ static const cairo_surface_backend_t null_surface_backend = { (_show_glyphs_func) _return_success, /* show_glyphs */ NULL, /* snapshot */ NULL, /* is_similar */ - NULL, /* reset */ NULL, /* fill_stroke */ NULL, /* create_solid_pattern_surface */ NULL, /* can_repaint_solid_pattern_surface */ diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c index d42700c8..164d4a71 100644 --- a/src/test-paginated-surface.c +++ b/src/test-paginated-surface.c @@ -61,37 +61,27 @@ static const cairo_surface_backend_t test_paginated_surface_backend; static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend; cairo_surface_t * -_cairo_test_paginated_surface_create_for_data (unsigned char *data, - cairo_content_t content, - int width, - int height, - int stride) +_cairo_test_paginated_surface_create (cairo_surface_t *target) { cairo_status_t status; - cairo_surface_t *target; cairo_surface_t *paginated; test_paginated_surface_t *surface; - target = _cairo_image_surface_create_for_data_with_content (data, content, - width, height, - stride); status = cairo_surface_status (target); - if (status) - return target; + if (unlikely (status)) + return _cairo_surface_create_in_error (status); surface = malloc (sizeof (test_paginated_surface_t)); - if (unlikely (surface == NULL)) { - cairo_surface_destroy (target); + if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - } _cairo_surface_init (&surface->base, &test_paginated_surface_backend, - content); + target->content); - surface->target = target; + surface->target = cairo_surface_reference (target); paginated = _cairo_paginated_surface_create (&surface->base, - content, width, height, + target->content, &test_paginated_surface_paginated_backend); status = paginated->status; if (status == CAIRO_STATUS_SUCCESS) { @@ -115,49 +105,7 @@ _test_paginated_surface_finish (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_test_paginated_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region) -{ - test_paginated_surface_t *surface = abstract_surface; - - if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return CAIRO_STATUS_SUCCESS; - - /* XXX: The whole surface backend clipping interface is a giant - * disaster right now. In particular, its uncleanness shows up - * when trying to implement one surface that wraps another one (as - * we are doing here). - * - * Here are two of the problems that show up: - * - * 1. The most critical piece of information in all this stuff, - * the "clip" isn't getting passed to the backend - * functions. Instead the generic surface layer is caching that as - * surface->clip. This is a problem for surfaces like this one - * that do wrapping. Our base surface will have the clip set, but - * our target's surface will not. - * - * 2. We're here in our backend's set_clip_region function, and we - * want to call into our target surface's set_clip_region. - * Generally, we would do this by calling an equivalent - * _cairo_surface function, but _cairo_surface_set_clip_region - * does not have the same signature/semantics, (it has the - * clip_serial stuff as well). - * - * We kludge around each of these by manually copying the clip - * object from our base surface into the target's base surface - * (yuck!) and by reaching directly into the image surface's - * set_clip_region instead of calling into the generic - * _cairo_surface_set_clip_region (double yuck!). - */ - - surface->target->clip = surface->base.clip; - - return _cairo_image_surface_set_clip_region (surface->target, region); -} - -static cairo_int_status_t +static cairo_bool_t _test_paginated_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { @@ -170,14 +118,14 @@ static cairo_int_status_t _test_paginated_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { test_paginated_surface_t *surface = abstract_surface; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return CAIRO_STATUS_SUCCESS; - return _cairo_surface_paint (surface->target, op, source, extents); + return _cairo_surface_paint (surface->target, op, source, clip); } static cairo_int_status_t @@ -185,14 +133,15 @@ _test_paginated_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { test_paginated_surface_t *surface = abstract_surface; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) return CAIRO_STATUS_SUCCESS; - return _cairo_surface_mask (surface->target, op, source, mask, extents); + return _cairo_surface_mask (surface->target, + op, source, mask, clip); } static cairo_int_status_t @@ -205,7 +154,7 @@ _test_paginated_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { test_paginated_surface_t *surface = abstract_surface; @@ -215,7 +164,8 @@ _test_paginated_surface_stroke (void *abstract_surface, return _cairo_surface_stroke (surface->target, op, source, path, style, ctm, ctm_inverse, - tolerance, antialias, extents); + tolerance, antialias, + clip); } static cairo_int_status_t @@ -226,7 +176,7 @@ _test_paginated_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { test_paginated_surface_t *surface = abstract_surface; @@ -235,7 +185,8 @@ _test_paginated_surface_fill (void *abstract_surface, return _cairo_surface_fill (surface->target, op, source, path, fill_rule, - tolerance, antialias, extents); + tolerance, antialias, + clip); } static cairo_bool_t @@ -258,7 +209,7 @@ _test_paginated_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { test_paginated_surface_t *surface = abstract_surface; @@ -268,8 +219,10 @@ _test_paginated_surface_show_text_glyphs (void *abstract_surface, return _cairo_surface_show_text_glyphs (surface->target, op, source, utf8, utf8_len, glyphs, num_glyphs, - clusters, num_clusters, cluster_flags, - scaled_font, extents); + clusters, num_clusters, + cluster_flags, + scaled_font, + clip); } @@ -302,8 +255,6 @@ static const cairo_surface_backend_t test_paginated_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - _test_paginated_surface_set_clip_region, - NULL, /* intersect_clip_path */ _test_paginated_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -319,11 +270,10 @@ static const cairo_surface_backend_t test_paginated_surface_backend = { _test_paginated_surface_mask, _test_paginated_surface_stroke, _test_paginated_surface_fill, - NULL, /* show_glyphs */ + NULL, /* replaced by show_text_glyphs */ NULL, /* snapshot */ NULL, /* is_similar */ - NULL, /* reset */ NULL, /* fill_stroke */ NULL, /* create_solid_pattern_surface */ NULL, /* can_repaint_solid_pattern_surface */ diff --git a/src/test-paginated-surface.h b/src/test-paginated-surface.h index 4879cfcd..76ce6890 100644 --- a/src/test-paginated-surface.h +++ b/src/test-paginated-surface.h @@ -41,11 +41,7 @@ CAIRO_BEGIN_DECLS cairo_surface_t * -_cairo_test_paginated_surface_create_for_data (unsigned char *data, - cairo_content_t content, - int width, - int height, - int stride); +_cairo_test_paginated_surface_create (cairo_surface_t *target); CAIRO_END_DECLS diff --git a/src/test-wrapping-surface.c b/src/test-wrapping-surface.c new file mode 100644 index 00000000..a634b48a --- /dev/null +++ b/src/test-wrapping-surface.c @@ -0,0 +1,272 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * Copyright © Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth <cworth@cworth.org> + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +/* Another mythical surface that exists to simply wrap another - do nothing + * itself but forward the calls onto a target surface. + */ + +#include "cairoint.h" + +#include "test-wrapping-surface.h" + +#include "cairo-surface-wrapper-private.h" + +typedef struct _test_wrapping_surface { + cairo_surface_t base; + cairo_surface_wrapper_t wrapper; +} test_wrapping_surface_t; + +static const cairo_surface_backend_t test_wrapping_surface_backend; + +slim_hidden_proto (_cairo_test_wrapping_surface_create); + +cairo_surface_t * +_cairo_test_wrapping_surface_create (cairo_surface_t *target) +{ + test_wrapping_surface_t *surface; + + if (unlikely (target->status)) + return _cairo_surface_create_in_error (target->status); + + surface = malloc (sizeof (test_wrapping_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &test_wrapping_surface_backend, + target->content); + + _cairo_surface_wrapper_init (&surface->wrapper, target); + + return &surface->base; +} +slim_hidden_def (_cairo_test_wrapping_surface_create); + +static cairo_surface_t * +_test_wrapping_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + + test_wrapping_surface_t *surface = abstract_surface; + + return _cairo_test_wrapping_surface_create ( + _cairo_surface_wrapper_create_similar (&surface->wrapper, + content, width, height)); +} + +static cairo_status_t +_test_wrapping_surface_finish (void *abstract_surface) +{ + test_wrapping_surface_t *surface = abstract_surface; + + _cairo_surface_wrapper_fini (&surface->wrapper); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_test_wrapping_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + test_wrapping_surface_t *surface = abstract_surface; + + return _cairo_surface_wrapper_acquire_source_image (&surface->wrapper, + image_out, image_extra); +} + +static void +_test_wrapping_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + test_wrapping_surface_t *surface = abstract_surface; + + _cairo_surface_wrapper_release_source_image (&surface->wrapper, + image, image_extra); +} + +static cairo_bool_t +_test_wrapping_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + test_wrapping_surface_t *surface = abstract_surface; + + return _cairo_surface_wrapper_get_extents (&surface->wrapper, rectangle); +} + +static cairo_int_status_t +_test_wrapping_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + test_wrapping_surface_t *surface = abstract_surface; + + return _cairo_surface_wrapper_paint (&surface->wrapper, op, source, clip); +} + +static cairo_int_status_t +_test_wrapping_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) +{ + test_wrapping_surface_t *surface = abstract_surface; + + return _cairo_surface_wrapper_mask (&surface->wrapper, + op, source, mask, clip); +} + +static cairo_int_status_t +_test_wrapping_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + test_wrapping_surface_t *surface = abstract_surface; + + return _cairo_surface_wrapper_stroke (&surface->wrapper, + op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); +} + +static cairo_int_status_t +_test_wrapping_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + test_wrapping_surface_t *surface = abstract_surface; + + return _cairo_surface_wrapper_fill (&surface->wrapper, + op, source, + path, fill_rule, + tolerance, antialias, + clip); +} + +static cairo_bool_t +_test_wrapping_surface_has_show_text_glyphs (void *abstract_surface) +{ + test_wrapping_surface_t *surface = abstract_surface; + + return _cairo_surface_wrapper_has_show_text_glyphs (&surface->wrapper); +} + +static cairo_int_status_t +_test_wrapping_surface_show_text_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip) +{ + test_wrapping_surface_t *surface = abstract_surface; + + return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper, + op, source, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font, + clip); +} + +static const cairo_surface_backend_t test_wrapping_surface_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING, + _test_wrapping_surface_create_similar, + _test_wrapping_surface_finish, + _test_wrapping_surface_acquire_source_image, + _test_wrapping_surface_release_source_image, + NULL, NULL, /* dest_image */ + NULL, /* clone_similar */ + NULL, /* composite */ + NULL, /* fill_rectangles */ + NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ + NULL, /* copy_page */ + NULL, /* show_page */ + _test_wrapping_surface_get_extents, + NULL, /* old_show_glyphs */ + NULL, /* get_font_options */ + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + NULL, /* scaled_font_fini */ + NULL, /* scaled_glyph_fini */ + + _test_wrapping_surface_paint, + _test_wrapping_surface_mask, + _test_wrapping_surface_stroke, + _test_wrapping_surface_fill, + NULL, /* replaced by show_text_glyphs */ + + NULL, /* snapshot */ + NULL, /* is_similar */ + NULL, /* fill_stroke */ + NULL, /* create_solid_pattern_surface */ + NULL, /* can_repaint_solid_pattern_surface */ + + _test_wrapping_surface_has_show_text_glyphs, + _test_wrapping_surface_show_text_glyphs + + /* XXX wrap fill-stroke and show_glyphs */ +}; diff --git a/src/test-wrapping-surface.h b/src/test-wrapping-surface.h new file mode 100644 index 00000000..32d2ca3a --- /dev/null +++ b/src/test-wrapping-surface.h @@ -0,0 +1,51 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth <cworth@cworth.org> + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#ifndef TEST_WRAPPING_SURFACE_H +#define TEST_WRAPPING_SURFACE_H + +#include "cairo.h" + +CAIRO_BEGIN_DECLS + +cairo_surface_t * +_cairo_test_wrapping_surface_create (cairo_surface_t *target); + +CAIRO_END_DECLS + +#endif /* TEST_WRAPPING_SURFACE_H */ + diff --git a/test/Makefile.am b/test/Makefile.am index 2e0eb106..ec5dfac9 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -185,8 +185,8 @@ REFERENCE_IMAGES = \ clip-nesting.rgb24.ref.png \ clip-nesting.test-paginated.rgb24.ref.png \ clip-nesting.xlib.rgb24.ref.png \ - clip-operator.pdf.argb32.xfail.png \ - clip-operator.pdf.rgb24.xfail.png \ + clip-operator.pdf.argb32.ref.png \ + clip-operator.pdf.rgb24.ref.png \ clip-operator.ps2.rgb24.ref.png \ clip-operator.ps3.argb32.ref.png \ clip-operator.ps3.ref.png \ @@ -198,15 +198,21 @@ REFERENCE_IMAGES = \ clip-operator.svg12.argb32.xfail.png \ clip-operator.svg12.rgb24.xfail.png \ clip-operator.test-paginated.argb32.ref.png \ - clip-operator.xlib-fallback.rgb24.ref.png \ + clip-operator.xlib-fallback.ref.png \ clip-operator.xlib.ref.png \ clip-operator.xlib.rgb24.ref.png \ + clip-unbounded.ref.png \ + clip-unbounded.rgb24.ref.png \ + clip-unbounded.svg12.rgb24.xfail.png \ + clipped-surface.ref.png \ + clip-push-group.pdf.ref.png \ clip-push-group.ps2.argb32.ref.png \ clip-push-group.ps2.rgb24.ref.png \ clip-push-group.ps3.argb32.ref.png \ clip-push-group.ps3.rgb24.ref.png \ clip-push-group.quartz.ref.png \ clip-push-group.ref.png \ + clip-push-group.xlib.ref.png \ clip-twice.pdf.argb32.ref.png \ clip-twice.ps2.argb32.ref.png \ clip-twice.ps2.rgb24.ref.png \ @@ -220,8 +226,7 @@ REFERENCE_IMAGES = \ clip-twice.test-paginated.rgb24.ref.png \ clip-twice.xlib.ref.png \ clip-twice.xlib.rgb24.ref.png \ - clipped-group.pdf.argb32.ref.png \ - clipped-group.pdf.rgb24.ref.png \ + clipped-group.pdf.ref.png \ clipped-group.ps2.ref.png \ clipped-group.ps3.ref.png \ clipped-group.ref.png \ @@ -240,6 +245,8 @@ REFERENCE_IMAGES = \ composite-integer-translate-source.ps2.ref.png \ composite-integer-translate-source.ps3.ref.png \ composite-integer-translate-source.ref.png \ + composite-integer-translate-source.svg12.argb32.xfail.png \ + composite-integer-translate-source.svg12.rgb24.xfail.png \ copy-path.ps2.ref.png \ copy-path.ps3.ref.png \ copy-path.ref.png \ @@ -299,7 +306,7 @@ REFERENCE_IMAGES = \ device-offset-fractional.gl.xfail.png \ device-offset-fractional.pdf.argb32.ref.png \ device-offset-fractional.pdf.ref.png \ - device-offset-fractional.pdf.rgb24.ref.png \ + device-offset-fractional.pdf.xfail.png \ device-offset-fractional.ps2.ref.png \ device-offset-fractional.ps3.ref.png \ device-offset-fractional.ref.png \ @@ -311,8 +318,12 @@ REFERENCE_IMAGES = \ device-offset.rgb24.ref.png \ extended-blend.argb32.ref.png \ extended-blend.rgb24.ref.png \ + extended-blend.svg12.argb32.xfail.png \ + extended-blend.svg12.rgb24.xfail.png \ extended-blend-alpha.argb32.ref.png \ extended-blend-alpha.rgb24.ref.png \ + extended-blend-alpha.svg12.argb32.xfail.png \ + extended-blend-alpha.svg12.rgb24.xfail.png \ extend-pad-border.ps.ref.png \ extend-pad-border.ref.png \ extend-pad-border.svg.xfail.png \ @@ -377,6 +388,9 @@ REFERENCE_IMAGES = \ fill-degenerate-sort-order.rgb24.ref.png \ fill-degenerate-sort-order.xlib.ref.png \ fill-degenerate-sort-order.xlib.rgb24.ref.png \ + fill-empty.argb32.ref.png \ + fill-empty.rgb24.ref.png \ + fill-empty.svg12.rgb24.xfail.png \ fill-image.ps.ref.png \ fill-image.ref.png \ fill-image.xlib.ref.png \ @@ -443,17 +457,13 @@ REFERENCE_IMAGES = \ ft-text-antialias-none.ps2.argb32.ref.png \ ft-text-antialias-none.ps3.argb32.ref.png \ ft-text-antialias-none.ref.png \ - ft-text-vertical-layout-type1.pdf.argb32.ref.png \ ft-text-vertical-layout-type1.pdf.ref.png \ - ft-text-vertical-layout-type1.pdf.rgb24.ref.png \ ft-text-vertical-layout-type1.ps2.ref.png \ ft-text-vertical-layout-type1.ps3.ref.png \ ft-text-vertical-layout-type1.ref.png \ ft-text-vertical-layout-type1.svg.ref.png \ ft-text-vertical-layout-type1.xlib.ref.png \ - ft-text-vertical-layout-type3.pdf.argb32.ref.png \ ft-text-vertical-layout-type3.pdf.ref.png \ - ft-text-vertical-layout-type3.pdf.rgb24.ref.png \ ft-text-vertical-layout-type3.ps2.ref.png \ ft-text-vertical-layout-type3.ps3.ref.png \ ft-text-vertical-layout-type3.ref.png \ @@ -498,6 +508,8 @@ REFERENCE_IMAGES = \ image-surface-source.ps2.ref.png \ image-surface-source.ps3.ref.png \ image-surface-source.ref.png \ + image-surface-source.svg12.argb32.xfail.png \ + image-surface-source.svg12.rgb24.xfail.png \ infinite-join.ps2.ref.png \ infinite-join.ps3.ref.png \ infinite-join.ref.png \ @@ -558,15 +570,14 @@ REFERENCE_IMAGES = \ mask-transformed-similar.pdf.ref.png \ mask-transformed-similar.ref.png \ mask-transformed-similar.svg.ref.png \ - mask.pdf.argb32.xfail.png \ - mask.pdf.rgb24.xfail.png \ + mask.pdf.argb32.ref.png \ + mask.pdf.rgb24.ref.png \ mask.quartz.ref.png \ mask.quartz.rgb24.ref.png \ mask.ref.png \ mask.rgb24.ref.png \ mask.svg.argb32.xfail.png \ mask.svg.rgb24.xfail.png \ - mask.xlib-fallback.rgb24.ref.png \ mask.xlib.ref.png \ mask.xlib.rgb24.ref.png \ meta-surface-pattern.gl.argb32.ref.png \ @@ -613,15 +624,16 @@ REFERENCE_IMAGES = \ operator-clear.rgb24.ref.png \ operator-clear.svg12.argb32.xfail.png \ operator-clear.svg12.rgb24.xfail.png \ - operator-clear.xlib.ref.png \ - operator-source.pdf.rgb24.xfail.png \ + operator-clear.xlib.argb32.ref.png \ + operator-clear.xlib.rgb24.ref.png \ + operator-source.pdf.rgb24.ref.png \ operator-source.quartz.ref.png \ operator-source.quartz.rgb24.ref.png \ operator-source.ref.png \ operator-source.rgb24.ref.png \ operator-source.svg12.argb32.xfail.png \ operator-source.svg12.rgb24.xfail.png \ - operator-source.xlib-fallback.rgb24.ref.png \ + operator-source.xlib-fallback.ref.png \ operator-source.xlib.ref.png \ operator-source.xlib.rgb24.ref.png \ operator.ref.png \ @@ -682,12 +694,15 @@ REFERENCE_IMAGES = \ path-append.xlib.ref.png \ pattern-getters.ref.png \ pdf-surface-source.ref.png \ + pdf-surface-source.svg12.argb32.xfail.png \ + pdf-surface-source.svg12.rgb24.xfail.png \ pixman-rotate.ref.png \ pixman-rotate.rgb24.ref.png \ ps-surface-source.ref.png \ + ps-surface-source.svg12.argb32.xfail.png \ + ps-surface-source.svg12.rgb24.xfail.png \ push-group.ref.png \ push-group.rgb24.ref.png \ - push-group.xlib-fallback.rgb24.ref.png \ push-group.xlib.ref.png \ push-group.xlib.rgb24.ref.png \ quartz-surface-source.ps2.ref.png \ @@ -727,19 +742,21 @@ REFERENCE_IMAGES = \ rotate-image-surface-paint.svg.ref.png \ scale-down-source-surface-paint.ref.png \ scale-offset-image.gl.ref.png \ - scale-offset-image.pdf.argb32.ref.png \ - scale-offset-image.pdf.rgb24.ref.png \ + scale-offset-image.pdf.xfail.png \ scale-offset-image.ps.ref.png \ scale-offset-image.ref.png \ scale-offset-image.xfail.png \ + scale-offset-image.meta.xfail.png \ scale-offset-image.xlib.xfail.png \ + scale-offset-image.xlib-fallback.xfail.png \ scale-offset-similar.gl.ref.png \ - scale-offset-similar.pdf.argb32.ref.png \ - scale-offset-similar.pdf.rgb24.ref.png \ + scale-offset-similar.pdf.xfail.png \ scale-offset-similar.ps.ref.png \ scale-offset-similar.ref.png \ scale-offset-similar.xfail.png \ + scale-offset-similar.meta.xfail.png \ scale-offset-similar.xlib.xfail.png \ + scale-offset-similar.xlib-fallback.xfail.png \ scale-source-surface-paint.ref.png \ scale-source-surface-paint.rgb24.ref.png \ scale-source-surface-paint.svg.argb32.xfail.png \ @@ -773,7 +790,6 @@ REFERENCE_IMAGES = \ skew-extreme.ref.png \ smask-fill.ref.png \ smask-fill.svg.ref.png \ - smask-fill.xlib-fallback.ref.png \ smask-fill.xlib.ref.png \ smask-image-mask.ref.png \ smask-mask.pdf.xfail.png \ @@ -789,11 +805,13 @@ REFERENCE_IMAGES = \ smask-text.ps3.ref.png \ smask-text.ref.png \ smask-text.svg.ref.png \ + smask-text.xlib.ref.png \ smask.pdf.xfail.png \ smask.ps2.ref.png \ smask.ps3.ref.png \ smask.ref.png \ smask.svg.ref.png \ + smask.xlib.ref.png \ solid-pattern-cache-stress.ref.png \ source-clip-scale.gl.ref.png \ source-clip-scale.pdf.ref.png \ @@ -821,6 +839,7 @@ REFERENCE_IMAGES = \ stroke-image.quartz.ref.png \ stroke-image.ref.png \ surface-pattern-big-scale-down.ref.png \ + surface-pattern-big-scale-down.ps.xfail.png \ surface-pattern-scale-down.pdf.ref.png \ surface-pattern-scale-down.ps2.ref.png \ surface-pattern-scale-down.ps3.ref.png \ @@ -835,8 +854,12 @@ REFERENCE_IMAGES = \ surface-pattern.ref.png \ surface-pattern.svg.xfail.png \ svg-surface-source.ref.png \ + svg-surface-source.svg12.argb32.xfail.png \ + svg-surface-source.svg12.rgb24.xfail.png \ test-fallback16-surface-source.ps.ref.png \ test-fallback16-surface-source.ref.png \ + test-fallback16-surface-source.svg12.argb32.xfail.png \ + test-fallback16-surface-source.svg12.rgb24.xfail.png \ text-antialias-gray.quartz.ref.png \ text-antialias-gray.ref.png \ text-antialias-none.quartz.ref.png \ @@ -846,8 +869,8 @@ REFERENCE_IMAGES = \ text-glyph-range.ps2.ref.png \ text-glyph-range.ps3.ref.png \ text-glyph-range.ref.png \ - text-pattern.pdf.argb32.xfail.png \ - text-pattern.pdf.rgb24.xfail.png \ + text-pattern.pdf.argb32.ref.png \ + text-pattern.pdf.rgb24.ref.png \ text-pattern.ps3.argb32.ref.png \ text-pattern.ps3.rgb24.ref.png \ text-pattern.quartz.ref.png \ @@ -924,6 +947,8 @@ REFERENCE_IMAGES = \ xlib-surface-source.ps2.ref.png \ xlib-surface-source.ps3.ref.png \ xlib-surface-source.ref.png \ + xlib-surface-source.svg12.argb32.xfail.png \ + xlib-surface-source.svg12.rgb24.xfail.png \ zero-alpha.ref.png EXTRA_DIST += \ @@ -1218,7 +1243,7 @@ run: # Check tests under valgrind. Saves log to valgrind-log check-valgrind: - $(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) CAIRO_TEST_MODE="$(MODE),foreground" $(top_builddir)/libtool --mode=execute valgrind $(VALGRIND_FLAGS)' 2>&1 | tee valgrind-log + $(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) CAIRO_TEST_MODE="$(MODE),foreground CAIRO_TEST_TIMEOUT=0" $(top_builddir)/libtool --mode=execute valgrind $(VALGRIND_FLAGS)' 2>&1 | tee valgrind-log %.log: %.c cairo-test-suite -./cairo-test-suite $(<:.c=) diff --git a/test/Makefile.sources b/test/Makefile.sources index 4d87a276..573ca848 100644 --- a/test/Makefile.sources +++ b/test/Makefile.sources @@ -21,6 +21,7 @@ test_sources = \ clip-operator.c \ clip-push-group.c \ clip-twice.c \ + clip-unbounded.c \ clip-zero.c \ clipped-group.c \ clipped-surface.c \ @@ -64,6 +65,7 @@ test_sources = \ fill-and-stroke-alpha.c \ fill-and-stroke-alpha-add.c \ fill-degenerate-sort-order.c \ + fill-empty.c \ fill-image.c \ fill-missed-stop.c \ fill-rule.c \ diff --git a/test/buffer-diff.c b/test/buffer-diff.c index f9b4a951..8fc3f891 100644 --- a/test/buffer-diff.c +++ b/test/buffer-diff.c @@ -70,13 +70,12 @@ buffer_diff_core (const unsigned char *_buf_a, int stride_a, stride_a /= sizeof (uint32_t); stride_b /= sizeof (uint32_t); stride_diff /= sizeof (uint32_t); - for (y = 0; y < height; y++) - { + for (y = 0; y < height; y++) { const uint32_t *row_a = buf_a + y * stride_a; const uint32_t *row_b = buf_b + y * stride_b; uint32_t *row = buf_diff + y * stride_diff; - for (x = 0; x < width; x++) - { + + for (x = 0; x < width; x++) { /* check if the pixels are the same */ if ((row_a[x] & mask) != (row_b[x] & mask)) { int channel; @@ -99,6 +98,11 @@ buffer_diff_core (const unsigned char *_buf_a, int stride_a, } result.pixels_changed++; + if ((diff_pixel & 0x00ffffff) == 0) { + /* alpha only difference, convert to luminance */ + uint8_t alpha = diff_pixel >> 24; + diff_pixel = alpha * 0x010101; + } row[x] = diff_pixel; } else { row[x] = 0; diff --git a/test/cairo-test.c b/test/cairo-test.c index ad74d13f..630036d1 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -566,7 +566,7 @@ cairo_test_file_is_older (const char *filename, while (num_ref_filenames--) { struct stat ref; - char *ref_filename = ref_filenames++; + char *ref_filename = *ref_filenames++; if (ref_filename == NULL) continue; @@ -912,6 +912,11 @@ REPEAT: goto UNWIND_SURFACE; } + cairo_surface_set_user_data (surface, + &cairo_boilerplate_output_basename_key, + base_path, + NULL); + cairo_surface_set_device_offset (surface, dev_offset, dev_offset); cr = cairo_create (surface); @@ -1080,13 +1085,17 @@ REPEAT: ctx->test->width, ctx->test->height); diff_status = cairo_surface_write_to_png (test_image, out_png_path); + cairo_surface_destroy (test_image); if (diff_status) { + if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS) + ret = CAIRO_TEST_CRASHED; + else + ret = CAIRO_TEST_FAILURE; cairo_test_log (ctx, "Error: Failed to write output image: %s\n", cairo_status_to_string (diff_status)); } have_output = TRUE; - cairo_surface_destroy (test_image); ret = CAIRO_TEST_XFAILURE; goto UNWIND_CAIRO; @@ -1167,8 +1176,11 @@ REPEAT: if (cairo_surface_status (test_image)) { cairo_test_log (ctx, "Error: Failed to extract image: %s\n", cairo_status_to_string (cairo_surface_status (test_image))); + if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS) + ret = CAIRO_TEST_CRASHED; + else + ret = CAIRO_TEST_FAILURE; cairo_surface_destroy (test_image); - ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } diff --git a/test/clip-operator.pdf.argb32.ref.png b/test/clip-operator.pdf.argb32.ref.png Binary files differnew file mode 100644 index 00000000..4213499b --- /dev/null +++ b/test/clip-operator.pdf.argb32.ref.png diff --git a/test/clip-operator.pdf.argb32.xfail.png b/test/clip-operator.pdf.argb32.xfail.png Binary files differdeleted file mode 100644 index c0a4078c..00000000 --- a/test/clip-operator.pdf.argb32.xfail.png +++ /dev/null diff --git a/test/clip-operator.pdf.rgb24.ref.png b/test/clip-operator.pdf.rgb24.ref.png Binary files differnew file mode 100644 index 00000000..55e7893d --- /dev/null +++ b/test/clip-operator.pdf.rgb24.ref.png diff --git a/test/clip-operator.pdf.rgb24.xfail.png b/test/clip-operator.pdf.rgb24.xfail.png Binary files differdeleted file mode 100644 index 01329b55..00000000 --- a/test/clip-operator.pdf.rgb24.xfail.png +++ /dev/null diff --git a/test/clip-operator.svg12.argb32.xfail.png b/test/clip-operator.svg12.argb32.xfail.png Binary files differindex 1c21d15f..be0696e0 100644 --- a/test/clip-operator.svg12.argb32.xfail.png +++ b/test/clip-operator.svg12.argb32.xfail.png diff --git a/test/clip-operator.svg12.rgb24.xfail.png b/test/clip-operator.svg12.rgb24.xfail.png Binary files differindex f79de48e..494852da 100644 --- a/test/clip-operator.svg12.rgb24.xfail.png +++ b/test/clip-operator.svg12.rgb24.xfail.png diff --git a/test/clip-operator.xlib-fallback.ref.png b/test/clip-operator.xlib-fallback.ref.png Binary files differnew file mode 100644 index 00000000..be1cac01 --- /dev/null +++ b/test/clip-operator.xlib-fallback.ref.png diff --git a/test/clip-operator.xlib-fallback.rgb24.ref.png b/test/clip-operator.xlib-fallback.rgb24.ref.png Binary files differdeleted file mode 100644 index 4a05f7ba..00000000 --- a/test/clip-operator.xlib-fallback.rgb24.ref.png +++ /dev/null diff --git a/test/clip-push-group.pdf.ref.png b/test/clip-push-group.pdf.ref.png Binary files differnew file mode 100644 index 00000000..37b58c59 --- /dev/null +++ b/test/clip-push-group.pdf.ref.png diff --git a/test/clip-push-group.ref.png b/test/clip-push-group.ref.png Binary files differindex 327cc90b..86724a23 100644 --- a/test/clip-push-group.ref.png +++ b/test/clip-push-group.ref.png diff --git a/test/clip-push-group.xlib.ref.png b/test/clip-push-group.xlib.ref.png Binary files differnew file mode 100644 index 00000000..de6ac632 --- /dev/null +++ b/test/clip-push-group.xlib.ref.png diff --git a/test/clip-unbounded.c b/test/clip-unbounded.c new file mode 100644 index 00000000..cd1c6022 --- /dev/null +++ b/test/clip-unbounded.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairo-test.h" + +#define SIZE 10 + +static cairo_surface_t * +create_source (cairo_surface_t *target) +{ + cairo_surface_t *similar; + cairo_t *cr; + + similar = cairo_surface_create_similar (target, + CAIRO_CONTENT_COLOR, SIZE/2, SIZE); + cr = cairo_create (similar); + cairo_surface_destroy (similar); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + similar = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return similar; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *source; + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_rectangle (cr, 0, 0, SIZE/2, SIZE); + cairo_clip (cr); + + /* Draw a source rectangle outside the image, the effect should be to + * clear only within the clip region. + */ + source = create_source (cairo_get_target (cr)); + cairo_set_source_surface (cr, source, SIZE/2, 0); + cairo_surface_destroy (source); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_unbounded, + "Test handling of an unbounded fill outside the clip region", + "clip", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) + diff --git a/test/clip-unbounded.ref.png b/test/clip-unbounded.ref.png Binary files differnew file mode 100644 index 00000000..0b659056 --- /dev/null +++ b/test/clip-unbounded.ref.png diff --git a/test/clip-unbounded.rgb24.ref.png b/test/clip-unbounded.rgb24.ref.png Binary files differnew file mode 100644 index 00000000..2baf9f46 --- /dev/null +++ b/test/clip-unbounded.rgb24.ref.png diff --git a/test/clip-unbounded.svg12.rgb24.xfail.png b/test/clip-unbounded.svg12.rgb24.xfail.png Binary files differnew file mode 100644 index 00000000..0b659056 --- /dev/null +++ b/test/clip-unbounded.svg12.rgb24.xfail.png diff --git a/test/clipped-group.pdf.argb32.ref.png b/test/clipped-group.pdf.argb32.ref.png Binary files differdeleted file mode 100644 index b9975e12..00000000 --- a/test/clipped-group.pdf.argb32.ref.png +++ /dev/null diff --git a/test/clipped-group.pdf.ref.png b/test/clipped-group.pdf.ref.png Binary files differnew file mode 100644 index 00000000..64958608 --- /dev/null +++ b/test/clipped-group.pdf.ref.png diff --git a/test/clipped-group.pdf.rgb24.ref.png b/test/clipped-group.pdf.rgb24.ref.png Binary files differdeleted file mode 100644 index b9975e12..00000000 --- a/test/clipped-group.pdf.rgb24.ref.png +++ /dev/null diff --git a/test/clipped-group.ref.png b/test/clipped-group.ref.png Binary files differindex 89a7b184..9855e619 100644 --- a/test/clipped-group.ref.png +++ b/test/clipped-group.ref.png diff --git a/test/composite-integer-translate-source.svg12.argb32.xfail.png b/test/composite-integer-translate-source.svg12.argb32.xfail.png Binary files differnew file mode 100644 index 00000000..c4f31970 --- /dev/null +++ b/test/composite-integer-translate-source.svg12.argb32.xfail.png diff --git a/test/composite-integer-translate-source.svg12.rgb24.xfail.png b/test/composite-integer-translate-source.svg12.rgb24.xfail.png Binary files differnew file mode 100644 index 00000000..c4f31970 --- /dev/null +++ b/test/composite-integer-translate-source.svg12.rgb24.xfail.png diff --git a/test/device-offset-fractional.pdf.argb32.ref.png b/test/device-offset-fractional.pdf.argb32.ref.png Binary files differdeleted file mode 100644 index c076932c..00000000 --- a/test/device-offset-fractional.pdf.argb32.ref.png +++ /dev/null diff --git a/test/device-offset-fractional.pdf.ref.png b/test/device-offset-fractional.pdf.ref.png Binary files differdeleted file mode 100644 index 9ff2b8d5..00000000 --- a/test/device-offset-fractional.pdf.ref.png +++ /dev/null diff --git a/test/device-offset-fractional.pdf.rgb24.ref.png b/test/device-offset-fractional.pdf.rgb24.ref.png Binary files differdeleted file mode 100644 index c076932c..00000000 --- a/test/device-offset-fractional.pdf.rgb24.ref.png +++ /dev/null diff --git a/test/device-offset-fractional.pdf.xfail.png b/test/device-offset-fractional.pdf.xfail.png Binary files differnew file mode 100644 index 00000000..77a49632 --- /dev/null +++ b/test/device-offset-fractional.pdf.xfail.png diff --git a/test/extended-blend-alpha.svg12.argb32.xfail.png b/test/extended-blend-alpha.svg12.argb32.xfail.png Binary files differnew file mode 100644 index 00000000..d09c168e --- /dev/null +++ b/test/extended-blend-alpha.svg12.argb32.xfail.png diff --git a/test/extended-blend-alpha.svg12.rgb24.xfail.png b/test/extended-blend-alpha.svg12.rgb24.xfail.png Binary files differnew file mode 100644 index 00000000..f80569e9 --- /dev/null +++ b/test/extended-blend-alpha.svg12.rgb24.xfail.png diff --git a/test/extended-blend.svg12.argb32.xfail.png b/test/extended-blend.svg12.argb32.xfail.png Binary files differnew file mode 100644 index 00000000..93297a5c --- /dev/null +++ b/test/extended-blend.svg12.argb32.xfail.png diff --git a/test/extended-blend.svg12.rgb24.xfail.png b/test/extended-blend.svg12.rgb24.xfail.png Binary files differnew file mode 100644 index 00000000..8db02c55 --- /dev/null +++ b/test/extended-blend.svg12.rgb24.xfail.png diff --git a/test/fill-empty.argb32.ref.png b/test/fill-empty.argb32.ref.png Binary files differnew file mode 100644 index 00000000..8c26f7eb --- /dev/null +++ b/test/fill-empty.argb32.ref.png diff --git a/test/fill-empty.c b/test/fill-empty.c new file mode 100644 index 00000000..0594e57a --- /dev/null +++ b/test/fill-empty.c @@ -0,0 +1,62 @@ +/* + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairo-test.h" + +#define SIZE 10 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + + /* first drawn an ordinary empty path */ + cairo_save (cr); + cairo_rectangle (cr, 0, 0, SIZE, SIZE/2); + cairo_clip (cr); + cairo_fill (cr); + cairo_restore (cr); + + /* and then an unbounded empty path */ + cairo_save (cr); + cairo_rectangle (cr, 0, SIZE/2, SIZE, SIZE/2); + cairo_clip (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN); + cairo_fill (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_empty, + "Test filling with an empty path", + "fill", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) + diff --git a/test/fill-empty.rgb24.ref.png b/test/fill-empty.rgb24.ref.png Binary files differnew file mode 100644 index 00000000..dc7a8a0e --- /dev/null +++ b/test/fill-empty.rgb24.ref.png diff --git a/test/fill-empty.svg12.rgb24.xfail.png b/test/fill-empty.svg12.rgb24.xfail.png Binary files differnew file mode 100644 index 00000000..8c26f7eb --- /dev/null +++ b/test/fill-empty.svg12.rgb24.xfail.png diff --git a/test/filter-nearest-offset.pdf.xfail.png b/test/filter-nearest-offset.pdf.xfail.png Binary files differindex 4d436aa1..ffe2df12 100644 --- a/test/filter-nearest-offset.pdf.xfail.png +++ b/test/filter-nearest-offset.pdf.xfail.png diff --git a/test/filter-nearest-transformed.pdf.xfail.png b/test/filter-nearest-transformed.pdf.xfail.png Binary files differindex 5ad98a75..7eb5988b 100644 --- a/test/filter-nearest-transformed.pdf.xfail.png +++ b/test/filter-nearest-transformed.pdf.xfail.png diff --git a/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png b/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png Binary files differdeleted file mode 100644 index 242c3be5..00000000 --- a/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png +++ /dev/null diff --git a/test/ft-text-vertical-layout-type1.pdf.ref.png b/test/ft-text-vertical-layout-type1.pdf.ref.png Binary files differindex ab6de47a..1f52ff23 100644 --- a/test/ft-text-vertical-layout-type1.pdf.ref.png +++ b/test/ft-text-vertical-layout-type1.pdf.ref.png diff --git a/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png b/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png Binary files differdeleted file mode 100644 index 242c3be5..00000000 --- a/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png +++ /dev/null diff --git a/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png b/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png Binary files differdeleted file mode 100644 index f232b9a5..00000000 --- a/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png +++ /dev/null diff --git a/test/ft-text-vertical-layout-type3.pdf.ref.png b/test/ft-text-vertical-layout-type3.pdf.ref.png Binary files differindex 04e679b4..a05ec1d7 100644 --- a/test/ft-text-vertical-layout-type3.pdf.ref.png +++ b/test/ft-text-vertical-layout-type3.pdf.ref.png diff --git a/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png b/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png Binary files differdeleted file mode 100644 index f232b9a5..00000000 --- a/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png +++ /dev/null diff --git a/test/ft-text-vertical-layout-type3.ref.png b/test/ft-text-vertical-layout-type3.ref.png Binary files differindex 6b59c56a..1bda421c 100644 --- a/test/ft-text-vertical-layout-type3.ref.png +++ b/test/ft-text-vertical-layout-type3.ref.png diff --git a/test/group-unaligned.svg.argb32.xfail.png b/test/group-unaligned.svg.argb32.xfail.png Binary files differindex 38550376..01c34bec 100644 --- a/test/group-unaligned.svg.argb32.xfail.png +++ b/test/group-unaligned.svg.argb32.xfail.png diff --git a/test/group-unaligned.xlib-fallback.ref.png b/test/group-unaligned.xlib-fallback.ref.png Binary files differindex ed615b22..5ddbc164 100644 --- a/test/group-unaligned.xlib-fallback.ref.png +++ b/test/group-unaligned.xlib-fallback.ref.png diff --git a/test/image-surface-source.svg12.argb32.xfail.png b/test/image-surface-source.svg12.argb32.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/image-surface-source.svg12.argb32.xfail.png diff --git a/test/image-surface-source.svg12.rgb24.xfail.png b/test/image-surface-source.svg12.rgb24.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/image-surface-source.svg12.rgb24.xfail.png diff --git a/test/in-fill-trapezoid.c b/test/in-fill-trapezoid.c index b05f0002..84b323a0 100644 --- a/test/in-fill-trapezoid.c +++ b/test/in-fill-trapezoid.c @@ -27,10 +27,15 @@ #include "cairo-test.h" static cairo_test_status_t -draw (cairo_t *cr, int width, int height) +preamble (cairo_test_context_t *ctx) { - const cairo_test_context_t *ctx = cairo_test_get_context (cr); cairo_test_status_t ret = CAIRO_TEST_SUCCESS; + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); + cr = cairo_create (surface); + cairo_surface_destroy (surface); cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); @@ -80,7 +85,7 @@ draw (cairo_t *cr, int width, int height) cairo_new_path (cr); cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); if (! cairo_in_fill (cr, 0, 0)) { - cairo_test_log (ctx, "Error: Failed to find point inside circle\n"); + cairo_test_log (ctx, "Error: Failed to find point inside circle [even-odd]\n"); ret = CAIRO_TEST_FAILURE; } @@ -117,7 +122,7 @@ draw (cairo_t *cr, int width, int height) cairo_new_path (cr); cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); if (! cairo_in_fill (cr, 0, 0)) { - cairo_test_log (ctx, "Error: Failed to find point inside circle\n"); + cairo_test_log (ctx, "Error: Failed to find point inside circle [nonzero]\n"); ret = CAIRO_TEST_FAILURE; } @@ -261,12 +266,14 @@ draw (cairo_t *cr, int width, int height) ret = CAIRO_TEST_FAILURE; } + cairo_destroy (cr); + return ret; } CAIRO_TEST (in_fill_trapezoid, - "Test _cairo_trap_contains via cairo_in_fill", + "Test cairo_in_fill", "in, trap", /* keywords */ NULL, /* requirements */ 0, 0, - NULL, draw) + preamble, NULL) diff --git a/test/mask-glyphs.svg.ref.png b/test/mask-glyphs.svg.ref.png Binary files differindex e99c3ccb..0058afc1 100644 --- a/test/mask-glyphs.svg.ref.png +++ b/test/mask-glyphs.svg.ref.png diff --git a/test/mask.pdf.argb32.ref.png b/test/mask.pdf.argb32.ref.png Binary files differnew file mode 100644 index 00000000..8c683550 --- /dev/null +++ b/test/mask.pdf.argb32.ref.png diff --git a/test/mask.pdf.argb32.xfail.png b/test/mask.pdf.argb32.xfail.png Binary files differdeleted file mode 100644 index 227d312a..00000000 --- a/test/mask.pdf.argb32.xfail.png +++ /dev/null diff --git a/test/mask.pdf.rgb24.ref.png b/test/mask.pdf.rgb24.ref.png Binary files differnew file mode 100644 index 00000000..be5dbfc9 --- /dev/null +++ b/test/mask.pdf.rgb24.ref.png diff --git a/test/mask.pdf.rgb24.xfail.png b/test/mask.pdf.rgb24.xfail.png Binary files differdeleted file mode 100644 index bb8e99d0..00000000 --- a/test/mask.pdf.rgb24.xfail.png +++ /dev/null diff --git a/test/mask.xlib-fallback.rgb24.ref.png b/test/mask.xlib-fallback.rgb24.ref.png Binary files differdeleted file mode 100644 index 34400504..00000000 --- a/test/mask.xlib-fallback.rgb24.ref.png +++ /dev/null diff --git a/test/meta-surface-pattern.pdf.argb32.ref.png b/test/meta-surface-pattern.pdf.argb32.ref.png Binary files differindex 7e3435b6..786587c3 100644 --- a/test/meta-surface-pattern.pdf.argb32.ref.png +++ b/test/meta-surface-pattern.pdf.argb32.ref.png diff --git a/test/meta-surface-pattern.pdf.rgb24.ref.png b/test/meta-surface-pattern.pdf.rgb24.ref.png Binary files differindex 9fef6feb..f542dabf 100644 --- a/test/meta-surface-pattern.pdf.rgb24.ref.png +++ b/test/meta-surface-pattern.pdf.rgb24.ref.png diff --git a/test/operator-clear.xlib.argb32.ref.png b/test/operator-clear.xlib.argb32.ref.png Binary files differnew file mode 100644 index 00000000..2f12e5e8 --- /dev/null +++ b/test/operator-clear.xlib.argb32.ref.png diff --git a/test/operator-clear.xlib.ref.png b/test/operator-clear.xlib.rgb24.ref.png Binary files differindex d9a59b15..d9a59b15 100644 --- a/test/operator-clear.xlib.ref.png +++ b/test/operator-clear.xlib.rgb24.ref.png diff --git a/test/operator-source.pdf.rgb24.xfail.png b/test/operator-source.pdf.rgb24.ref.png Binary files differindex 9482ed81..9482ed81 100644 --- a/test/operator-source.pdf.rgb24.xfail.png +++ b/test/operator-source.pdf.rgb24.ref.png diff --git a/test/operator-source.svg12.argb32.xfail.png b/test/operator-source.svg12.argb32.xfail.png Binary files differindex 722e5ac4..ccf43156 100644 --- a/test/operator-source.svg12.argb32.xfail.png +++ b/test/operator-source.svg12.argb32.xfail.png diff --git a/test/operator-source.svg12.rgb24.xfail.png b/test/operator-source.svg12.rgb24.xfail.png Binary files differindex 5f445fc5..827521b8 100644 --- a/test/operator-source.svg12.rgb24.xfail.png +++ b/test/operator-source.svg12.rgb24.xfail.png diff --git a/test/operator-source.xlib-fallback.ref.png b/test/operator-source.xlib-fallback.ref.png Binary files differnew file mode 100644 index 00000000..79fb2c52 --- /dev/null +++ b/test/operator-source.xlib-fallback.ref.png diff --git a/test/operator-source.xlib-fallback.rgb24.ref.png b/test/operator-source.xlib-fallback.rgb24.ref.png Binary files differdeleted file mode 100644 index fe0d3c61..00000000 --- a/test/operator-source.xlib-fallback.rgb24.ref.png +++ /dev/null diff --git a/test/path-append.xlib-fallback.ref.png b/test/path-append.xlib-fallback.ref.png Binary files differindex 08a33a26..d34cce12 100644 --- a/test/path-append.xlib-fallback.ref.png +++ b/test/path-append.xlib-fallback.ref.png diff --git a/test/pdf-surface-source.svg12.argb32.xfail.png b/test/pdf-surface-source.svg12.argb32.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/pdf-surface-source.svg12.argb32.xfail.png diff --git a/test/pdf-surface-source.svg12.rgb24.xfail.png b/test/pdf-surface-source.svg12.rgb24.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/pdf-surface-source.svg12.rgb24.xfail.png diff --git a/test/ps-surface-source.svg12.argb32.xfail.png b/test/ps-surface-source.svg12.argb32.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/ps-surface-source.svg12.argb32.xfail.png diff --git a/test/ps-surface-source.svg12.rgb24.xfail.png b/test/ps-surface-source.svg12.rgb24.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/ps-surface-source.svg12.rgb24.xfail.png diff --git a/test/push-group.xlib-fallback.rgb24.ref.png b/test/push-group.xlib-fallback.rgb24.ref.png Binary files differdeleted file mode 100644 index 3a951827..00000000 --- a/test/push-group.xlib-fallback.rgb24.ref.png +++ /dev/null diff --git a/test/scale-offset-image.meta.xfail.png b/test/scale-offset-image.meta.xfail.png Binary files differnew file mode 100644 index 00000000..3e0191a1 --- /dev/null +++ b/test/scale-offset-image.meta.xfail.png diff --git a/test/scale-offset-image.pdf.rgb24.ref.png b/test/scale-offset-image.pdf.rgb24.ref.png Binary files differdeleted file mode 100644 index 12507d9c..00000000 --- a/test/scale-offset-image.pdf.rgb24.ref.png +++ /dev/null diff --git a/test/scale-offset-image.pdf.argb32.ref.png b/test/scale-offset-image.pdf.xfail.png Binary files differindex 4c7fe283..4c7fe283 100644 --- a/test/scale-offset-image.pdf.argb32.ref.png +++ b/test/scale-offset-image.pdf.xfail.png diff --git a/test/scale-offset-image.xlib-fallback.xfail.png b/test/scale-offset-image.xlib-fallback.xfail.png Binary files differnew file mode 100644 index 00000000..1a286cdb --- /dev/null +++ b/test/scale-offset-image.xlib-fallback.xfail.png diff --git a/test/scale-offset-similar.meta.xfail.png b/test/scale-offset-similar.meta.xfail.png Binary files differnew file mode 100644 index 00000000..83d53e65 --- /dev/null +++ b/test/scale-offset-similar.meta.xfail.png diff --git a/test/scale-offset-similar.pdf.argb32.ref.png b/test/scale-offset-similar.pdf.argb32.ref.png Binary files differdeleted file mode 100644 index 7d0406d5..00000000 --- a/test/scale-offset-similar.pdf.argb32.ref.png +++ /dev/null diff --git a/test/scale-offset-similar.pdf.rgb24.ref.png b/test/scale-offset-similar.pdf.rgb24.ref.png Binary files differdeleted file mode 100644 index 7d0406d5..00000000 --- a/test/scale-offset-similar.pdf.rgb24.ref.png +++ /dev/null diff --git a/test/scale-offset-similar.pdf.xfail.png b/test/scale-offset-similar.pdf.xfail.png Binary files differnew file mode 100644 index 00000000..4b600f4c --- /dev/null +++ b/test/scale-offset-similar.pdf.xfail.png diff --git a/test/scale-offset-similar.xlib-fallback.xfail.png b/test/scale-offset-similar.xlib-fallback.xfail.png Binary files differnew file mode 100644 index 00000000..1a286cdb --- /dev/null +++ b/test/scale-offset-similar.xlib-fallback.xfail.png diff --git a/test/self-intersecting.argb32.xfail.png b/test/self-intersecting.argb32.xfail.png Binary files differindex bf08d03a..f644ed46 100644 --- a/test/self-intersecting.argb32.xfail.png +++ b/test/self-intersecting.argb32.xfail.png diff --git a/test/self-intersecting.pdf.argb32.xfail.png b/test/self-intersecting.pdf.argb32.xfail.png Binary files differindex f29b0a69..eb38a893 100644 --- a/test/self-intersecting.pdf.argb32.xfail.png +++ b/test/self-intersecting.pdf.argb32.xfail.png diff --git a/test/self-intersecting.pdf.rgb24.xfail.png b/test/self-intersecting.pdf.rgb24.xfail.png Binary files differindex c32df82c..a79a2975 100644 --- a/test/self-intersecting.pdf.rgb24.xfail.png +++ b/test/self-intersecting.pdf.rgb24.xfail.png diff --git a/test/self-intersecting.rgb24.xfail.png b/test/self-intersecting.rgb24.xfail.png Binary files differindex 9529f098..958215c2 100644 --- a/test/self-intersecting.rgb24.xfail.png +++ b/test/self-intersecting.rgb24.xfail.png diff --git a/test/smask-fill.xlib-fallback.ref.png b/test/smask-fill.xlib-fallback.ref.png Binary files differdeleted file mode 100644 index 28ab7338..00000000 --- a/test/smask-fill.xlib-fallback.ref.png +++ /dev/null diff --git a/test/smask-text.xlib.ref.png b/test/smask-text.xlib.ref.png Binary files differnew file mode 100644 index 00000000..ee7fc8b6 --- /dev/null +++ b/test/smask-text.xlib.ref.png diff --git a/test/smask.xlib.ref.png b/test/smask.xlib.ref.png Binary files differnew file mode 100644 index 00000000..bb70abfe --- /dev/null +++ b/test/smask.xlib.ref.png diff --git a/test/surface-pattern-big-scale-down.ps.xfail.png b/test/surface-pattern-big-scale-down.ps.xfail.png Binary files differnew file mode 100644 index 00000000..f4c1b481 --- /dev/null +++ b/test/surface-pattern-big-scale-down.ps.xfail.png diff --git a/test/svg-surface-source.svg12.argb32.xfail.png b/test/svg-surface-source.svg12.argb32.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/svg-surface-source.svg12.argb32.xfail.png diff --git a/test/svg-surface-source.svg12.rgb24.xfail.png b/test/svg-surface-source.svg12.rgb24.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/svg-surface-source.svg12.rgb24.xfail.png diff --git a/test/test-fallback16-surface-source.svg12.argb32.xfail.png b/test/test-fallback16-surface-source.svg12.argb32.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/test-fallback16-surface-source.svg12.argb32.xfail.png diff --git a/test/test-fallback16-surface-source.svg12.rgb24.xfail.png b/test/test-fallback16-surface-source.svg12.rgb24.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/test-fallback16-surface-source.svg12.rgb24.xfail.png diff --git a/test/text-pattern.pdf.argb32.ref.png b/test/text-pattern.pdf.argb32.ref.png Binary files differnew file mode 100644 index 00000000..0c06629a --- /dev/null +++ b/test/text-pattern.pdf.argb32.ref.png diff --git a/test/text-pattern.pdf.argb32.xfail.png b/test/text-pattern.pdf.argb32.xfail.png Binary files differdeleted file mode 100644 index 227058ce..00000000 --- a/test/text-pattern.pdf.argb32.xfail.png +++ /dev/null diff --git a/test/text-pattern.pdf.rgb24.ref.png b/test/text-pattern.pdf.rgb24.ref.png Binary files differnew file mode 100644 index 00000000..b81de88e --- /dev/null +++ b/test/text-pattern.pdf.rgb24.ref.png diff --git a/test/text-pattern.pdf.rgb24.xfail.png b/test/text-pattern.pdf.rgb24.xfail.png Binary files differdeleted file mode 100644 index a3a37205..00000000 --- a/test/text-pattern.pdf.rgb24.xfail.png +++ /dev/null diff --git a/test/unbounded-operator.svg12.argb32.xfail.png b/test/unbounded-operator.svg12.argb32.xfail.png Binary files differindex 45b173fa..15965c8e 100644 --- a/test/unbounded-operator.svg12.argb32.xfail.png +++ b/test/unbounded-operator.svg12.argb32.xfail.png diff --git a/test/unbounded-operator.svg12.rgb24.xfail.png b/test/unbounded-operator.svg12.rgb24.xfail.png Binary files differindex c369fd26..828a9db9 100644 --- a/test/unbounded-operator.svg12.rgb24.xfail.png +++ b/test/unbounded-operator.svg12.rgb24.xfail.png diff --git a/test/user-font-proxy.svg.ref.png b/test/user-font-proxy.svg.ref.png Binary files differindex 747750a5..6c458485 100644 --- a/test/user-font-proxy.svg.ref.png +++ b/test/user-font-proxy.svg.ref.png diff --git a/test/xlib-surface-source.svg12.argb32.xfail.png b/test/xlib-surface-source.svg12.argb32.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/xlib-surface-source.svg12.argb32.xfail.png diff --git a/test/xlib-surface-source.svg12.rgb24.xfail.png b/test/xlib-surface-source.svg12.rgb24.xfail.png Binary files differnew file mode 100644 index 00000000..6ebcaf9a --- /dev/null +++ b/test/xlib-surface-source.svg12.rgb24.xfail.png diff --git a/util/cairo-script/cairo-script-file.c b/util/cairo-script/cairo-script-file.c index 18b5b862..2a7296d2 100644 --- a/util/cairo-script/cairo-script-file.c +++ b/util/cairo-script/cairo-script-file.c @@ -37,6 +37,7 @@ #include <stdio.h> #include <limits.h> /* INT_MAX */ #include <string.h> +#include <zlib.h> #define CHUNK_SIZE 32768 @@ -148,17 +149,43 @@ csi_file_new_from_string (csi_t *ctx, csi_file_t *file; file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); - if (file == NULL) + if (_csi_unlikely (file == NULL)) return _csi_error (CAIRO_STATUS_NO_MEMORY); file->base.type = CSI_OBJECT_TYPE_FILE; file->base.ref = 1; - file->type = BYTES; - file->src = src; src->base.ref++; - file->data = src->string; - file->bp = file->data; - file->rem = src->len; + if (src->deflate) { + uLongf len = src->deflate; + csi_object_t tmp_obj; + csi_string_t *tmp_str; + csi_status_t status; + + status = csi_string_new (ctx, &tmp_obj, NULL, src->deflate); + if (_csi_unlikely (status)) + return status; + + tmp_str = tmp_obj.datum.string; + if (uncompress ((Bytef *) tmp_str->string, &len, + (Bytef *) src->string, src->len) != Z_OK) + { + csi_string_free (ctx, tmp_str); + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + + file->type = BYTES; + file->src = tmp_str; + file->data = tmp_str->string; + file->bp = file->data; + file->rem = tmp_str->len; + } else { + file->type = BYTES; + file->src = src; src->base.ref++; + file->data = src->string; + file->bp = file->data; + file->rem = src->len; + } obj->type = CSI_OBJECT_TYPE_FILE; obj->datum.file = file; diff --git a/util/cairo-script/cairo-script-objects.c b/util/cairo-script/cairo-script-objects.c index 784376b2..9cc59c90 100644 --- a/util/cairo-script/cairo-script-objects.c +++ b/util/cairo-script/cairo-script-objects.c @@ -507,6 +507,7 @@ csi_string_new (csi_t *ctx, string->string[len] = '\0'; } string->len = len; + string->deflate = 0; string->base.type = CSI_OBJECT_TYPE_STRING; string->base.ref = 1; @@ -518,6 +519,26 @@ csi_string_new (csi_t *ctx, } csi_status_t +csi_string_deflate_new (csi_t *ctx, + csi_object_t *obj, + void *bytes, + int in_len, + int out_len) +{ + csi_status_t status; + csi_string_t *string; + + status = csi_string_new (ctx, obj, bytes, in_len); + if (_csi_unlikely (status)) + return status; + + string = obj->datum.string; + string->deflate = out_len; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t csi_string_new_from_bytes (csi_t *ctx, csi_object_t *obj, char *bytes, @@ -534,6 +555,7 @@ csi_string_new_from_bytes (csi_t *ctx, string->string = bytes; string->len = len; + string->deflate = 0; string->base.type = CSI_OBJECT_TYPE_STRING; string->base.ref = 1; diff --git a/util/cairo-script/cairo-script-private.h b/util/cairo-script/cairo-script-private.h index 996b40d7..54a840f2 100644 --- a/util/cairo-script/cairo-script-private.h +++ b/util/cairo-script/cairo-script-private.h @@ -386,6 +386,7 @@ struct _csi_matrix { struct _csi_string { csi_compound_object_t base; csi_integer_t len; + csi_integer_t deflate; char *string; }; @@ -435,7 +436,6 @@ struct _csi_scanner { csi_stack_t procedure_stack; csi_object_t build_procedure; - int string_p; unsigned int accumulator; unsigned int accumulator_count; @@ -757,6 +757,13 @@ csi_string_new (csi_t *ctx, int len); csi_private csi_status_t +csi_string_deflate_new (csi_t *ctx, + csi_object_t *obj, + void *bytes, + int in_len, + int out_len); + +csi_private csi_status_t csi_string_new_from_bytes (csi_t *ctx, csi_object_t *obj, char *bytes, diff --git a/util/cairo-script/cairo-script-scanner.c b/util/cairo-script/cairo-script-scanner.c index b3217cd7..3cc39575 100644 --- a/util/cairo-script/cairo-script-scanner.c +++ b/util/cairo-script/cairo-script-scanner.c @@ -39,6 +39,7 @@ #include <stdio.h> /* EOF */ #include <string.h> /* memset */ #include <assert.h> +#include <zlib.h> #define DEBUG_SCAN 0 @@ -488,18 +489,6 @@ token_end (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src) } static void -string_inc_p (csi_scanner_t *scan) -{ - scan->string_p++; -} - -static int -string_dec_p (csi_scanner_t *scan) -{ - return --scan->string_p == 0; -} - -static void string_add (csi_t *ctx, csi_scanner_t *scan, int c) { buffer_check (ctx, scan, 1); @@ -616,7 +605,7 @@ base85_add (csi_t *ctx, csi_scanner_t *scan, int c) } static void -base85_end (csi_t *ctx, csi_scanner_t *scan) +base85_end (csi_t *ctx, csi_scanner_t *scan, cairo_bool_t deflate) { csi_object_t obj; cairo_status_t status; @@ -647,12 +636,24 @@ base85_end (csi_t *ctx, csi_scanner_t *scan) break; } - status = csi_string_new (ctx, - &obj, - scan->buffer.base, - scan->buffer.ptr - scan->buffer.base); - if (_csi_unlikely (status)) - longjmp (scan->jmpbuf, status); + if (deflate) { + uLongf len = *(uint32_t *) scan->buffer.base; + Bytef *source = (Bytef *) (scan->buffer.base + sizeof (uint32_t)); + + status = csi_string_deflate_new (ctx, &obj, + source, + (Bytef *) scan->buffer.ptr - source, + len); + if (_csi_unlikely (status)) + longjmp (scan->jmpbuf, status); + } else { + status = csi_string_new (ctx, + &obj, + scan->buffer.base, + scan->buffer.ptr - scan->buffer.base); + if (_csi_unlikely (status)) + longjmp (scan->jmpbuf, status); + } if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) status = csi_array_append (ctx, @@ -714,6 +715,8 @@ _scan_file (csi_t *ctx, csi_file_t *src) uint32_t u32; float f; } u; + int deflate = 0; + int string_p; scan_none: while ((c = csi_file_getc (src)) != EOF) { @@ -757,6 +760,8 @@ scan_none: token_add_unchecked (scan, '<'); token_end (ctx, scan, src); goto scan_none; + case '|': + deflate = 1; case '~': goto scan_base85; default: @@ -1000,7 +1005,7 @@ scan_comment: scan_string: buffer_reset (&scan->buffer); - scan->string_p = 1; + string_p = 1; while ((c = csi_file_getc (src)) != EOF) { switch (c) { case '\\': /* escape */ @@ -1086,12 +1091,12 @@ scan_string: break; case '(': - string_inc_p (scan); + string_p++; string_add (ctx, scan, c); break; case ')': - if (string_dec_p (scan)) { + if (--string_p == 0) { string_end (ctx, scan); goto scan_none; } @@ -1166,7 +1171,8 @@ scan_base85: return; case '>': - base85_end (ctx, scan); + base85_end (ctx, scan, deflate); + deflate = 0; goto scan_none; } csi_file_putc (src, next); diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c index 3af1fffd..2775d46e 100644 --- a/util/cairo-trace/trace.c +++ b/util/cairo-trace/trace.c @@ -1189,15 +1189,6 @@ _write_base85_data_start (struct _data_stream *stream) stream->base85_pending = 0; } -static void -_write_data_start (struct _data_stream *stream) -{ - _write_zlib_data_start (stream); - _write_base85_data_start (stream); - - _trace_printf ("<~"); -} - static bool _expand_four_tuple_to_five (unsigned char four_tuple[4], unsigned char five_tuple[5]) @@ -1271,6 +1262,16 @@ _write_zlib_data (struct _data_stream *stream, bool flush) } static void +_write_data_start (struct _data_stream *stream, uint32_t len) +{ + _write_zlib_data_start (stream); + _write_base85_data_start (stream); + + _trace_printf ("<|"); + _write_base85_data (stream, (unsigned char *) &len, len); +} + +static void _write_data (struct _data_stream *stream, const void *data, unsigned int length) @@ -1328,7 +1329,7 @@ _emit_data (const void *data, unsigned int length) { struct _data_stream stream; - _write_data_start (&stream); + _write_data_start (&stream, length); _write_data (&stream, data, length); _write_data_end (&stream); } @@ -1391,6 +1392,7 @@ _emit_image (cairo_surface_t *image, ...) { int stride, row, width, height; + uint32_t len; cairo_format_t format; uint8_t row_stack[BUFFER_SIZE]; uint8_t *rowdata; @@ -1400,9 +1402,7 @@ _emit_image (cairo_surface_t *image, status = DLCALL (cairo_surface_status, image); if (status) { - _trace_printf ("dict\n" - " /status //%s set\n" - " image", + _trace_printf ("<< /status //%s >> image", _status_to_string (status)); return; } @@ -1430,6 +1430,7 @@ _emit_image (cairo_surface_t *image, if (DLCALL (cairo_version) >= CAIRO_VERSION_ENCODE (1, 9, 0)) { const char *mime_types[] = { CAIRO_MIME_TYPE_JPEG, + CAIRO_MIME_TYPE_JP2, CAIRO_MIME_TYPE_PNG, NULL }, **mime_type; @@ -1454,8 +1455,16 @@ _emit_image (cairo_surface_t *image, } } + switch (format) { + case CAIRO_FORMAT_A1: len = (width + 7)/8; break; + case CAIRO_FORMAT_A8: len = width; break; + case CAIRO_FORMAT_RGB24: len = 3*width; break; + default: + case CAIRO_FORMAT_ARGB32: len = 4*width; break; + } + _trace_printf (" /source "); - _write_data_start (&stream); + _write_data_start (&stream, len * height); #ifdef WORDS_BIGENDIAN switch (format) { @@ -1549,8 +1558,7 @@ _emit_image (cairo_surface_t *image, BAIL: _write_data_end (&stream); #endif - _trace_printf (" /deflate filter set\n" - " image"); + _trace_printf (" set\n image"); } static void @@ -2658,31 +2666,33 @@ _emit_font_options (const cairo_font_options_t *options) cairo_hint_style_t hint_style; cairo_hint_metrics_t hint_metrics; - _trace_printf ("dict\n"); + _trace_printf ("<<"); antialias = DLCALL (cairo_font_options_get_antialias, options); if (antialias != CAIRO_ANTIALIAS_DEFAULT) { - _trace_printf (" /antialias //%s set\n", + _trace_printf (" /antialias //%s", _antialias_to_string (antialias)); } subpixel_order = DLCALL (cairo_font_options_get_subpixel_order, options); if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) { - _trace_printf (" /subpixel-order //%s set\n", + _trace_printf (" /subpixel-order //%s", _subpixel_order_to_string (subpixel_order)); } hint_style = DLCALL (cairo_font_options_get_hint_style, options); if (hint_style != CAIRO_HINT_STYLE_DEFAULT) { - _trace_printf (" /hint-style //%s set\n", + _trace_printf (" /hint-style //%s", _hint_style_to_string (hint_style)); } hint_metrics = DLCALL (cairo_font_options_get_hint_metrics, options); if (hint_style != CAIRO_HINT_METRICS_DEFAULT) { - _trace_printf (" /hint-metrics //%s set\n", + _trace_printf (" /hint-metrics //%s", _hint_metrics_to_string (hint_metrics)); } + + _trace_printf (" >>"); } void @@ -2692,7 +2702,7 @@ cairo_set_font_options (cairo_t *cr, const cairo_font_options_t *options) if (cr != NULL && options != NULL && _write_lock ()) { _emit_context (cr); _emit_font_options (options); - _trace_printf (" set-font-options\n"); + _trace_printf (" set-font-options\n"); _write_unlock (); } @@ -3621,16 +3631,10 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face, int load_flags) if (obj->operand != -1) _object_remove (obj); - _trace_printf ("dict\n" - " /type 42 set\n" - " /source "); + _trace_printf ("<< /type 42 /source "); _emit_data (data->data, data->size); - _trace_printf (" /deflate filter set\n" - " /size %lu set\n" - " /index %lu set\n" - " /flags %d set\n" - " font\n", - data->size, data->index, load_flags); + _trace_printf (" /index %lu /flags %d font\n", + data->index, load_flags); _push_operand (FONT_FACE, ret); _write_unlock (); } @@ -4245,17 +4249,12 @@ _cairo_test_fallback_surface_create (cairo_content_t content, #include <test-paginated-surface.h> cairo_surface_t * -_cairo_test_paginated_surface_create_for_data (unsigned char *data, - cairo_content_t content, - int width, - int height, - int stride) +_cairo_test_paginated_surface_create (cairo_surface_t *surface) { cairo_surface_t *ret; long surface_id; - ret = DLCALL (_cairo_test_paginated_surface_create_for_data, - data, content, width, height, stride); + ret = DLCALL (_cairo_test_paginated_surface_create, surface); surface_id = _create_surface_id (ret); _emit_line_info (); @@ -4263,16 +4262,10 @@ _cairo_test_paginated_surface_create_for_data (unsigned char *data, /* XXX store initial data? */ _trace_printf ("dict\n" " /type /test-paginated set\n" - " /content //%s set\n" - " /width %d set\n" - " /height %d set\n" - " /stride %d set\n" + " /target s%ld set\n" " surface dup /s%ld exch def\n", - _content_to_string (content), - width, height, stride, + _get_surface_id (surface), surface_id); - _surface_object_set_size (ret, width, height); - _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); } @@ -4310,27 +4303,35 @@ _cairo_test_null_surface_create (cairo_content_t content) cairo_surface_t * cairo_meta_surface_create (cairo_content_t content, - double width, - double height) + const cairo_rectangle_t *extents) { cairo_surface_t *ret; long surface_id; - ret = DLCALL (cairo_meta_surface_create, content, width, height); + ret = DLCALL (cairo_meta_surface_create, content, extents); surface_id = _create_surface_id (ret); _emit_line_info (); if (_write_lock ()) { - _trace_printf ("dict\n" - " /type /meta set\n" - " /content //%s set\n" - " /width %f set\n" - " /height %f set\n" - " surface dup /s%ld exch def\n", - _content_to_string (content), - width, height, - surface_id); - _surface_object_set_size (ret, width, height); + if (extents) { + _trace_printf ("dict\n" + " /type /meta set\n" + " /content //%s set\n" + " /extents [%f %f %f %f] set\n" + " surface dup /s%ld exch def\n", + _content_to_string (content), + extents->x, extents->y, + extents->width, extents->height, + surface_id); + _surface_object_set_size (ret, extents->width, extents->height); + } else { + _trace_printf ("dict\n" + " /type /meta set\n" + " /content //%s set\n" + " surface dup /s%ld exch def\n", + _content_to_string (content), + surface_id); + } _get_object (SURFACE, ret)->defined = true; _push_operand (SURFACE, ret); _write_unlock (); |