[cairo-commit] src/cairo-composite-rectangles.c src/cairo-composite-rectangles-private.h src/cairo-xcb-connection.c src/cairo-xcb-private.h src/cairo-xcb-surface.c src/cairo-xcb-surface-render.c

Chris Wilson ickle at kemper.freedesktop.org
Mon Sep 19 07:25:45 PDT 2011


 src/cairo-composite-rectangles-private.h |    4 
 src/cairo-composite-rectangles.c         |   18 +
 src/cairo-xcb-connection.c               |    6 
 src/cairo-xcb-private.h                  |   14 -
 src/cairo-xcb-surface-render.c           |  122 +++---------
 src/cairo-xcb-surface.c                  |  314 ++++++++++++++++++++++++-------
 6 files changed, 310 insertions(+), 168 deletions(-)

New commits:
commit fd613cb9f94daff0c8d4fdb27ff89894d41682a3
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Aug 2 13:51:30 2011 +0100

    xcb: track fallback damage
    
    And only upload the parts of the image that are modified during the
    fallback. I have to keep reminding myself that the goal is always to
    reduce the amount of fallbacks required...
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-composite-rectangles-private.h b/src/cairo-composite-rectangles-private.h
index 8603108..fd77289 100644
--- a/src/cairo-composite-rectangles-private.h
+++ b/src/cairo-composite-rectangles-private.h
@@ -147,6 +147,10 @@ cairo_private cairo_bool_t
 _cairo_composite_rectangles_can_reduce_clip (cairo_composite_rectangles_t *composite,
 					     cairo_clip_t *clip);
 
+cairo_private cairo_int_status_t
+_cairo_composite_rectangles_add_to_damage (cairo_composite_rectangles_t *composite,
+					   cairo_boxes_t *damage);
+
 cairo_private void
 _cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents);
 
diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c
index c66d3d6..7fc0f5f 100644
--- a/src/cairo-composite-rectangles.c
+++ b/src/cairo-composite-rectangles.c
@@ -436,3 +436,21 @@ _cairo_composite_rectangles_can_reduce_clip (cairo_composite_rectangles_t *compo
     _cairo_box_from_rectangle (&box, &extents);
     return _cairo_clip_contains_box (clip, &box);
 }
+
+cairo_int_status_t
+_cairo_composite_rectangles_add_to_damage (cairo_composite_rectangles_t *composite,
+					   cairo_boxes_t *damage)
+{
+    cairo_int_status_t status;
+    int n;
+
+    for (n = 0; n < composite->clip->num_boxes; n++) {
+	status = _cairo_boxes_add (damage,
+			  CAIRO_ANTIALIAS_NONE,
+			  &composite->clip->boxes[n]);
+	if (unlikely (status))
+	    return status;
+    }
+
+    return CAIRO_INT_STATUS_SUCCESS;
+}
diff --git a/src/cairo-xcb-connection.c b/src/cairo-xcb-connection.c
index 2808395..2c63a93 100644
--- a/src/cairo-xcb-connection.c
+++ b/src/cairo-xcb-connection.c
@@ -806,10 +806,9 @@ cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device,
                                          int minor_version)
 {
     cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
-    cairo_status_t status;
 
     if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
-	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+	_cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
 	return;
     }
 
@@ -843,10 +842,9 @@ cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
                                             int minor_version)
 {
     cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
-    cairo_status_t status;
 
     if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
-	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+	_cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
 	return;
     }
 
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index c27843a..42a112c 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -87,7 +87,8 @@ struct _cairo_xcb_shm_info {
 
 struct _cairo_xcb_surface {
     cairo_surface_t base;
-    cairo_surface_t *fallback;
+    cairo_image_surface_t *fallback;
+    cairo_boxes_t fallback_damage;
 
     cairo_xcb_connection_t *connection;
     cairo_xcb_screen_t *screen;
@@ -430,14 +431,14 @@ cairo_private cairo_int_status_t
 _cairo_xcb_surface_render_paint (cairo_xcb_surface_t	*surface,
 				 cairo_operator_t	 op,
 				 const cairo_pattern_t	*source,
-				 const cairo_clip_t		*clip);
+				 cairo_composite_rectangles_t *composite);
 
 cairo_private cairo_int_status_t
 _cairo_xcb_surface_render_mask (cairo_xcb_surface_t	*surface,
 				cairo_operator_t		 op,
 				const cairo_pattern_t	*source,
 				const cairo_pattern_t	*mask,
-				const cairo_clip_t		*clip);
+				cairo_composite_rectangles_t *composite);
 
 cairo_private cairo_int_status_t
 _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t		*surface,
