mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 13:28:03 +02:00
[clip] Use the rectilinear tessellator
We can ensure that we always produce a clip region when possible by using the rectilinear tessellator to convert complex, device-aligned polygons to regions. Prior to using the tessellator, we relied on pixman's region code which could only handle a union of rectangles.
This commit is contained in:
parent
e3820bef20
commit
6f0340e2e5
2 changed files with 66 additions and 22 deletions
|
|
@ -586,16 +586,11 @@ _cairo_clip_path_to_region (cairo_clip_path_t *clip_path)
|
|||
_cairo_path_fixed_fill_rectilinear_to_region (&clip_path->path,
|
||||
clip_path->fill_rule,
|
||||
&clip_path->extents);
|
||||
if (clip_path->region == NULL) {
|
||||
clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
assert (clip_path->region != NULL);
|
||||
|
||||
status = clip_path->region->status;
|
||||
if (unlikely (status)) {
|
||||
clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
}
|
||||
|
||||
if (prev != NULL) {
|
||||
status = cairo_region_intersect (clip_path->region, prev);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "cairoint.h"
|
||||
#include "cairo-path-fixed-private.h"
|
||||
#include "cairo-region-private.h"
|
||||
|
||||
typedef struct cairo_filler {
|
||||
double tolerance;
|
||||
|
|
@ -177,12 +178,61 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
|
|||
return status;
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
_cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
const cairo_rectangle_int_t *extents)
|
||||
{
|
||||
cairo_polygon_t polygon;
|
||||
cairo_traps_t traps;
|
||||
cairo_status_t status;
|
||||
cairo_region_t *region;
|
||||
|
||||
_cairo_polygon_init (&polygon);
|
||||
if (extents != NULL) {
|
||||
cairo_box_t box;
|
||||
|
||||
_cairo_box_from_rectangle (&box, extents);
|
||||
_cairo_polygon_limit (&polygon, &box);
|
||||
}
|
||||
|
||||
/* tolerance will be ignored as the path is rectilinear */
|
||||
status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
|
||||
if (unlikely (status))
|
||||
goto CLEANUP_POLYGON;
|
||||
|
||||
if (polygon.num_edges == 0) {
|
||||
region = cairo_region_create ();
|
||||
} else {
|
||||
_cairo_traps_init (&traps);
|
||||
|
||||
status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
|
||||
&polygon,
|
||||
fill_rule);
|
||||
if (likely (status == CAIRO_STATUS_SUCCESS))
|
||||
status = _cairo_traps_extract_region (&traps, ®ion);
|
||||
|
||||
_cairo_traps_fini (&traps);
|
||||
}
|
||||
|
||||
CLEANUP_POLYGON:
|
||||
_cairo_polygon_fini (&polygon);
|
||||
|
||||
if (unlikely (status)) { /* XXX _cairo_region_create_in_error() */
|
||||
region = cairo_region_create ();
|
||||
if (likely (region->status) == CAIRO_STATUS_SUCCESS)
|
||||
region->status = status;
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
/* This special-case filler supports only a path that describes a
|
||||
* device-axis aligned rectangle. It exists to avoid the overhead of
|
||||
* the general tessellator when drawing very common rectangles.
|
||||
*
|
||||
* If the path described anything but a device-axis aligned rectangle,
|
||||
* this function will return %CAIRO_INT_STATUS_UNSUPPORTED.
|
||||
* this function will abort.
|
||||
*/
|
||||
cairo_region_t *
|
||||
_cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path,
|
||||
|
|
@ -212,10 +262,6 @@ _cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path,
|
|||
box.p2.y = t;
|
||||
}
|
||||
|
||||
assert (_cairo_fixed_is_integer (box.p1.x) &&
|
||||
_cairo_fixed_is_integer (box.p1.y));
|
||||
assert (_cairo_fixed_is_integer (box.p2.x) &&
|
||||
_cairo_fixed_is_integer (box.p2.y));
|
||||
rectangle_stack[0].x = _cairo_fixed_integer_part (box.p1.x);
|
||||
rectangle_stack[0].y = _cairo_fixed_integer_part (box.p1.y);
|
||||
rectangle_stack[0].width = _cairo_fixed_integer_part (box.p2.x) -
|
||||
|
|
@ -260,13 +306,10 @@ _cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path,
|
|||
cw = ! cw;
|
||||
}
|
||||
|
||||
if (last_cw < 0) {
|
||||
if (last_cw < 0)
|
||||
last_cw = cw;
|
||||
} else if (last_cw != cw) {
|
||||
if (rects != rectangle_stack)
|
||||
free (rects);
|
||||
return NULL;
|
||||
}
|
||||
else if (last_cw != cw)
|
||||
goto TESSELLATE;
|
||||
|
||||
if (count == size) {
|
||||
cairo_rectangle_int_t *new_rects;
|
||||
|
|
@ -291,10 +334,6 @@ _cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path,
|
|||
rects = new_rects;
|
||||
}
|
||||
|
||||
assert (_cairo_fixed_is_integer (box.p1.x) &&
|
||||
_cairo_fixed_is_integer (box.p1.y));
|
||||
assert (_cairo_fixed_is_integer (box.p2.x) &&
|
||||
_cairo_fixed_is_integer (box.p2.y));
|
||||
rects[count].x = _cairo_fixed_integer_part (box.p1.x);
|
||||
rects[count].y = _cairo_fixed_integer_part (box.p1.y);
|
||||
rects[count].width = _cairo_fixed_integer_part (box.p2.x) - rects[count].x;
|
||||
|
|
@ -306,9 +345,19 @@ _cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path,
|
|||
if (_cairo_path_fixed_iter_at_end (&iter))
|
||||
region = cairo_region_create_rectangles (rects, count);
|
||||
|
||||
TESSELLATE:
|
||||
if (rects != rectangle_stack)
|
||||
free (rects);
|
||||
}
|
||||
|
||||
if (region == NULL) {
|
||||
/* Hmm, complex polygon */
|
||||
region = _cairo_path_fixed_fill_rectilinear_tessellate_to_region (path,
|
||||
fill_rule,
|
||||
extents);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue