[cairo-commit] 2 commits - src/cairo-path-fixed.c
Chris Wilson
ickle at kemper.freedesktop.org
Fri Oct 30 01:10:49 PDT 2009
src/cairo-path-fixed.c | 108 ++++++++++++++++++++++++++-----------------------
1 file changed, 59 insertions(+), 49 deletions(-)
New commits:
commit 19c411a5b8b84d31516d9c85642ad55ef5d29aba
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Oct 30 07:58:45 2009 +0000
path: Skip any secondary degenerate line-to segments.
Only the very first line-to following a move-to can have any
significance if degenerate whilst stroking, so skip all others.
In other words,
0 0 m 0 0 l stroke
produces a capped degenerate path (i.e a dot),
0 0 m 0 0 l 0 0 l stroke
produces the same degenerate stroke, and
0 0 m 0 0 l 1 0 l stroke
produce a horizontal line.
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index db0e493..42172c6 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -446,6 +446,16 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
if (! path->has_current_point)
return _cairo_path_fixed_move_to (path, point.x, point.y);
+ /* If the previous op was but the initial MOVE_TO and this segment
+ * is degenerate, then we can simply skip this point. Note that
+ * a move-to followed by a degenerate line-to is a valid path for
+ * stroking, but at all other times is simply a degenerate segment.
+ */
+ if (_cairo_path_last_op (path) != CAIRO_PATH_OP_MOVE_TO) {
+ if (x == path->current_point.x && y == path->current_point.y)
+ return CAIRO_STATUS_SUCCESS;
+ }
+
/* If the previous op was also a LINE_TO with the same gradient,
* then just change its end-point rather than adding a new op.
*/
@@ -453,9 +463,6 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
cairo_path_buf_t *buf;
const cairo_point_t *p;
- if (x == path->current_point.x && y == path->current_point.y)
- return CAIRO_STATUS_SUCCESS;
-
buf = cairo_path_tail (path);
if (likely (buf->num_points >= 2)) {
p = &buf->points[buf->num_points-2];
commit 23bcf91748c4bb04c16e503b913da3bfc237463f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Oct 30 07:49:56 2009 +0000
path: Misclassification of rectilinear after degenerate line-to
Malte Nuhn reported hitting an assertion:
cairo-path-stroke.c:1816: _cairo_rectilinear_stroker_line_to: Assertion `a->x == b->x || a->y == b->y' failed.
http://bugs.freedesktop.org/show_bug.cgi?id=24797
when stroking an apparently simple path:
0 8.626485 m
0 8.626485 l
5.208333 2.5 l
10.416667 2.5 l
15.625 2.5 l
20.833333 2.5 l
26.041667 2.5 l
31.25 2.5 l
36.458333 2.5 l
41.666667 2.5 l
46.875 2.5 l
52.083333 2.5 l
57.291667 2.5 l
62.5 2.5 l
67.708333 2.5 l
72.916667 2.5 l
78.125 2.5 l
83.333333 2.5 l
88.541667 2.5 l
93.75 2.5 l
98.958333 2.5 l
104.166667 2.5 l
109.375 2.5 l
114.583333 2.5 l
119.791667 2.5 l
125 2.5 l
stroke
which upon reduction becomes:
0.000000 8.625000 m 5.207031 2.500000 l 125.000000 2.500000 l stroke
The bug is that after spotting a repeated line-to we move the previous
end-point without reclassifying the path, hence we miss the
non-rectilinear step.
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index 4a2ce01..db0e493 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -443,61 +443,64 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
* explicitly calling into _cairo_path_fixed_move_to to ensure
* that the last_move_point state is updated properly.
*/
- if (! path->has_current_point) {
- status = _cairo_path_fixed_move_to (path, point.x, point.y);
- } else {
- /* If the previous op was also a LINE_TO with the same gradient,
- * then just change its end-point rather than adding a new op.
- */
- if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
- if (x == path->current_point.x &&
- y == path->current_point.y)
- {
- return CAIRO_STATUS_SUCCESS;
- }
- else
- {
- cairo_path_buf_t *buf;
- cairo_point_t *p;
- cairo_slope_t prev, self;
-
- buf = cairo_path_tail (path);
- if (likely (buf->num_points >= 2)) {
- p = &buf->points[buf->num_points-2];
- } else {
- cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
- p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
- }
-
- _cairo_slope_init (&prev, p, &path->current_point);
- _cairo_slope_init (&self, &path->current_point, &point);
- if (_cairo_slope_equal (&prev, &self)) {
- buf->points[buf->num_points - 1] = point;
- path->current_point = point;
- return CAIRO_STATUS_SUCCESS;
- }
- }
- }
+ if (! path->has_current_point)
+ return _cairo_path_fixed_move_to (path, point.x, point.y);
- status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
- if (path->is_rectilinear) {
- path->is_rectilinear = path->current_point.x == x ||
- path->current_point.y == y;
- path->maybe_fill_region &= path->is_rectilinear;
- }
- if (path->maybe_fill_region) {
- path->maybe_fill_region = _cairo_fixed_is_integer (x) &&
- _cairo_fixed_is_integer (y);
+ /* If the previous op was also a LINE_TO with the same gradient,
+ * then just change its end-point rather than adding a new op.
+ */
+ if (_cairo_path_last_op (path) == CAIRO_PATH_OP_LINE_TO) {
+ cairo_path_buf_t *buf;
+ const cairo_point_t *p;
+
+ if (x == path->current_point.x && y == path->current_point.y)
+ return CAIRO_STATUS_SUCCESS;
+
+ buf = cairo_path_tail (path);
+ if (likely (buf->num_points >= 2)) {
+ p = &buf->points[buf->num_points-2];
+ } else {
+ cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf);
+ p = &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)];
}
- if (path->is_empty_fill) {
- path->is_empty_fill = path->current_point.x == x &&
- path->current_point.y == y;
+
+ if (p->x == path->current_point.x && p->y == path->current_point.y) {
+ /* previous line element was degenerate, replace */
+ buf->points[buf->num_points - 1] = point;
+ goto FLAGS;
+ } else {
+ cairo_slope_t prev, self;
+
+ _cairo_slope_init (&prev, p, &path->current_point);
+ _cairo_slope_init (&self, &path->current_point, &point);
+ if (_cairo_slope_equal (&prev, &self)) {
+ buf->points[buf->num_points - 1] = point;
+ goto FLAGS;
+ }
}
+ }
+
+ status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
+ if (unlikely (status))
+ return status;
- path->current_point = point;
+ FLAGS:
+ if (path->is_rectilinear) {
+ path->is_rectilinear = path->current_point.x == x ||
+ path->current_point.y == y;
+ path->maybe_fill_region &= path->is_rectilinear;
+ }
+ if (path->maybe_fill_region) {
+ path->maybe_fill_region = _cairo_fixed_is_integer (x) &&
+ _cairo_fixed_is_integer (y);
+ }
+ if (path->is_empty_fill) {
+ path->is_empty_fill = path->current_point.x == x &&
+ path->current_point.y == y;
}
- return status;
+ path->current_point = point;
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
More information about the cairo-commit
mailing list