summaryrefslogtreecommitdiff
path: root/src/cairo-recording-surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-recording-surface.c')
-rw-r--r--[-rwxr-xr-x]src/cairo-recording-surface.c139
1 files changed, 129 insertions, 10 deletions
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 9e672df2c..ee9304746 100755..100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -87,6 +87,7 @@
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-recording-surface-inline.h"
+#include "cairo-surface-snapshot-inline.h"
#include "cairo-surface-wrapper-private.h"
#include "cairo-traps-private.h"
@@ -257,7 +258,7 @@ static cairo_bool_t box_outside (const cairo_box_t *a, const cairo_box_t *b)
static void
bbtree_foreach_mark_visible (struct bbtree *bbt,
const cairo_box_t *box,
- int **indices)
+ unsigned int **indices)
{
cairo_command_header_t *chain;
@@ -270,13 +271,13 @@ bbtree_foreach_mark_visible (struct bbtree *bbt,
bbtree_foreach_mark_visible (bbt->right, box, indices);
}
-static inline int intcmp (const int a, const int b)
+static inline int intcmp (const unsigned int a, const unsigned int b)
{
return a - b;
}
-CAIRO_COMBSORT_DECLARE (sort_indices, int, intcmp)
+CAIRO_COMBSORT_DECLARE (sort_indices, unsigned int, intcmp)
-static inline int sizecmp (int a, int b, cairo_command_header_t **elements)
+static inline int sizecmp (unsigned int a, unsigned int b, cairo_command_header_t **elements)
{
const cairo_rectangle_int_t *r;
@@ -288,7 +289,7 @@ static inline int sizecmp (int a, int b, cairo_command_header_t **elements)
return b - a;
}
-CAIRO_COMBSORT_DECLARE_WITH_DATA (sort_commands, int, sizecmp)
+CAIRO_COMBSORT_DECLARE_WITH_DATA (sort_commands, unsigned int, sizecmp)
static void
_cairo_recording_surface_destroy_bbtree (cairo_recording_surface_t *surface)
@@ -323,9 +324,9 @@ _cairo_recording_surface_create_bbtree (cairo_recording_surface_t *surface)
if (unlikely (elements == NULL))
return _cairo_error (CAIRO_STATUS_NULL_POINTER);
+ unsigned int *indices;
cairo_status_t status;
- int i, count;
- int *indices;
+ unsigned int i, count;
count = surface->commands.num_elements;
if (count > surface->num_indices) {
@@ -423,6 +424,8 @@ cairo_recording_surface_create (cairo_content_t content,
surface->indices = NULL;
surface->num_indices = 0;
surface->optimize_clears = TRUE;
+ surface->has_bilevel_alpha = FALSE;
+ surface->has_only_op_over = FALSE;
return &surface->base;
}
@@ -1589,9 +1592,12 @@ static int
_cairo_recording_surface_get_visible_commands (cairo_recording_surface_t *surface,
const cairo_rectangle_int_t *extents)
{
- int num_visible, *indices;
+ unsigned int num_visible, *indices;
cairo_box_t box;
+ if (surface->commands.num_elements == 0)
+ return 0;
+
_cairo_box_from_rectangle (&box, extents);
if (surface->bbtree.chain == INVALID_CHAIN)
@@ -1606,6 +1612,68 @@ _cairo_recording_surface_get_visible_commands (cairo_recording_surface_t *surfac
return num_visible;
}
+static void
+_cairo_recording_surface_merge_source_attributes (cairo_recording_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source)
+{
+ if (op != CAIRO_OPERATOR_OVER)
+ surface->has_only_op_over = FALSE;
+
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) source;
+ cairo_surface_t *surf = surf_pat->surface;
+ cairo_surface_t *free_me = NULL;
+
+ if (_cairo_surface_is_snapshot (surf))
+ free_me = surf = _cairo_surface_snapshot_get_target (surf);
+
+ if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) {
+ cairo_recording_surface_t *rec_surf = (cairo_recording_surface_t *) surf;
+
+ if (! _cairo_recording_surface_has_only_bilevel_alpha (rec_surf))
+ surface->has_bilevel_alpha = FALSE;
+
+ if (! _cairo_recording_surface_has_only_op_over (rec_surf))
+ surface->has_only_op_over = FALSE;
+
+ } else if (surf->type == CAIRO_SURFACE_TYPE_IMAGE) {
+ cairo_image_surface_t *img_surf = (cairo_image_surface_t *) surf;
+
+ if (_cairo_image_analyze_transparency (img_surf) == CAIRO_IMAGE_HAS_ALPHA)
+ surface->has_bilevel_alpha = FALSE;
+
+ } else {
+ if (!_cairo_pattern_is_clear (source) && !_cairo_pattern_is_opaque (source, NULL))
+ surface->has_bilevel_alpha = FALSE;
+ }
+
+ cairo_surface_destroy (free_me);
+ return;
+
+ } else if (source->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
+ cairo_surface_t *image;
+ cairo_surface_t *raster;
+
+ image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ raster = _cairo_raster_source_pattern_acquire (source, image, NULL);
+ cairo_surface_destroy (image);
+ if (raster) {
+ if (raster->type == CAIRO_SURFACE_TYPE_IMAGE) {
+ if (_cairo_image_analyze_transparency ((cairo_image_surface_t *)raster) == CAIRO_IMAGE_HAS_ALPHA)
+ surface->has_bilevel_alpha = FALSE;
+ }
+
+ _cairo_raster_source_pattern_release (source, raster);
+ if (raster->type == CAIRO_SURFACE_TYPE_IMAGE)
+ return;
+ }
+ }
+
+ if (!_cairo_pattern_is_clear (source) && !_cairo_pattern_is_opaque (source, NULL))
+ surface->has_bilevel_alpha = FALSE;
+}
+
static cairo_status_t
_cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
const cairo_rectangle_int_t *surface_extents,
@@ -1624,7 +1692,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
cairo_rectangle_int_t extents;
cairo_bool_t use_indices = FALSE;
const cairo_rectangle_int_t *r;
- int i, num_elements;
+ unsigned int i, num_elements;
if (unlikely (surface->base.status))
return surface->base.status;
@@ -1655,6 +1723,9 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
if (! _cairo_surface_wrapper_get_target_extents (&wrapper, &extents))
goto done;
+ surface->has_bilevel_alpha = TRUE;
+ surface->has_only_op_over = TRUE;
+
num_elements = surface->commands.num_elements;
elements = _cairo_array_index (&surface->commands, 0);
if (elements == NULL) {
@@ -1665,7 +1736,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
if (extents.width < r->width || extents.height < r->height) {
num_elements =
_cairo_recording_surface_get_visible_commands (surface, &extents);
- use_indices = TRUE;
+ use_indices = num_elements != surface->commands.num_elements;
}
for (i = 0; i < num_elements; i++) {
@@ -1683,6 +1754,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
command->header.op,
&command->paint.source.base,
command->header.clip);
+ if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+ _cairo_recording_surface_merge_source_attributes (surface,
+ command->header.op,
+ &command->paint.source.base);
+ }
break;
case CAIRO_COMMAND_MASK:
@@ -1691,6 +1767,14 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
&command->mask.source.base,
&command->mask.mask.base,
command->header.clip);
+ if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+ _cairo_recording_surface_merge_source_attributes (surface,
+ command->header.op,
+ &command->mask.source.base);
+ _cairo_recording_surface_merge_source_attributes (surface,
+ command->header.op,
+ &command->mask.mask.base);
+ }
break;
case CAIRO_COMMAND_STROKE:
@@ -1704,6 +1788,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
command->stroke.tolerance,
command->stroke.antialias,
command->header.clip);
+ if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+ _cairo_recording_surface_merge_source_attributes (surface,
+ command->header.op,
+ &command->stroke.source.base);
+ }
break;
case CAIRO_COMMAND_FILL:
@@ -1745,6 +1834,14 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
stroke_command->stroke.tolerance,
stroke_command->stroke.antialias,
command->header.clip);
+ if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+ _cairo_recording_surface_merge_source_attributes (surface,
+ command->header.op,
+ &command->fill.source.base);
+ _cairo_recording_surface_merge_source_attributes (surface,
+ command->header.op,
+ &command->stroke.source.base);
+ }
i++;
}
}
@@ -1757,6 +1854,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
command->fill.tolerance,
command->fill.antialias,
command->header.clip);
+ if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+ _cairo_recording_surface_merge_source_attributes (surface,
+ command->header.op,
+ &command->fill.source.base);
+ }
}
break;
@@ -1770,6 +1872,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
command->show_text_glyphs.cluster_flags,
command->show_text_glyphs.scaled_font,
command->header.clip);
+ if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+ _cairo_recording_surface_merge_source_attributes (surface,
+ command->header.op,
+ &command->show_text_glyphs.source.base);
+ }
break;
default:
@@ -2083,3 +2190,15 @@ cairo_recording_surface_get_extents (cairo_surface_t *surface,
*extents = record->extents_pixels;
return TRUE;
}
+
+cairo_bool_t
+_cairo_recording_surface_has_only_bilevel_alpha (cairo_recording_surface_t *surface)
+{
+ return surface->has_bilevel_alpha;
+}
+
+cairo_bool_t
+_cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface)
+{
+ return surface->has_only_op_over;
+}