[cairo-commit] 5 commits - src/cairo-surface.c src/cairo-surface-subsurface.c src/cairo-surface-subsurface-private.h src/cairo-xcb-screen.c src/cairo-xlib-render-compositor.c src/cairo-xlib-source.c

Chris Wilson ickle at kemper.freedesktop.org
Wed Nov 23 09:42:48 PST 2011


 src/cairo-surface-subsurface-private.h |    4 +
 src/cairo-surface-subsurface.c         |   28 +++++++
 src/cairo-surface.c                    |   53 ++++++++------
 src/cairo-xcb-screen.c                 |    4 -
 src/cairo-xlib-render-compositor.c     |    8 +-
 src/cairo-xlib-source.c                |  124 +++++++++++++++++++++++++++++++++
 6 files changed, 194 insertions(+), 27 deletions(-)

New commits:
commit 49d3a6a95e52876a8660855589d01bd0ec8ab473
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Nov 23 17:34:29 2011 +0000

    xlib: Cache the subsurface Picture
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
index c00953e..eca4fa9 100644
--- a/src/cairo-xlib-source.c
+++ b/src/cairo-xlib-source.c
@@ -551,6 +551,7 @@ subsurface_source (cairo_xlib_surface_t *dst,
 {
     cairo_surface_subsurface_t *sub;
     cairo_xlib_surface_t *src;
+    cairo_xlib_source_t *source;
     Display *dpy = dst->display->display;
     cairo_bool_t is_contained = FALSE;
     cairo_int_status_t status;
@@ -580,32 +581,44 @@ subsurface_source (cairo_xlib_surface_t *dst,
 	return cairo_surface_reference (&src->base);
     }
 
-    src = (cairo_xlib_surface_t *)
-	_cairo_surface_create_similar_scratch (&dst->base,
-					       sub->base.content,
-					       sub->extents.width,
-					       sub->extents.height);
-    if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
-	cairo_surface_destroy (&src->base);
-	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
-    }
+    if (sub->snapshot) {
+	src = (cairo_xlib_surface_t *) cairo_surface_reference (sub->snapshot);
+	source = &src->embedded_source;
+    } else {
+	src = (cairo_xlib_surface_t *)
+	    _cairo_surface_create_similar_scratch (&dst->base,
+						   sub->base.content,
+						   sub->extents.width,
+						   sub->extents.height);
+	if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	    cairo_surface_destroy (&src->base);
+	    return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+	}
 
-    _cairo_pattern_init_for_surface (&local_pattern, sub->target);
-    cairo_matrix_init_translate (&local_pattern.base.matrix,
-				 sub->extents.x, sub->extents.y);
-    local_pattern.base.filter = CAIRO_FILTER_NEAREST;
-    status = _cairo_surface_paint (&src->base,
-				   CAIRO_OPERATOR_SOURCE,
-				   &local_pattern.base,
-				   NULL);
-    _cairo_pattern_fini (&local_pattern.base);
+	_cairo_pattern_init_for_surface (&local_pattern, sub->target);
+	cairo_matrix_init_translate (&local_pattern.base.matrix,
+				     sub->extents.x, sub->extents.y);
+	local_pattern.base.filter = CAIRO_FILTER_NEAREST;
+	status = _cairo_surface_paint (&src->base,
+				       CAIRO_OPERATOR_SOURCE,
+				       &local_pattern.base,
+				       NULL);
+	_cairo_pattern_fini (&local_pattern.base);
 
-    if (unlikely (status)) {
-	cairo_surface_destroy (&src->base);
-	return _cairo_surface_create_in_error (status);
-    }
+	if (unlikely (status)) {
+	    cairo_surface_destroy (&src->base);
+	    return _cairo_surface_create_in_error (status);
+	}
 
-    _cairo_xlib_surface_ensure_picture (src);
+	_cairo_xlib_surface_ensure_picture (src);
+	_cairo_surface_subsurface_set_snapshot (&sub->base, &src->base);
+
+	source = &src->embedded_source;
+	source->has_component_alpha = 0;
+	source->has_matrix = 0;
+	source->filter = CAIRO_FILTER_NEAREST;
+	source->extend = CAIRO_EXTEND_NONE;
+    }
 
     status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
 						    pattern->base.filter,
@@ -613,20 +626,32 @@ subsurface_source (cairo_xlib_surface_t *dst,
 						    extents->y + extents->height / 2,
 						    (pixman_transform_t *)&xtransform,
 						    src_x, src_y);
+    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
+	if (source->has_matrix) {
+	    source->has_matrix = 0;
+	    memcpy (&xtransform, &identity, sizeof (identity));
+	    status = CAIRO_INT_STATUS_SUCCESS;
+	}
+    } else
+	source->has_matrix = 1;
     if (status == CAIRO_INT_STATUS_SUCCESS)
 	XRenderSetPictureTransform (dpy, src->picture, &xtransform);
 
-    if (pattern->base.filter != CAIRO_FILTER_NEAREST)
+    if (source->filter != pattern->base.filter) {
 	picture_set_filter (dpy, src->picture, pattern->base.filter);
+	source->filter = pattern->base.filter;
+    }
 
-    if (pattern->base.has_component_alpha) {
-	pa.component_alpha = 1;
+    if (source->has_component_alpha != pattern->base.has_component_alpha) {
+	pa.component_alpha = pattern->base.has_component_alpha;
 	mask |= CPComponentAlpha;
+	source->has_component_alpha = pattern->base.has_component_alpha;
     }
 
-    if (pattern->base.extend != CAIRO_EXTEND_NONE) {
+    if (source->extend != pattern->base.extend) {
 	pa.repeat = extend_to_repeat (pattern->base.extend);
 	mask |= CPRepeat;
+	source->extend = pattern->base.extend;
     }
 
     if (mask)
commit 763d98071e2bdcddb7694e993905d27345b54b2d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Nov 23 17:32:53 2011 +0000

    surface: Bump reference count around finish
    
    In order to handle reference cycles during finish (through snapshots) we
    need to bump the reference on the surface first.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index c026a3d..a7e0430 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -150,6 +150,8 @@ static DEFINE_NIL_SURFACE(CAIRO_STATUS_DEVICE_ERROR, _cairo_surface_nil_device_e
 static DEFINE_NIL_SURFACE(CAIRO_INT_STATUS_UNSUPPORTED, _cairo_surface_nil_unsupported);
 static DEFINE_NIL_SURFACE(CAIRO_INT_STATUS_NOTHING_TO_DO, _cairo_surface_nil_nothing_to_do);
 
+static void _cairo_surface_finish (cairo_surface_t *surface);
+
 /**
  * _cairo_surface_set_error:
  * @surface: a surface
@@ -841,7 +843,7 @@ cairo_surface_destroy (cairo_surface_t *surface)
     assert (surface->snapshot_of == NULL);
 
     if (! surface->finished)
-	cairo_surface_finish (surface);
+	_cairo_surface_finish (surface);
 
     /* paranoid check that nobody took a reference whilst finishing */
     assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
@@ -880,6 +882,31 @@ cairo_surface_get_reference_count (cairo_surface_t *surface)
     return CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count);
 }
 
+static void
+_cairo_surface_finish (cairo_surface_t *surface)
+{
+    cairo_status_t status;
+
+    cairo_surface_flush (surface);
+
+    /* update the snapshots *before* we declare the surface as finished */
+    _cairo_surface_detach_snapshots (surface);
+    if (surface->snapshot_of != NULL)
+	_cairo_surface_detach_snapshot (surface);
+
+    surface->finished = TRUE;
+
+    /* call finish even if in error mode */
+    if (surface->backend->finish) {
+	status = surface->backend->finish (surface);
+	if (unlikely (status))
+	    _cairo_surface_set_error (surface, status);
+    }
+
+    assert (surface->snapshot_of == NULL);
+    assert (!_cairo_surface_has_snapshots (surface));
+}
+
 /**
  * cairo_surface_finish:
  * @surface: the #cairo_surface_t to finish
@@ -902,8 +929,6 @@ cairo_surface_get_reference_count (cairo_surface_t *surface)
 void
 cairo_surface_finish (cairo_surface_t *surface)
 {
-    cairo_status_t status;
-
     if (surface == NULL)
 	return;
 
@@ -913,24 +938,10 @@ cairo_surface_finish (cairo_surface_t *surface)
     if (surface->finished)
 	return;
 
-    cairo_surface_flush (surface);
-
-    /* update the snapshots *before* we declare the surface as finished */
-    _cairo_surface_detach_snapshots (surface);
-    if (surface->snapshot_of != NULL)
-	_cairo_surface_detach_snapshot (surface);
-
-    surface->finished = TRUE;
-
-    /* call finish even if in error mode */
-    if (surface->backend->finish) {
-	status = surface->backend->finish (surface);
-	if (unlikely (status))
-	    _cairo_surface_set_error (surface, status);
-    }
-
-    assert (surface->snapshot_of == NULL);
-    assert (!_cairo_surface_has_snapshots (surface));
+    /* We have to becareful when decoupling potential reference cycles */
+    cairo_surface_reference (surface);
+    _cairo_surface_finish (surface);
+    cairo_surface_destroy (surface);
 }
 slim_hidden_def (cairo_surface_finish);
 