@@ -449,7 +450,7 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t		*surface,
 				  const cairo_matrix_t		*ctm_inverse,
 				  double			 tolerance,
 				  cairo_antialias_t		 antialias,
-				  const cairo_clip_t		*clip);
+				  cairo_composite_rectangles_t *composite);
 
 cairo_private cairo_int_status_t
 _cairo_xcb_surface_render_fill (cairo_xcb_surface_t	*surface,
@@ -459,7 +460,7 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t	*surface,
 				cairo_fill_rule_t	 fill_rule,
 				double			 tolerance,
 				cairo_antialias_t	 antialias,
-				const cairo_clip_t	*clip);
+				cairo_composite_rectangles_t *composite);
 
 cairo_private cairo_int_status_t
 _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
@@ -468,7 +469,8 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
 				  cairo_scaled_font_t	*scaled_font,
 				  cairo_glyph_t		*glyphs,
 				  int			 num_glyphs,
-				  const cairo_clip_t		*clip);
+				  cairo_composite_rectangles_t *composite,
+				  cairo_bool_t overlap);
 cairo_private void
 _cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
 
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 42178b2..0cb7e15 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -3415,9 +3415,8 @@ cairo_int_status_t
 _cairo_xcb_surface_render_paint (cairo_xcb_surface_t	*surface,
 				 cairo_operator_t	 op,
 				 const cairo_pattern_t	*source,
-				 const cairo_clip_t	*clip)
+				 cairo_composite_rectangles_t *composite)
 {
-    cairo_composite_rectangles_t extents;
     cairo_boxes_t boxes;
     cairo_status_t status;
 
@@ -3430,36 +3429,20 @@ _cairo_xcb_surface_render_paint (cairo_xcb_surface_t	*surface,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) {
-	surface->deferred_clear = TRUE;
-	surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT;
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    if (clip == NULL &&
-	source->type == CAIRO_PATTERN_TYPE_SOLID &&
+    if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
 	(op == CAIRO_OPERATOR_SOURCE ||
+	 op == CAIRO_OPERATOR_CLEAR ||
 	 (surface->base.is_clear &&
 	  (op == CAIRO_OPERATOR_ADD || op == CAIRO_OPERATOR_OVER))))
     {
-	cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
 	surface->deferred_clear = TRUE;
-	surface->deferred_clear_color = solid->color;
+	surface->deferred_clear_color = composite->source_pattern.solid.color;
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    status = _cairo_composite_rectangles_init_for_paint (&extents,
-							 &surface->base,
-							 op, source,
-							 clip);
-    if (unlikely (status))
-	return status;
-
-     _cairo_clip_steal_boxes(extents.clip, &boxes);
-     status = _clip_and_composite_boxes (surface, op, source, &boxes, &extents);
-     _cairo_clip_unsteal_boxes (extents.clip, &boxes);
-
-    _cairo_composite_rectangles_fini (&extents);
+     _cairo_clip_steal_boxes(composite->clip, &boxes);
+     status = _clip_and_composite_boxes (surface, op, source, &boxes, composite);
+     _cairo_clip_unsteal_boxes (composite->clip, &boxes);
 
     return status;
 }
@@ -3469,9 +3452,8 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t	*surface,
 				cairo_operator_t	 op,
 				const cairo_pattern_t	*source,
 				const cairo_pattern_t	*mask,
-				const cairo_clip_t	*clip)
+				cairo_composite_rectangles_t *composite)
 {
-    cairo_composite_rectangles_t extents;
     cairo_status_t status;
 
     if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
@@ -3480,31 +3462,24 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t	*surface,
     if ((surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    status = _cairo_composite_rectangles_init_for_mask (&extents, &surface->base,
-							op, source, mask, clip);
-    if (unlikely (status))
-	return status;
-
     if (mask->type == CAIRO_PATTERN_TYPE_SOLID &&
-	extents.clip->path == NULL &&
-	! _cairo_clip_is_region (extents.clip)) {
+	composite->clip->path == NULL &&
+	! _cairo_clip_is_region (composite->clip)) {
 	status = _clip_and_composite (surface, op, source,
 				      _composite_opacity_boxes,
 				      _composite_opacity_boxes,
 				      (void *) mask,
-				      &extents, need_unbounded_clip (&extents));
+				      composite, need_unbounded_clip (composite));
     } else {
 	xcb_draw_func_t mask_func = NULL;
 	if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS)
-	    mask_func = extents.clip->path ? _composite_mask_clip : _composite_mask_clip_boxes;
+	    mask_func = composite->clip->path ? _composite_mask_clip : _composite_mask_clip_boxes;
 	status = _clip_and_composite (surface, op, source,
 				      _composite_mask, mask_func,
 				      (void *) mask,
-				      &extents, need_bounded_clip (&extents));
+				      composite, need_bounded_clip (composite));
     }
 
