[cairo-commit] 2 commits - src/cairo.c src/cairoint.h src/cairo-surface-fallback.c src/cairo-traps.c

Carl Worth cworth at kemper.freedesktop.org
Fri Apr 27 22:47:06 PDT 2007


 src/cairo-surface-fallback.c |   52 ++++++++++++++++++++++++++++++++
 src/cairo-traps.c            |   68 ++++++++++++++++++++++++++++++++++++++++++-
 src/cairo.c                  |    6 ++-
 src/cairoint.h               |    7 ++++
 4 files changed, 130 insertions(+), 3 deletions(-)

New commits:
diff-tree a392cc85081dd1e0fa3342c313af94a1e0c289b1 (from 8286b8741675ae163fc40187cd04e84395954c6e)
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Apr 27 22:46:47 2007 -0700

    Clarify documentation of cairo_in_stroke and cairo_in_fill
    
    Like cairo_stroke_extents and cairo_fill_extents, these functions
    work without regard to the surface dimensions or the current clip
    region.

diff --git a/src/cairo.c b/src/cairo.c
index cd28cbb..69dfee2 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -2151,7 +2151,8 @@ cairo_show_page (cairo_t *cr)
  *
  * Tests whether the given point is inside the area that would be
  * affected by a cairo_stroke() operation given the current path and
- * stroking parameters.
+ * stroking parameters. Surface dimensions and clipping are not taken
+ * into account.
  *
  * See cairo_stroke(), cairo_set_line_width(), cairo_set_line_join(),
  * cairo_set_line_cap(), cairo_set_dash(), and
