[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