diff --git a/src/cairo-paginated-private.h b/src/cairo-paginated-private.h index 0c042746d..5cb2e48b6 100644 --- a/src/cairo-paginated-private.h +++ b/src/cairo-paginated-private.h @@ -65,7 +65,7 @@ struct _cairo_paginated_surface_backend { * before the mode is changed to RENDER. */ cairo_warn cairo_int_status_t - (*set_bounding_box) (void *surface, + (*set_bounding_box) (void *surface, cairo_box_t *bbox); /* Optional. Indicates whether the page requires fallback images. @@ -73,8 +73,11 @@ struct _cairo_paginated_surface_backend { * mode is changed to RENDER. */ cairo_warn cairo_int_status_t - (*set_fallback_images_required)(void *surface, - cairo_bool_t fallbacks_required); + (*set_fallback_images_required) (void *surface, + cairo_bool_t fallbacks_required); + + cairo_bool_t + (*supports_fine_grained_fallbacks) (void *surface); }; /* A #cairo_paginated_surface_t provides a very convenient wrapper that diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c index e4e84d502..131d289b1 100644 --- a/src/cairo-paginated-surface.c +++ b/src/cairo-paginated-surface.c @@ -329,36 +329,23 @@ _paint_page (cairo_paginated_surface_t *surface) /* Finer grained fallbacks are currently only supported for some * surface types */ - switch (surface->target->type) { - case CAIRO_SURFACE_TYPE_PDF: - case CAIRO_SURFACE_TYPE_PS: - case CAIRO_SURFACE_TYPE_WIN32_PRINTING: - has_supported = _cairo_analysis_surface_has_supported (analysis); - has_page_fallback = FALSE; - has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis); - break; - - case CAIRO_SURFACE_TYPE_IMAGE: - case CAIRO_SURFACE_TYPE_XLIB: - case CAIRO_SURFACE_TYPE_XCB: - case CAIRO_SURFACE_TYPE_GLITZ: - case CAIRO_SURFACE_TYPE_QUARTZ: - case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: - case CAIRO_SURFACE_TYPE_WIN32: - case CAIRO_SURFACE_TYPE_BEOS: - case CAIRO_SURFACE_TYPE_DIRECTFB: - case CAIRO_SURFACE_TYPE_SVG: - case CAIRO_SURFACE_TYPE_OS2: - default: - if (_cairo_analysis_surface_has_unsupported (analysis)) { - has_supported = FALSE; - has_page_fallback = TRUE; - } else { - has_supported = TRUE; - has_page_fallback = FALSE; - } - has_finegrained_fallback = FALSE; - break; + if (surface->backend->supports_fine_grained_fallbacks != NULL && + surface->backend->supports_fine_grained_fallbacks (surface->target)) + { + has_supported = _cairo_analysis_surface_has_supported (analysis); + has_page_fallback = FALSE; + has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis); + } + else + { + if (_cairo_analysis_surface_has_unsupported (analysis)) { + has_supported = FALSE; + has_page_fallback = TRUE; + } else { + has_supported = TRUE; + has_page_fallback = FALSE; + } + has_finegrained_fallback = FALSE; } if (has_supported) { diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 16abab336..e073eb454 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -1277,8 +1277,8 @@ _cairo_pdf_surface_start_page (void *abstract_surface) } static cairo_int_status_t -_cairo_pdf_surface_has_fallback_images (void *abstract_surface, - cairo_bool_t has_fallbacks) +_cairo_pdf_surface_has_fallback_images (void *abstract_surface, + cairo_bool_t has_fallbacks) { cairo_status_t status; cairo_pdf_surface_t *surface = abstract_surface; @@ -1291,6 +1291,12 @@ _cairo_pdf_surface_has_fallback_images (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +static cairo_bool_t +_cairo_pdf_surface_supports_fine_grained_fallbacks (void *abstract_surface) +{ + return TRUE; +} + /* Emit alpha channel from the image into the given data, providing * an id that can be used to reference the resulting SMask object. * @@ -4981,9 +4987,11 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = { _cairo_pdf_surface_show_text_glyphs, }; -static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend = { +static const cairo_paginated_surface_backend_t +cairo_pdf_surface_paginated_backend = { _cairo_pdf_surface_start_page, _cairo_pdf_surface_set_paginated_mode, NULL, /* set_bounding_box */ _cairo_pdf_surface_has_fallback_images, + _cairo_pdf_surface_supports_fine_grained_fallbacks, }; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index bef876c7a..b107a54d5 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -3284,6 +3284,12 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface, return _cairo_output_stream_get_status (surface->stream); } +static cairo_bool_t +_cairo_ps_surface_supports_fine_grained_fallbacks (void *abstract_surface) +{ + return TRUE; +} + static const cairo_surface_backend_t cairo_ps_surface_backend = { CAIRO_SURFACE_TYPE_PS, _cairo_ps_surface_create_similar, @@ -3322,4 +3328,6 @@ static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backen _cairo_ps_surface_start_page, _cairo_ps_surface_set_paginated_mode, _cairo_ps_surface_set_bounding_box, + NULL, /* _cairo_ps_surface_has_fallback_images, */ + _cairo_ps_surface_supports_fine_grained_fallbacks, }; diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c index 8095aa48f..19af8737b 100644 --- a/src/cairo-svg-surface.c +++ b/src/cairo-svg-surface.c @@ -2022,11 +2022,8 @@ _cairo_svg_surface_paint (void *abstract_surface, * 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 optimiszation in meta surface. */ - if (surface->clip_level == 0 && - (op == CAIRO_OPERATOR_CLEAR || - op == CAIRO_OPERATOR_SOURCE)) - { + * and an optimization in meta surface. */ + if (surface->clip_level == 0 && op == CAIRO_OPERATOR_CLEAR) { status = _cairo_output_stream_destroy (surface->xml_node); if (status) { surface->xml_node = NULL; @@ -2054,7 +2051,8 @@ _cairo_svg_surface_paint (void *abstract_surface, } } - return _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, 0, NULL); + return _cairo_svg_surface_emit_paint (surface->xml_node, + surface, op, source, 0, NULL); } static cairo_int_status_t @@ -2551,15 +2549,33 @@ _cairo_svg_document_finish (cairo_svg_document_t *document) } static void -_cairo_svg_surface_set_paginated_mode (void *abstract_surface, - cairo_paginated_mode_t paginated_mode) +_cairo_svg_surface_set_paginated_mode (void *abstract_surface, + cairo_paginated_mode_t paginated_mode) { cairo_svg_surface_t *surface = abstract_surface; surface->paginated_mode = paginated_mode; } +static cairo_bool_t +_cairo_svg_surface_supports_fine_grained_fallbacks (void *abstract_surface) +{ + cairo_svg_surface_t *surface = abstract_surface; + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (surface->document->svg_version >= CAIRO_SVG_VERSION_1_2) { + status = _cairo_svg_surface_analyze_operator (surface, + CAIRO_OPERATOR_SOURCE); + } + + return status == CAIRO_STATUS_SUCCESS; +} + static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend = { NULL /*_cairo_svg_surface_start_page*/, - _cairo_svg_surface_set_paginated_mode + _cairo_svg_surface_set_paginated_mode, + NULL, /* _cairo_svg_surface_set_bounding_box */ + NULL, /* _cairo_svg_surface_set_fallback_images_required */ + _cairo_svg_surface_supports_fine_grained_fallbacks, + }; diff --git a/test/Makefile.am b/test/Makefile.am index a33ca4131..eb961accb 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -478,9 +478,9 @@ REFERENCE_IMAGES = \ filter-nearest-offset-svg12-ref.png \ finer-grained-fallbacks-ref.png \ finer-grained-fallbacks-rgb24-ref.png \ - finer-grained-fallbacks-ps2-argb32-ref.png \ - finer-grained-fallbacks-ps3-argb32-ref.png \ + finer-grained-fallbacks-ps2-ref.png \ finer-grained-fallbacks-ps2-rgb24-ref.png \ + finer-grained-fallbacks-ps3-ref.png \ finer-grained-fallbacks-ps3-rgb24-ref.png \ font-matrix-translation-ps2-argb32-ref.png \ font-matrix-translation-ps3-argb32-ref.png \ diff --git a/test/finer-grained-fallbacks-ps2-argb32-ref.png b/test/finer-grained-fallbacks-ps2-argb32-ref.png deleted file mode 100644 index 402f01b85..000000000 Binary files a/test/finer-grained-fallbacks-ps2-argb32-ref.png and /dev/null differ diff --git a/test/finer-grained-fallbacks-ps2-ref.png b/test/finer-grained-fallbacks-ps2-ref.png new file mode 100644 index 000000000..1744100c9 Binary files /dev/null and b/test/finer-grained-fallbacks-ps2-ref.png differ diff --git a/test/finer-grained-fallbacks-ps2-rgb24-ref.png b/test/finer-grained-fallbacks-ps2-rgb24-ref.png index e821344f0..de4828607 100644 Binary files a/test/finer-grained-fallbacks-ps2-rgb24-ref.png and b/test/finer-grained-fallbacks-ps2-rgb24-ref.png differ diff --git a/test/finer-grained-fallbacks-ps3-argb32-ref.png b/test/finer-grained-fallbacks-ps3-argb32-ref.png deleted file mode 100644 index 402f01b85..000000000 Binary files a/test/finer-grained-fallbacks-ps3-argb32-ref.png and /dev/null differ diff --git a/test/finer-grained-fallbacks-ps3-ref.png b/test/finer-grained-fallbacks-ps3-ref.png new file mode 100644 index 000000000..1744100c9 Binary files /dev/null and b/test/finer-grained-fallbacks-ps3-ref.png differ diff --git a/test/finer-grained-fallbacks-ps3-rgb24-ref.png b/test/finer-grained-fallbacks-ps3-rgb24-ref.png index e821344f0..de4828607 100644 Binary files a/test/finer-grained-fallbacks-ps3-rgb24-ref.png and b/test/finer-grained-fallbacks-ps3-rgb24-ref.png differ diff --git a/test/finer-grained-fallbacks-ref.png b/test/finer-grained-fallbacks-ref.png index 7dce860f0..c7eb113d8 100644 Binary files a/test/finer-grained-fallbacks-ref.png and b/test/finer-grained-fallbacks-ref.png differ diff --git a/test/finer-grained-fallbacks-rgb24-ref.png b/test/finer-grained-fallbacks-rgb24-ref.png index 732848202..3b8e9c38d 100644 Binary files a/test/finer-grained-fallbacks-rgb24-ref.png and b/test/finer-grained-fallbacks-rgb24-ref.png differ diff --git a/test/finer-grained-fallbacks.c b/test/finer-grained-fallbacks.c index f7cd5f366..65bceb46c 100644 --- a/test/finer-grained-fallbacks.c +++ b/test/finer-grained-fallbacks.c @@ -31,7 +31,7 @@ static cairo_test_draw_function_t draw; #define CIRCLE_SIZE 10 #define PAD 2 #define WIDTH (CIRCLE_SIZE*6.5 + PAD) -#define HEIGHT (CIRCLE_SIZE*3.5 + PAD) +#define HEIGHT (CIRCLE_SIZE*7.0 + PAD) static const cairo_test_t test = { "finer-grained-fallbacks", @@ -50,6 +50,19 @@ draw_circle (cairo_t *cr, double x, double y) cairo_restore (cr); } +static void +draw_image_circle (cairo_t *cr, cairo_surface_t *source, double x, double y) +{ + cairo_save (cr); + + cairo_set_source_surface (cr, source, x, y); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT); + cairo_rectangle (cr, x, y, CIRCLE_SIZE, CIRCLE_SIZE); + cairo_fill (cr); + + cairo_restore (cr); +} + static void draw_circles (cairo_t *cr) { @@ -61,6 +74,17 @@ draw_circles (cairo_t *cr) draw_circle (cr, CIRCLE_SIZE*6, 0); } +static void +draw_image_circles (cairo_t *cr, cairo_surface_t *source) +{ + draw_image_circle (cr, source, 0, -CIRCLE_SIZE*0.1); + draw_image_circle (cr, source, CIRCLE_SIZE*0.4, CIRCLE_SIZE*0.25); + + draw_image_circle (cr, source, CIRCLE_SIZE*2, 0); + draw_image_circle (cr, source, CIRCLE_SIZE*4, 0); + draw_image_circle (cr, source, CIRCLE_SIZE*6, 0); +} + /* For each of circle and fallback_circle we draw: * - two overlapping * - one isolated @@ -74,12 +98,40 @@ draw_circles (cairo_t *cr) * * Fallback circles are drawn in red. CAIRO_OPERATOR_ADD is used to * ensure they will be emitted as a fallback image in PS/PDF. + * + * In order to trigger a fallback for SVG, we need to use a surface with + * REFLECT. */ +static cairo_surface_t * +surface_create (cairo_t *target) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_surface_create_similar (cairo_get_target (target), + CAIRO_CONTENT_COLOR_ALPHA, + CIRCLE_SIZE, CIRCLE_SIZE); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + draw_circle (cr, CIRCLE_SIZE/2, CIRCLE_SIZE/2); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + static cairo_test_status_t draw (cairo_t *cr, int width, int height) { + cairo_surface_t *surface; + cairo_translate (cr, PAD, PAD); + cairo_save (cr); + /* Draw overlapping circle and fallback circle */ cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); @@ -101,6 +153,31 @@ draw (cairo_t *cr, int width, int height) cairo_translate (cr, 0, CIRCLE_SIZE*2); draw_circles (cr); + cairo_restore (cr); + cairo_translate (cr, 0, CIRCLE_SIZE * 3.5); + + /* Draw using fallback surface */ + surface = surface_create (cr); + + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + draw_circle (cr, CIRCLE_SIZE*0.5, CIRCLE_SIZE*1.5); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + draw_image_circle (cr, surface, CIRCLE_SIZE/4, CIRCLE_SIZE + CIRCLE_SIZE/4); + + /* Draw circles */ + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_translate (cr, CIRCLE_SIZE*2.5, CIRCLE_SIZE*0.6); + draw_circles (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + cairo_translate (cr, -CIRCLE_SIZE/2, CIRCLE_SIZE*1.5); + draw_image_circles (cr, surface); + + cairo_surface_destroy (surface); + return CAIRO_TEST_SUCCESS; }