-    _cairo_composite_rectangles_fini (&extents);
-
     return status;
 }
 
@@ -3613,9 +3588,8 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t	*surface,
 				  const cairo_matrix_t	*ctm_inverse,
 				  double		 tolerance,
 				  cairo_antialias_t	 antialias,
-				  const cairo_clip_t		*clip)
+				  cairo_composite_rectangles_t *composite)
 {
-    cairo_composite_rectangles_t extents;
     cairo_int_status_t status;
 
     if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
@@ -3627,19 +3601,11 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t	*surface,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_composite_rectangles_init_for_stroke (&extents,
-							  &surface->base,
-							  op, source,
-							  path, style, ctm,
-							  clip);
-    if (unlikely (status))
-	return status;
-
     status = CAIRO_INT_STATUS_UNSUPPORTED;
     if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
 	cairo_boxes_t boxes;
 
-	_cairo_boxes_init_with_clip (&boxes, extents.clip);
+	_cairo_boxes_init_with_clip (&boxes, composite->clip);
 	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
 								style,
 								ctm,
@@ -3647,7 +3613,7 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t	*surface,
 								&boxes);
 	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
 	    status = _clip_and_composite_boxes (surface, op, source,
-						&boxes, &extents);
+						&boxes, composite);
 	}
 	_cairo_boxes_fini (&boxes);
     }
@@ -3658,20 +3624,18 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t	*surface,
 								  path, style,
 								  ctm, ctm_inverse,
 								  tolerance, antialias,
-								  &extents);
+								  composite);
 	} else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
 	    status = _cairo_xcb_surface_render_stroke_via_mask (surface, op, source,
 								path, style,
 								ctm, ctm_inverse,
 								tolerance, antialias,
-								&extents);
+								composite);
 	} else {
 	    ASSERT_NOT_REACHED;
 	}
     }
 
-    _cairo_composite_rectangles_fini (&extents);
-
     return status;
 }
 
@@ -3763,9 +3727,8 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t	*surface,
 			       cairo_fill_rule_t	 fill_rule,
 			       double			 tolerance,
 			       cairo_antialias_t	 antialias,
-			       const cairo_clip_t	*clip)
+			       cairo_composite_rectangles_t *composite)
 {
-    cairo_composite_rectangles_t extents;
     cairo_int_status_t status;
 
     if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
@@ -3777,24 +3740,18 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t	*surface,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_composite_rectangles_init_for_fill (&extents, &surface->base,
-							op, source, path,
-							clip);
-    if (unlikely (status))
-	return status;
-
     status = CAIRO_INT_STATUS_UNSUPPORTED;
     if (_cairo_path_fixed_fill_is_rectilinear (path)) {
 	cairo_boxes_t boxes;
 
-	_cairo_boxes_init_with_clip (&boxes, extents.clip);
+	_cairo_boxes_init_with_clip (&boxes, composite->clip);
 	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
 							      fill_rule,
 							      antialias,
 							      &boxes);
 	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
 	    status = _clip_and_composite_boxes (surface, op, source,
-						&boxes, &extents);
+						&boxes, composite);
 	}
 	_cairo_boxes_fini (&boxes);
     }
