[cairo-commit] 3 commits - src/cairo-analysis-surface.c src/cairo-path-bounds.c src/cairo-path-fill.c src/cairo-path-fixed.c src/cairo-path-fixed-private.h src/cairo-xlib-surface.c
Chris Wilson
ickle at kemper.freedesktop.org
Tue Nov 25 04:55:54 PST 2008
src/cairo-analysis-surface.c | 2
src/cairo-path-bounds.c | 20 +++---
src/cairo-path-fill.c | 85 ++++++++++++++++++++++------
src/cairo-path-fixed-private.h | 17 +++++
src/cairo-path-fixed.c | 124 ++++++++++++++++++++++++++++++++++++++---
src/cairo-xlib-surface.c | 5 -
6 files changed, 216 insertions(+), 37 deletions(-)
New commits:
commit 4ac38f7c2bde67cab37805cab8a2effb2a8617e4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Nov 25 11:52:01 2008 +0000
[fill] Emit rectangles for GdkRegion
Scan the path for a series of consistently wound rectangles.
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index 46046bb..a6dea08 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -150,6 +150,7 @@ _cairo_filler_close_path (void *closure)
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
cairo_traps_t *traps);
cairo_status_t
@@ -163,7 +164,7 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
/* Before we do anything else, we use a special-case filler for
* a device-axis aligned rectangle if possible. */
- status = _cairo_path_fixed_fill_rectangle (path, traps);
+ status = _cairo_path_fixed_fill_rectangle (path, fill_rule, traps);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
@@ -205,27 +206,77 @@ BAIL:
*/
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
- if (_cairo_path_fixed_is_box (path, NULL)) {
- cairo_point_t *p = path->buf_head.base.points;
- cairo_point_t *top_left, *bot_right;
-
- top_left = &p[0];
- bot_right = &p[2];
- if (top_left->x > bot_right->x || top_left->y > bot_right->y) {
- int n;
-
- /* not a simple cairo_rectangle() */
- for (n = 0; n < 4; n++) {
- if (p[n].x <= top_left->x && p[n].y <= top_left->y)
- top_left = &p[n];
- if (p[n].x >= bot_right->x && p[n].y >= bot_right->y)
- bot_right = &p[n];
+ cairo_box_t box;
+
+ if (_cairo_path_fixed_is_box (path, &box)) {
+ if (box.p1.x > box.p2.x) {
+ cairo_fixed_t t;
+
+ t = box.p1.x;
+ box.p1.x = box.p2.x;
+ box.p2.x = t;
+ }
+
+ if (box.p1.y > box.p2.y) {
+ cairo_fixed_t t;
+
+ t = box.p1.y;
+ box.p1.y = box.p2.y;
+ box.p2.y = t;
+ }
+
+ return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
+ } else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
+ cairo_path_fixed_iter_t iter;
+ int last_cw = -1;
+
+ /* Support a series of rectangles as can be expected to describe a
+ * GdkRegion clip region during exposes.
+ */
+ _cairo_path_fixed_iter_init (&iter, path);
+ while (_cairo_path_fixed_iter_is_box (&iter, &box)) {
+ cairo_status_t status;
+ int cw = 0;
+
+ if (box.p1.x > box.p2.x) {
+ cairo_fixed_t t;
+
+ t = box.p1.x;
+ box.p1.x = box.p2.x;
+ box.p2.x = t;
+
+ cw = ! cw;
}
+
+ if (box.p1.y > box.p2.y) {
+ cairo_fixed_t t;
+
+ t = box.p1.y;
+ box.p1.y = box.p2.y;
+ box.p2.y = t;
+
+ cw = ! cw;
+ }
+
+ if (last_cw < 0) {
+ last_cw = cw;
+ } else if (last_cw != cw) {
+ _cairo_traps_clear (traps);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ status = _cairo_traps_tessellate_rectangle (traps,
+ &box.p1, &box.p2);
+ if (unlikely (status))
+ return status;
}
+ if (_cairo_path_fixed_iter_at_end (&iter))
+ return CAIRO_STATUS_SUCCESS;
- return _cairo_traps_tessellate_rectangle (traps, top_left, bot_right);
+ _cairo_traps_clear (traps);
}
return CAIRO_INT_STATUS_UNSUPPORTED;
diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h
index 43c33c1..c995e2a 100644
--- a/src/cairo-path-fixed-private.h
+++ b/src/cairo-path-fixed-private.h
@@ -88,4 +88,21 @@ cairo_private cairo_bool_t
_cairo_path_fixed_equal (const cairo_path_fixed_t *a,
const cairo_path_fixed_t *b);
+typedef struct _cairo_path_fixed_iter {
+ cairo_path_buf_t *buf;
+ int n_op;
+ int n_point;
+} cairo_path_fixed_iter_t;
+
+cairo_private void
+_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
+ cairo_path_fixed_t *path);
+
+cairo_private cairo_bool_t
+_cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter,
+ cairo_box_t *box);
+
+cairo_private cairo_bool_t
+_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter);
+
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index b36f4d8..ffaf58c 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -1002,10 +1002,8 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
buf->points[2].y == buf->points[3].y &&
buf->points[3].x == buf->points[0].x)
{
- if (box) {
- box->p1 = buf->points[0];
- box->p2 = buf->points[2];
- }
+ box->p1 = buf->points[0];
+ box->p2 = buf->points[2];
return TRUE;
}
@@ -1014,10 +1012,8 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
buf->points[2].x == buf->points[3].x &&
buf->points[3].y == buf->points[0].y)
{
- if (box) {
- box->p1 = buf->points[0];
- box->p2 = buf->points[2];
- }
+ box->p1 = buf->points[0];
+ box->p2 = buf->points[2];
return TRUE;
}
@@ -1049,3 +1045,115 @@ _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
return FALSE;
}
+
+void
+_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
+ cairo_path_fixed_t *path)
+{
+ iter->buf = &path->buf_head.base;
+ iter->n_op = 0;
+ iter->n_point = 0;
+}
+
+static cairo_bool_t
+_cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter)
+{
+ if (++iter->n_op == iter->buf->num_ops) {
+ iter->buf = iter->buf->next;
+ iter->n_op = 0;
+ iter->n_point = 0;
+ }
+
+ return iter->buf != NULL;
+}
+
+cairo_bool_t
+_cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter,
+ cairo_box_t *box)
+{
+ cairo_point_t points[5];
+ cairo_path_fixed_iter_t iter;
+
+ if (_iter->buf == NULL)
+ return FALSE;
+
+ iter = *_iter;
+
+ /* Check whether the ops are those that would be used for a rectangle */
+ if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_MOVE_TO)
+ return FALSE;
+ points[0] = iter.buf->points[iter.n_point++];
+ if (! _cairo_path_fixed_iter_next_op (&iter))
+ return FALSE;
+
+ if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
+ return FALSE;
+ points[1] = iter.buf->points[iter.n_point++];
+ if (! _cairo_path_fixed_iter_next_op (&iter))
+ return FALSE;
+
+ if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
+ return FALSE;
+ points[2] = iter.buf->points[iter.n_point++];
+ if (! _cairo_path_fixed_iter_next_op (&iter))
+ return FALSE;
+
+ if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
+ return FALSE;
+ points[3] = iter.buf->points[iter.n_point++];
+ if (! _cairo_path_fixed_iter_next_op (&iter))
+ return FALSE;
+
+ /* Now, there are choices. The rectangle might end with a LINE_TO
+ * (to the original point), but this isn't required. If it
+ * doesn't, then it must end with a CLOSE_PATH. */
+ if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO) {
+ points[4] = iter.buf->points[iter.n_point++];
+ if (points[4].x != points[0].x || points[4].y != points[0].y)
+ return FALSE;
+ } else if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_CLOSE_PATH) {
+ return FALSE;
+ }
+ if (! _cairo_path_fixed_iter_next_op (&iter))
+ return FALSE;
+
+ /* Ok, we may have a box, if the points line up */
+ if (points[0].y == points[1].y &&
+ points[1].x == points[2].x &&
+ points[2].y == points[3].y &&
+ points[3].x == points[0].x)
+ {
+ box->p1 = points[0];
+ box->p2 = points[2];
+ *_iter = iter;
+ return TRUE;
+ }
+
+ if (points[0].x == points[1].x &&
+ points[1].y == points[2].y &&
+ points[2].x == points[3].x &&
+ points[3].y == points[0].y)
+ {
+ box->p1 = points[0];
+ box->p2 = points[2];
+ *_iter = iter;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+cairo_bool_t
+_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter)
+{
+ if (iter->buf == NULL)
+ return TRUE;
+
+ if (iter->buf->op[iter->n_op] == CAIRO_PATH_OP_MOVE_TO &&
+ iter->buf->num_ops == iter->n_op + 1)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
commit 23df74e5ffd6be876f3c19ee9d71683f5a0ed6f4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Nov 25 11:45:30 2008 +0000
[xlib] Cosmetic tweak.
Tightly scope the local rects.
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 2ae727f..136e554 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1924,8 +1924,6 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
{
cairo_xlib_surface_t *surface = abstract_surface;
XRenderColor render_color;
- XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
- XRectangle *xrects = static_xrects;
int i;
_cairo_xlib_display_notify (surface->display);
@@ -1961,6 +1959,9 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
rects->width,
rects->height);
} else {
+ XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
+ XRectangle *xrects = static_xrects;
+
if (num_rects > ARRAY_LENGTH (static_xrects)) {
xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
if (xrects == NULL)
commit 06fabd6cbd0ad187f5f9f155d6b7962f76ec5dda
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Nov 25 12:05:26 2008 +0000
[path] Fix up extents.
Forgot to round the box to the integer rectangle and missed why only
testing on image. Very naughty.
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 431f98e..3109dee 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -290,7 +290,7 @@ _cairo_analysis_surface_intersect_clip_path (void *abstract_surface,
surface->current_clip.width = surface->width;
surface->current_clip.height = surface->height;
} else {
- cairo_rectangle_int_t extent;
+ cairo_rectangle_int_t extent;
cairo_bool_t is_empty;
_cairo_path_fixed_approximate_extents (path, &extent);
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index 54df5bf..6245cd2 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -172,18 +172,20 @@ _cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path,
_cairo_path_bounder_init (&bounder);
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
- _cairo_path_bounder_move_to,
- _cairo_path_bounder_line_to,
- _cairo_path_bounder_curve_to,
- _cairo_path_bounder_close_path,
- &bounder);
+ _cairo_path_bounder_move_to,
+ _cairo_path_bounder_line_to,
+ _cairo_path_bounder_curve_to,
+ _cairo_path_bounder_close_path,
+ &bounder);
assert (status == CAIRO_STATUS_SUCCESS);
if (bounder.has_point) {
- extents->x = bounder.min_x;
- extents->y = bounder.min_y;
- extents->width = bounder.max_x - extents->x;
- extents->height = bounder.max_y - extents->y;
+ extents->x = _cairo_fixed_integer_floor (bounder.min_x);
+ extents->y = _cairo_fixed_integer_floor (bounder.min_y);
+ extents->width =
+ _cairo_fixed_integer_ceil (bounder.max_x) - extents->x;
+ extents->height =
+ _cairo_fixed_integer_ceil (bounder.max_y) - extents->y;
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
More information about the cairo-commit
mailing list