@@ -2186,7 +2187,8 @@ cairo_in_stroke (cairo_t *cr, double x, 
  *
  * Tests whether the given point is inside the area that would be
  * affected by a cairo_fill() operation given the current path and
- * filling parameters.
+ * filling parameters. Surface dimensions and clipping are not taken
+ * into account.
  *
  * See cairo_fill(), cairo_set_fill_rule() and cairo_fill_preserve().
  *
diff-tree 8286b8741675ae163fc40187cd04e84395954c6e (from 2dcfb944b044172640a3784246d6b3129b686b60)
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Apr 27 17:23:08 2007 -0700

    Clip trapezoids that are partially (or wholly) outside the clip region.
    
    It's quite simple to add a new _cairo_traps_limit call which installs
    a box into the cairo_traps_t structure. Then at the time of
    _cairo_traps_add we can discard any trapezoid that is wholly outside
    the box and also clip any trapezoid that is partially outside the box.
    
    We take advantage of this for both cairo_stroke and cairo_fill, (when
    cairo is computing the trapezoids in cairo-surface-fallback.c). Note
    that we explicitly do not do any clipping for cairo_stroke_extents,
    cairo_fill_extents, cairo_in_stroke, or cairo_in_fill which are
    defined to ignore clipping.
    
    As seen by the long-lines perf case, this fix successfully works
    around the bug in the X server where it creates overly large masks for
    partially-outside-the-destination-surface trapezoids:
    
     xlib-rgba   long-lines-uncropped-100  545.84 -> 5.83: 93.09x speedup
    ██████████████████████████████████████████████
     xlib-rgb    long-lines-uncropped-100  554.74 -> 8.10: 69.04x speedup
    ██████████████████████████████████

diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index aa43496..cfdff2c 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -804,9 +804,35 @@ _cairo_surface_fallback_stroke (cairo_su
 {
     cairo_status_t status;
     cairo_traps_t traps;
+    cairo_box_t box;
+    cairo_rectangle_int16_t extents;
+
+    status = _cairo_surface_get_extents (surface, &extents);
+    if (status)
+        return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int16_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
+    }
+
+    status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
+    if (status)
+        return status;
+
+    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,
 						stroke_style,
 						ctm, ctm_inverse,
@@ -840,9 +866,35 @@ _cairo_surface_fallback_fill (cairo_surf
 {
     cairo_status_t status;
     cairo_traps_t traps;
+    cairo_box_t box;
+    cairo_rectangle_int16_t extents;
+
+    status = _cairo_surface_get_extents (surface, &extents);
+    if (status)
+        return status;
+
+    if (_cairo_operator_bounded_by_source (op)) {
+	cairo_rectangle_int16_t source_extents;
+	status = _cairo_pattern_get_extents (source, &source_extents);
+	if (status)
+	    return status;
+
+	_cairo_rectangle_intersect (&extents, &source_extents);
+    }
+
+    status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
+    if (status)
+        return status;
+
+    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,
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index f2b5ccb..51ea1a3 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -61,6 +61,17 @@ _cairo_traps_init (cairo_traps_t *traps)
     traps->traps = NULL;
     traps->extents.p1.x = traps->extents.p1.y = INT32_MAX;
     traps->extents.p2.x = traps->extents.p2.y = INT32_MIN;
+
+    traps->has_limits = FALSE;
+}
+
+void
+_cairo_traps_limit (cairo_traps_t	*traps,
+		    cairo_box_t		*limits)
+{
+    traps->has_limits = TRUE;
+
+    traps->limits = *limits;
 }
 
 void
@@ -124,7 +135,62 @@ _cairo_traps_add_trap (cairo_traps_t *tr
     if (traps->status)
 	return;
 
-    if (top == bottom) {
+    /* Note: With the goofy trapezoid specification, (where an
+     * arbitrary two points on the lines can specified for the left
+     * and right edges), these limit checks would not work in
+     * general. For example, one can imagine a trapezoid entirely
+     * within the limits, but with two points used to specify the left
+     * edge entirely to the right of the limits.  Fortunately, for our
+     * purposes, cairo will never generate such a crazy
+     * trapezoid. Instead, cairo always uses for its points the
+     * extreme positions of the edge that are visible on at least some
+     * trapezoid. With this constraint, it's impossible for both
+     * points to be outside the limits while the relevant edge is
+     * entirely inside the limits.
+     */
+    if (traps->has_limits) {
+	/* Trivially reject if trapezoid is entirely to the right or
+	 * to the left of the limits. */
+	if (left->p1.x >= traps->limits.p2.x &&
+	    left->p2.x >= traps->limits.p2.x)
+	{
+	    return;
+	}
+
+	if (right->p1.x <= traps->limits.p1.x &&
+	    right->p2.x <= traps->limits.p1.x)
+	{
+	    return;
+	}
+
+	/* Otherwise, clip the trapezoid to the limits. We only clip
+	 * where an edge is entirely outside the limits. If we wanted
+	 * to be more clever, we could handle cases where a trapezoid
+	 * edge intersects the edge of the limits, but that would
+	 * require slicing this trapezoid into multiple trapezoids,
+	 * and I'm not sure the effort would be worth it. */
+	if (top < traps->limits.p1.y)
+	    top = traps->limits.p1.y;
+
+	if (bottom > traps->limits.p2.y)
+	    bottom = traps->limits.p2.y;
+
+	if (left->p1.x < traps->limits.p1.x &&
+	    left->p2.x < traps->limits.p1.x)
+	{
+	    left->p1.x = traps->limits.p1.x;
+	    left->p2.x = traps->limits.p1.x;
+	}
+
+	if (right->p1.x > traps->limits.p2.x &&
+	    right->p2.x > traps->limits.p2.x)
+	{
+	    right->p1.x = traps->limits.p2.x;
+	    right->p2.x = traps->limits.p2.x;
+	}
+    }
+
+    if (top >= bottom) {
 	return;
     }
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 701258f..4ecfc0d 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1036,6 +1036,9 @@ typedef struct _cairo_traps {
     int traps_size;
     cairo_trapezoid_t *traps;
     cairo_trapezoid_t  traps_embedded[1];
+
+    cairo_bool_t has_limits;
+    cairo_box_t limits;
 } cairo_traps_t;
 
 #define CAIRO_FONT_SLANT_DEFAULT   CAIRO_FONT_SLANT_NORMAL
@@ -2171,6 +2174,10 @@ _cairo_matrix_to_pixman_matrix (const ca
 cairo_private void
 _cairo_traps_init (cairo_traps_t *traps);
 
+cairo_private void
+_cairo_traps_limit (cairo_traps_t	*traps,
+		    cairo_box_t		*limits);
+
 cairo_private cairo_status_t
 _cairo_traps_init_box (cairo_traps_t *traps,
 		       cairo_box_t   *box);


More information about the cairo-commit mailing list