@@ -3803,18 +3760,16 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t	*surface,
 	if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) {
 	    status = _cairo_xcb_surface_render_fill_as_polygon (surface, op, source, path,
 								fill_rule, tolerance, antialias,
-								&extents);
+								composite);
 	} else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
 	    status = _cairo_xcb_surface_render_fill_via_mask (surface, op, source, path,
 							      fill_rule, tolerance, antialias,
-							      &extents);
+							      composite);
 	} else {
 	    ASSERT_NOT_REACHED;
 	}
     }
 
-    _cairo_composite_rectangles_fini (&extents);
-
     return status;
 }
 
@@ -4759,11 +4714,10 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
 				  cairo_scaled_font_t	*scaled_font,
 				  cairo_glyph_t		*glyphs,
 				  int			 num_glyphs,
-				  const cairo_clip_t	*clip)
+				  cairo_composite_rectangles_t *composite,
+				  cairo_bool_t overlap)
 {
-    cairo_composite_rectangles_t extents;
     cairo_int_status_t status;
-    cairo_bool_t overlap;
 
     if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -4771,19 +4725,11 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
     if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    status = _cairo_composite_rectangles_init_for_glyphs (&extents, &surface->base,
-							  op, source,
-							  scaled_font,
-							  glyphs, num_glyphs,
-							  clip, &overlap);
-    if (unlikely (status))
-	return status;
-
     status = CAIRO_INT_STATUS_UNSUPPORTED;
     if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS && 0) {
 	_cairo_scaled_font_freeze_cache (scaled_font);
 
-	status = _can_composite_glyphs (surface, &extents.bounded,
+	status = _can_composite_glyphs (surface, &composite->bounded,
 					scaled_font, glyphs, &num_glyphs);
 	if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
 	    composite_glyphs_info_t info;
@@ -4794,11 +4740,11 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
 	    info.num_glyphs = num_glyphs;
 	    info.use_mask =
 		overlap ||
-		! extents.is_bounded ||
-		! _cairo_clip_is_region(extents.clip);
+		! composite->is_bounded ||
+		! _cairo_clip_is_region(composite->clip);
 
-	    if (extents.mask.width > extents.unbounded.width ||
-		extents.mask.height > extents.unbounded.height)
+	    if (composite->mask.width  > composite->unbounded.width ||
+		composite->mask.height > composite->unbounded.height)
 	    {
 		/* Glyphs are tricky since we do not directly control the
 		 * geometry and their inked extents depend on the
@@ -4809,8 +4755,8 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
 	    }
 	    status = _clip_and_composite (surface, op, source,
 					  _composite_glyphs, NULL,
-					  &info, &extents,
-					  need_bounded_clip (&extents) |
+					  &info, composite,
+					  need_bounded_clip (composite) |
 					  flags);
 	}
 
@@ -4822,10 +4768,8 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
 	status =
 	    _cairo_xcb_surface_render_glyphs_via_mask (surface, op, source,
 						       scaled_font, glyphs, num_glyphs,
-						       &extents);
+						       composite);
     }
 
-    _cairo_composite_rectangles_fini (&extents);
-
     return status;
 }
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 67568bd..b3ca319 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -43,6 +43,7 @@
 #include "cairo-xcb.h"
 #include "cairo-xcb-private.h"
 
+#include "cairo-composite-rectangles-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-image-surface-private.h"
 #include "cairo-surface-backend-private.h"
@@ -188,9 +189,10 @@ _cairo_xcb_surface_finish (void *abstract_surface)
     cairo_status_t status;
 
     if (surface->fallback != NULL) {
-	cairo_surface_finish (surface->fallback);
-	cairo_surface_destroy (surface->fallback);
+	cairo_surface_finish (&surface->fallback->base);
+	cairo_surface_destroy (&surface->fallback->base);
     }
+    _cairo_boxes_fini (&surface->fallback_damage);
 
     cairo_list_del (&surface->link);
 
@@ -455,7 +457,7 @@ _cairo_xcb_surface_acquire_source_image (void *abstract_surface,
     cairo_surface_t *image;
 
     if (surface->fallback != NULL) {
-	image = cairo_surface_reference (surface->fallback);
+	image = cairo_surface_reference (&surface->fallback->base);
 	goto DONE;
     }
 
@@ -582,6 +584,108 @@ _put_image (cairo_xcb_surface_t    *surface,
     return status;
 }
 
+static cairo_int_status_t
+_put_shm_image_boxes (cairo_xcb_surface_t    *surface,
+		      cairo_image_surface_t  *image,
+		      xcb_gcontext_t gc,
+		      cairo_boxes_t *boxes)
+{
+#if CAIRO_HAS_XCB_SHM_FUNCTIONS
+    cairo_xcb_shm_info_t *shm_info;
+
+    shm_info = _cairo_user_data_array_get_data (&image->base.user_data,
+						(const cairo_user_data_key_t *) surface->connection);
+    if (shm_info != NULL) {
+	struct _cairo_boxes_chunk *chunk;
+
+	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	    int i;
+
+	    for (i = 0; i < chunk->count; i++) {
+		cairo_box_t *b = &chunk->base[i];
+		int x = _cairo_fixed_integer_part (b->p1.x);
+		int y = _cairo_fixed_integer_part (b->p1.y);
+		int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x);
+		int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y);
+
+		_cairo_xcb_connection_shm_put_image (surface->connection,
+						     surface->drawable,
+						     gc,
+						     surface->width, surface->height,
+						     x, y,
+						     width, height,
+						     x, y,
+						     image->depth,
+						     shm_info->shm,
+						     shm_info->offset);
+	    }
+	}
+    }
+
+    return CAIRO_INT_STATUS_SUCCESS;
+#endif
+
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_put_image_boxes (cairo_xcb_surface_t    *surface,
+		  cairo_image_surface_t  *image,
+		  cairo_boxes_t *boxes)
+{
+    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
+    xcb_gcontext_t gc;
+
+    if (boxes->num_boxes == 0)
+	    return CAIRO_STATUS_SUCCESS;
+
+    /* XXX track damaged region? */
+
+    status = _cairo_xcb_connection_acquire (surface->connection);
+    if (unlikely (status))
+	return status;
+
+    assert (image->pixman_format == surface->pixman_format);
+    assert (image->depth == surface->depth);
+    assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)));
+
+    gc = _cairo_xcb_screen_get_gc (surface->screen,
+				   surface->drawable,
+				   surface->depth);
+
+    status = _put_shm_image_boxes (surface, image, gc, boxes);
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	    struct _cairo_boxes_chunk *chunk;
+
+	    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+		    int i;
+
+		    for (i = 0; i < chunk->count; i++) {
+			    cairo_box_t *b = &chunk->base[i];
+			    int x = _cairo_fixed_integer_part (b->p1.x);
+			    int y = _cairo_fixed_integer_part (b->p1.y);
+			    int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x);
+			    int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y);
+			    _cairo_xcb_connection_put_image (surface->connection,
+							     surface->drawable, gc,
+							     width, height,
+							     x, y,
+							     image->depth,
+							     image->stride,
+							     image->data +
+							     x * PIXMAN_FORMAT_BPP (image->pixman_format) / 8 +
+							     y * image->stride);
+
+		    }
+	    }
+	    status = CAIRO_STATUS_SUCCESS;
+    }
+
+    _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
+    _cairo_xcb_connection_release (surface->connection);
+    return status;
+}
+
 static cairo_status_t
 _cairo_xcb_surface_flush (void *abstract_surface)
 {
@@ -598,20 +702,27 @@ _cairo_xcb_surface_flush (void *abstract_surface)
 
     status = surface->base.status;
     if (status == CAIRO_STATUS_SUCCESS && ! surface->base.finished) {
-	status = cairo_surface_status (surface->fallback);
+	status = cairo_surface_status (&surface->fallback->base);
 
-	if (status == CAIRO_STATUS_SUCCESS) {
-	    status = _put_image (surface, (cairo_image_surface_t *)surface->fallback);
-	}
+	if (status == CAIRO_STATUS_SUCCESS)
+		status = _cairo_bentley_ottmann_tessellate_boxes (&surface->fallback_damage,
+								  CAIRO_FILL_RULE_WINDING,
+								  &surface->fallback_damage);
+
+	if (status == CAIRO_STATUS_SUCCESS)
+	    status = _put_image_boxes (surface,
+				       surface->fallback,
+				       &surface->fallback_damage);
 
 	if (status == CAIRO_STATUS_SUCCESS) {
 	    _cairo_surface_attach_snapshot (&surface->base,
-					    surface->fallback,
+					    &surface->fallback->base,
 					    cairo_surface_finish);
 	}
     }
 
-    cairo_surface_destroy (surface->fallback);
+    _cairo_boxes_clear (&surface->fallback_damage);
+    cairo_surface_destroy (&surface->fallback->base);
     surface->fallback = NULL;
 
     return status;
@@ -625,7 +736,7 @@ _cairo_xcb_surface_map_to_image (void *abstract_surface,
     cairo_surface_t *image;
 
     if (surface->fallback)
-	return surface->fallback->backend->map_to_image (surface->fallback, extents);
+	return surface->fallback->base.backend->map_to_image (&surface->fallback->base, extents);
 
     image = _get_image (surface, TRUE,
 			extents->x, extents->y,
@@ -638,10 +749,8 @@ _cairo_xcb_surface_map_to_image (void *abstract_surface,
      * uploading the image will handle the problem for us.
      */
     if (surface->deferred_clear &&
-	    ! (extents->x == 0 &&
-	       extents->y == 0 &&
-	       extents->width == surface->width &&
-	       extents->height == surface->height)) {
+	! (extents->width == surface->width &&
+	   extents->height == surface->height)) {
 	cairo_status_t status = _cairo_xcb_surface_clear (surface);
 	if (unlikely (status)) {
 	    cairo_surface_destroy(image);
@@ -661,22 +770,32 @@ _cairo_xcb_surface_unmap (void *abstract_surface,
     cairo_xcb_surface_t *surface = abstract_surface;
 
     if (surface->fallback)
-	return surface->fallback->backend->unmap_image (surface->fallback, image);
+	return surface->fallback->base.backend->unmap_image (&surface->fallback->base, image);
     return _put_image (abstract_surface, image);
 }
 
 static cairo_surface_t *
-_cairo_xcb_surface_fallback (cairo_xcb_surface_t *surface)
+_cairo_xcb_surface_fallback (cairo_xcb_surface_t *surface,
+			     cairo_composite_rectangles_t *composite)
 {
-    cairo_surface_t *image;
+    cairo_image_surface_t *image;
+    cairo_status_t status;
 
-    image = _get_image (surface, TRUE, 0, 0, surface->width, surface->height);
+    image = (cairo_image_surface_t *)
+	    _get_image (surface, TRUE, 0, 0, surface->width, surface->height);
 
     /* If there was a deferred clear, _get_image applied it */
-    if (image->status == CAIRO_STATUS_SUCCESS)
+    if (image->base.status == CAIRO_STATUS_SUCCESS) {
 	surface->deferred_clear = FALSE;
 
-    return image;
+	surface->fallback = image;
+    }
+
+    status = _cairo_composite_rectangles_add_to_damage (composite,
+							&surface->fallback_damage);
+    if (unlikely (status))
+	    return _cairo_surface_create_in_error (status);
+    return &surface->fallback->base;
 }
 
 static cairo_int_status_t
@@ -686,21 +805,34 @@ _cairo_xcb_surface_paint (void			*abstract_surface,
 			  const cairo_clip_t	*clip)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
+    cairo_composite_rectangles_t composite;
     cairo_int_status_t status;
 
+    status = _cairo_composite_rectangles_init_for_paint (&composite,
+							 &surface->base,
+							 op, source,
+							 clip);
+    if (unlikely (status))
+	return status;
+
     if (surface->fallback == NULL) {
 	status = _cairo_xcb_surface_cairo_paint (surface, op, source, clip);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+	    goto done;
 
-	status = _cairo_xcb_surface_render_paint (surface, op, source, clip);
+	status = _cairo_xcb_surface_render_paint (surface, op, source,
+						  &composite);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-
-	surface->fallback = _cairo_xcb_surface_fallback (surface);
+	    goto done;
     }
 
-    return _cairo_surface_paint (surface->fallback, op, source, clip);
+    status = _cairo_surface_paint (_cairo_xcb_surface_fallback (surface,
+								&composite),
+				   op, source, clip);
+
+done:
+    _cairo_composite_rectangles_fini (&composite);
+    return status;
 }
 
 static cairo_int_status_t
@@ -711,25 +843,34 @@ _cairo_xcb_surface_mask (void			*abstract_surface,
 			 const cairo_clip_t	*clip)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
+    cairo_composite_rectangles_t composite;
     cairo_int_status_t status;
 
+    status = _cairo_composite_rectangles_init_for_mask (&composite,
+							&surface->base,
+							op, source, mask, clip);
+    if (unlikely (status))
+	return status;
+
     if (surface->fallback == NULL) {
 	status =  _cairo_xcb_surface_cairo_mask (surface,
 						 op, source, mask, clip);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+	    goto done;
 
 	status =  _cairo_xcb_surface_render_mask (surface,
-						  op, source, mask, clip);
+						  op, source, mask, &composite);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-
-	surface->fallback = _cairo_xcb_surface_fallback (surface);
+	    goto done;
     }
 
-    return _cairo_surface_mask (surface->fallback,
-				op, source, mask,
-				clip);
+    status = _cairo_surface_mask (_cairo_xcb_surface_fallback (surface,
+							       &composite),
+				  op, source, mask,
+				  clip);
+done:
+    _cairo_composite_rectangles_fini (&composite);
+    return status;
 }
 
 static cairo_int_status_t
@@ -745,8 +886,17 @@ _cairo_xcb_surface_stroke (void				*abstract_surface,
 			   const cairo_clip_t		*clip)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
+    cairo_composite_rectangles_t composite;
     cairo_int_status_t status;
 
+    status = _cairo_composite_rectangles_init_for_stroke (&composite,
+							  &surface->base,
+							  op, source,
+							  path, style, ctm,
+							  clip);
+    if (unlikely (status))
+	return status;
+
     if (surface->fallback == NULL) {
 	status = _cairo_xcb_surface_cairo_stroke (surface, op, source,
 						  path, style,
@@ -755,26 +905,28 @@ _cairo_xcb_surface_stroke (void				*abstract_surface,
 						  clip);
 
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+	    goto done;
 
 	status = _cairo_xcb_surface_render_stroke (surface, op, source,
 						   path, style,
 						   ctm, ctm_inverse,
 						   tolerance, antialias,
-						   clip);
+						   &composite);
 
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-
-	surface->fallback = _cairo_xcb_surface_fallback (surface);
+	    goto done;
     }
 
-    return _cairo_surface_stroke (surface->fallback,
-				  op, source,
-				  path, style,
-				  ctm, ctm_inverse,
-				  tolerance, antialias,
-				  clip);
+    status = _cairo_surface_stroke (_cairo_xcb_surface_fallback (surface,
+								 &composite),
+				    op, source,
+				    path, style,
+				    ctm, ctm_inverse,
+				    tolerance, antialias,
+				    clip);
+done:
+    _cairo_composite_rectangles_fini (&composite);
+    return status;
 }
 
 static cairo_int_status_t
@@ -788,31 +940,41 @@ _cairo_xcb_surface_fill (void			*abstract_surface,
 			 const cairo_clip_t	*clip)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
+    cairo_composite_rectangles_t composite;
     cairo_int_status_t status;
 
+    status = _cairo_composite_rectangles_init_for_fill (&composite,
+							&surface->base,
+							op, source, path,
+							clip);
+    if (unlikely (status))
+	return status;
+
     if (surface->fallback == NULL) {
 	status = _cairo_xcb_surface_cairo_fill (surface, op, source,
 						path, fill_rule,
 						tolerance, antialias,
 						clip);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+	    goto done;
 
 	status = _cairo_xcb_surface_render_fill (surface, op, source,
 						 path, fill_rule,
 						 tolerance, antialias,
-						 clip);
+						 &composite);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-
-	surface->fallback = _cairo_xcb_surface_fallback (surface);
+	    goto done;
     }
 
-    return _cairo_surface_fill (surface->fallback,
-				op, source,
-				path, fill_rule,
-				tolerance, antialias,
-				clip);
+    status = _cairo_surface_fill (_cairo_xcb_surface_fallback (surface,
+							       &composite),
+				  op, source,
+				  path, fill_rule,
+				  tolerance, antialias,
+				  clip);
+done:
+    _cairo_composite_rectangles_fini (&composite);
+    return status;
 }
 
 static cairo_int_status_t
