[cairo-commit] 2 commits - src/cairo-analysis-surface.c src/cairo-analysis-surface-private.h src/cairoint.h src/cairo-meta-surface.c src/cairo-meta-surface-private.h src/cairo-paginated-surface.c src/cairo-ps-surface.c src/cairo-region.c src/cairo-region-private.h
Carl Worth
cworth at kemper.freedesktop.org
Tue Aug 21 15:16:28 PDT 2007
src/cairo-analysis-surface-private.h | 3
src/cairo-analysis-surface.c | 358 ++++++++++++++++++++++++++++++-----
src/cairo-meta-surface-private.h | 34 ++-
src/cairo-meta-surface.c | 78 ++++++-
src/cairo-paginated-surface.c | 131 ++++++++++--
src/cairo-ps-surface.c | 97 +++++----
src/cairo-region-private.h | 4
src/cairo-region.c | 13 +
src/cairoint.h | 4
9 files changed, 589 insertions(+), 133 deletions(-)
New commits:
diff-tree e66b2b68ab456d779524d9b4ab34acf5d38362b5 (from bf92255edd20595a6eb220c6ee9d6aa40b244eef)
Author: Carl Worth <cworth at cworth.org>
Date: Tue Aug 21 14:52:54 2007 -0700
Use 8-bit math to flatten color when emitting a solid pattern to PostScript
This isn't necessarily more correct than the old code using the doubles,
but it does result in bit-for-bit color equivalence when comparing the
results against the image backend. So that's both good consistency, and
more ease is using the test suite to verify things.
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index df78212..676014c 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1681,25 +1681,29 @@ static void
_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
cairo_solid_pattern_t *pattern)
{
- cairo_color_t color = pattern->color;
+ cairo_color_t *color = &pattern->color;
+ double red, green, blue;
- if (!CAIRO_COLOR_IS_OPAQUE(&color)) {
- /* Blend into white */
- color.red = color.red*color.alpha + 1 - color.alpha;
- color.green = color.green*color.alpha + 1 - color.alpha;
- color.blue = color.blue*color.alpha + 1 - color.alpha;
+ red = color->red;
+ green = color->green;
+ blue = color->blue;
+
+ if (!CAIRO_COLOR_IS_OPAQUE(color)) {
+ uint8_t one_minus_alpha = 255 - (color->alpha_short >> 8);
+
+ red = ((color->red_short >> 8) + one_minus_alpha) / 255.0;
+ green = ((color->green_short >> 8) + one_minus_alpha) / 255.0;
+ blue = ((color->blue_short >> 8) + one_minus_alpha) / 255.0;
}
- if (color_is_gray (&color))
+ if (color_is_gray (color))
_cairo_output_stream_printf (surface->stream,
"%f G\n",
- color.red);
+ red);
else
_cairo_output_stream_printf (surface->stream,
"%f %f %f R\n",
- color.red,
- color.green,
- color.blue);
+ red, green, blue);
}
static cairo_status_t
diff-tree bf92255edd20595a6eb220c6ee9d6aa40b244eef (from bf4bdbb6076dbe3b74534bc4308dbc9213bf628d)
Author: Adrian Johnson <ajohnson at redneon.com>
Date: Tue Aug 21 22:27:57 2007 +0930
PS: Add finer-grained image fallback support
The analysis surface now keeps track of two regions: supported
operations, and unsupported operations. If the target surface returns
CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY, the analysis surface will check
if any previous operation intersects with this operation. If there is
nothing previously drawn under the operation, the status is changed to
supported.
The meta surface has two new functions:
_cairo_meta_surface_replay_region()
_cairo_meta_surface_replay_and_create_regions()
During the analysis stage, the paginated surface replays the meta
surface using _cairo_meta_surface_replay_and_create_regions(). The
return status from each analyzed operation is saved in the meta
surface. The _cairo_meta_surface_replay_region() function allows only
operations from either the supported or unsupported region to be
replayed. This allows the paginated surface to replay only the
supported operations before emitting a fallback image for each
rectangle in the unsupported region.
diff --git a/src/cairo-analysis-surface-private.h b/src/cairo-analysis-surface-private.h
index 056972a..c17b0ef 100644
--- a/src/cairo-analysis-surface-private.h
+++ b/src/cairo-analysis-surface-private.h
@@ -49,6 +49,9 @@ cairo_private cairo_region_t *
_cairo_analysis_surface_get_unsupported (cairo_surface_t *unsupported);
cairo_private cairo_bool_t
+_cairo_analysis_surface_has_supported (cairo_surface_t *unsupported);
+
+cairo_private cairo_bool_t
_cairo_analysis_surface_has_unsupported (cairo_surface_t *unsupported);
#endif /* CAIRO_ANALYSIS_SURFACE_H */
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 3dbc73c..b2295ea 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2006 Keith Packard
+ * Copyright © 2007 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -30,12 +31,14 @@
*
* Contributor(s):
* Keith Packard <keithp at keithp.com>
+ * Adrian Johnson <ajohnson at redneon.com>
*/
#include "cairoint.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-paginated-private.h"
+#include "cairo-region-private.h"
typedef struct {
cairo_surface_t base;
@@ -44,10 +47,122 @@ typedef struct {
cairo_surface_t *target;
- cairo_bool_t fallback;
+ cairo_bool_t has_supported;
+ cairo_bool_t has_unsupported;
+
+ cairo_region_t supported_region;
+ cairo_region_t fallback_region;
+ cairo_rectangle_int_t current_clip;
+
} cairo_analysis_surface_t;
static cairo_int_status_t
+_cairo_analysis_surface_add_operation (cairo_analysis_surface_t *surface,
+ cairo_rectangle_int_t *rect,
+ cairo_int_status_t backend_status)
+{
+ cairo_int_status_t status;
+
+ if (rect->width == 0 || rect->height == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* If the operation is completely enclosed within the fallback
+ * region there is no benefit in emitting a native operation as
+ * the fallback image will be painted on top.
+ */
+ if (_cairo_region_contains_rectangle (&surface->fallback_region, rect) == PIXMAN_REGION_IN)
+ return CAIRO_INT_STATUS_IMAGE_FALLBACK;
+
+ if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
+ /* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
+ * that the backend only supports this operation if the
+ * transparency removed. If the extents of this operation does
+ * not intersect any other native operation, the operation is
+ * natively supported and the backend will blend the
+ * transparency into the white background.
+ */
+ if (_cairo_region_contains_rectangle (&surface->supported_region, rect) == PIXMAN_REGION_OUT)
+ backend_status = CAIRO_STATUS_SUCCESS;
+ }
+
+ if (backend_status == CAIRO_STATUS_SUCCESS) {
+ /* Add the operation to the supported region. Operations in
+ * this region will be emitted as native operations.
+ */
+ surface->has_supported = TRUE;
+ status = _cairo_region_union_rect (&surface->supported_region,
+ &surface->supported_region,
+ rect);
+ return status;
+ }
+
+ /* Add the operation to the unsupported region. This region will
+ * be painted as an image after all native operations have been
+ * emitted.
+ */
+ surface->has_unsupported = TRUE;
+ status = _cairo_region_union_rect (&surface->fallback_region,
+ &surface->fallback_region,
+ rect);
+
+ /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
+ * unsupported operations to the meta surface as using
+ * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
+ * invoke the cairo-surface-fallback path then return
+ * CAIRO_STATUS_SUCCESS.
+ */
+ if (status == CAIRO_STATUS_SUCCESS)
+ return CAIRO_INT_STATUS_IMAGE_FALLBACK;
+ else
+ return status;
+}
+
+static cairo_status_t
+_cairo_analysis_surface_finish (void *abstract_surface)
+{
+ cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
+
+ _cairo_region_fini (&surface->supported_region);
+ _cairo_region_fini (&surface->fallback_region);
+
+ 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)
+{
+ cairo_analysis_surface_t *surface = abstract_surface;
+ double x1, y1, x2, y2;
+ cairo_rectangle_int_t extent;
+ cairo_status_t status;
+
+ 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;
+ status = CAIRO_STATUS_SUCCESS;
+ } else {
+ status = _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2);
+ if (status)
+ return status;
+
+ extent.x = floor (x1);
+ extent.y = floor (y1);
+ extent.width = ceil (x2) - extent.x;
+ extent.height = ceil (y2) - extent.y;
+
+ _cairo_rectangle_intersect (&surface->current_clip, &extent);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
_cairo_analysis_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -62,17 +177,32 @@ _cairo_analysis_surface_paint (void *a
cairo_pattern_t *source)
{
cairo_analysis_surface_t *surface = abstract_surface;
- cairo_status_t status;
+ cairo_status_t status, backend_status;
+ cairo_rectangle_int_t extents;
if (!surface->target->backend->paint)
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
- status = (*surface->target->backend->paint) (surface->target, op,
- source);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- surface->fallback = TRUE;
- status = CAIRO_STATUS_SUCCESS;
+ backend_status = (*surface->target->backend->paint) (surface->target, op,
+ source);
+
+ status = _cairo_surface_get_extents (&surface->base, &extents);
+ if (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 (status)
+ return status;
+
+ _cairo_rectangle_intersect (&extents, &source_extents);
}
+
+ _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+ status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
return status;
}
@@ -83,17 +213,38 @@ _cairo_analysis_surface_mask (void *abs
cairo_pattern_t *mask)
{
cairo_analysis_surface_t *surface = abstract_surface;
- cairo_status_t status;
+ cairo_status_t status, backend_status;
+ cairo_rectangle_int_t extents;
if (!surface->target->backend->mask)
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
- status = (*surface->target->backend->mask) (surface->target, op,
- source, mask);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- surface->fallback = TRUE;
- status = CAIRO_STATUS_SUCCESS;
+ backend_status = (*surface->target->backend->mask) (surface->target, op,
+ source, mask);
+
+ status = _cairo_surface_get_extents (&surface->base, &extents);
+ if (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 (status)
+ return status;
+
+ _cairo_rectangle_intersect (&extents, &source_extents);
+
+ status = _cairo_pattern_get_extents (mask, &source_extents);
+ if (status)
+ return status;
+
+ _cairo_rectangle_intersect (&extents, &source_extents);
}
+
+ _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+ status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
return status;
}
@@ -109,19 +260,61 @@ _cairo_analysis_surface_stroke (void *
cairo_antialias_t antialias)
{
cairo_analysis_surface_t *surface = abstract_surface;
- cairo_status_t status;
+ cairo_status_t status, backend_status;
+ cairo_traps_t traps;
+ cairo_box_t box;
+ cairo_rectangle_int_t extents;
if (!surface->target->backend->stroke)
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
- status = (*surface->target->backend->stroke) (surface->target, op,
- source, path, style,
- ctm, ctm_inverse,
- tolerance, antialias);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- surface->fallback = TRUE;
- status = CAIRO_STATUS_SUCCESS;
+ backend_status = (*surface->target->backend->stroke) (surface->target, op,
+ source, path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias);
+
+ status = _cairo_surface_get_extents (&surface->base, &extents);
+ if (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 (status)
+ return status;
+
+ _cairo_rectangle_intersect (&extents, &source_extents);
}
+
+ _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+ box.p1.x = _cairo_fixed_from_int (extents.x);
+ box.p1.y = _cairo_fixed_from_int (extents.y);
+ box.p2.x = _cairo_fixed_from_int (extents.x + extents.width);
+ box.p2.y = _cairo_fixed_from_int (extents.y + extents.height);
+
+ _cairo_traps_init (&traps);
+
+ _cairo_traps_limit (&traps, &box);
+
+ status = _cairo_path_fixed_stroke_to_traps (path,
+ style,
+ ctm, ctm_inverse,
+ tolerance,
+ &traps);
+ if (status)
+ goto FINISH;
+
+ _cairo_traps_extents (&traps, &box);
+ extents.x = _cairo_fixed_integer_floor (box.p1.x);
+ extents.y = _cairo_fixed_integer_floor (box.p1.y);
+ extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x;
+ extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y;
+ status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
+FINISH:
+ _cairo_traps_fini (&traps);
+
return status;
}
@@ -135,18 +328,59 @@ _cairo_analysis_surface_fill (void *ab
cairo_antialias_t antialias)
{
cairo_analysis_surface_t *surface = abstract_surface;
- cairo_status_t status;
+ cairo_status_t status, backend_status;
+ cairo_traps_t traps;
+ cairo_box_t box;
+ cairo_rectangle_int_t extents;
if (!surface->target->backend->fill)
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
- status = (*surface->target->backend->fill) (surface->target, op,
+ backend_status = (*surface->target->backend->fill) (surface->target, op,
source, path, fill_rule,
tolerance, antialias);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- surface->fallback = TRUE;
- status = CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_surface_get_extents (&surface->base, &extents);
+ if (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 (status)
+ return status;
+
+ _cairo_rectangle_intersect (&extents, &source_extents);
}
+
+ _cairo_rectangle_intersect (&extents, &surface->current_clip);
+
+ box.p1.x = _cairo_fixed_from_int (extents.x);
+ box.p1.y = _cairo_fixed_from_int (extents.y);
+ box.p2.x = _cairo_fixed_from_int (extents.x + extents.width);
+ box.p2.y = _cairo_fixed_from_int (extents.y + extents.height);
+
+ _cairo_traps_init (&traps);
+
+ _cairo_traps_limit (&traps, &box);
+
+ status = _cairo_path_fixed_fill_to_traps (path,
+ fill_rule,
+ tolerance,
+ &traps);
+ if (status)
+ goto FINISH;
+
+ _cairo_traps_extents (&traps, &box);
+ extents.x = _cairo_fixed_integer_floor (box.p1.x);
+ extents.y = _cairo_fixed_integer_floor (box.p1.y);
+ extents.width = _cairo_fixed_integer_ceil (box.p2.x) - extents.x;
+ extents.height = _cairo_fixed_integer_ceil (box.p2.y) - extents.y;
+ status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
+
+FINISH:
+ _cairo_traps_fini (&traps);
+
return status;
}
@@ -159,26 +393,34 @@ _cairo_analysis_surface_show_glyphs (voi
cairo_scaled_font_t *scaled_font)
{
cairo_analysis_surface_t *surface = abstract_surface;
- cairo_status_t status;
+ cairo_status_t status, backend_status;
+ cairo_rectangle_int_t extent;
if (!surface->target->backend->show_glyphs)
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
- status = (*surface->target->backend->show_glyphs) (surface->target, op,
+ backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- surface->fallback = TRUE;
- status = CAIRO_STATUS_SUCCESS;
- }
+
+ status = _cairo_scaled_font_glyph_device_extents (scaled_font,
+ glyphs,
+ num_glyphs,
+ &extent);
+ if (status)
+ return status;
+
+ _cairo_rectangle_intersect (&extent, &surface->current_clip);
+ status = _cairo_analysis_surface_add_operation (surface, &extent, backend_status);
+
return status;
}
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
NULL, /* create_similar */
- NULL, /* finish_surface */
+ _cairo_analysis_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
NULL, /* acquire_dest_image */
@@ -190,7 +432,7 @@ static const cairo_surface_backend_t cai
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
- NULL, /* clip_path */
+ _cairo_analysis_surface_intersect_clip_path,
_cairo_analysis_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
@@ -206,7 +448,7 @@ static const cairo_surface_backend_t cai
NULL, /* snapshot */
};
-cairo_private cairo_surface_t *
+cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target,
int width,
int height)
@@ -226,7 +468,15 @@ _cairo_analysis_surface_create (cairo_su
surface->height = height;
surface->target = target;
- surface->fallback = FALSE;
+ surface->has_supported = FALSE;
+ surface->has_unsupported = FALSE;
+ _cairo_region_init (&surface->supported_region);
+ _cairo_region_init (&surface->fallback_region);
+
+ surface->current_clip.x = 0;
+ surface->current_clip.y = 0;
+ surface->current_clip.width = width;
+ surface->current_clip.height = height;
return &surface->base;
FAIL:
@@ -234,24 +484,34 @@ FAIL:
return NULL;
}
-cairo_private cairo_region_t *
+cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
{
- /* XXX */
- return NULL;
+ cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
+
+ return &surface->supported_region;
}
-cairo_private cairo_region_t *
+cairo_region_t *
_cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
{
- /* XXX */
- return NULL;
+ cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
+
+ return &surface->fallback_region;
+}
+
+cairo_bool_t
+_cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
+{
+ cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
+
+ return surface->has_supported;
}
-cairo_private cairo_bool_t
+cairo_bool_t
_cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
- return surface->fallback;
+ return surface->has_unsupported;
}
diff --git a/src/cairo-meta-surface-private.h b/src/cairo-meta-surface-private.h
index 3f2d390..b6d5730 100644
--- a/src/cairo-meta-surface-private.h
+++ b/src/cairo-meta-surface-private.h
@@ -31,6 +31,7 @@
*
* Contributor(s):
* Kristian Høgsberg <krh at redhat.com>
+ * Adrian Johnson <ajohnson at redneon.com>
*/
#ifndef CAIRO_META_SURFACE_H
@@ -57,21 +58,32 @@ typedef enum {
} cairo_command_type_t;
-typedef struct _cairo_command_paint {
+typedef enum {
+ CAIRO_META_REGION_ALL,
+ CAIRO_META_REGION_NATIVE,
+ CAIRO_META_REGION_IMAGE_FALLBACK,
+} cairo_meta_region_type_t;
+
+typedef struct _cairo_command_header {
cairo_command_type_t type;
+ cairo_meta_region_type_t region;
+} 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_type_t type;
+ 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_type_t type;
+ cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
@@ -83,7 +95,7 @@ typedef struct _cairo_command_stroke {
} cairo_command_stroke_t;
typedef struct _cairo_command_fill {
- cairo_command_type_t type;
+ cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
@@ -93,7 +105,7 @@ typedef struct _cairo_command_fill {
} cairo_command_fill_t;
typedef struct _cairo_command_show_glyphs {
- cairo_command_type_t type;
+ cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
cairo_glyph_t *glyphs;
@@ -102,7 +114,7 @@ typedef struct _cairo_command_show_glyph
} cairo_command_show_glyphs_t;
typedef struct _cairo_command_intersect_clip_path {
- cairo_command_type_t type;
+ cairo_command_header_t header;
cairo_path_fixed_t *path_pointer;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
@@ -111,7 +123,7 @@ typedef struct _cairo_command_intersect_
} cairo_command_intersect_clip_path_t;
typedef union _cairo_command {
- cairo_command_type_t type;
+ cairo_command_header_t header;
/* The 5 basic drawing operations. */
cairo_command_paint_t paint;
@@ -151,6 +163,14 @@ cairo_private cairo_status_t
_cairo_meta_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target);
+cairo_private cairo_status_t
+_cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
+ cairo_surface_t *target);
+cairo_private cairo_status_t
+_cairo_meta_surface_replay_region (cairo_surface_t *surface,
+ cairo_surface_t *target,
+ cairo_meta_region_type_t region);
+
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 9997baf..35039ad 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
+ * Copyright © 2007 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -32,6 +33,7 @@
* Contributor(s):
* Kristian Høgsberg <krh at redhat.com>
* Carl Worth <cworth at cworth.org>
+ * Adrian Johnson <ajohnson at redneon.com>
*/
/* A meta surface is a surface that records all drawing operations at
@@ -123,7 +125,7 @@ _cairo_meta_surface_finish (void *abstra
elements = _cairo_array_index (&meta->commands, 0);
for (i = 0; i < num_elements; i++) {
command = elements[i];
- switch (command->type) {
+ switch (command->header.type) {
/* 5 basic drawing operations */
@@ -253,7 +255,8 @@ _cairo_meta_surface_paint (void *abstr
if (command == NULL)
return CAIRO_STATUS_NO_MEMORY;
- command->type = CAIRO_COMMAND_PAINT;
+ command->header.type = CAIRO_COMMAND_PAINT;
+ command->header.region = CAIRO_META_REGION_ALL;
command->op = op;
status = _init_pattern_with_snapshot (&command->source.base, source);
@@ -287,7 +290,8 @@ _cairo_meta_surface_mask (void *abstra
if (command == NULL)
return CAIRO_STATUS_NO_MEMORY;
- command->type = CAIRO_COMMAND_MASK;
+ command->header.type = CAIRO_COMMAND_MASK;
+ command->header.region = CAIRO_META_REGION_ALL;
command->op = op;
status = _init_pattern_with_snapshot (&command->source.base, source);
@@ -332,7 +336,8 @@ _cairo_meta_surface_stroke (void *abst
if (command == NULL)
return CAIRO_STATUS_NO_MEMORY;
- command->type = CAIRO_COMMAND_STROKE;
+ command->header.type = CAIRO_COMMAND_STROKE;
+ command->header.region = CAIRO_META_REGION_ALL;
command->op = op;
status = _init_pattern_with_snapshot (&command->source.base, source);
@@ -386,7 +391,8 @@ _cairo_meta_surface_fill (void *abstra
if (command == NULL)
return CAIRO_STATUS_NO_MEMORY;
- command->type = CAIRO_COMMAND_FILL;
+ command->header.type = CAIRO_COMMAND_FILL;
+ command->header.region = CAIRO_META_REGION_ALL;
command->op = op;
status = _init_pattern_with_snapshot (&command->source.base, source);
@@ -432,7 +438,8 @@ _cairo_meta_surface_show_glyphs (void
if (command == NULL)
return CAIRO_STATUS_NO_MEMORY;
- command->type = CAIRO_COMMAND_SHOW_GLYPHS;
+ command->header.type = CAIRO_COMMAND_SHOW_GLYPHS;
+ command->header.region = CAIRO_META_REGION_ALL;
command->op = op;
status = _init_pattern_with_snapshot (&command->source.base, source);
@@ -521,7 +528,8 @@ _cairo_meta_surface_intersect_clip_path
if (command == NULL)
return CAIRO_STATUS_NO_MEMORY;
- command->type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
+ 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);
@@ -622,7 +630,7 @@ static const cairo_surface_backend_t cai
static cairo_path_fixed_t *
_cairo_command_get_path (cairo_command_t *command)
{
- switch (command->type) {
+ switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
case CAIRO_COMMAND_MASK:
case CAIRO_COMMAND_SHOW_GLYPHS:
@@ -639,9 +647,11 @@ _cairo_command_get_path (cairo_command_t
return NULL;
}
-cairo_status_t
-_cairo_meta_surface_replay (cairo_surface_t *surface,
- cairo_surface_t *target)
+static cairo_status_t
+_cairo_meta_surface_replay_internal (cairo_surface_t *surface,
+ cairo_surface_t *target,
+ cairo_bool_t create_regions,
+ cairo_meta_region_type_t region)
{
cairo_meta_surface_t *meta;
cairo_command_t *command, **elements;
@@ -665,9 +675,14 @@ _cairo_meta_surface_replay (cairo_surfac
for (i = meta->replay_start_idx; i < num_elements; i++) {
command = elements[i];
+ if (!create_regions && 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->type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
+ if (command->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
status = _cairo_surface_set_clip (target, &clip);
if (status)
break;
@@ -682,7 +697,7 @@ _cairo_meta_surface_replay (cairo_surfac
dev_path = &path_copy;
}
- switch (command->type) {
+ switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
status = _cairo_surface_paint (target,
command->paint.op,
@@ -770,6 +785,7 @@ _cairo_meta_surface_replay (cairo_surfac
command->intersect_clip_path.tolerance,
command->intersect_clip_path.antialias,
target);
+ assert (status == 0);
break;
default:
ASSERT_NOT_REACHED;
@@ -778,6 +794,14 @@ _cairo_meta_surface_replay (cairo_surfac
if (dev_path == &path_copy)
_cairo_path_fixed_fini (&path_copy);
+ if (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;
+ }
+ }
if (status)
break;
}
@@ -786,3 +810,31 @@ _cairo_meta_surface_replay (cairo_surfac
return status;
}
+
+cairo_status_t
+_cairo_meta_surface_replay (cairo_surface_t *surface,
+ cairo_surface_t *target)
+{
+ return _cairo_meta_surface_replay_internal (surface, target, FALSE, CAIRO_META_REGION_ALL);
+}
+
+/* Replay meta to surface. When the return status of each operation is
+ * one of CAIRO_STATUS_SUCCESS, CAIRO_INT_STATUS_UNSUPPORTED, or
+ * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
+ * will be stored in the meta surface. Any other status will abort the
+ * replay and return the status.
+ */
+cairo_status_t
+_cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
+ cairo_surface_t *target)
+{
+ return _cairo_meta_surface_replay_internal (surface, target, TRUE, CAIRO_META_REGION_ALL);
+}
+
+cairo_status_t
+_cairo_meta_surface_replay_region (cairo_surface_t *surface,
+ cairo_surface_t *target,
+ cairo_meta_region_type_t region)
+{
+ return _cairo_meta_surface_replay_internal (surface, target, FALSE, region);
+}
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index d687037..1886bef 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
+ * Copyright © 2007 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -32,6 +33,7 @@
* Contributor(s):
* Carl Worth <cworth at cworth.org>
* Keith Packard <keithp at keithp.com>
+ * Adrian Johnson <ajohnson at redneon.com>
*/
/* The paginated surface layer exists to provide as much code sharing
@@ -210,12 +212,54 @@ _cairo_paginated_surface_release_source_
}
static cairo_int_status_t
-_paint_page (cairo_paginated_surface_t *surface)
+_paint_fallback_image (cairo_paginated_surface_t *surface,
+ cairo_box_int_t *box)
{
- cairo_surface_t *analysis;
+ double x_scale = surface->base.x_fallback_resolution / 72.0;
+ double y_scale = surface->base.y_fallback_resolution / 72.0;
+ cairo_matrix_t matrix;
+ int x, y, width, height;
+ cairo_status_t status;
cairo_surface_t *image;
cairo_pattern_t *pattern;
+
+ x = box->p1.x;
+ y = box->p1.y;
+ width = box->p2.x - x;
+ height = box->p2.y - y;
+ image = _cairo_paginated_surface_create_image_surface (surface,
+ width * x_scale,
+ height * y_scale);
+ _cairo_surface_set_device_scale (image, x_scale, y_scale);
+ /* set_device_offset just sets the x0/y0 components of the matrix;
+ * so we have to do the scaling manually. */
+ cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
+
+ status = _cairo_meta_surface_replay (surface->meta, image);
+ if (status)
+ goto CLEANUP_IMAGE;
+
+ pattern = cairo_pattern_create_for_surface (image);
+ cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ status = _cairo_surface_paint (surface->target,
+ CAIRO_OPERATOR_SOURCE,
+ pattern);
+
+ cairo_pattern_destroy (pattern);
+CLEANUP_IMAGE:
+ cairo_surface_destroy (image);
+
+ return status;
+}
+
+static cairo_int_status_t
+_paint_page (cairo_paginated_surface_t *surface)
+{
+ cairo_surface_t *analysis;
cairo_status_t status;
+ cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
analysis = _cairo_analysis_surface_create (surface->target,
surface->width, surface->height);
@@ -223,7 +267,7 @@ _paint_page (cairo_paginated_surface_t *
return CAIRO_STATUS_NO_MEMORY;
surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE);
- status = _cairo_meta_surface_replay (surface->meta, analysis);
+ status = _cairo_meta_surface_replay_and_create_regions (surface->meta, analysis);
surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER);
if (status || analysis->status) {
@@ -233,35 +277,70 @@ _paint_page (cairo_paginated_surface_t *
return status;
}
- if (_cairo_analysis_surface_has_unsupported (analysis))
- {
- double x_scale = surface->base.x_fallback_resolution / 72.0;
- double y_scale = surface->base.y_fallback_resolution / 72.0;
- cairo_matrix_t matrix;
-
- image = _cairo_paginated_surface_create_image_surface (surface,
- surface->width * x_scale,
- surface->height * y_scale);
- _cairo_surface_set_device_scale (image, x_scale, y_scale);
+ /* Finer grained fallbacks are currently only supported for PostScript surfaces */
+ if (surface->target->type == CAIRO_SURFACE_TYPE_PS) {
+ 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;
+ }
- status = _cairo_meta_surface_replay (surface->meta, image);
+ if (has_supported) {
+ status = _cairo_meta_surface_replay_region (surface->meta,
+ surface->target,
+ CAIRO_META_REGION_NATIVE);
if (status)
- goto CLEANUP_IMAGE;
-
- pattern = cairo_pattern_create_for_surface (image);
- cairo_matrix_init_scale (&matrix, x_scale, y_scale);
- cairo_pattern_set_matrix (pattern, &matrix);
-
- status = _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern);
+ return status;
+ }
- cairo_pattern_destroy (pattern);
+ if (has_page_fallback)
+ {
+ cairo_box_int_t box;
- CLEANUP_IMAGE:
- cairo_surface_destroy (image);
+ box.p1.x = 0;
+ box.p1.y = 0;
+ box.p2.x = surface->width;
+ box.p2.y = surface->height;
+ status = _paint_fallback_image (surface, &box);
+ if (status)
+ return status;
}
- else
+
+ if (has_finegrained_fallback)
{
- status = _cairo_meta_surface_replay (surface->meta, surface->target);
+ cairo_region_t *region;
+ cairo_box_int_t *boxes;
+ int num_boxes, i;
+
+ /* 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 (status)
+ return status;
+
+ region = _cairo_analysis_surface_get_unsupported (analysis);
+ status = _cairo_region_get_boxes (region, &num_boxes, &boxes);
+ if (status)
+ return status;
+ for (i = 0; i < num_boxes; i++) {
+ status = _paint_fallback_image (surface, &boxes[i]);
+ if (status) {
+ _cairo_region_boxes_fini (region, boxes);
+ return status;
+ }
+ }
+ _cairo_region_boxes_fini (region, boxes);
}
cairo_surface_destroy (analysis);
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 05746a8..df78212 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1359,34 +1359,53 @@ pattern_supported (const cairo_pattern_t
}
static cairo_int_status_t
-_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *pattern)
+_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern)
{
- if (surface->force_fallbacks)
- return FALSE;
+ if (surface->force_fallbacks && surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
if (! pattern_supported (pattern))
- return FALSE;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (op == CAIRO_OPERATOR_SOURCE)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (op != CAIRO_OPERATOR_OVER)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
+ * the pattern contains transparency, we return
+ * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis
+ * surface. If the analysis surface determines that there is
+ * anything drawn under this operation, a fallback image will be
+ * used. Otherwise the operation will be replayed during the
+ * render stage and we blend the transarency into the white
+ * background to convert the pattern to opaque.
+ */
if (_cairo_operator_always_opaque (op))
- return TRUE;
+ return CAIRO_STATUS_SUCCESS;
if (_cairo_operator_always_translucent (op))
- return FALSE;
+ return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
- return _cairo_pattern_is_opaque (pattern);
+ if (_cairo_pattern_is_opaque (pattern))
+ return CAIRO_STATUS_SUCCESS;
+ else
+ return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
}
-static cairo_int_status_t
-_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *pattern)
+static cairo_bool_t
+_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern)
{
- if (_cairo_ps_surface_operation_supported (surface, op, pattern))
- return CAIRO_STATUS_SUCCESS;
+ if (_cairo_ps_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
+ return TRUE;
else
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return FALSE;
}
/* The "standard" implementation limit for PostScript string sizes is
@@ -1514,8 +1533,8 @@ _string_array_stream_create (cairo_outpu
static cairo_status_t
_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
- cairo_image_surface_t *image,
- const char *name)
+ cairo_image_surface_t *image,
+ const char *name)
{
cairo_status_t status, status2;
unsigned char *rgb, *compressed;
@@ -1659,24 +1678,33 @@ _cairo_ps_surface_emit_image (cairo_ps_s
}
static void
-_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
- cairo_solid_pattern_t *pattern)
+_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
+ cairo_solid_pattern_t *pattern)
{
- if (color_is_gray (&pattern->color))
+ cairo_color_t color = pattern->color;
+
+ if (!CAIRO_COLOR_IS_OPAQUE(&color)) {
+ /* Blend into white */
+ color.red = color.red*color.alpha + 1 - color.alpha;
+ color.green = color.green*color.alpha + 1 - color.alpha;
+ color.blue = color.blue*color.alpha + 1 - color.alpha;
+ }
+
+ if (color_is_gray (&color))
_cairo_output_stream_printf (surface->stream,
"%f G\n",
- pattern->color.red);
+ color.red);
else
_cairo_output_stream_printf (surface->stream,
"%f %f %f R\n",
- pattern->color.red,
- pattern->color.green,
- pattern->color.blue);
+ color.red,
+ color.green,
+ color.blue);
}
static cairo_status_t
-_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
- cairo_surface_pattern_t *pattern)
+_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
+ cairo_surface_pattern_t *pattern)
{
cairo_status_t status;
double bbox_width, bbox_height;
@@ -1919,15 +1947,7 @@ _cairo_ps_surface_paint (void *abstrac
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_ps_surface_analyze_operation (surface, op, source);
- /* XXX: It would be nice to be able to assert this condition
- * here. But, we actually allow one 'cheat' that is used when
- * painting the final image-based fallbacks. The final fallbacks
- * do have alpha which we support by blending with white. This is
- * possible only because there is nothing between the fallback
- * images and the paper, nor is anything painted above. */
- /*
- assert (_cairo_ps_surface_operation_supported (op, source));
- */
+ assert (_cairo_ps_surface_operation_supported (surface, op, source));
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_paint\n");
@@ -2017,7 +2037,6 @@ _cairo_ps_surface_stroke (void *abstra
assert (_cairo_ps_surface_operation_supported (surface, op, source));
-
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_stroke\n");
diff --git a/src/cairo-region-private.h b/src/cairo-region-private.h
index a3ee759..7f92f9c 100644
--- a/src/cairo-region-private.h
+++ b/src/cairo-region-private.h
@@ -102,4 +102,8 @@ cairo_private void
_cairo_region_translate (cairo_region_t *region,
int x, int y);
+cairo_private pixman_region_overlap_t
+_cairo_region_contains_rectangle (cairo_region_t *region, cairo_rectangle_int_t *box);
+
+
#endif /* CAIRO_REGION_PRIVATE_H */
diff --git a/src/cairo-region.c b/src/cairo-region.c
index fe2b405..4fe6832 100644
--- a/src/cairo-region.c
+++ b/src/cairo-region.c
@@ -207,3 +207,16 @@ _cairo_region_translate (cairo_region_t
{
pixman_region_translate (®ion->rgn, x, y);
}
+
+pixman_region_overlap_t
+_cairo_region_contains_rectangle (cairo_region_t *region, cairo_rectangle_int_t *rect)
+{
+ pixman_box16_t pbox;
+
+ pbox.x1 = rect->x;
+ pbox.y1 = rect->y;
+ pbox.x2 = rect->x + rect->width;
+ pbox.y2 = rect->y + rect->height;
+
+ return pixman_region_contains_rectangle (®ion->rgn, &pbox);
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index dca8e6a..fd3a647 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -325,7 +325,9 @@ typedef enum cairo_int_status {
CAIRO_INT_STATUS_DEGENERATE = 1000,
CAIRO_INT_STATUS_UNSUPPORTED,
CAIRO_INT_STATUS_NOTHING_TO_DO,
- CAIRO_INT_STATUS_CACHE_EMPTY
+ CAIRO_INT_STATUS_CACHE_EMPTY,
+ CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY,
+ CAIRO_INT_STATUS_IMAGE_FALLBACK
} cairo_int_status_t;
typedef enum cairo_internal_surface_type {
More information about the cairo-commit
mailing list