diff --git a/src/cairo-xcb-screen.c b/src/cairo-xcb-screen.c
index 18e75a5..9dd476e 100644
--- a/src/cairo-xcb-screen.c
+++ b/src/cairo-xcb-screen.c
@@ -57,9 +57,7 @@ _cairo_xcb_screen_finish (cairo_xcb_screen_t *screen)
 					   cairo_xcb_surface_t,
 					   link)->base;
 
-	cairo_surface_reference (surface);
 	cairo_surface_finish (surface);
-	cairo_surface_destroy (surface);
     }
 
     while (! cairo_list_is_empty (&screen->pictures)) {
@@ -69,9 +67,7 @@ _cairo_xcb_screen_finish (cairo_xcb_screen_t *screen)
 					   cairo_xcb_picture_t,
 					   link)->base;
 
-	cairo_surface_reference (surface);
 	cairo_surface_finish (surface);
-	cairo_surface_destroy (surface);
     }
 
     for (i = 0; i < screen->solid_cache_size; i++)
commit 2fb4a0e119b075921442dd2266f4dcc24c9f12e7
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Nov 23 15:49:53 2011 +0000

    subsurface: Support caching for cloned subsurfaces
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-surface-subsurface-private.h b/src/cairo-surface-subsurface-private.h
index 6a43c8f..dc0e82b 100644
--- a/src/cairo-surface-subsurface-private.h
+++ b/src/cairo-surface-subsurface-private.h
@@ -45,6 +45,7 @@ struct _cairo_surface_subsurface {
     cairo_rectangle_int_t extents;
 
     cairo_surface_t *target;
+    cairo_surface_t *snapshot;
 };
 
 static inline cairo_surface_t *
@@ -78,4 +79,7 @@ _cairo_surface_is_subsurface (cairo_surface_t *surface)
     return surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE;
 }
 
+void
+_cairo_surface_subsurface_set_snapshot (cairo_surface_t *surface,
+					cairo_surface_t *snapshot);
 #endif /* CAIRO_SURFACE_SUBSURFACE_PRIVATE_H */
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 49f181c..2fb9562 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -50,6 +50,7 @@ _cairo_surface_subsurface_finish (void *abstract_surface)
     cairo_surface_subsurface_t *surface = abstract_surface;
 
     cairo_surface_destroy (surface->target);
+    cairo_surface_destroy (surface->snapshot);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -471,6 +472,8 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
     surface->target = cairo_surface_reference (target);
     surface->base.type = surface->target->type;
 
+    surface->snapshot = NULL;
+
     return &surface->base;
 }
 
@@ -501,9 +504,34 @@ _cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
     surface->extents = *extents;
     surface->extents.x += target->device_transform.x0;
     surface->extents.y += target->device_transform.y0;
+
     surface->target = cairo_surface_reference (target);
     surface->base.type = surface->target->type;
 
+    surface->snapshot = NULL;
+
     return &surface->base;
 }
 /* XXX observe mark-dirty */
+
+static void
+_cairo_surface_subsurface_detach_snapshot (cairo_surface_t *surface)
+{
+    cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface;
+
+    cairo_surface_destroy (ss->snapshot);
+    ss->snapshot = NULL;
+}
+
+void
+_cairo_surface_subsurface_set_snapshot (cairo_surface_t *surface,
+					cairo_surface_t *snapshot)
+{
+    cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface;
+
+    assert (ss->snapshot == NULL);
+    ss->snapshot = cairo_surface_reference (snapshot);
+
+    _cairo_surface_attach_snapshot (ss->target, &ss->base,
+				    _cairo_surface_subsurface_detach_snapshot);
+}
commit 894d8c8bf7cd83be8775c79233f21d9c11c14b2a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Nov 23 15:40:15 2011 +0000

    xlib: Handle subsurfaces correctly
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
index eb1dc8f..c00953e 100644
--- a/src/cairo-xlib-source.c
+++ b/src/cairo-xlib-source.c
@@ -542,6 +542,100 @@ solid_source (cairo_xlib_surface_t *dst,
 }
 
 static cairo_surface_t *
