[svg] Use finer-grained fallbacks for SVG 1.2

The use of fine-grained fallbacks requires the native support of the
SOURCE operator applied to an image on the target surface. SVG 1.2
introduces the "comp-op:src" mode fulfilling this criteria - so we can
enable fine-grained fallbacks for 1.2+.

Update test/fine-grained-fallbacks to exercise this pathway in SVG 1.2 -
as SVG natively supported all the current operations within that test.
This reveals yet another librsvg bug in handling SVG 1.2.
This commit is contained in:
Chris Wilson 2008-10-08 11:06:42 +01:00
parent 0c777a3e0d
commit 565c02a37e
15 changed files with 147 additions and 48 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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 \

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 819 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 819 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 796 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 590 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -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;
}