@@ -825,7 +987,18 @@ _cairo_xcb_surface_glyphs (void				*abstract_surface,
 			   const cairo_clip_t		*clip)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
+    cairo_composite_rectangles_t composite;
     cairo_int_status_t status;
+    cairo_bool_t overlap;
+
+    status = _cairo_composite_rectangles_init_for_glyphs (&composite,
+							  &surface->base,
+							  op, source,
+							  scaled_font,
+							  glyphs, num_glyphs,
+							  clip, &overlap);
+    if (unlikely (status))
+	return status;
 
     if (surface->fallback == NULL) {
 	status = _cairo_xcb_surface_cairo_glyphs (surface,
@@ -833,25 +1006,27 @@ _cairo_xcb_surface_glyphs (void				*abstract_surface,
 						  scaled_font, glyphs, num_glyphs,
 						  clip);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+	    goto done;
 
 	status = _cairo_xcb_surface_render_glyphs (surface,
 						   op, source,
 						   scaled_font, glyphs, num_glyphs,
-						   clip);
+						   &composite, overlap);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-
-	surface->fallback = _cairo_xcb_surface_fallback (surface);
+	    goto done;
     }
 
-    return _cairo_surface_show_text_glyphs (surface->fallback,
-					    op, source,
-					    NULL, 0,
-					    glyphs, num_glyphs,
-					    NULL, 0, 0,
-					    scaled_font,
-					    clip);
+    status =  _cairo_surface_show_text_glyphs (_cairo_xcb_surface_fallback (surface,
+									    &composite),
+					       op, source,
+					       NULL, 0,
+					       glyphs, num_glyphs,
+					       NULL, 0, 0,
+					       scaled_font,
+					       clip);
+done:
+    _cairo_composite_rectangles_fini (&composite);
+    return status;
 }
 
 const cairo_surface_backend_t _cairo_xcb_surface_backend = {
@@ -910,8 +1085,6 @@ _cairo_xcb_surface_create_internal (cairo_xcb_screen_t		*screen,
     surface->screen = screen;
     cairo_list_add (&surface->link, &screen->surfaces);
 
-    surface->fallback = NULL;
-
     surface->drawable = drawable;
     surface->owns_pixmap = owns_pixmap;
 
@@ -931,6 +1104,9 @@ _cairo_xcb_surface_create_internal (cairo_xcb_screen_t		*screen,
     surface->pixman_format = pixman_format;
     surface->xrender_format = xrender_format;
 
+    surface->fallback = NULL;
+    _cairo_boxes_init (&surface->fallback_damage);
+
     return &surface->base;
 }
 


More information about the cairo-commit mailing list