+subsurface_source (cairo_xlib_surface_t *dst,
+		   const cairo_surface_pattern_t *pattern,
+		   cairo_bool_t is_mask,
+		   const cairo_rectangle_int_t *extents,
+		   const cairo_rectangle_int_t *sample,
+		   int *src_x, int *src_y)
+{
+    cairo_surface_subsurface_t *sub;
+    cairo_xlib_surface_t *src;
+    Display *dpy = dst->display->display;
+    cairo_bool_t is_contained = FALSE;
+    cairo_int_status_t status;
+    cairo_surface_pattern_t local_pattern;
+    XTransform xtransform;
+    XRenderPictureAttributes pa;
+    unsigned mask = 0;
+
+    sub = (cairo_surface_subsurface_t *) pattern->surface;
+
+    if (sample->x >= 0 && sample->y >= 0 &&
+	sample->x + sample->width  <= sub->extents.width &&
+	sample->y + sample->height <= sub->extents.height)
+    {
+	is_contained = TRUE;
+    }
+
+    if (pattern->base.filter == CAIRO_FILTER_NEAREST && is_contained &&
+	_cairo_matrix_is_translation (&pattern->base.matrix))
+    {
+	src = (cairo_xlib_surface_t *) sub->target;
+	_cairo_xlib_surface_ensure_picture (src);
+
+	*src_x += pattern->base.matrix.x0 + sub->extents.x;
+	*src_y += pattern->base.matrix.y0 + sub->extents.y;
+
+	return cairo_surface_reference (&src->base);
+    }
+
+    src = (cairo_xlib_surface_t *)
+	_cairo_surface_create_similar_scratch (&dst->base,
+					       sub->base.content,
+					       sub->extents.width,
+					       sub->extents.height);
+    if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	cairo_surface_destroy (&src->base);
+	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    _cairo_pattern_init_for_surface (&local_pattern, sub->target);
+    cairo_matrix_init_translate (&local_pattern.base.matrix,
+				 sub->extents.x, sub->extents.y);
+    local_pattern.base.filter = CAIRO_FILTER_NEAREST;
+    status = _cairo_surface_paint (&src->base,
+				   CAIRO_OPERATOR_SOURCE,
+				   &local_pattern.base,
+				   NULL);
+    _cairo_pattern_fini (&local_pattern.base);
+
+    if (unlikely (status)) {
+	cairo_surface_destroy (&src->base);
+	return _cairo_surface_create_in_error (status);
+    }
+
+    _cairo_xlib_surface_ensure_picture (src);
+
+    status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
+						    pattern->base.filter,
+						    extents->x + extents->width / 2,
+						    extents->y + extents->height / 2,
+						    (pixman_transform_t *)&xtransform,
+						    src_x, src_y);
+    if (status == CAIRO_INT_STATUS_SUCCESS)
+	XRenderSetPictureTransform (dpy, src->picture, &xtransform);
+
+    if (pattern->base.filter != CAIRO_FILTER_NEAREST)
+	picture_set_filter (dpy, src->picture, pattern->base.filter);
+
+    if (pattern->base.has_component_alpha) {
+	pa.component_alpha = 1;
+	mask |= CPComponentAlpha;
+    }
+
+    if (pattern->base.extend != CAIRO_EXTEND_NONE) {
+	pa.repeat = extend_to_repeat (pattern->base.extend);
+	mask |= CPRepeat;
+    }
+
+    if (mask)
+	XRenderChangePicture (dpy, src->picture, mask, &pa);
+
+    return &src->base;
+}
+
+static cairo_surface_t *
 native_source (cairo_xlib_surface_t *dst,
 	       const cairo_surface_pattern_t *pattern,
 	       cairo_bool_t is_mask,
@@ -558,6 +652,11 @@ native_source (cairo_xlib_surface_t *dst,
     XRenderPictureAttributes pa;
     int mask = 0;
 
+    if (_cairo_surface_is_subsurface (pattern->surface))
+	return subsurface_source (dst, pattern, is_mask,
+				  extents, sample,
+				  src_x, src_y);
+
     src = (cairo_xlib_surface_t *)
 	    unwrap_surface (pattern->surface, src_x, src_y);
 
commit e217677ce6a3f853144d1bc2b33423e1e0a64773
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Nov 23 14:57:35 2011 +0000

    xlib: ADD only reduces to SOURCE for alpha-only targets
    
    Fixes operator.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-xlib-render-compositor.c b/src/cairo-xlib-render-compositor.c
index 4088281..5dd7668 100644
--- a/src/cairo-xlib-render-compositor.c
+++ b/src/cairo-xlib-render-compositor.c
@@ -313,8 +313,12 @@ fill_reduces_to_source (cairo_operator_t op,
 			const cairo_color_t *color,
 			cairo_xlib_surface_t *dst)
 {
-    if (dst->base.is_clear || CAIRO_COLOR_IS_OPAQUE (color))
-	return op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD;
+    if (dst->base.is_clear || CAIRO_COLOR_IS_OPAQUE (color)) {
+	if (op == CAIRO_OPERATOR_OVER)
+	    return TRUE;
+	if (op == CAIRO_OPERATOR_ADD)
+	    return (dst->base.content & CAIRO_CONTENT_COLOR) == 0;
+    }
 
     return FALSE;
 }


More information about the cairo-commit mailing list