summaryrefslogtreecommitdiff
path: root/src/cairo-spans.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2008-12-17 09:32:16 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2009-08-29 08:08:28 +0100
commitf8bb3617c3a7ec598c42eff1f8562e3ccc95127f (patch)
treef6c8f949ab44ca126053fb5cea2b9b88a4748cb8 /src/cairo-spans.c
parent7c499db8afe8a7cf8c512ec166fe7dbf11a25c02 (diff)
downloadcairo-f8bb3617c3a7ec598c42eff1f8562e3ccc95127f.tar.gz
Eliminate self-intersecting strokes.
We refactor the surface fallbacks to convert full strokes and fills to the intermediate polygon representation (as opposed to before where we returned the trapezoidal representation). This allow greater flexibility to choose how then to rasterize the polygon. Where possible we use the local spans rasteriser for its increased performance, but still have the option to use the tessellator instead (for example, with the current Render protocol which does not yet have a polygon image). In order to accommodate this, the spans interface is tweaked to accept whole polygons instead of a path and the tessellator is tweaked for speed. Performance Impact ================== ... Still measuring, expecting some severe regressions. ...
Diffstat (limited to 'src/cairo-spans.c')
-rw-r--r--src/cairo-spans.c179
1 files changed, 36 insertions, 143 deletions
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
index 48396b54f..369cd5827 100644
--- a/src/cairo-spans.c
+++ b/src/cairo-spans.c
@@ -26,107 +26,7 @@
*/
#include "cairoint.h"
-typedef struct {
- cairo_scan_converter_t *converter;
- cairo_point_t current_point;
- cairo_point_t first_point;
- cairo_bool_t has_first_point;
-} scan_converter_filler_t;
-
-static void
-scan_converter_filler_init (scan_converter_filler_t *filler,
- cairo_scan_converter_t *converter)
-{
- filler->converter = converter;
- filler->current_point.x = 0;
- filler->current_point.y = 0;
- filler->first_point = filler->current_point;
- filler->has_first_point = FALSE;
-}
-
-static cairo_status_t
-scan_converter_filler_close_path (void *closure)
-{
- scan_converter_filler_t *filler = closure;
- cairo_status_t status;
-
- filler->has_first_point = FALSE;
-
- if (filler->first_point.x == filler->current_point.x &&
- filler->first_point.y == filler->current_point.y)
- {
- return CAIRO_STATUS_SUCCESS;
- }
-
- status = filler->converter->add_edge (
- filler->converter,
- filler->current_point.x, filler->current_point.y,
- filler->first_point.x, filler->first_point.y);
-
- filler->current_point = filler->first_point;
- return status;
-}
-
-static cairo_status_t
-scan_converter_filler_move_to (void *closure,
- const cairo_point_t *p)
-{
- scan_converter_filler_t *filler = closure;
- if (filler->has_first_point) {
- cairo_status_t status = scan_converter_filler_close_path (closure);
- if (status)
- return status;
- }
- filler->current_point.x = p->x;
- filler->current_point.y = p->y;
- filler->first_point = filler->current_point;
- filler->has_first_point = TRUE;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-scan_converter_filler_line_to (void *closure,
- const cairo_point_t *p)
-{
- scan_converter_filler_t *filler = closure;
- cairo_status_t status;
- cairo_point_t to;
-
- to.x = p->x;
- to.y = p->y;
-
- status = filler->converter->add_edge (
- filler->converter,
- filler->current_point.x, filler->current_point.y,
- to.x, to.y);
-
- filler->current_point = to;
-
- return status;
-}
-
-static cairo_status_t
-_cairo_path_fixed_fill_to_scan_converter (
- cairo_path_fixed_t *path,
- double tolerance,
- cairo_scan_converter_t *converter)
-{
- scan_converter_filler_t filler;
- cairo_status_t status;
-
- scan_converter_filler_init (&filler, converter);
-
- status = _cairo_path_fixed_interpret_flat (
- path, CAIRO_DIRECTION_FORWARD,
- scan_converter_filler_move_to,
- scan_converter_filler_line_to,
- scan_converter_filler_close_path,
- &filler, tolerance);
- if (status)
- return status;
-
- return scan_converter_filler_close_path (&filler);
-}
+#include "cairo-fixed-private.h"
static cairo_scan_converter_t *
_create_scan_converter (cairo_fill_rule_t fill_rule,
@@ -135,51 +35,50 @@ _create_scan_converter (cairo_fill_rule_t fill_rule,
{
if (antialias == CAIRO_ANTIALIAS_NONE) {
ASSERT_NOT_REACHED;
- return _cairo_scan_converter_create_in_error (
- CAIRO_INT_STATUS_UNSUPPORTED);
- }
- else {
- return _cairo_tor_scan_converter_create (
- rects->mask.x,
- rects->mask.y,
- rects->mask.x + rects->width,
- rects->mask.y + rects->height,
- fill_rule);
+ return NULL;
}
+
+ return _cairo_tor_scan_converter_create (rects->mask.x,
+ rects->mask.y,
+ rects->mask.x + rects->width,
+ rects->mask.y + rects->height,
+ fill_rule);
}
+/* XXX Add me to the compositor interface. Ok, first create the compositor
+ * interface, and then add this with associated fallback!
+ */
cairo_status_t
-_cairo_path_fixed_fill_using_spans (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- cairo_path_fixed_t *path,
- cairo_surface_t *dst,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects,
- cairo_region_t *clip_region)
+_cairo_surface_composite_polygon (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *rects,
+ cairo_polygon_t *polygon,
+ cairo_region_t *clip_region)
{
+ cairo_span_renderer_t *renderer;
+ cairo_scan_converter_t *converter;
cairo_status_t status;
- cairo_span_renderer_t *renderer = _cairo_surface_create_span_renderer (
- op, pattern, dst, antialias, rects, clip_region);
- cairo_scan_converter_t *converter = _create_scan_converter (
- fill_rule, antialias, rects);
- status = _cairo_path_fixed_fill_to_scan_converter (
- path, tolerance, converter);
- if (status)
- goto BAIL;
+ converter = _create_scan_converter (fill_rule, antialias, rects);
+ status = converter->add_polygon (converter, polygon);
+ if (unlikely (status))
+ goto CLEANUP_CONVERTER;
+ renderer = _cairo_surface_create_span_renderer (op, pattern, surface,
+ antialias, rects,
+ clip_region);
status = converter->generate (converter, renderer);
- if (status)
- goto BAIL;
+ if (unlikely (status))
+ goto CLEANUP_RENDERER;
status = renderer->finish (renderer);
- if (status)
- goto BAIL;
- BAIL:
+ CLEANUP_RENDERER:
renderer->destroy (renderer);
+ CLEANUP_CONVERTER:
converter->destroy (converter);
return status;
}
@@ -191,17 +90,11 @@ _cairo_nil_destroy (void *abstract)
}
static cairo_status_t
-_cairo_nil_scan_converter_add_edge (void *abstract_converter,
- cairo_fixed_t x1,
- cairo_fixed_t y1,
- cairo_fixed_t x2,
- cairo_fixed_t y2)
+_cairo_nil_scan_converter_add_polygon (void *abstract_converter,
+ const cairo_polygon_t *polygon)
{
(void) abstract_converter;
- (void) x1;
- (void) y1;
- (void) x2;
- (void) y2;
+ (void) polygon;
return _cairo_scan_converter_status (abstract_converter);
}
@@ -229,7 +122,7 @@ _cairo_scan_converter_set_error (void *abstract_converter,
if (error == CAIRO_STATUS_SUCCESS)
ASSERT_NOT_REACHED;
if (converter->status == CAIRO_STATUS_SUCCESS) {
- converter->add_edge = _cairo_nil_scan_converter_add_edge;
+ converter->add_polygon = _cairo_nil_scan_converter_add_polygon;
converter->generate = _cairo_nil_scan_converter_generate;
converter->status = error;
}