diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2009-10-30 07:49:56 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2009-10-30 08:08:13 +0000 |
commit | 23bcf91748c4bb04c16e503b913da3bfc237463f (patch) | |
tree | 19653595893421620435babf6660c5d34d731129 | |
parent | 600dd833983bd85bf8aea487393ce156abb622bd (diff) |
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.
-rw-r--r-- | src/cairo-path-fixed.c | 101 |
1 files changed, 52 insertions, 49 deletions
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index 4a2ce014..db0e4937 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 |