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. ...
18
NEWS
|
|
@ -69,6 +69,24 @@ New experimental backends:
|
|||
more offloading onto the GPU.
|
||||
The initial work on the backend was performed by Eric Anholt.
|
||||
|
||||
Long standing bugs fixed:
|
||||
|
||||
Self-intersecting strokes.
|
||||
|
||||
A long standing bug where the coverage from overlapping semi-opaque
|
||||
strokes (including neighbouring edges) was simply summed in lieu of
|
||||
a costly global calculation has been fixed (by performing the costly
|
||||
global calculation!) In order to mitigate the extra cost, the
|
||||
tessellator has been overhauled and tune, which handles the fallback
|
||||
for when we are unable to use the new span rasteriser on the stroke
|
||||
(e.g. when using the current RENDER protocol). The large number of
|
||||
pixel artefacts that implementing self-intersection elimination
|
||||
removes is ample justification for the potential performance
|
||||
regression. If you unfortunately do suffer a substantial performance
|
||||
regression in your application, please consider obtaining a
|
||||
cairo-trace and submitting it to us for analysis and inclusion into
|
||||
our performance suite.
|
||||
|
||||
|
||||
Snapshot 1.9.2 (2009-06-12)
|
||||
===========================
|
||||
|
|
|
|||
|
|
@ -99,5 +99,7 @@ COMPILE_ARGS = $(PREPROCESS_ARGS) $(AM_CFLAGS) $(CFLAGS)
|
|||
# cairo has been compiled with symbol hiding.
|
||||
.c.i: $(cairoinclude_HEADERS) $(nodist_cairoinclude_HEADERS) cairoint.h $(top_builddir)/config.h
|
||||
$(CPP) $(PREPROCESS_ARGS) $< -o $@
|
||||
.c.s: $(cairoinclude_HEADERS) $(nodist_cairoinclude_HEADERS) cairoint.h $(top_builddir)/config.h
|
||||
$(CC) $(COMPILE_ARGS) $< -S -o $@
|
||||
|
||||
include $(srcdir)/Makefile.am.analysis
|
||||
|
|
|
|||
|
|
@ -588,17 +588,19 @@ _cairo_clip_path_to_region (cairo_clip_path_t *clip_path)
|
|||
_cairo_box_from_rectangle (&box, &clip_path->extents);
|
||||
_cairo_traps_limit (&traps, &box);
|
||||
|
||||
status = _cairo_path_fixed_fill_to_traps (&clip_path->path,
|
||||
clip_path->fill_rule,
|
||||
clip_path->tolerance,
|
||||
&traps);
|
||||
if (unlikely (status))
|
||||
status = _cairo_path_fixed_fill_rectilinear_to_traps (&clip_path->path,
|
||||
clip_path->fill_rule,
|
||||
&traps);
|
||||
if (status) {
|
||||
_cairo_traps_fini (&traps);
|
||||
clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
|
||||
return status;
|
||||
}
|
||||
|
||||
status = _cairo_traps_extract_region (&traps, &clip_path->region);
|
||||
_cairo_traps_fini (&traps);
|
||||
|
||||
if (status) {
|
||||
if (unlikely (status)) {
|
||||
clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,15 +226,61 @@ _cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b)
|
|||
return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS));
|
||||
}
|
||||
|
||||
/* computes a * b / c */
|
||||
/* computes round (a * b / c) */
|
||||
static inline cairo_fixed_t
|
||||
_cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
|
||||
{
|
||||
cairo_int64_t ab = _cairo_int32x32_64_mul (a, b);
|
||||
cairo_int64_t c64 = _cairo_int32_to_int64 (c);
|
||||
cairo_int64_t quo = _cairo_int64_divrem (ab, c64).quo;
|
||||
return _cairo_int64_to_int32 (_cairo_int64_divrem (ab, c64).quo);
|
||||
}
|
||||
|
||||
return _cairo_int64_to_int32(quo);
|
||||
/* computes floor (a * b / c) */
|
||||
static inline cairo_fixed_t
|
||||
_cairo_fixed_mul_div_floor (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
|
||||
{
|
||||
return _cairo_int64_32_div (_cairo_int32x32_64_mul (a, b), c);
|
||||
}
|
||||
|
||||
|
||||
static inline cairo_fixed_t
|
||||
_cairo_edge_compute_intersection_y_for_x (const cairo_point_t *p1,
|
||||
const cairo_point_t *p2,
|
||||
cairo_fixed_t x)
|
||||
{
|
||||
cairo_fixed_t y, dx;
|
||||
|
||||
if (x == p1->x)
|
||||
return p1->y;
|
||||
if (x == p2->x)
|
||||
return p2->y;
|
||||
|
||||
y = p1->y;
|
||||
dx = p2->x - p1->x;
|
||||
if (dx != 0)
|
||||
y += _cairo_fixed_mul_div_floor (x - p1->x, p2->y - p1->y, dx);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
static inline cairo_fixed_t
|
||||
_cairo_edge_compute_intersection_x_for_y (const cairo_point_t *p1,
|
||||
const cairo_point_t *p2,
|
||||
cairo_fixed_t y)
|
||||
{
|
||||
cairo_fixed_t x, dy;
|
||||
|
||||
if (y == p1->y)
|
||||
return p1->x;
|
||||
if (y == p2->y)
|
||||
return p2->x;
|
||||
|
||||
x = p1->x;
|
||||
dy = p2->y - p1->y;
|
||||
if (dy != 0)
|
||||
x += _cairo_fixed_mul_div_floor (y - p1->y, p2->x - p1->x, dy);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -67,4 +67,9 @@ typedef int32_t cairo_fixed_t;
|
|||
/* An unsigned type of the same size as #cairo_fixed_t */
|
||||
typedef uint32_t cairo_fixed_unsigned_t;
|
||||
|
||||
typedef struct _cairo_point {
|
||||
cairo_fixed_t x;
|
||||
cairo_fixed_t y;
|
||||
} cairo_point_t;
|
||||
|
||||
#endif /* CAIRO_FIXED_TYPE_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -1184,7 +1184,7 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
|
|||
&gstate->ctm_inverse,
|
||||
gstate->tolerance,
|
||||
&traps);
|
||||
if (status == CAIRO_STATUS_SUCCESS) {
|
||||
if (likely (status == CAIRO_STATUS_SUCCESS)) {
|
||||
_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
|
||||
x1, y1, x2, y2);
|
||||
}
|
||||
|
|
@ -1209,7 +1209,7 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
|
|||
gstate->fill_rule,
|
||||
gstate->tolerance,
|
||||
&traps);
|
||||
if (status == CAIRO_STATUS_SUCCESS) {
|
||||
if (likely (status == CAIRO_STATUS_SUCCESS)) {
|
||||
_cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
|
||||
x1, y1, x2, y2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,9 +191,6 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
|
|||
void
|
||||
_cairo_hash_table_destroy (cairo_hash_table_t *hash_table)
|
||||
{
|
||||
if (hash_table == NULL)
|
||||
return;
|
||||
|
||||
/* The hash table must be empty. Otherwise, halt. */
|
||||
assert (hash_table->live_entries == 0);
|
||||
/* No iterators can be running. Otherwise, halt. */
|
||||
|
|
@ -525,9 +522,6 @@ _cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
|
|||
unsigned long i;
|
||||
cairo_hash_entry_t *entry;
|
||||
|
||||
if (hash_table == NULL)
|
||||
return;
|
||||
|
||||
/* Mark the table for iteration */
|
||||
++hash_table->iterating;
|
||||
for (i = 0; i < hash_table->arrangement->size; i++) {
|
||||
|
|
|
|||
|
|
@ -688,16 +688,9 @@ _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/* By pixel exact here, we mean a matrix that is composed only of
|
||||
* 90 degree rotations, flips, and integer translations and produces a 1:1
|
||||
* mapping between source and destination pixels. If we transform an image
|
||||
* with a pixel-exact matrix, filtering is not useful.
|
||||
*/
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
|
||||
cairo_bool_t
|
||||
_cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_fixed_t x0_fixed, y0_fixed;
|
||||
|
||||
if (matrix->xy == 0.0 && matrix->yx == 0.0) {
|
||||
if (! (matrix->xx == 1.0 || matrix->xx == -1.0))
|
||||
return FALSE;
|
||||
|
|
@ -711,6 +704,22 @@ _cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
|
|||
} else
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* By pixel exact here, we mean a matrix that is composed only of
|
||||
* 90 degree rotations, flips, and integer translations and produces a 1:1
|
||||
* mapping between source and destination pixels. If we transform an image
|
||||
* with a pixel-exact matrix, filtering is not useful.
|
||||
*/
|
||||
cairo_bool_t
|
||||
_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_fixed_t x0_fixed, y0_fixed;
|
||||
|
||||
if (! _cairo_matrix_has_unity_scale (matrix))
|
||||
return FALSE;
|
||||
|
||||
x0_fixed = _cairo_fixed_from_double (matrix->x0);
|
||||
y0_fixed = _cairo_fixed_from_double (matrix->y0);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,29 +39,25 @@
|
|||
|
||||
typedef struct cairo_filler {
|
||||
double tolerance;
|
||||
cairo_traps_t *traps;
|
||||
|
||||
cairo_point_t current_point;
|
||||
|
||||
cairo_polygon_t polygon;
|
||||
cairo_polygon_t *polygon;
|
||||
} cairo_filler_t;
|
||||
|
||||
static void
|
||||
_cairo_filler_init (cairo_filler_t *filler, double tolerance, cairo_traps_t *traps)
|
||||
_cairo_filler_init (cairo_filler_t *filler,
|
||||
double tolerance,
|
||||
cairo_polygon_t *polygon)
|
||||
{
|
||||
filler->tolerance = tolerance;
|
||||
filler->traps = traps;
|
||||
filler->polygon = polygon;
|
||||
|
||||
filler->current_point.x = 0;
|
||||
filler->current_point.y = 0;
|
||||
|
||||
_cairo_polygon_init (&filler->polygon);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_filler_fini (cairo_filler_t *filler)
|
||||
{
|
||||
_cairo_polygon_fini (&filler->polygon);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
|
|
@ -69,14 +65,14 @@ _cairo_filler_move_to (void *closure,
|
|||
const cairo_point_t *point)
|
||||
{
|
||||
cairo_filler_t *filler = closure;
|
||||
cairo_polygon_t *polygon = &filler->polygon;
|
||||
cairo_polygon_t *polygon = filler->polygon;
|
||||
|
||||
_cairo_polygon_close (polygon);
|
||||
_cairo_polygon_move_to (polygon, point);
|
||||
|
||||
filler->current_point = *point;
|
||||
|
||||
return _cairo_polygon_status (&filler->polygon);
|
||||
return _cairo_polygon_status (filler->polygon);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
|
|
@ -84,13 +80,13 @@ _cairo_filler_line_to (void *closure,
|
|||
const cairo_point_t *point)
|
||||
{
|
||||
cairo_filler_t *filler = closure;
|
||||
cairo_polygon_t *polygon = &filler->polygon;
|
||||
cairo_polygon_t *polygon = filler->polygon;
|
||||
|
||||
_cairo_polygon_line_to (polygon, point);
|
||||
|
||||
filler->current_point = *point;
|
||||
|
||||
return _cairo_polygon_status (&filler->polygon);
|
||||
return _cairo_polygon_status (filler->polygon);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
|
|
@ -103,11 +99,10 @@ _cairo_filler_curve_to (void *closure,
|
|||
cairo_spline_t spline;
|
||||
|
||||
if (! _cairo_spline_init (&spline,
|
||||
_cairo_filler_line_to,
|
||||
filler,
|
||||
_cairo_filler_line_to, filler,
|
||||
&filler->current_point, b, c, d))
|
||||
{
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
return _cairo_filler_line_to (closure, d);
|
||||
}
|
||||
|
||||
return _cairo_spline_decompose (&spline, filler->tolerance);
|
||||
|
|
@ -117,36 +112,22 @@ static cairo_status_t
|
|||
_cairo_filler_close_path (void *closure)
|
||||
{
|
||||
cairo_filler_t *filler = closure;
|
||||
cairo_polygon_t *polygon = &filler->polygon;
|
||||
cairo_polygon_t *polygon = filler->polygon;
|
||||
|
||||
_cairo_polygon_close (polygon);
|
||||
|
||||
return _cairo_polygon_status (polygon);
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_path_fixed_fill_rectangle (const cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
cairo_traps_t *traps);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance,
|
||||
cairo_traps_t *traps)
|
||||
_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
|
||||
double tolerance,
|
||||
cairo_polygon_t *polygon)
|
||||
{
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_filler_t filler;
|
||||
cairo_status_t status;
|
||||
|
||||
traps->maybe_region = path->maybe_fill_region;
|
||||
|
||||
/* 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, fill_rule, traps);
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
return status;
|
||||
|
||||
_cairo_filler_init (&filler, tolerance, traps);
|
||||
_cairo_filler_init (&filler, tolerance, polygon);
|
||||
|
||||
status = _cairo_path_fixed_interpret (path,
|
||||
CAIRO_DIRECTION_FORWARD,
|
||||
|
|
@ -156,25 +137,48 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
|
|||
_cairo_filler_close_path,
|
||||
&filler);
|
||||
if (unlikely (status))
|
||||
goto BAIL;
|
||||
return status;
|
||||
|
||||
_cairo_polygon_close (&filler.polygon);
|
||||
status = _cairo_polygon_status (&filler.polygon);
|
||||
if (unlikely (status))
|
||||
goto BAIL;
|
||||
|
||||
status = _cairo_bentley_ottmann_tessellate_polygon (filler.traps,
|
||||
&filler.polygon,
|
||||
fill_rule);
|
||||
if (unlikely (status))
|
||||
goto BAIL;
|
||||
|
||||
BAIL:
|
||||
_cairo_polygon_close (polygon);
|
||||
status = _cairo_polygon_status (polygon);
|
||||
_cairo_filler_fini (&filler);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance,
|
||||
cairo_traps_t *traps)
|
||||
{
|
||||
cairo_polygon_t polygon;
|
||||
cairo_status_t status;
|
||||
|
||||
if (path->is_rectilinear) {
|
||||
status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
|
||||
fill_rule,
|
||||
traps);
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
return status;
|
||||
}
|
||||
|
||||
_cairo_polygon_init (&polygon);
|
||||
status = _cairo_path_fixed_fill_to_polygon (path,
|
||||
tolerance,
|
||||
&polygon);
|
||||
if (unlikely (status))
|
||||
goto CLEANUP;
|
||||
|
||||
status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon,
|
||||
fill_rule);
|
||||
|
||||
CLEANUP:
|
||||
_cairo_polygon_fini (&polygon);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* 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.
|
||||
|
|
@ -182,15 +186,14 @@ BAIL:
|
|||
* If the path described anything but a device-axis aligned rectangle,
|
||||
* this function will return %CAIRO_INT_STATUS_UNSUPPORTED.
|
||||
*/
|
||||
static cairo_int_status_t
|
||||
_cairo_path_fixed_fill_rectangle (const cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
cairo_traps_t *traps)
|
||||
cairo_int_status_t
|
||||
_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
cairo_traps_t *traps)
|
||||
{
|
||||
cairo_box_t box;
|
||||
|
||||
if (! path->is_rectilinear)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
assert (path->is_rectilinear);
|
||||
|
||||
if (_cairo_path_fixed_is_box (path, &box)) {
|
||||
if (box.p1.x > box.p2.x) {
|
||||
|
|
|
|||
191
src/cairo-pen.c
|
|
@ -393,194 +393,3 @@ _cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
|
|||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_pen_stroke_spline_add_convolved_point (cairo_pen_stroke_spline_t *stroker,
|
||||
const cairo_point_t *last_point,
|
||||
const cairo_slope_t *slope,
|
||||
cairo_point_t *last_hull_point,
|
||||
int active,
|
||||
int step)
|
||||
{
|
||||
do {
|
||||
cairo_point_t hull_point;
|
||||
|
||||
hull_point.x = last_point->x + stroker->pen.vertices[active].point.x;
|
||||
hull_point.y = last_point->y + stroker->pen.vertices[active].point.y;
|
||||
_cairo_polygon_add_edge (&stroker->polygon,
|
||||
last_hull_point, &hull_point,
|
||||
step);
|
||||
*last_hull_point = hull_point;
|
||||
|
||||
/* The strict inequalities here ensure that if a spline slope
|
||||
* compares identically with either of the slopes of the
|
||||
* active vertex, then it remains the active vertex. This is
|
||||
* very important since otherwise we can trigger an infinite
|
||||
* loop in the case of a degenerate pen, (a line), where
|
||||
* neither vertex considers itself active for the slope---one
|
||||
* will consider it as equal and reject, and the other will
|
||||
* consider it unequal and reject. This is due to the inherent
|
||||
* ambiguity when comparing slopes that differ by exactly
|
||||
* pi. */
|
||||
if (_cairo_slope_compare (slope,
|
||||
&stroker->pen.vertices[active].slope_ccw) > 0)
|
||||
{
|
||||
if (++active == stroker->pen.num_vertices)
|
||||
active = 0;
|
||||
}
|
||||
else if (_cairo_slope_compare (slope,
|
||||
&stroker->pen.vertices[active].slope_cw) < 0)
|
||||
{
|
||||
if (--active == -1)
|
||||
active = stroker->pen.num_vertices - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return active;
|
||||
}
|
||||
} while (TRUE);
|
||||
}
|
||||
|
||||
|
||||
/* Compute outline of a given spline using the pen.
|
||||
* The trapezoids needed to fill that outline will be added to traps
|
||||
*/
|
||||
cairo_status_t
|
||||
_cairo_pen_stroke_spline (cairo_pen_stroke_spline_t *stroker,
|
||||
double tolerance,
|
||||
cairo_traps_t *traps)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_slope_t slope;
|
||||
|
||||
/* If the line width is so small that the pen is reduced to a
|
||||
single point, then we have nothing to do. */
|
||||
if (stroker->pen.num_vertices <= 1)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
/* open the polygon */
|
||||
slope = stroker->spline.initial_slope;
|
||||
stroker->forward_vertex =
|
||||
_cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope);
|
||||
stroker->forward_hull_point.x = stroker->last_point.x +
|
||||
stroker->pen.vertices[stroker->forward_vertex].point.x;
|
||||
stroker->forward_hull_point.y = stroker->last_point.y +
|
||||
stroker->pen.vertices[stroker->forward_vertex].point.y;
|
||||
|
||||
slope.dx = -slope.dx;
|
||||
slope.dy = -slope.dy;
|
||||
stroker->backward_vertex =
|
||||
_cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope);
|
||||
stroker->backward_hull_point.x = stroker->last_point.x +
|
||||
stroker->pen.vertices[stroker->backward_vertex].point.x;
|
||||
stroker->backward_hull_point.y = stroker->last_point.y +
|
||||
stroker->pen.vertices[stroker->backward_vertex].point.y;
|
||||
|
||||
_cairo_polygon_add_edge (&stroker->polygon,
|
||||
&stroker->backward_hull_point,
|
||||
&stroker->forward_hull_point,
|
||||
1);
|
||||
|
||||
status = _cairo_spline_decompose (&stroker->spline, tolerance);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
/* close the polygon */
|
||||
slope = stroker->spline.final_slope;
|
||||
_cairo_pen_stroke_spline_add_convolved_point (stroker,
|
||||
&stroker->last_point,
|
||||
&slope,
|
||||
&stroker->forward_hull_point,
|
||||
stroker->forward_vertex,
|
||||
1);
|
||||
|
||||
slope.dx = -slope.dx;
|
||||
slope.dy = -slope.dy;
|
||||
_cairo_pen_stroke_spline_add_convolved_point (stroker,
|
||||
&stroker->last_point,
|
||||
&slope,
|
||||
&stroker->backward_hull_point,
|
||||
stroker->backward_vertex,
|
||||
-1);
|
||||
|
||||
_cairo_polygon_add_edge (&stroker->polygon,
|
||||
&stroker->forward_hull_point,
|
||||
&stroker->backward_hull_point,
|
||||
1);
|
||||
|
||||
status = _cairo_polygon_status (&stroker->polygon);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
status = _cairo_bentley_ottmann_tessellate_polygon (traps,
|
||||
&stroker->polygon,
|
||||
CAIRO_FILL_RULE_WINDING);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_pen_stroke_spline_add_point (void *closure,
|
||||
const cairo_point_t *point)
|
||||
{
|
||||
cairo_pen_stroke_spline_t *stroker = closure;
|
||||
cairo_slope_t slope;
|
||||
|
||||
_cairo_slope_init (&slope, &stroker->last_point, point);
|
||||
stroker->forward_vertex =
|
||||
_cairo_pen_stroke_spline_add_convolved_point (stroker,
|
||||
&stroker->last_point,
|
||||
&slope,
|
||||
&stroker->forward_hull_point,
|
||||
stroker->forward_vertex,
|
||||
1);
|
||||
|
||||
slope.dx = -slope.dx;
|
||||
slope.dy = -slope.dy;
|
||||
stroker->backward_vertex =
|
||||
_cairo_pen_stroke_spline_add_convolved_point (stroker,
|
||||
&stroker->last_point,
|
||||
&slope,
|
||||
&stroker->backward_hull_point,
|
||||
stroker->backward_vertex,
|
||||
-1);
|
||||
stroker->last_point = *point;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_int_status_t
|
||||
_cairo_pen_stroke_spline_init (cairo_pen_stroke_spline_t *stroker,
|
||||
const cairo_pen_t *pen,
|
||||
const cairo_point_t *a,
|
||||
const cairo_point_t *b,
|
||||
const cairo_point_t *c,
|
||||
const cairo_point_t *d)
|
||||
{
|
||||
cairo_int_status_t status;
|
||||
|
||||
if (! _cairo_spline_init (&stroker->spline,
|
||||
_cairo_pen_stroke_spline_add_point,
|
||||
stroker,
|
||||
a, b, c, d))
|
||||
{
|
||||
return CAIRO_INT_STATUS_DEGENERATE;
|
||||
}
|
||||
|
||||
status = _cairo_pen_init_copy (&stroker->pen, pen);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
_cairo_polygon_init (&stroker->polygon);
|
||||
|
||||
stroker->last_point = *a;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_pen_stroke_spline_fini (cairo_pen_stroke_spline_t *stroker)
|
||||
{
|
||||
_cairo_polygon_fini (&stroker->polygon);
|
||||
_cairo_pen_fini (&stroker->pen);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,18 @@ _cairo_polygon_init (cairo_polygon_t *polygon)
|
|||
polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded);
|
||||
|
||||
polygon->has_current_point = FALSE;
|
||||
polygon->has_limits = FALSE;
|
||||
|
||||
polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX;
|
||||
polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_polygon_limit (cairo_polygon_t *polygon,
|
||||
const cairo_box_t *limits)
|
||||
{
|
||||
polygon->has_limits = TRUE;
|
||||
polygon->limits = *limits;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -93,17 +105,16 @@ _cairo_polygon_grow (cairo_polygon_t *polygon)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_polygon_add_edge (cairo_polygon_t *polygon,
|
||||
const cairo_point_t *p1,
|
||||
const cairo_point_t *p2,
|
||||
int dir)
|
||||
static void
|
||||
_add_edge (cairo_polygon_t *polygon,
|
||||
const cairo_point_t *p1,
|
||||
const cairo_point_t *p2,
|
||||
int top, int bottom,
|
||||
int dir)
|
||||
{
|
||||
cairo_edge_t *edge;
|
||||
|
||||
/* drop horizontal edges */
|
||||
if (p1->y == p2->y)
|
||||
return;
|
||||
assert (top < bottom);
|
||||
|
||||
if (polygon->num_edges == polygon->edges_size) {
|
||||
if (! _cairo_polygon_grow (polygon))
|
||||
|
|
@ -111,26 +122,247 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon,
|
|||
}
|
||||
|
||||
edge = &polygon->edges[polygon->num_edges++];
|
||||
if (p1->y < p2->y) {
|
||||
edge->edge.p1 = *p1;
|
||||
edge->edge.p2 = *p2;
|
||||
edge->dir = dir;
|
||||
} else {
|
||||
edge->edge.p1 = *p2;
|
||||
edge->edge.p2 = *p1;
|
||||
edge->dir = -dir;
|
||||
edge->line.p1 = *p1;
|
||||
edge->line.p2 = *p2;
|
||||
edge->top = top;
|
||||
edge->bottom = bottom;
|
||||
edge->dir = dir;
|
||||
|
||||
if (top < polygon->extents.p1.y)
|
||||
polygon->extents.p1.y = top;
|
||||
if (bottom > polygon->extents.p2.y)
|
||||
polygon->extents.p2.y = bottom;
|
||||
|
||||
if (p1->x < polygon->extents.p1.x || p1->x > polygon->extents.p2.x) {
|
||||
cairo_fixed_t x = p1->x;
|
||||
if (top != p1->y)
|
||||
x = _cairo_edge_compute_intersection_x_for_y (p1, p2, top);
|
||||
if (x < polygon->extents.p1.x)
|
||||
polygon->extents.p1.x = x;
|
||||
if (x > polygon->extents.p2.x)
|
||||
polygon->extents.p2.x = x;
|
||||
}
|
||||
|
||||
if (p2->x < polygon->extents.p1.x || p2->x > polygon->extents.p2.x) {
|
||||
cairo_fixed_t x = p2->x;
|
||||
if (bottom != p2->y)
|
||||
x = _cairo_edge_compute_intersection_x_for_y (p1, p2, bottom);
|
||||
if (x < polygon->extents.p1.x)
|
||||
polygon->extents.p1.x = x;
|
||||
if (x > polygon->extents.p2.x)
|
||||
polygon->extents.p2.x = x;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_add_clipped_edge (cairo_polygon_t *polygon,
|
||||
const cairo_point_t *p1,
|
||||
const cairo_point_t *p2,
|
||||
int dir)
|
||||
{
|
||||
cairo_point_t p[2];
|
||||
int top_y, bot_y;
|
||||
|
||||
if (p1->x <= polygon->limits.p1.x && p2->x <= polygon->limits.p1.x)
|
||||
{
|
||||
p[0].x = polygon->limits.p1.x;
|
||||
p[0].y = polygon->limits.p1.y;
|
||||
top_y = p1->y;
|
||||
if (top_y < p[0].y)
|
||||
top_y = p[0].y;
|
||||
|
||||
p[1].x = polygon->limits.p1.x;
|
||||
p[1].y = polygon->limits.p2.y;
|
||||
bot_y = p2->y;
|
||||
if (bot_y > p[1].y)
|
||||
bot_y = p[1].y;
|
||||
|
||||
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
|
||||
}
|
||||
else if (p1->x >= polygon->limits.p2.x && p2->x >= polygon->limits.p2.x)
|
||||
{
|
||||
p[0].x = polygon->limits.p2.x;
|
||||
p[0].y = polygon->limits.p1.y;
|
||||
top_y = p1->y;
|
||||
if (top_y < p[0].y)
|
||||
top_y = p[0].y;
|
||||
|
||||
p[1].x = polygon->limits.p2.x;
|
||||
p[1].y = polygon->limits.p2.y;
|
||||
bot_y = p2->y;
|
||||
if (bot_y > p[1].y)
|
||||
bot_y = p[1].y;
|
||||
|
||||
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
|
||||
}
|
||||
else if (p1->x >= polygon->limits.p1.x && p2->x >= polygon->limits.p1.x &&
|
||||
p1->x <= polygon->limits.p2.x && p2->x <= polygon->limits.p2.x)
|
||||
{
|
||||
top_y = p1->y;
|
||||
if (top_y < polygon->limits.p1.y)
|
||||
top_y = polygon->limits.p1.y;
|
||||
|
||||
bot_y = p2->y;
|
||||
if (bot_y > polygon->limits.p2.y)
|
||||
bot_y = polygon->limits.p2.y;
|
||||
|
||||
_add_edge (polygon, p1, p2, top_y, bot_y, dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
int left_y, right_y;
|
||||
int p1_y, p2_y;
|
||||
|
||||
left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
|
||||
polygon->limits.p1.x);
|
||||
right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
|
||||
polygon->limits.p2.x);
|
||||
|
||||
if (left_y == right_y) /* horizontal within bounds */
|
||||
return;
|
||||
|
||||
p1_y = p1->y;
|
||||
p2_y = p2->y;
|
||||
|
||||
if (left_y < right_y) {
|
||||
if (p1->x < polygon->limits.p1.x && left_y > polygon->limits.p1.y)
|
||||
{
|
||||
p[0].x = polygon->limits.p1.x;
|
||||
p[0].y = polygon->limits.p1.y;
|
||||
top_y = p1_y;
|
||||
if (top_y < p[0].y)
|
||||
top_y = p[0].y;
|
||||
|
||||
p[1].x = polygon->limits.p1.x;
|
||||
p[1].y = polygon->limits.p2.y;
|
||||
bot_y = left_y;
|
||||
if (bot_y > p[1].y)
|
||||
bot_y = p[1].y;
|
||||
|
||||
if (bot_y > top_y)
|
||||
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
|
||||
p1_y = bot_y;
|
||||
}
|
||||
|
||||
if (p2->x > polygon->limits.p2.x && right_y < polygon->limits.p2.y)
|
||||
{
|
||||
p[0].x = polygon->limits.p2.x;
|
||||
p[0].y = polygon->limits.p1.y;
|
||||
top_y = right_y;
|
||||
if (top_y < p[0].y)
|
||||
top_y = p[0].y;
|
||||
|
||||
p[1].x = polygon->limits.p2.x;
|
||||
p[1].y = polygon->limits.p2.y;
|
||||
bot_y = p2_y;
|
||||
if (bot_y > p[1].y)
|
||||
bot_y = p[1].y;
|
||||
|
||||
if (bot_y > top_y)
|
||||
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
|
||||
p2_y = top_y;
|
||||
}
|
||||
} else {
|
||||
if (p1->x > polygon->limits.p2.x && right_y > polygon->limits.p1.y)
|
||||
{
|
||||
p[0].x = polygon->limits.p2.x;
|
||||
p[0].y = polygon->limits.p1.y;
|
||||
top_y = p1_y;
|
||||
if (top_y < p[0].y)
|
||||
top_y = p[0].y;
|
||||
|
||||
p[1].x = polygon->limits.p2.x;
|
||||
p[1].y = polygon->limits.p2.y;
|
||||
bot_y = right_y;
|
||||
if (bot_y > p[1].y)
|
||||
bot_y = p[1].y;
|
||||
|
||||
if (bot_y > top_y)
|
||||
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
|
||||
p1_y = bot_y;
|
||||
}
|
||||
|
||||
if (p2->x < polygon->limits.p1.x && left_y < polygon->limits.p2.y)
|
||||
{
|
||||
p[0].x = polygon->limits.p1.x;
|
||||
p[0].y = polygon->limits.p1.y;
|
||||
top_y = left_y;
|
||||
if (top_y < p[0].y)
|
||||
top_y = p[0].y;
|
||||
|
||||
p[1].x = polygon->limits.p1.x;
|
||||
p[1].y = polygon->limits.p2.y;
|
||||
bot_y = p2_y;
|
||||
if (bot_y > p[1].y)
|
||||
bot_y = p[1].y;
|
||||
|
||||
if (bot_y > top_y)
|
||||
_add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir);
|
||||
p2_y = top_y;
|
||||
}
|
||||
}
|
||||
|
||||
if (p1_y < polygon->limits.p1.y)
|
||||
p1_y = polygon->limits.p1.y;
|
||||
if (p2_y > polygon->limits.p2.y)
|
||||
p2_y = polygon->limits.p2.y;
|
||||
if (p2_y > p1_y)
|
||||
_add_edge (polygon, p1, p2, p1_y, p2_y, dir);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_polygon_add_edge (cairo_polygon_t *polygon,
|
||||
const cairo_point_t *p1,
|
||||
const cairo_point_t *p2)
|
||||
{
|
||||
int dir;
|
||||
|
||||
/* drop horizontal edges */
|
||||
if (p1->y == p2->y)
|
||||
return;
|
||||
|
||||
if (p1->y < p2->y) {
|
||||
dir = 1;
|
||||
} else {
|
||||
const cairo_point_t *t;
|
||||
t = p1, p1 = p2, p2 = t;
|
||||
dir = -1;
|
||||
}
|
||||
|
||||
if (polygon->has_limits) {
|
||||
if (p2->y <= polygon->limits.p1.y)
|
||||
return;
|
||||
|
||||
if (p1->y >= polygon->limits.p2.y)
|
||||
return;
|
||||
|
||||
_add_clipped_edge (polygon, p1, p2, dir);
|
||||
} else
|
||||
_add_edge (polygon, p1, p2, p1->y, p2->y, dir);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_polygon_add_external_edge (void *polygon,
|
||||
const cairo_point_t *p1,
|
||||
const cairo_point_t *p2)
|
||||
{
|
||||
_cairo_polygon_add_edge (polygon, p1, p2);
|
||||
return _cairo_polygon_status (polygon);
|
||||
}
|
||||
|
||||
/* flattened path operations */
|
||||
|
||||
void
|
||||
_cairo_polygon_move_to (cairo_polygon_t *polygon,
|
||||
const cairo_point_t *point)
|
||||
{
|
||||
if (! polygon->has_current_point)
|
||||
if (! polygon->has_current_point) {
|
||||
polygon->first_point = *point;
|
||||
polygon->has_current_point = TRUE;
|
||||
}
|
||||
|
||||
polygon->current_point = *point;
|
||||
polygon->has_current_point = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -138,7 +370,7 @@ _cairo_polygon_line_to (cairo_polygon_t *polygon,
|
|||
const cairo_point_t *point)
|
||||
{
|
||||
if (polygon->has_current_point)
|
||||
_cairo_polygon_add_edge (polygon, &polygon->current_point, point, 1);
|
||||
_cairo_polygon_add_edge (polygon, &polygon->current_point, point);
|
||||
|
||||
_cairo_polygon_move_to (polygon, point);
|
||||
}
|
||||
|
|
@ -149,8 +381,7 @@ _cairo_polygon_close (cairo_polygon_t *polygon)
|
|||
if (polygon->has_current_point) {
|
||||
_cairo_polygon_add_edge (polygon,
|
||||
&polygon->current_point,
|
||||
&polygon->first_point,
|
||||
1);
|
||||
&polygon->first_point);
|
||||
|
||||
polygon->has_current_point = FALSE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ typedef struct _skip_elt {
|
|||
#define SKIP_LIST_ELT_TO_DATA(type, elt) ((type *) ((char *) (elt) - (sizeof (type) - sizeof (skip_elt_t))))
|
||||
|
||||
typedef int
|
||||
(*cairo_skip_list_compare_t) (void *list, void *a, void *b);
|
||||
(*cairo_skip_list_compare_t) (void *list, const void *a, const void *b);
|
||||
|
||||
typedef struct _skip_list {
|
||||
cairo_skip_list_compare_t compare;
|
||||
|
|
@ -101,7 +101,7 @@ _cairo_skip_list_fini (cairo_skip_list_t *list);
|
|||
* Otherwise data will be copied (elt_size bytes from <data> via
|
||||
* memcpy) and the new element is returned. */
|
||||
cairo_private void *
|
||||
_cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique);
|
||||
_cairo_skip_list_insert (cairo_skip_list_t *list, void *data);
|
||||
|
||||
/* Find an element which compare considers equal to <data> */
|
||||
cairo_private void *
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ free_elt (cairo_skip_list_t *list, skip_elt_t *elt)
|
|||
* Insert 'data' into the list
|
||||
*/
|
||||
void *
|
||||
_cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique)
|
||||
_cairo_skip_list_insert (cairo_skip_list_t *list, void *data)
|
||||
{
|
||||
skip_elt_t **update[MAX_LEVEL];
|
||||
skip_elt_t *prev[MAX_LEVEL];
|
||||
|
|
@ -209,7 +209,7 @@ _cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique)
|
|||
for (; (elt = next[i]); next = elt->next)
|
||||
{
|
||||
int cmp = list->compare (list, ELT_DATA(elt), data);
|
||||
if (unique && 0 == cmp)
|
||||
if (0 == cmp)
|
||||
return ELT_DATA(elt);
|
||||
if (cmp > 0)
|
||||
break;
|
||||
|
|
@ -369,7 +369,7 @@ typedef struct {
|
|||
} test_elt_t;
|
||||
|
||||
static int
|
||||
test_cmp (void *list, void *A, void *B)
|
||||
test_cmp (void *list, const void *A, const void *B)
|
||||
{
|
||||
const test_elt_t *a = A, *b = B;
|
||||
return a->n - b->n;
|
||||
|
|
@ -386,7 +386,7 @@ main (void)
|
|||
for (n = 0; n < 10000000; n++) {
|
||||
void *elt_and_data;
|
||||
elt.n = n;
|
||||
elt_and_data = _cairo_skip_list_insert (&list, &elt, TRUE);
|
||||
elt_and_data = _cairo_skip_list_insert (&list, &elt);
|
||||
assert (elt_and_data != NULL);
|
||||
}
|
||||
_cairo_skip_list_fini (&list);
|
||||
|
|
|
|||
|
|
@ -94,9 +94,7 @@ _cairo_slope_compare (const cairo_slope_t *a, const cairo_slope_t *b)
|
|||
* of b by an infinitesimally small amount, (that is, 'a' will
|
||||
* always be considered less than 'b').
|
||||
*/
|
||||
if (((a->dx > 0) != (b->dx > 0)) ||
|
||||
((a->dy > 0) != (b->dy > 0)))
|
||||
{
|
||||
if ((a->dx ^ b->dx) < 0 || (a->dy ^ b->dy) < 0) {
|
||||
if (a->dx > 0 || (a->dx == 0 && a->dy > 0))
|
||||
return +1;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -75,22 +75,15 @@ struct _cairo_scan_converter {
|
|||
/* Destroy this scan converter. */
|
||||
cairo_destroy_func_t destroy;
|
||||
|
||||
/* Add an edge to the converter. */
|
||||
cairo_status_t
|
||||
(*add_edge)(
|
||||
void *abstract_converter,
|
||||
cairo_fixed_t x1,
|
||||
cairo_fixed_t y1,
|
||||
cairo_fixed_t x2,
|
||||
cairo_fixed_t y2);
|
||||
/* Add a polygon (set of edges) to the converter. */
|
||||
cairo_status_t (*add_polygon) (void *abstract_converter,
|
||||
const cairo_polygon_t *polygon);
|
||||
|
||||
/* Generates coverage spans for rows for the added edges and calls
|
||||
* the renderer function for each row. After generating spans the
|
||||
* only valid thing to do with the converter is to destroy it. */
|
||||
cairo_status_t
|
||||
(*generate)(
|
||||
void *abstract_converter,
|
||||
cairo_span_renderer_t *renderer);
|
||||
cairo_status_t (*generate) (void *abstract_converter,
|
||||
cairo_span_renderer_t *renderer);
|
||||
|
||||
/* Private status. Read with _cairo_scan_converter_status(). */
|
||||
cairo_status_t status;
|
||||
|
|
@ -99,12 +92,11 @@ struct _cairo_scan_converter {
|
|||
/* Scan converter constructors. */
|
||||
|
||||
cairo_private cairo_scan_converter_t *
|
||||
_cairo_tor_scan_converter_create(
|
||||
int xmin,
|
||||
int ymin,
|
||||
int xmax,
|
||||
int ymax,
|
||||
cairo_fill_rule_t fill_rule);
|
||||
_cairo_tor_scan_converter_create (int xmin,
|
||||
int ymin,
|
||||
int xmax,
|
||||
int ymax,
|
||||
cairo_fill_rule_t fill_rule);
|
||||
|
||||
/* cairo-spans.c: */
|
||||
|
||||
|
|
@ -132,14 +124,13 @@ _cairo_span_renderer_set_error (void *abstract_renderer,
|
|||
cairo_status_t error);
|
||||
|
||||
cairo_private 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);
|
||||
|
||||
#endif /* CAIRO_SPANS_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Carl D. Worth <cworth@cworth.org>
|
||||
* Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
|
||||
* Chris Wilson <chris@chris-wilson.co.uk>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
|
@ -41,6 +43,7 @@
|
|||
#include "cairo-surface-fallback-private.h"
|
||||
#include "cairo-clip-private.h"
|
||||
#include "cairo-region-private.h"
|
||||
#include "cairo-spans-private.h"
|
||||
|
||||
typedef struct {
|
||||
cairo_surface_t *dst;
|
||||
|
|
@ -739,8 +742,15 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
|
|||
}
|
||||
}
|
||||
|
||||
/* Otherwise we need to render the trapezoids to a mask and composite
|
||||
* in the usual fashion.
|
||||
/* No fast path, exclude self-intersections and clip trapezoids. */
|
||||
if (traps->has_intersections) {
|
||||
status = _cairo_bentley_ottmann_tessellate_traps (traps);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Otherwise render the trapezoids to a mask and composite in the usual
|
||||
* fashion.
|
||||
*/
|
||||
if (_cairo_operator_bounded_by_mask (op)) {
|
||||
cairo_rectangle_int_t trap_extents;
|
||||
|
|
@ -754,20 +764,20 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
|
|||
|
||||
traps_info.traps = traps;
|
||||
traps_info.antialias = antialias;
|
||||
|
||||
return _clip_and_composite (clip, op, src,
|
||||
_composite_traps_draw_func,
|
||||
&traps_info, dst, extents);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
cairo_path_fixed_t *path;
|
||||
cairo_polygon_t *polygon;
|
||||
cairo_fill_rule_t fill_rule;
|
||||
double tolerance;
|
||||
cairo_antialias_t antialias;
|
||||
} cairo_composite_spans_fill_info_t;
|
||||
} cairo_composite_spans_info_t;
|
||||
|
||||
static cairo_status_t
|
||||
_composite_spans_fill_func (void *closure,
|
||||
_composite_spans_draw_func (void *closure,
|
||||
cairo_operator_t op,
|
||||
const cairo_pattern_t *src,
|
||||
cairo_surface_t *dst,
|
||||
|
|
@ -777,7 +787,7 @@ _composite_spans_fill_func (void *closure,
|
|||
cairo_region_t *clip_region)
|
||||
{
|
||||
cairo_composite_rectangles_t rects;
|
||||
cairo_composite_spans_fill_info_t *info = closure;
|
||||
cairo_composite_spans_info_t *info = closure;
|
||||
|
||||
_cairo_composite_rectangles_init (
|
||||
&rects, extents->x, extents->y,
|
||||
|
|
@ -789,12 +799,12 @@ _composite_spans_fill_func (void *closure,
|
|||
rects.dst.x -= dst_x;
|
||||
rects.dst.y -= dst_y;
|
||||
|
||||
return _cairo_path_fixed_fill_using_spans (op, src, info->path, dst,
|
||||
info->fill_rule,
|
||||
info->tolerance,
|
||||
info->antialias,
|
||||
&rects,
|
||||
clip_region);
|
||||
return _cairo_surface_composite_polygon (dst, op, src,
|
||||
info->fill_rule,
|
||||
info->antialias,
|
||||
&rects,
|
||||
info->polygon,
|
||||
clip_region);
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
|
|
@ -930,11 +940,12 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
|
|||
cairo_antialias_t antialias,
|
||||
cairo_clip_t *clip)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_polygon_t polygon;
|
||||
cairo_traps_t traps;
|
||||
cairo_box_t box;
|
||||
cairo_rectangle_int_t extents;
|
||||
cairo_bool_t is_bounded;
|
||||
cairo_status_t status;
|
||||
|
||||
is_bounded = _cairo_surface_get_extents (surface, &extents);
|
||||
assert (is_bounded || clip);
|
||||
|
|
@ -952,22 +963,70 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
|
|||
|
||||
_cairo_box_from_rectangle (&box, &extents);
|
||||
|
||||
_cairo_polygon_init (&polygon);
|
||||
_cairo_polygon_limit (&polygon, &box);
|
||||
|
||||
_cairo_traps_init (&traps);
|
||||
_cairo_traps_limit (&traps, &box);
|
||||
|
||||
status = _cairo_path_fixed_stroke_to_traps (path,
|
||||
stroke_style,
|
||||
ctm, ctm_inverse,
|
||||
tolerance,
|
||||
&traps);
|
||||
if (unlikely (status))
|
||||
goto FAIL;
|
||||
if (path->is_rectilinear) {
|
||||
status = _cairo_path_fixed_stroke_rectilinear_to_traps (path,
|
||||
stroke_style,
|
||||
ctm,
|
||||
&traps);
|
||||
if (likely (status == CAIRO_STATUS_SUCCESS))
|
||||
goto DO_TRAPS;
|
||||
|
||||
status = _clip_and_composite_trapezoids (source, op,
|
||||
surface, &traps, antialias,
|
||||
if (_cairo_status_is_error (status))
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
status = _cairo_path_fixed_stroke_to_polygon (path,
|
||||
stroke_style,
|
||||
ctm, ctm_inverse,
|
||||
tolerance,
|
||||
&polygon);
|
||||
if (unlikely (status))
|
||||
goto CLEANUP;
|
||||
|
||||
if (_cairo_operator_bounded_by_mask (op)) {
|
||||
cairo_rectangle_int_t polygon_extents;
|
||||
|
||||
_cairo_box_round_to_rectangle (&polygon.extents, &polygon_extents);
|
||||
if (! _cairo_rectangle_intersect (&extents, &polygon_extents))
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
if (antialias != CAIRO_ANTIALIAS_NONE &&
|
||||
_cairo_surface_check_span_renderer (op, source, surface,
|
||||
antialias, NULL))
|
||||
{
|
||||
cairo_composite_spans_info_t info;
|
||||
|
||||
info.polygon = &polygon;
|
||||
info.fill_rule = CAIRO_FILL_RULE_WINDING;
|
||||
info.antialias = antialias;
|
||||
|
||||
status = _clip_and_composite (clip, op, source,
|
||||
_composite_spans_draw_func,
|
||||
&info, surface, &extents);
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
/* Fall back to trapezoid fills. */
|
||||
status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
|
||||
&polygon,
|
||||
CAIRO_FILL_RULE_WINDING);
|
||||
if (unlikely (status))
|
||||
goto CLEANUP;
|
||||
|
||||
DO_TRAPS:
|
||||
status = _clip_and_composite_trapezoids (source, op, surface,
|
||||
&traps, antialias,
|
||||
clip, &extents);
|
||||
FAIL:
|
||||
CLEANUP:
|
||||
_cairo_traps_fini (&traps);
|
||||
_cairo_polygon_fini (&polygon);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -982,11 +1041,12 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
|
|||
cairo_antialias_t antialias,
|
||||
cairo_clip_t *clip)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_polygon_t polygon;
|
||||
cairo_traps_t traps;
|
||||
cairo_box_t box;
|
||||
cairo_rectangle_int_t extents;
|
||||
cairo_bool_t is_bounded;
|
||||
cairo_status_t status;
|
||||
|
||||
is_bounded = _cairo_surface_get_extents (surface, &extents);
|
||||
assert (is_bounded || clip);
|
||||
|
|
@ -1002,71 +1062,69 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
|
|||
if (! _rectangle_intersect_clip (&extents, clip))
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
/* XXX future direction:
|
||||
status = _cairo_path_fixed_fill_to_region (path, fill_rule, ®ion);
|
||||
if (status != CAIRO_STATUS_INT_UNSUPPORTED) {
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
status = _clip_and_composite_region ();
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
return status;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Ask if the surface would like to render this combination of
|
||||
* op/source/dst/antialias with spans or not, but don't actually
|
||||
* make a renderer yet. We'll try to hit the region optimisations
|
||||
* in _clip_and_composite_trapezoids() if it looks like the path
|
||||
* is a region. */
|
||||
/* TODO: Until we have a mono scan converter we won't even try
|
||||
* to use spans for CAIRO_ANTIALIAS_NONE. */
|
||||
/* TODO: The region filling code should be lifted from
|
||||
* _clip_and_composite_trapezoids() and given first priority
|
||||
* explicitly before deciding between spans and trapezoids. */
|
||||
if (antialias != CAIRO_ANTIALIAS_NONE && ! path->is_rectilinear &&
|
||||
_cairo_surface_check_span_renderer (
|
||||
op, source, surface, antialias, NULL))
|
||||
{
|
||||
cairo_composite_spans_fill_info_t info;
|
||||
info.path = path;
|
||||
info.fill_rule = fill_rule;
|
||||
info.tolerance = tolerance;
|
||||
info.antialias = antialias;
|
||||
|
||||
if (_cairo_operator_bounded_by_mask (op)) {
|
||||
cairo_rectangle_int_t path_extents;
|
||||
|
||||
_cairo_path_fixed_approximate_clip_extents (path,
|
||||
&path_extents);
|
||||
if (! _cairo_rectangle_intersect (&extents, &path_extents))
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return _clip_and_composite (clip, op, source,
|
||||
_composite_spans_fill_func,
|
||||
&info,
|
||||
surface,
|
||||
&extents);
|
||||
}
|
||||
|
||||
/* Fall back to trapezoid fills. */
|
||||
_cairo_box_from_rectangle (&box, &extents);
|
||||
|
||||
_cairo_polygon_init (&polygon);
|
||||
_cairo_polygon_limit (&polygon, &box);
|
||||
|
||||
_cairo_traps_init (&traps);
|
||||
_cairo_traps_limit (&traps, &box);
|
||||
|
||||
status = _cairo_path_fixed_fill_to_traps (path,
|
||||
fill_rule,
|
||||
tolerance,
|
||||
&traps);
|
||||
if (unlikely (status))
|
||||
goto FAIL;
|
||||
if (path->is_rectilinear) {
|
||||
status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
|
||||
fill_rule,
|
||||
&traps);
|
||||
if (likely (status == CAIRO_STATUS_SUCCESS))
|
||||
goto DO_TRAPS;
|
||||
|
||||
if (_cairo_status_is_error (status))
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
status = _cairo_path_fixed_fill_to_polygon (path,
|
||||
tolerance,
|
||||
&polygon);
|
||||
if (unlikely (status))
|
||||
goto CLEANUP;
|
||||
|
||||
if (_cairo_operator_bounded_by_mask (op)) {
|
||||
cairo_rectangle_int_t polygon_extents;
|
||||
|
||||
_cairo_box_round_to_rectangle (&polygon.extents, &polygon_extents);
|
||||
if (! _cairo_rectangle_intersect (&extents, &polygon_extents))
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
if (antialias != CAIRO_ANTIALIAS_NONE &&
|
||||
_cairo_surface_check_span_renderer (op, source, surface,
|
||||
antialias, NULL))
|
||||
{
|
||||
cairo_composite_spans_info_t info;
|
||||
|
||||
info.polygon = &polygon;
|
||||
info.fill_rule = fill_rule;
|
||||
info.antialias = antialias;
|
||||
|
||||
status = _clip_and_composite (clip, op, source,
|
||||
_composite_spans_draw_func,
|
||||
&info, surface, &extents);
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
/* Fall back to trapezoid fills. */
|
||||
status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
|
||||
&polygon,
|
||||
fill_rule);
|
||||
if (unlikely (status))
|
||||
goto CLEANUP;
|
||||
|
||||
DO_TRAPS:
|
||||
status = _clip_and_composite_trapezoids (source, op, surface,
|
||||
&traps, antialias,
|
||||
clip, &extents);
|
||||
FAIL:
|
||||
CLEANUP:
|
||||
_cairo_traps_fini (&traps);
|
||||
_cairo_polygon_fini (&polygon);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,11 +199,8 @@ glitter_scan_converter_reset(
|
|||
* converter should be reset or destroyed. Dir must be +1 or -1,
|
||||
* with the latter reversing the orientation of the edge. */
|
||||
I glitter_status_t
|
||||
glitter_scan_converter_add_edge(
|
||||
glitter_scan_converter_t *converter,
|
||||
glitter_input_scaled_t x1, glitter_input_scaled_t y1,
|
||||
glitter_input_scaled_t x2, glitter_input_scaled_t y2,
|
||||
int dir);
|
||||
glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
|
||||
const cairo_edge_t *edge);
|
||||
|
||||
/* Render the polygon in the scan converter to the given A8 format
|
||||
* image raster. Only the pixels accessible as pixels[y*stride+x] for
|
||||
|
|
@ -623,10 +620,8 @@ _pool_alloc_from_new_chunk(
|
|||
}
|
||||
|
||||
if (NULL == chunk) {
|
||||
chunk = _pool_chunk_create(
|
||||
pool->current,
|
||||
capacity);
|
||||
if (NULL == chunk)
|
||||
chunk = _pool_chunk_create (pool->current, capacity);
|
||||
if (unlikely (NULL == chunk))
|
||||
return NULL;
|
||||
}
|
||||
pool->current = chunk;
|
||||
|
|
@ -643,9 +638,7 @@ _pool_alloc_from_new_chunk(
|
|||
* allocation failures. The pool retains ownership of the returned
|
||||
* memory. */
|
||||
inline static void *
|
||||
pool_alloc(
|
||||
struct pool *pool,
|
||||
size_t size)
|
||||
pool_alloc (struct pool *pool, size_t size)
|
||||
{
|
||||
struct _pool_chunk *chunk = pool->current;
|
||||
|
||||
|
|
@ -653,15 +646,14 @@ pool_alloc(
|
|||
void *obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size);
|
||||
chunk->size += size;
|
||||
return obj;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return _pool_alloc_from_new_chunk(pool, size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Relinquish all pool_alloced memory back to the pool. */
|
||||
static void
|
||||
pool_reset(struct pool *pool)
|
||||
pool_reset (struct pool *pool)
|
||||
{
|
||||
/* Transfer all used chunks to the chunk free list. */
|
||||
struct _pool_chunk *chunk = pool->current;
|
||||
|
|
@ -680,19 +672,18 @@ pool_reset(struct pool *pool)
|
|||
/* Rewinds the cell list's cursor to the beginning. After rewinding
|
||||
* we're good to cell_list_find() the cell any x coordinate. */
|
||||
inline static void
|
||||
cell_list_rewind(struct cell_list *cells)
|
||||
cell_list_rewind (struct cell_list *cells)
|
||||
{
|
||||
cells->cursor = &cells->head;
|
||||
}
|
||||
|
||||
/* Rewind the cell list if its cursor has been advanced past x. */
|
||||
inline static void
|
||||
cell_list_maybe_rewind(struct cell_list *cells, int x)
|
||||
cell_list_maybe_rewind (struct cell_list *cells, int x)
|
||||
{
|
||||
struct cell *tail = *cells->cursor;
|
||||
if (tail->x > x) {
|
||||
cell_list_rewind(cells);
|
||||
}
|
||||
if (tail->x > x)
|
||||
cell_list_rewind (cells);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -704,24 +695,24 @@ cell_list_init(struct cell_list *cells)
|
|||
cells->tail.next = NULL;
|
||||
cells->tail.x = INT_MAX;
|
||||
cells->head = &cells->tail;
|
||||
cell_list_rewind(cells);
|
||||
cell_list_rewind (cells);
|
||||
}
|
||||
|
||||
static void
|
||||
cell_list_fini(struct cell_list *cells)
|
||||
{
|
||||
pool_fini(cells->cell_pool.base);
|
||||
cell_list_init(cells);
|
||||
pool_fini (cells->cell_pool.base);
|
||||
cell_list_init (cells);
|
||||
}
|
||||
|
||||
/* Empty the cell list. This is called at the start of every pixel
|
||||
* row. */
|
||||
inline static void
|
||||
cell_list_reset(struct cell_list *cells)
|
||||
cell_list_reset (struct cell_list *cells)
|
||||
{
|
||||
cell_list_rewind(cells);
|
||||
cell_list_rewind (cells);
|
||||
cells->head = &cells->tail;
|
||||
pool_reset(cells->cell_pool.base);
|
||||
pool_reset (cells->cell_pool.base);
|
||||
}
|
||||
|
||||
/* Find a cell at the given x-coordinate. Returns %NULL if a new cell
|
||||
|
|
@ -730,7 +721,7 @@ cell_list_reset(struct cell_list *cells)
|
|||
* cell_list_rewind(). Ownership of the returned cell is retained by
|
||||
* the cell list. */
|
||||
inline static struct cell *
|
||||
cell_list_find(struct cell_list *cells, int x)
|
||||
cell_list_find (struct cell_list *cells, int x)
|
||||
{
|
||||
struct cell **cursor = cells->cursor;
|
||||
struct cell *tail;
|
||||
|
|
@ -749,11 +740,12 @@ cell_list_find(struct cell_list *cells, int x)
|
|||
if (tail->x == x) {
|
||||
return tail;
|
||||
} else {
|
||||
struct cell *cell = pool_alloc(
|
||||
cells->cell_pool.base,
|
||||
sizeof(struct cell));
|
||||
if (NULL == cell)
|
||||
struct cell *cell;
|
||||
|
||||
cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell));
|
||||
if (unlikely (NULL == cell))
|
||||
return NULL;
|
||||
|
||||
*cursor = cell;
|
||||
cell->next = tail;
|
||||
cell->x = x;
|
||||
|
|
@ -785,17 +777,18 @@ cell_list_find_pair(struct cell_list *cells, int x1, int x2)
|
|||
cell1 = *cursor;
|
||||
if (cell1->x > x1)
|
||||
break;
|
||||
|
||||
if (cell1->x == x1)
|
||||
goto found_first;
|
||||
|
||||
cursor = &cell1->next;
|
||||
});
|
||||
}
|
||||
|
||||
/* New first cell at x1. */
|
||||
newcell = pool_alloc(
|
||||
cells->cell_pool.base,
|
||||
sizeof(struct cell));
|
||||
if (NULL != newcell) {
|
||||
newcell = pool_alloc (cells->cell_pool.base,
|
||||
sizeof (struct cell));
|
||||
if (likely (NULL != newcell)) {
|
||||
*cursor = newcell;
|
||||
newcell->next = cell1;
|
||||
newcell->x = x1;
|
||||
|
|
@ -818,10 +811,9 @@ cell_list_find_pair(struct cell_list *cells, int x1, int x2)
|
|||
}
|
||||
|
||||
/* New second cell at x2. */
|
||||
newcell = pool_alloc(
|
||||
cells->cell_pool.base,
|
||||
sizeof(struct cell));
|
||||
if (NULL != newcell) {
|
||||
newcell = pool_alloc (cells->cell_pool.base,
|
||||
sizeof (struct cell));
|
||||
if (likely (NULL != newcell)) {
|
||||
*cursor = newcell;
|
||||
newcell->next = cell2;
|
||||
newcell->x = x2;
|
||||
|
|
@ -849,12 +841,13 @@ cell_list_add_unbounded_subspan(
|
|||
|
||||
GRID_X_TO_INT_FRAC(x, ix, fx);
|
||||
|
||||
cell = cell_list_find(cells, ix);
|
||||
if (cell) {
|
||||
cell = cell_list_find (cells, ix);
|
||||
if (likely (cell != NULL)) {
|
||||
cell->uncovered_area += 2*fx;
|
||||
cell->covered_height++;
|
||||
return GLITTER_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return GLITTER_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
|
@ -874,17 +867,16 @@ cell_list_add_subspan(
|
|||
if (ix1 != ix2) {
|
||||
struct cell_pair p;
|
||||
p = cell_list_find_pair(cells, ix1, ix2);
|
||||
if (p.cell1 && p.cell2) {
|
||||
if (likely (p.cell1 != NULL && p.cell2 != NULL)) {
|
||||
p.cell1->uncovered_area += 2*fx1;
|
||||
++p.cell1->covered_height;
|
||||
p.cell2->uncovered_area -= 2*fx2;
|
||||
--p.cell2->covered_height;
|
||||
return GLITTER_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
struct cell *cell = cell_list_find(cells, ix1);
|
||||
if (cell) {
|
||||
if (likely (cell != NULL)) {
|
||||
cell->uncovered_area += 2*(fx1-fx2);
|
||||
return GLITTER_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -938,8 +930,9 @@ cell_list_render_edge(
|
|||
/* We always know that ix1 is >= the cell list cursor in this
|
||||
* case due to the no-intersections precondition. */
|
||||
struct cell *cell = cell_list_find(cells, ix1);
|
||||
if (NULL == cell)
|
||||
if (unlikely (NULL == cell))
|
||||
return GLITTER_STATUS_NO_MEMORY;
|
||||
|
||||
cell->covered_height += sign*GRID_Y;
|
||||
cell->uncovered_area += sign*(fx1 + fx2)*GRID_Y;
|
||||
return GLITTER_STATUS_SUCCESS;
|
||||
|
|
@ -988,7 +981,7 @@ cell_list_render_edge(
|
|||
cell_list_maybe_rewind(cells, ix1);
|
||||
|
||||
pair = cell_list_find_pair(cells, ix1, ix1+1);
|
||||
if (!pair.cell1 || !pair.cell2)
|
||||
if (unlikely (!pair.cell1 || !pair.cell2))
|
||||
return GLITTER_STATUS_NO_MEMORY;
|
||||
|
||||
pair.cell1->uncovered_area += sign*y.quo*(GRID_X + fx1);
|
||||
|
|
@ -1016,7 +1009,7 @@ cell_list_render_edge(
|
|||
|
||||
++ix1;
|
||||
cell = cell_list_find(cells, ix1);
|
||||
if (NULL == cell)
|
||||
if (unlikely (NULL == cell))
|
||||
return GLITTER_STATUS_NO_MEMORY;
|
||||
} while (ix1 != ix2);
|
||||
|
||||
|
|
@ -1030,22 +1023,22 @@ cell_list_render_edge(
|
|||
}
|
||||
|
||||
static void
|
||||
polygon_init(struct polygon *polygon)
|
||||
polygon_init (struct polygon *polygon)
|
||||
{
|
||||
polygon->ymin = polygon->ymax = 0;
|
||||
polygon->y_buckets = polygon->y_buckets_embedded;
|
||||
pool_init(polygon->edge_pool.base,
|
||||
8192 - sizeof(struct _pool_chunk),
|
||||
sizeof(polygon->edge_pool.embedded));
|
||||
pool_init (polygon->edge_pool.base,
|
||||
8192 - sizeof (struct _pool_chunk),
|
||||
sizeof (polygon->edge_pool.embedded));
|
||||
}
|
||||
|
||||
static void
|
||||
polygon_fini(struct polygon *polygon)
|
||||
polygon_fini (struct polygon *polygon)
|
||||
{
|
||||
if (polygon->y_buckets != polygon->y_buckets_embedded)
|
||||
free(polygon->y_buckets);
|
||||
pool_fini(polygon->edge_pool.base);
|
||||
polygon_init(polygon);
|
||||
free (polygon->y_buckets);
|
||||
|
||||
pool_fini (polygon->edge_pool.base);
|
||||
}
|
||||
|
||||
/* Empties the polygon of all edges. The polygon is then prepared to
|
||||
|
|
@ -1063,11 +1056,12 @@ polygon_reset(
|
|||
|
||||
pool_reset(polygon->edge_pool.base);
|
||||
|
||||
if (h > 0x7FFFFFFFU - EDGE_Y_BUCKET_HEIGHT)
|
||||
if (unlikely (h > 0x7FFFFFFFU - EDGE_Y_BUCKET_HEIGHT))
|
||||
goto bail_no_mem; /* even if you could, you wouldn't want to. */
|
||||
|
||||
if (polygon->y_buckets != polygon->y_buckets_embedded)
|
||||
free (polygon->y_buckets);
|
||||
|
||||
polygon->y_buckets = polygon->y_buckets_embedded;
|
||||
if (num_buckets > ARRAY_LENGTH (polygon->y_buckets_embedded)) {
|
||||
polygon->y_buckets = _cairo_malloc_ab (num_buckets,
|
||||
|
|
@ -1099,11 +1093,8 @@ _polygon_insert_edge_into_its_y_bucket(
|
|||
}
|
||||
|
||||
inline static glitter_status_t
|
||||
polygon_add_edge(
|
||||
struct polygon *polygon,
|
||||
int x0, int y0,
|
||||
int x1, int y1,
|
||||
int dir)
|
||||
polygon_add_edge (struct polygon *polygon,
|
||||
const cairo_edge_t *edge)
|
||||
{
|
||||
struct edge *e;
|
||||
grid_scaled_x_t dx;
|
||||
|
|
@ -1112,54 +1103,45 @@ polygon_add_edge(
|
|||
grid_scaled_y_t ymin = polygon->ymin;
|
||||
grid_scaled_y_t ymax = polygon->ymax;
|
||||
|
||||
if (y0 == y1)
|
||||
assert (edge->bottom > edge->top);
|
||||
|
||||
if (unlikely (edge->top >= ymax || edge->bottom <= ymin))
|
||||
return GLITTER_STATUS_SUCCESS;
|
||||
|
||||
if (y0 > y1) {
|
||||
int tmp;
|
||||
tmp = x0; x0 = x1; x1 = tmp;
|
||||
tmp = y0; y0 = y1; y1 = tmp;
|
||||
dir = -dir;
|
||||
}
|
||||
|
||||
if (y0 >= ymax || y1 <= ymin)
|
||||
return GLITTER_STATUS_SUCCESS;
|
||||
|
||||
e = pool_alloc(polygon->edge_pool.base,
|
||||
sizeof(struct edge));
|
||||
if (NULL == e)
|
||||
e = pool_alloc (polygon->edge_pool.base, sizeof (struct edge));
|
||||
if (unlikely (NULL == e))
|
||||
return GLITTER_STATUS_NO_MEMORY;
|
||||
|
||||
dx = x1 - x0;
|
||||
dy = y1 - y0;
|
||||
dx = edge->line.p2.x - edge->line.p1.x;
|
||||
dy = edge->line.p2.y - edge->line.p1.y;
|
||||
e->dy = dy;
|
||||
e->dxdy = floored_divrem(dx, dy);
|
||||
e->dxdy = floored_divrem (dx, dy);
|
||||
|
||||
if (ymin <= y0) {
|
||||
ytop = y0;
|
||||
e->x.quo = x0;
|
||||
e->x.rem = 0;
|
||||
}
|
||||
else {
|
||||
if (ymin <= edge->top)
|
||||
ytop = edge->top;
|
||||
else
|
||||
ytop = ymin;
|
||||
e->x = floored_muldivrem(ymin - y0, dx, dy);
|
||||
e->x.quo += x0;
|
||||
if (ytop == edge->line.p1.y) {
|
||||
e->x.quo = edge->line.p1.x;
|
||||
e->x.rem = 0;
|
||||
} else {
|
||||
e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy);
|
||||
e->x.quo += edge->line.p1.x;
|
||||
}
|
||||
|
||||
e->dir = dir;
|
||||
e->dir = edge->dir;
|
||||
e->ytop = ytop;
|
||||
ybot = y1 < ymax ? y1 : ymax;
|
||||
ybot = edge->bottom < ymax ? edge->bottom : ymax;
|
||||
e->height_left = ybot - ytop;
|
||||
|
||||
if (e->height_left >= GRID_Y) {
|
||||
e->dxdy_full = floored_muldivrem(GRID_Y, dx, dy);
|
||||
}
|
||||
else {
|
||||
e->dxdy_full = floored_muldivrem (GRID_Y, dx, dy);
|
||||
} else {
|
||||
e->dxdy_full.quo = 0;
|
||||
e->dxdy_full.rem = 0;
|
||||
}
|
||||
|
||||
_polygon_insert_edge_into_its_y_bucket(polygon, e);
|
||||
_polygon_insert_edge_into_its_y_bucket (polygon, e);
|
||||
|
||||
e->x.rem -= dy; /* Bias the remainder for faster
|
||||
* edge advancement. */
|
||||
|
|
@ -1167,8 +1149,7 @@ polygon_add_edge(
|
|||
}
|
||||
|
||||
static void
|
||||
active_list_reset(
|
||||
struct active_list *active)
|
||||
active_list_reset (struct active_list *active)
|
||||
{
|
||||
active->head = NULL;
|
||||
active->min_height = 0;
|
||||
|
|
@ -1292,8 +1273,7 @@ active_list_merge_edges_from_polygon(
|
|||
subrow_edges = tail;
|
||||
if (tail->height_left < min_height)
|
||||
min_height = tail->height_left;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ptail = &tail->next;
|
||||
}
|
||||
}
|
||||
|
|
@ -1347,9 +1327,8 @@ active_list_substep_edges(
|
|||
}
|
||||
|
||||
inline static glitter_status_t
|
||||
apply_nonzero_fill_rule_for_subrow(
|
||||
struct active_list *active,
|
||||
struct cell_list *coverages)
|
||||
apply_nonzero_fill_rule_for_subrow (struct active_list *active,
|
||||
struct cell_list *coverages)
|
||||
{
|
||||
struct edge *edge = active->head;
|
||||
int winding = 0;
|
||||
|
|
@ -1357,25 +1336,26 @@ apply_nonzero_fill_rule_for_subrow(
|
|||
int xend;
|
||||
int status;
|
||||
|
||||
cell_list_rewind(coverages);
|
||||
cell_list_rewind (coverages);
|
||||
|
||||
while (NULL != edge) {
|
||||
xstart = edge->x.quo;
|
||||
winding = edge->dir;
|
||||
while (1) {
|
||||
edge = edge->next;
|
||||
if (NULL == edge) {
|
||||
return cell_list_add_unbounded_subspan(
|
||||
coverages, xstart);
|
||||
}
|
||||
if (NULL == edge)
|
||||
return cell_list_add_unbounded_subspan (coverages, xstart);
|
||||
|
||||
winding += edge->dir;
|
||||
if (0 == winding)
|
||||
break;
|
||||
if (0 == winding) {
|
||||
if (edge->next == NULL || edge->next->x.quo != edge->x.quo)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xend = edge->x.quo;
|
||||
status = cell_list_add_subspan(coverages, xstart, xend);
|
||||
if (status)
|
||||
status = cell_list_add_subspan (coverages, xstart, xend);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
edge = edge->next;
|
||||
|
|
@ -1385,29 +1365,33 @@ apply_nonzero_fill_rule_for_subrow(
|
|||
}
|
||||
|
||||
static glitter_status_t
|
||||
apply_evenodd_fill_rule_for_subrow(
|
||||
struct active_list *active,
|
||||
struct cell_list *coverages)
|
||||
apply_evenodd_fill_rule_for_subrow (struct active_list *active,
|
||||
struct cell_list *coverages)
|
||||
{
|
||||
struct edge *edge = active->head;
|
||||
int xstart;
|
||||
int xend;
|
||||
int status;
|
||||
|
||||
cell_list_rewind(coverages);
|
||||
cell_list_rewind (coverages);
|
||||
|
||||
while (NULL != edge) {
|
||||
xstart = edge->x.quo;
|
||||
|
||||
edge = edge->next;
|
||||
if (NULL == edge) {
|
||||
return cell_list_add_unbounded_subspan(
|
||||
coverages, xstart);
|
||||
while (1) {
|
||||
edge = edge->next;
|
||||
if (NULL == edge)
|
||||
return cell_list_add_unbounded_subspan (coverages, xstart);
|
||||
|
||||
if (edge->next == NULL || edge->next->x.quo != edge->x.quo)
|
||||
break;
|
||||
|
||||
edge = edge->next;
|
||||
}
|
||||
|
||||
xend = edge->x.quo;
|
||||
status = cell_list_add_subspan(coverages, xstart, xend);
|
||||
if (status)
|
||||
status = cell_list_add_subspan (coverages, xstart, xend);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
edge = edge->next;
|
||||
|
|
@ -1417,9 +1401,8 @@ apply_evenodd_fill_rule_for_subrow(
|
|||
}
|
||||
|
||||
static glitter_status_t
|
||||
apply_nonzero_fill_rule_and_step_edges(
|
||||
struct active_list *active,
|
||||
struct cell_list *coverages)
|
||||
apply_nonzero_fill_rule_and_step_edges (struct active_list *active,
|
||||
struct cell_list *coverages)
|
||||
{
|
||||
struct edge **cursor = &active->head;
|
||||
struct edge *left_edge;
|
||||
|
|
@ -1431,32 +1414,30 @@ apply_nonzero_fill_rule_and_step_edges(
|
|||
int winding = left_edge->dir;
|
||||
|
||||
left_edge->height_left -= GRID_Y;
|
||||
if (left_edge->height_left) {
|
||||
if (left_edge->height_left)
|
||||
cursor = &left_edge->next;
|
||||
}
|
||||
else {
|
||||
else
|
||||
*cursor = left_edge->next;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
right_edge = *cursor;
|
||||
|
||||
if (NULL == right_edge) {
|
||||
return cell_list_render_edge(
|
||||
coverages, left_edge, +1);
|
||||
}
|
||||
if (NULL == right_edge)
|
||||
return cell_list_render_edge (coverages, left_edge, +1);
|
||||
|
||||
right_edge->height_left -= GRID_Y;
|
||||
if (right_edge->height_left) {
|
||||
if (right_edge->height_left)
|
||||
cursor = &right_edge->next;
|
||||
}
|
||||
else {
|
||||
else
|
||||
*cursor = right_edge->next;
|
||||
}
|
||||
|
||||
winding += right_edge->dir;
|
||||
if (0 == winding)
|
||||
break;
|
||||
if (0 == winding) {
|
||||
if (right_edge->next == NULL ||
|
||||
right_edge->next->x.quo != right_edge->x.quo)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
right_edge->x.quo += right_edge->dxdy_full.quo;
|
||||
right_edge->x.rem += right_edge->dxdy_full.rem;
|
||||
|
|
@ -1466,13 +1447,12 @@ apply_nonzero_fill_rule_and_step_edges(
|
|||
}
|
||||
}
|
||||
|
||||
status = cell_list_render_edge(
|
||||
coverages, left_edge, +1);
|
||||
if (status)
|
||||
status = cell_list_render_edge (coverages, left_edge, +1);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
status = cell_list_render_edge(
|
||||
coverages, right_edge, -1);
|
||||
if (status)
|
||||
|
||||
status = cell_list_render_edge (coverages, right_edge, -1);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
left_edge = *cursor;
|
||||
|
|
@ -1482,9 +1462,8 @@ apply_nonzero_fill_rule_and_step_edges(
|
|||
}
|
||||
|
||||
static glitter_status_t
|
||||
apply_evenodd_fill_rule_and_step_edges(
|
||||
struct active_list *active,
|
||||
struct cell_list *coverages)
|
||||
apply_evenodd_fill_rule_and_step_edges (struct active_list *active,
|
||||
struct cell_list *coverages)
|
||||
{
|
||||
struct edge **cursor = &active->head;
|
||||
struct edge *left_edge;
|
||||
|
|
@ -1495,35 +1474,42 @@ apply_evenodd_fill_rule_and_step_edges(
|
|||
struct edge *right_edge;
|
||||
|
||||
left_edge->height_left -= GRID_Y;
|
||||
if (left_edge->height_left) {
|
||||
if (left_edge->height_left)
|
||||
cursor = &left_edge->next;
|
||||
}
|
||||
else {
|
||||
else
|
||||
*cursor = left_edge->next;
|
||||
|
||||
while (1) {
|
||||
right_edge = *cursor;
|
||||
if (NULL == right_edge)
|
||||
return cell_list_render_edge (coverages, left_edge, +1);
|
||||
|
||||
right_edge->height_left -= GRID_Y;
|
||||
if (right_edge->height_left)
|
||||
cursor = &right_edge->next;
|
||||
else
|
||||
*cursor = right_edge->next;
|
||||
|
||||
if (right_edge->next == NULL ||
|
||||
right_edge->next->x.quo != right_edge->x.quo)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
right_edge->x.quo += right_edge->dxdy_full.quo;
|
||||
right_edge->x.rem += right_edge->dxdy_full.rem;
|
||||
if (right_edge->x.rem >= 0) {
|
||||
++right_edge->x.quo;
|
||||
right_edge->x.rem -= right_edge->dy;
|
||||
}
|
||||
}
|
||||
|
||||
right_edge = *cursor;
|
||||
|
||||
if (NULL == right_edge) {
|
||||
return cell_list_render_edge(
|
||||
coverages, left_edge, +1);
|
||||
}
|
||||
|
||||
right_edge->height_left -= GRID_Y;
|
||||
if (right_edge->height_left) {
|
||||
cursor = &right_edge->next;
|
||||
}
|
||||
else {
|
||||
*cursor = right_edge->next;
|
||||
}
|
||||
|
||||
status = cell_list_render_edge(
|
||||
coverages, left_edge, +1);
|
||||
if (status)
|
||||
status = cell_list_render_edge (coverages, left_edge, +1);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
status = cell_list_render_edge(
|
||||
coverages, right_edge, -1);
|
||||
if (status)
|
||||
|
||||
status = cell_list_render_edge (coverages, right_edge, -1);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
left_edge = *cursor;
|
||||
|
|
@ -1692,26 +1678,28 @@ glitter_scan_converter_reset(
|
|||
} while (0)
|
||||
|
||||
I glitter_status_t
|
||||
glitter_scan_converter_add_edge(
|
||||
glitter_scan_converter_t *converter,
|
||||
glitter_input_scaled_t x1, glitter_input_scaled_t y1,
|
||||
glitter_input_scaled_t x2, glitter_input_scaled_t y2,
|
||||
int dir)
|
||||
glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
|
||||
const cairo_edge_t *edge)
|
||||
{
|
||||
/* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */
|
||||
grid_scaled_y_t sx1, sy1;
|
||||
grid_scaled_y_t sx2, sy2;
|
||||
cairo_edge_t e;
|
||||
|
||||
INPUT_TO_GRID_Y(y1, sy1);
|
||||
INPUT_TO_GRID_Y(y2, sy2);
|
||||
if (sy1 == sy2)
|
||||
INPUT_TO_GRID_Y (edge->top, e.top);
|
||||
INPUT_TO_GRID_Y (edge->bottom, e.bottom);
|
||||
if (e.top == e.bottom)
|
||||
return GLITTER_STATUS_SUCCESS;
|
||||
|
||||
INPUT_TO_GRID_X(x1, sx1);
|
||||
INPUT_TO_GRID_X(x2, sx2);
|
||||
/* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */
|
||||
INPUT_TO_GRID_Y (edge->line.p1.y, e.line.p1.y);
|
||||
INPUT_TO_GRID_Y (edge->line.p2.y, e.line.p2.y);
|
||||
if (e.line.p1.y == e.line.p2.y)
|
||||
return GLITTER_STATUS_SUCCESS;
|
||||
|
||||
return polygon_add_edge(
|
||||
converter->polygon, sx1, sy1, sx2, sy2, dir);
|
||||
INPUT_TO_GRID_X (edge->line.p1.x, e.line.p1.x);
|
||||
INPUT_TO_GRID_X (edge->line.p2.x, e.line.p2.x);
|
||||
|
||||
e.dir = edge->dir;
|
||||
|
||||
return polygon_add_edge (converter->polygon, &e);
|
||||
}
|
||||
|
||||
#ifndef GLITTER_BLIT_COVERAGES_BEGIN
|
||||
|
|
@ -1756,58 +1744,54 @@ glitter_scan_converter_render(
|
|||
|
||||
/* Determine if we can ignore this row or use the full pixel
|
||||
* stepper. */
|
||||
if (GRID_Y == EDGE_Y_BUCKET_HEIGHT
|
||||
&& !polygon->y_buckets[i])
|
||||
{
|
||||
if (!active->head) {
|
||||
GLITTER_BLIT_COVERAGES_EMPTY(i+ymin_i, xmin_i, xmax_i);
|
||||
if (GRID_Y == EDGE_Y_BUCKET_HEIGHT && ! polygon->y_buckets[i]) {
|
||||
if (! active->head) {
|
||||
GLITTER_BLIT_COVERAGES_EMPTY (i+ymin_i, xmin_i, xmax_i);
|
||||
continue;
|
||||
}
|
||||
do_full_step = active_list_can_step_full_row(active);
|
||||
|
||||
do_full_step = active_list_can_step_full_row (active);
|
||||
}
|
||||
|
||||
cell_list_reset(coverages);
|
||||
cell_list_reset (coverages);
|
||||
|
||||
if (do_full_step) {
|
||||
/* Step by a full pixel row's worth. */
|
||||
if (nonzero_fill) {
|
||||
status = apply_nonzero_fill_rule_and_step_edges(
|
||||
active, coverages);
|
||||
status = apply_nonzero_fill_rule_and_step_edges (active,
|
||||
coverages);
|
||||
} else {
|
||||
status = apply_evenodd_fill_rule_and_step_edges (active,
|
||||
coverages);
|
||||
}
|
||||
else {
|
||||
status = apply_evenodd_fill_rule_and_step_edges(
|
||||
active, coverages);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* Subsample this row. */
|
||||
grid_scaled_y_t suby;
|
||||
for (suby = 0; suby < GRID_Y; suby++) {
|
||||
grid_scaled_y_t y = (i+ymin_i)*GRID_Y + suby;
|
||||
|
||||
active_list_merge_edges_from_polygon(
|
||||
active, y, polygon);
|
||||
active_list_merge_edges_from_polygon (active, y, polygon);
|
||||
|
||||
if (nonzero_fill)
|
||||
status |= apply_nonzero_fill_rule_for_subrow(
|
||||
active, coverages);
|
||||
else
|
||||
status |= apply_evenodd_fill_rule_for_subrow(
|
||||
active, coverages);
|
||||
if (nonzero_fill) {
|
||||
status |= apply_nonzero_fill_rule_for_subrow (active,
|
||||
coverages);
|
||||
} else {
|
||||
status |= apply_evenodd_fill_rule_for_subrow (active,
|
||||
coverages);
|
||||
}
|
||||
|
||||
active_list_substep_edges(active);
|
||||
}
|
||||
}
|
||||
|
||||
if (status)
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
GLITTER_BLIT_COVERAGES(coverages, i+ymin_i, xmin_i, xmax_i);
|
||||
|
||||
if (!active->head) {
|
||||
if (! active->head) {
|
||||
active->min_height = INT_MAX;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
active->min_height -= GRID_Y;
|
||||
}
|
||||
}
|
||||
|
|
@ -1860,7 +1844,7 @@ blit_with_span_renderer(
|
|||
/* Allocate enough spans for the row. */
|
||||
pool_reset (span_pool);
|
||||
spans = pool_alloc (span_pool, sizeof(spans[0])*num_spans);
|
||||
if (spans == NULL)
|
||||
if (unlikely (spans == NULL))
|
||||
return GLITTER_STATUS_NO_MEMORY;
|
||||
|
||||
num_spans = 0;
|
||||
|
|
@ -1906,6 +1890,7 @@ blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y)
|
|||
|
||||
struct _cairo_tor_scan_converter {
|
||||
cairo_scan_converter_t base;
|
||||
|
||||
glitter_scan_converter_t converter[1];
|
||||
cairo_fill_rule_t fill_rule;
|
||||
|
||||
|
|
@ -1918,9 +1903,9 @@ struct _cairo_tor_scan_converter {
|
|||
typedef struct _cairo_tor_scan_converter cairo_tor_scan_converter_t;
|
||||
|
||||
static void
|
||||
_cairo_tor_scan_converter_destroy(void *abstract_converter)
|
||||
_cairo_tor_scan_converter_destroy (void *converter)
|
||||
{
|
||||
cairo_tor_scan_converter_t *self = abstract_converter;
|
||||
cairo_tor_scan_converter_t *self = converter;
|
||||
if (self == NULL) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1930,69 +1915,70 @@ _cairo_tor_scan_converter_destroy(void *abstract_converter)
|
|||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_tor_scan_converter_add_edge(
|
||||
void *abstract_converter,
|
||||
cairo_fixed_t x1,
|
||||
cairo_fixed_t y1,
|
||||
cairo_fixed_t x2,
|
||||
cairo_fixed_t y2)
|
||||
_cairo_tor_scan_converter_add_polygon (void *converter,
|
||||
const cairo_polygon_t *polygon)
|
||||
{
|
||||
cairo_tor_scan_converter_t *self = abstract_converter;
|
||||
cairo_tor_scan_converter_t *self = converter;
|
||||
cairo_status_t status;
|
||||
status = glitter_scan_converter_add_edge (
|
||||
self->converter,
|
||||
x1, y1, x2, y2, +1);
|
||||
if (status) {
|
||||
return _cairo_scan_converter_set_error (self,
|
||||
_cairo_error (status));
|
||||
int i;
|
||||
|
||||
for (i = 0; i < polygon->num_edges; i++) {
|
||||
status = glitter_scan_converter_add_edge (self->converter,
|
||||
&polygon->edges[i]);
|
||||
if (unlikely (status)) {
|
||||
return _cairo_scan_converter_set_error (self,
|
||||
_cairo_error (status));
|
||||
}
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_tor_scan_converter_generate(
|
||||
void *abstract_converter,
|
||||
cairo_span_renderer_t *renderer)
|
||||
_cairo_tor_scan_converter_generate (void *converter,
|
||||
cairo_span_renderer_t *renderer)
|
||||
{
|
||||
cairo_tor_scan_converter_t *self = abstract_converter;
|
||||
cairo_status_t status = glitter_scan_converter_render (
|
||||
self->converter,
|
||||
self->fill_rule == CAIRO_FILL_RULE_WINDING,
|
||||
renderer,
|
||||
self->span_pool.base);
|
||||
if (status) {
|
||||
return _cairo_scan_converter_set_error (self,
|
||||
_cairo_error (status));
|
||||
}
|
||||
cairo_tor_scan_converter_t *self = converter;
|
||||
cairo_status_t status;
|
||||
|
||||
status = glitter_scan_converter_render (self->converter,
|
||||
self->fill_rule == CAIRO_FILL_RULE_WINDING,
|
||||
renderer,
|
||||
self->span_pool.base);
|
||||
if (unlikely (status))
|
||||
return _cairo_scan_converter_set_error (self, _cairo_error (status));
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_scan_converter_t *
|
||||
_cairo_tor_scan_converter_create(
|
||||
int xmin,
|
||||
int ymin,
|
||||
int xmax,
|
||||
int ymax,
|
||||
cairo_fill_rule_t fill_rule)
|
||||
_cairo_tor_scan_converter_create (int xmin,
|
||||
int ymin,
|
||||
int xmax,
|
||||
int ymax,
|
||||
cairo_fill_rule_t fill_rule)
|
||||
{
|
||||
cairo_tor_scan_converter_t *self;
|
||||
cairo_status_t status;
|
||||
cairo_tor_scan_converter_t *self =
|
||||
calloc (1, sizeof(struct _cairo_tor_scan_converter));
|
||||
if (self == NULL)
|
||||
goto bail_nomem;
|
||||
|
||||
self->base.destroy = &_cairo_tor_scan_converter_destroy;
|
||||
self->base.add_edge = &_cairo_tor_scan_converter_add_edge;
|
||||
self->base.generate = &_cairo_tor_scan_converter_generate;
|
||||
self = calloc (1, sizeof(struct _cairo_tor_scan_converter));
|
||||
if (unlikely (self == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto bail_nomem;
|
||||
}
|
||||
|
||||
self->base.destroy = _cairo_tor_scan_converter_destroy;
|
||||
self->base.add_polygon = _cairo_tor_scan_converter_add_polygon;
|
||||
self->base.generate = _cairo_tor_scan_converter_generate;
|
||||
|
||||
pool_init (self->span_pool.base,
|
||||
250 * sizeof(self->span_pool.embedded[0]),
|
||||
sizeof(self->span_pool.embedded));
|
||||
|
||||
_glitter_scan_converter_init (self->converter);
|
||||
status = glitter_scan_converter_reset (
|
||||
self->converter, xmin, ymin, xmax, ymax);
|
||||
if (status != CAIRO_STATUS_SUCCESS)
|
||||
status = glitter_scan_converter_reset (self->converter,
|
||||
xmin, ymin, xmax, ymax);
|
||||
if (unlikely (status))
|
||||
goto bail;
|
||||
|
||||
self->fill_rule = fill_rule;
|
||||
|
|
@ -2002,5 +1988,5 @@ _cairo_tor_scan_converter_create(
|
|||
bail:
|
||||
self->base.destroy(&self->base);
|
||||
bail_nomem:
|
||||
return _cairo_scan_converter_create_in_error (CAIRO_STATUS_NO_MEMORY);
|
||||
return _cairo_scan_converter_create_in_error (status);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -520,5 +520,6 @@ _cairo_toy_font_face_reset_static_data (void)
|
|||
cairo_toy_font_face_hash_table = NULL;
|
||||
CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex);
|
||||
|
||||
_cairo_hash_table_destroy (hash_table);
|
||||
if (hash_table != NULL)
|
||||
_cairo_hash_table_destroy (hash_table);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ _cairo_traps_init (cairo_traps_t *traps)
|
|||
traps->extents.p2.x = traps->extents.p2.y = INT32_MIN;
|
||||
|
||||
traps->has_limits = FALSE;
|
||||
traps->has_intersections = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -74,14 +75,6 @@ _cairo_traps_limit (cairo_traps_t *traps,
|
|||
traps->limits = *limits;
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_traps_get_limit (cairo_traps_t *traps,
|
||||
cairo_box_t *limits)
|
||||
{
|
||||
*limits = traps->limits;
|
||||
return traps->has_limits;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_traps_clear (cairo_traps_t *traps)
|
||||
{
|
||||
|
|
@ -90,6 +83,7 @@ _cairo_traps_clear (cairo_traps_t *traps)
|
|||
traps->maybe_region = 1;
|
||||
|
||||
traps->num_traps = 0;
|
||||
traps->has_intersections = FALSE;
|
||||
traps->extents.p1.x = traps->extents.p1.y = INT32_MAX;
|
||||
traps->extents.p2.x = traps->extents.p2.y = INT32_MIN;
|
||||
}
|
||||
|
|
@ -165,6 +159,12 @@ _cairo_traps_grow (cairo_traps_t *traps)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static cairo_fixed_t
|
||||
_line_compute_intersection_x_for_y (const cairo_line_t *line,
|
||||
cairo_fixed_t y)
|
||||
{
|
||||
return _cairo_edge_compute_intersection_x_for_y (&line->p1, &line->p2, y);
|
||||
}
|
||||
void
|
||||
_cairo_traps_add_trap (cairo_traps_t *traps,
|
||||
cairo_fixed_t top, cairo_fixed_t bottom,
|
||||
|
|
@ -257,23 +257,44 @@ _cairo_traps_add_trap (cairo_traps_t *traps,
|
|||
traps->extents.p1.y = top;
|
||||
if (bottom > traps->extents.p2.y)
|
||||
traps->extents.p2.y = bottom;
|
||||
/*
|
||||
* This isn't generally accurate, but it is close enough for
|
||||
* this purpose. Assuming that the left and right segments always
|
||||
* contain the trapezoid vertical extents, these compares will
|
||||
* yield a containing box. Assuming that the points all come from
|
||||
* the same figure which will eventually be completely drawn, then
|
||||
* the compares will yield the correct overall extents
|
||||
*/
|
||||
if (left->p1.x < traps->extents.p1.x)
|
||||
traps->extents.p1.x = left->p1.x;
|
||||
if (left->p2.x < traps->extents.p1.x)
|
||||
traps->extents.p1.x = left->p2.x;
|
||||
|
||||
if (right->p1.x > traps->extents.p2.x)
|
||||
traps->extents.p2.x = right->p1.x;
|
||||
if (right->p2.x > traps->extents.p2.x)
|
||||
traps->extents.p2.x = right->p2.x;
|
||||
if (left->p1.x < traps->extents.p1.x) {
|
||||
cairo_fixed_t x = left->p1.x;
|
||||
if (top != left->p1.y) {
|
||||
x = _line_compute_intersection_x_for_y (left, top);
|
||||
if (x < traps->extents.p1.x)
|
||||
traps->extents.p1.x = x;
|
||||
} else
|
||||
traps->extents.p1.x = x;
|
||||
}
|
||||
if (left->p2.x < traps->extents.p1.x) {
|
||||
cairo_fixed_t x = left->p2.x;
|
||||
if (bottom != left->p2.y) {
|
||||
x = _line_compute_intersection_x_for_y (left, bottom);
|
||||
if (x < traps->extents.p1.x)
|
||||
traps->extents.p1.x = x;
|
||||
} else
|
||||
traps->extents.p1.x = x;
|
||||
}
|
||||
|
||||
if (right->p1.x > traps->extents.p2.x) {
|
||||
cairo_fixed_t x = right->p1.x;
|
||||
if (top != right->p1.y) {
|
||||
x = _line_compute_intersection_x_for_y (right, top);
|
||||
if (x > traps->extents.p2.x)
|
||||
traps->extents.p2.x = x;
|
||||
} else
|
||||
traps->extents.p2.x = x;
|
||||
}
|
||||
if (right->p2.x > traps->extents.p2.x) {
|
||||
cairo_fixed_t x = right->p2.x;
|
||||
if (bottom != right->p2.y) {
|
||||
x = _line_compute_intersection_x_for_y (right, bottom);
|
||||
if (x > traps->extents.p2.x)
|
||||
traps->extents.p2.x = x;
|
||||
} else
|
||||
traps->extents.p2.x = x;
|
||||
}
|
||||
|
||||
traps->num_traps++;
|
||||
}
|
||||
|
|
@ -284,9 +305,8 @@ _compare_point_fixed_by_y (const void *av, const void *bv)
|
|||
const cairo_point_t *a = av, *b = bv;
|
||||
|
||||
int ret = a->y - b->y;
|
||||
if (ret == 0) {
|
||||
if (ret == 0)
|
||||
ret = a->x - b->x;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -177,13 +177,7 @@ typedef enum _cairo_internal_surface_type {
|
|||
#define CAIRO_HAS_TEST_NULL_SURFACE 1
|
||||
#define CAIRO_HAS_TEST_WRAPPING_SURFACE 1
|
||||
|
||||
typedef struct _cairo_point {
|
||||
cairo_fixed_t x;
|
||||
cairo_fixed_t y;
|
||||
} cairo_point_t;
|
||||
|
||||
typedef struct _cairo_slope
|
||||
{
|
||||
typedef struct _cairo_slope {
|
||||
cairo_fixed_t dx;
|
||||
cairo_fixed_t dy;
|
||||
} cairo_slope_t, cairo_distance_t;
|
||||
|
|
@ -244,7 +238,8 @@ typedef enum _cairo_direction {
|
|||
} cairo_direction_t;
|
||||
|
||||
typedef struct _cairo_edge {
|
||||
cairo_line_t edge;
|
||||
cairo_line_t line;
|
||||
int top, bottom;
|
||||
int dir;
|
||||
} cairo_edge_t;
|
||||
|
||||
|
|
@ -255,6 +250,10 @@ typedef struct _cairo_polygon {
|
|||
cairo_point_t current_point;
|
||||
cairo_bool_t has_current_point;
|
||||
|
||||
cairo_box_t extents;
|
||||
cairo_box_t limits;
|
||||
cairo_bool_t has_limits;
|
||||
|
||||
int num_edges;
|
||||
int edges_size;
|
||||
cairo_edge_t *edges;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@
|
|||
|
||||
#if !HAVE_UINT64_T
|
||||
|
||||
cairo_uquorem64_t I
|
||||
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den);
|
||||
|
||||
cairo_uint64_t I _cairo_uint32_to_uint64 (uint32_t i);
|
||||
#define _cairo_uint64_to_uint32(a) ((a).lo)
|
||||
cairo_uint64_t I _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b);
|
||||
|
|
@ -90,6 +93,16 @@ int I _cairo_int64_cmp (cairo_int64_t a, cairo_int64_t b);
|
|||
|
||||
#else
|
||||
|
||||
static inline cairo_uquorem64_t
|
||||
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
|
||||
{
|
||||
cairo_uquorem64_t qr;
|
||||
|
||||
qr.quo = num / den;
|
||||
qr.rem = num % den;
|
||||
return qr;
|
||||
}
|
||||
|
||||
#define _cairo_uint32_to_uint64(i) ((uint64_t) (i))
|
||||
#define _cairo_uint64_to_uint32(i) ((uint32_t) (i))
|
||||
#define _cairo_uint64_add(a,b) ((a) + (b))
|
||||
|
|
@ -147,11 +160,35 @@ int I _cairo_int64_cmp (cairo_int64_t a, cairo_int64_t b);
|
|||
* a function which returns both for the 'native' type as well
|
||||
*/
|
||||
|
||||
cairo_uquorem64_t I
|
||||
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den);
|
||||
static inline cairo_quorem64_t
|
||||
_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
|
||||
{
|
||||
int num_neg = _cairo_int64_negative (num);
|
||||
int den_neg = _cairo_int64_negative (den);
|
||||
cairo_uquorem64_t uqr;
|
||||
cairo_quorem64_t qr;
|
||||
|
||||
cairo_quorem64_t I
|
||||
_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den);
|
||||
if (num_neg)
|
||||
num = _cairo_int64_negate (num);
|
||||
if (den_neg)
|
||||
den = _cairo_int64_negate (den);
|
||||
uqr = _cairo_uint64_divrem (num, den);
|
||||
if (num_neg)
|
||||
qr.rem = _cairo_int64_negate (uqr.rem);
|
||||
else
|
||||
qr.rem = uqr.rem;
|
||||
if (num_neg != den_neg)
|
||||
qr.quo = (cairo_int64_t) _cairo_int64_negate (uqr.quo);
|
||||
else
|
||||
qr.quo = (cairo_int64_t) uqr.quo;
|
||||
return qr;
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
_cairo_int64_32_div (cairo_int64_t num, int32_t den)
|
||||
{
|
||||
return num / den;
|
||||
}
|
||||
|
||||
/*
|
||||
* 128-bit datatypes. Again, provide two implementations in
|
||||
|
|
|
|||
|
|
@ -39,16 +39,6 @@
|
|||
|
||||
#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
|
||||
|
||||
cairo_uquorem64_t
|
||||
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
|
||||
{
|
||||
cairo_uquorem64_t qr;
|
||||
|
||||
qr.quo = num / den;
|
||||
qr.rem = num % den;
|
||||
return qr;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
cairo_uint64_t
|
||||
|
|
@ -317,30 +307,6 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
|
|||
|
||||
#endif /* !HAVE_UINT64_T */
|
||||
|
||||
cairo_quorem64_t
|
||||
_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
|
||||
{
|
||||
int num_neg = _cairo_int64_negative (num);
|
||||
int den_neg = _cairo_int64_negative (den);
|
||||
cairo_uquorem64_t uqr;
|
||||
cairo_quorem64_t qr;
|
||||
|
||||
if (num_neg)
|
||||
num = _cairo_int64_negate (num);
|
||||
if (den_neg)
|
||||
den = _cairo_int64_negate (den);
|
||||
uqr = _cairo_uint64_divrem (num, den);
|
||||
if (num_neg)
|
||||
qr.rem = _cairo_int64_negate (uqr.rem);
|
||||
else
|
||||
qr.rem = uqr.rem;
|
||||
if (num_neg != den_neg)
|
||||
qr.quo = (cairo_int64_t) _cairo_int64_negate (uqr.quo);
|
||||
else
|
||||
qr.quo = (cairo_int64_t) uqr.quo;
|
||||
return qr;
|
||||
}
|
||||
|
||||
#if HAVE_UINT128_T
|
||||
|
||||
cairo_uquorem128_t
|
||||
|
|
|
|||
102
src/cairoint.h
|
|
@ -952,6 +952,7 @@ typedef struct _cairo_traps {
|
|||
cairo_status_t status;
|
||||
|
||||
cairo_box_t extents;
|
||||
cairo_box_t limits;
|
||||
|
||||
unsigned int maybe_region : 1; /* hint: 0 implies that it cannot be */
|
||||
|
||||
|
|
@ -962,7 +963,7 @@ typedef struct _cairo_traps {
|
|||
cairo_trapezoid_t traps_embedded[4];
|
||||
|
||||
cairo_bool_t has_limits;
|
||||
cairo_box_t limits;
|
||||
cairo_bool_t has_intersections;
|
||||
} cairo_traps_t;
|
||||
|
||||
#define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL
|
||||
|
|
@ -1609,13 +1610,36 @@ _cairo_path_fixed_in_fill (const cairo_path_fixed_t *path,
|
|||
|
||||
/* cairo-path-fill.c */
|
||||
cairo_private cairo_status_t
|
||||
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance,
|
||||
cairo_traps_t *traps);
|
||||
_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
|
||||
double tolerance,
|
||||
cairo_polygon_t *polygon);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
cairo_traps_t *traps);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance,
|
||||
cairo_traps_t *traps);
|
||||
|
||||
/* cairo-path-stroke.c */
|
||||
cairo_private cairo_status_t
|
||||
_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
|
||||
cairo_stroke_style_t *stroke_style,
|
||||
const cairo_matrix_t *ctm,
|
||||
const cairo_matrix_t *ctm_inverse,
|
||||
double tolerance,
|
||||
cairo_polygon_t *polygon);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path,
|
||||
cairo_stroke_style_t *stroke_style,
|
||||
const cairo_matrix_t *ctm,
|
||||
cairo_traps_t *traps);
|
||||
cairo_private cairo_status_t
|
||||
_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
|
||||
cairo_stroke_style_t *stroke_style,
|
||||
const cairo_matrix_t *ctm,
|
||||
|
|
@ -1623,6 +1647,22 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
|
|||
double tolerance,
|
||||
cairo_traps_t *traps);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path,
|
||||
cairo_stroke_style_t *stroke_style,
|
||||
cairo_matrix_t *ctm,
|
||||
cairo_matrix_t *ctm_inverse,
|
||||
double tolerance,
|
||||
cairo_status_t (*add_triangle) (void *closure,
|
||||
const cairo_point_t triangle[3]),
|
||||
cairo_status_t (*add_triangle_fan) (void *closure,
|
||||
const cairo_point_t *midpt,
|
||||
const cairo_point_t *points,
|
||||
int npoints),
|
||||
cairo_status_t (*add_quad) (void *closure,
|
||||
const cairo_point_t quad[4]),
|
||||
void *closure);
|
||||
|
||||
/* cairo-scaled-font.c */
|
||||
|
||||
cairo_private void
|
||||
|
|
@ -2201,45 +2241,21 @@ cairo_private int
|
|||
_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
|
||||
const cairo_slope_t *slope);
|
||||
|
||||
typedef struct _cairo_pen_stroke_spline {
|
||||
cairo_pen_t pen;
|
||||
cairo_spline_t spline;
|
||||
cairo_polygon_t polygon;
|
||||
cairo_point_t last_point;
|
||||
cairo_point_t forward_hull_point;
|
||||
cairo_point_t backward_hull_point;
|
||||
int forward_vertex;
|
||||
int backward_vertex;
|
||||
} cairo_pen_stroke_spline_t;
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_pen_stroke_spline_init (cairo_pen_stroke_spline_t *stroker,
|
||||
const cairo_pen_t *pen,
|
||||
const cairo_point_t *a,
|
||||
const cairo_point_t *b,
|
||||
const cairo_point_t *c,
|
||||
const cairo_point_t *d);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_pen_stroke_spline (cairo_pen_stroke_spline_t *pen,
|
||||
double tolerance,
|
||||
cairo_traps_t *traps);
|
||||
|
||||
cairo_private void
|
||||
_cairo_pen_stroke_spline_fini (cairo_pen_stroke_spline_t *stroker);
|
||||
|
||||
/* cairo-polygon.c */
|
||||
cairo_private void
|
||||
_cairo_polygon_init (cairo_polygon_t *polygon);
|
||||
|
||||
cairo_private void
|
||||
_cairo_polygon_fini (cairo_polygon_t *polygon);
|
||||
_cairo_polygon_limit (cairo_polygon_t *polygon,
|
||||
const cairo_box_t *limits);
|
||||
|
||||
cairo_private void
|
||||
_cairo_polygon_add_edge (cairo_polygon_t *polygon,
|
||||
const cairo_point_t *p1,
|
||||
const cairo_point_t *p2,
|
||||
int dir);
|
||||
_cairo_polygon_fini (cairo_polygon_t *polygon);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_polygon_add_external_edge (void *polygon,
|
||||
const cairo_point_t *p1,
|
||||
const cairo_point_t *p2);
|
||||
|
||||
cairo_private void
|
||||
_cairo_polygon_move_to (cairo_polygon_t *polygon,
|
||||
|
|
@ -2252,7 +2268,7 @@ _cairo_polygon_line_to (cairo_polygon_t *polygon,
|
|||
cairo_private void
|
||||
_cairo_polygon_close (cairo_polygon_t *polygon);
|
||||
|
||||
#define _cairo_polygon_status(P) (P)->status
|
||||
#define _cairo_polygon_status(P) ((cairo_polygon_t *) (P))->status
|
||||
|
||||
/* cairo-spline.c */
|
||||
cairo_private cairo_bool_t
|
||||
|
|
@ -2309,6 +2325,9 @@ cairo_private cairo_bool_t
|
|||
_cairo_matrix_is_integer_translation(const cairo_matrix_t *matrix,
|
||||
int *itx, int *ity);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix) cairo_pure;
|
||||
|
||||
|
|
@ -2330,10 +2349,6 @@ cairo_private void
|
|||
_cairo_traps_limit (cairo_traps_t *traps,
|
||||
cairo_box_t *limits);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_traps_get_limit (cairo_traps_t *traps,
|
||||
cairo_box_t *limits);
|
||||
|
||||
cairo_private void
|
||||
_cairo_traps_init_box (cairo_traps_t *traps,
|
||||
const cairo_box_t *box);
|
||||
|
|
@ -2372,6 +2387,9 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
|
|||
const cairo_polygon_t *polygon,
|
||||
cairo_fill_rule_t fill_rule);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_bentley_ottmann_tessellate_traps (cairo_traps_t *traps);
|
||||
|
||||
cairo_private int
|
||||
_cairo_traps_contain (const cairo_traps_t *traps,
|
||||
double x, double y);
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ include $(top_srcdir)/test/Makefile.sources
|
|||
|
||||
SUBDIRS=pdiff .
|
||||
|
||||
CLEANFILES += have-similar.*
|
||||
|
||||
# Then we have a collection of tests that are only run if certain
|
||||
# features are compiled into cairo
|
||||
if HAVE_PTHREAD
|
||||
|
|
@ -147,8 +145,10 @@ REFERENCE_IMAGES = \
|
|||
bitmap-font.rgb24.ref.png \
|
||||
caps-joins-alpha.quartz.ref.png \
|
||||
caps-joins-alpha.ref.png \
|
||||
caps-joins-alpha.xlib.ref.png \
|
||||
caps-joins-curve.ps.ref.png \
|
||||
caps-joins-curve.ref.png \
|
||||
caps-joins-curve.xlib.ref.png \
|
||||
caps-joins.ps.ref.png \
|
||||
caps-joins.ref.png \
|
||||
caps-sub-paths.ref.png \
|
||||
|
|
@ -156,6 +156,8 @@ REFERENCE_IMAGES = \
|
|||
caps.ref.png \
|
||||
clear.argb32.ref.png \
|
||||
clear.rgb24.ref.png \
|
||||
clear.pdf.argb32.ref.png \
|
||||
clear.ps.argb32.ref.png \
|
||||
clear.svg12.argb32.xfail.png \
|
||||
clear.svg12.rgb24.xfail.png \
|
||||
clip-all.ref.png \
|
||||
|
|
@ -237,6 +239,7 @@ REFERENCE_IMAGES = \
|
|||
clipped-group.ps3.ref.png \
|
||||
clipped-group.ref.png \
|
||||
clipped-surface.ref.png \
|
||||
clipped-trapezoids.ref.png \
|
||||
close-path-current-point.ps.ref.png \
|
||||
close-path-current-point.ref.png \
|
||||
close-path.ps2.ref.png \
|
||||
|
|
@ -275,6 +278,7 @@ REFERENCE_IMAGES = \
|
|||
dash-curve.ps3.ref.png \
|
||||
dash-curve.quartz.ref.png \
|
||||
dash-curve.ref.png \
|
||||
dash-curve.xlib.ref.png \
|
||||
dash-infinite-loop.ref.png \
|
||||
dash-no-dash.ref.png \
|
||||
dash-offset-negative.ref.png \
|
||||
|
|
@ -302,16 +306,18 @@ REFERENCE_IMAGES = \
|
|||
degenerate-curve-to.ps.xfail.png \
|
||||
degenerate-dash.ps.xfail.png \
|
||||
degenerate-dash.ref.png \
|
||||
degenerate-dash.xlib.ref.png \
|
||||
degenerate-path.ps.argb32.xfail.png \
|
||||
degenerate-path.ps.rgb24.xfail.png \
|
||||
degenerate-path.quartz.ref.png \
|
||||
degenerate-path.quartz.rgb24.ref.png \
|
||||
degenerate-path.ref.png \
|
||||
degenerate-path.argb32.ref.png \
|
||||
degenerate-path.rgb24.ref.png \
|
||||
degenerate-pen.ps2.ref.png \
|
||||
degenerate-pen.ps3.ref.png \
|
||||
degenerate-pen.quartz.ref.png \
|
||||
degenerate-pen.ref.png \
|
||||
degenerate-pen.xlib.ref.png \
|
||||
degenerate-rel-curve-to.ref.png \
|
||||
degenerate-rel-curve-to.ps.xfail.png \
|
||||
device-offset-fractional.gl.xfail.png \
|
||||
|
|
@ -389,8 +395,10 @@ REFERENCE_IMAGES = \
|
|||
fill-and-stroke.ps3.rgb24.ref.png \
|
||||
fill-and-stroke.quartz.ref.png \
|
||||
fill-and-stroke.quartz.rgb24.ref.png \
|
||||
fill-and-stroke.ref.png \
|
||||
fill-and-stroke.argb32.ref.png \
|
||||
fill-and-stroke.rgb24.ref.png \
|
||||
fill-and-stroke.xlib.argb32.ref.png \
|
||||
fill-and-stroke.xlib.rgb24.ref.png \
|
||||
fill-degenerate-sort-order.ps.argb32.xfail.png \
|
||||
fill-degenerate-sort-order.ps.rgb24.xfail.png \
|
||||
fill-degenerate-sort-order.quartz.ref.png \
|
||||
|
|
@ -469,14 +477,12 @@ REFERENCE_IMAGES = \
|
|||
ft-text-antialias-none.ps3.argb32.ref.png \
|
||||
ft-text-antialias-none.ref.png \
|
||||
ft-text-vertical-layout-type1.pdf.ref.png \
|
||||
ft-text-vertical-layout-type1.ps2.ref.png \
|
||||
ft-text-vertical-layout-type1.ps3.ref.png \
|
||||
ft-text-vertical-layout-type1.ps.ref.png \
|
||||
ft-text-vertical-layout-type1.ref.png \
|
||||
ft-text-vertical-layout-type1.svg.ref.png \
|
||||
ft-text-vertical-layout-type1.xlib.ref.png \
|
||||
ft-text-vertical-layout-type3.pdf.ref.png \
|
||||
ft-text-vertical-layout-type3.ps2.ref.png \
|
||||
ft-text-vertical-layout-type3.ps3.ref.png \
|
||||
ft-text-vertical-layout-type3.ps.ref.png \
|
||||
ft-text-vertical-layout-type3.ref.png \
|
||||
ft-text-vertical-layout-type3.svg.ref.png \
|
||||
ft-text-vertical-layout-type3.xlib.ref.png \
|
||||
|
|
@ -538,9 +544,11 @@ REFERENCE_IMAGES = \
|
|||
leaky-dashed-rectangle.pdf.ref.png \
|
||||
leaky-dashed-rectangle.ps.ref.png \
|
||||
leaky-dashed-rectangle.ref.png \
|
||||
leaky-dashed-rectangle.xlib.ref.png \
|
||||
leaky-dashed-stroke.ps2.ref.png \
|
||||
leaky-dashed-stroke.ps3.ref.png \
|
||||
leaky-dashed-stroke.ref.png \
|
||||
leaky-dashed-stroke.xlib.ref.png \
|
||||
leaky-polygon.ps2.ref.png \
|
||||
leaky-polygon.ps3.ref.png \
|
||||
leaky-polygon.ref.png \
|
||||
|
|
@ -613,13 +621,14 @@ REFERENCE_IMAGES = \
|
|||
miter-precision.ps3.ref.png \
|
||||
miter-precision.ref.png \
|
||||
move-to-show-surface.ref.png \
|
||||
new-sub-path.pdf.argb32.ref.png \
|
||||
new-sub-path.ps2.argb32.ref.png \
|
||||
new-sub-path.ps2.rgb24.ref.png \
|
||||
new-sub-path.ps3.argb32.ref.png \
|
||||
new-sub-path.ps3.rgb24.ref.png \
|
||||
new-sub-path.quartz.ref.png \
|
||||
new-sub-path.quartz.rgb24.ref.png \
|
||||
new-sub-path.ref.png \
|
||||
new-sub-path.argb32.ref.png \
|
||||
new-sub-path.rgb24.ref.png \
|
||||
nil-surface.ref.png \
|
||||
nil-surface.rgb24.ref.png \
|
||||
|
|
@ -726,11 +735,13 @@ REFERENCE_IMAGES = \
|
|||
radial-gradient.pdf.ref.png \
|
||||
radial-gradient.quartz.ref.png \
|
||||
radial-gradient.ref.png \
|
||||
random-intersections.ps2.ref.png \
|
||||
random-intersections.ps3.ref.png \
|
||||
random-intersections.quartz.ref.png \
|
||||
random-intersections.ref.png \
|
||||
random-intersections.xlib.ref.png \
|
||||
random-intersections-eo.ps.ref.png \
|
||||
random-intersections-eo.quartz.ref.png \
|
||||
random-intersections-eo.ref.png \
|
||||
random-intersections-eo.xlib.ref.png \
|
||||
random-intersections-nonzero.ref.png \
|
||||
random-intersections-nonzero.ps.ref.png \
|
||||
random-intersections-nonzero.xlib.ref.png \
|
||||
rectangle-rounding-error.ref.png \
|
||||
rectilinear-dash.ref.png \
|
||||
rectilinear-fill.ref.png \
|
||||
|
|
@ -783,16 +794,9 @@ REFERENCE_IMAGES = \
|
|||
self-copy.ps2.ref.png \
|
||||
self-copy.ps3.ref.png \
|
||||
self-copy.ref.png \
|
||||
self-intersecting.argb32.xfail.png \
|
||||
self-intersecting.pdf.argb32.xfail.png \
|
||||
self-intersecting.pdf.rgb24.xfail.png \
|
||||
self-intersecting.ps.argb32.xfail.png \
|
||||
self-intersecting.ps.rgb24.xfail.png \
|
||||
self-intersecting.ps.ref.png \
|
||||
self-intersecting.ref.png \
|
||||
self-intersecting.rgb24.ref.png \
|
||||
self-intersecting.rgb24.xfail.png \
|
||||
self-intersecting.xlib.argb32.xfail.png \
|
||||
self-intersecting.xlib.rgb24.xfail.png \
|
||||
self-intersecting.xlib.ref.png \
|
||||
set-source.ref.png \
|
||||
set-source.rgb24.ref.png \
|
||||
show-glyphs-many.ref.png \
|
||||
|
|
@ -815,6 +819,7 @@ REFERENCE_IMAGES = \
|
|||
smask-paint.svg.ref.png \
|
||||
smask-stroke.pdf.xfail.png \
|
||||
smask-stroke.ref.png \
|
||||
smask-stroke.xlib.ref.png \
|
||||
smask-text.pdf.ref.png \
|
||||
smask-text.ps2.ref.png \
|
||||
smask-text.ps3.ref.png \
|
||||
|
|
@ -822,8 +827,7 @@ REFERENCE_IMAGES = \
|
|||
smask-text.svg.ref.png \
|
||||
smask-text.xlib.ref.png \
|
||||
smask.pdf.xfail.png \
|
||||
smask.ps2.ref.png \
|
||||
smask.ps3.ref.png \
|
||||
smask.ps.ref.png \
|
||||
smask.ref.png \
|
||||
smask.svg.ref.png \
|
||||
smask.xlib.ref.png \
|
||||
|
|
@ -844,15 +848,16 @@ REFERENCE_IMAGES = \
|
|||
spline-decomposition.ps.ref.png \
|
||||
spline-decomposition.ref.png \
|
||||
spline-decomposition.svg.ref.png \
|
||||
spline-decomposition.xlib.ref.png \
|
||||
stroke-ctm-caps.ps2.ref.png \
|
||||
stroke-ctm-caps.ps3.ref.png \
|
||||
stroke-ctm-caps.quartz.ref.png \
|
||||
stroke-ctm-caps.ref.png \
|
||||
stroke-image.pdf.ref.png \
|
||||
stroke-image.ps2.ref.png \
|
||||
stroke-image.ps3.ref.png \
|
||||
stroke-image.ps.ref.png \
|
||||
stroke-image.quartz.ref.png \
|
||||
stroke-image.ref.png \
|
||||
stroke-image.xlib.ref.png \
|
||||
surface-pattern-big-scale-down.ref.png \
|
||||
surface-pattern-big-scale-down.ps.xfail.png \
|
||||
surface-pattern-scale-down.pdf.ref.png \
|
||||
|
|
@ -900,6 +905,7 @@ REFERENCE_IMAGES = \
|
|||
text-rotate.quartz.ref.png \
|
||||
text-rotate.ref.png \
|
||||
text-rotate.svg.ref.png \
|
||||
text-rotate.xlib.ref.png \
|
||||
text-transform.pdf.ref.png \
|
||||
text-transform.ps2.ref.png \
|
||||
text-transform.ps3.ref.png \
|
||||
|
|
@ -923,6 +929,7 @@ REFERENCE_IMAGES = \
|
|||
twin.ps.ref.png \
|
||||
twin.ref.png \
|
||||
twin.svg.ref.png \
|
||||
twin.xlib.ref.png \
|
||||
unantialiased-shapes.quartz.ref.png \
|
||||
unantialiased-shapes.ref.png \
|
||||
unbounded-operator.gl.argb32.xfail.png \
|
||||
|
|
@ -934,7 +941,7 @@ REFERENCE_IMAGES = \
|
|||
unbounded-operator.quartz.rgb24.ref.png \
|
||||
unbounded-operator.ref.png \
|
||||
unbounded-operator.rgb24.ref.png \
|
||||
unbounded-operator.svg12.argb32.xfail.png \
|
||||
unbounded-operator.svg12.argb32.ref.png \
|
||||
unbounded-operator.svg12.rgb24.xfail.png \
|
||||
unbounded-operator.xlib.rgb24.ref.png \
|
||||
user-font-mask.pdf.ref.png \
|
||||
|
|
@ -953,8 +960,7 @@ REFERENCE_IMAGES = \
|
|||
user-font-rescale.ps3.ref.png \
|
||||
user-font-rescale.ref.png \
|
||||
user-font-rescale.svg.ref.png \
|
||||
user-font.ps2.ref.png \
|
||||
user-font.ps3.ref.png \
|
||||
user-font.ps.ref.png \
|
||||
user-font.ref.png \
|
||||
user-font.svg.ref.png \
|
||||
user-font.xlib.ref.png \
|
||||
|
|
@ -1132,14 +1138,22 @@ imagediff_LDADD = \
|
|||
$(top_builddir)/src/libcairo.la
|
||||
|
||||
png_flatten_SOURCES = png-flatten.c
|
||||
png_flatten_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD)
|
||||
png_flatten_LDADD = $(top_builddir)/src/libcairo.la \
|
||||
$(CAIRO_LDADD)
|
||||
|
||||
if BUILD_ANY2PPM
|
||||
check_PROGRAMS += any2ppm
|
||||
any2ppm_CFLAGS = $(AM_CFLAGS) $(POPPLER_CFLAGS) $(LIBRSVG_CFLAGS) $(LIBSPECTRE_CFLAGS)
|
||||
# add LDADD, so poppler/librsvg uses "our" cairo
|
||||
any2ppm_LDFLAGS = $(AM_LDFLAGS) $(CAIRO_TEST_UNDEFINED_LDFLAGS)
|
||||
any2ppm_LDADD = $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(CAIROBOILERPLATE_LIBS) $(POPPLER_LIBS) $(LIBRSVG_LIBS) $(LIBSPECTRE_LIBS)
|
||||
any2ppm_LDADD = \
|
||||
$(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
|
||||
$(top_builddir)/src/libcairo.la \
|
||||
$(CAIRO_LDADD) \
|
||||
$(CAIROBOILERPLATE_LIBS) \
|
||||
$(POPPLER_LIBS) \
|
||||
$(LIBRSVG_LIBS) \
|
||||
$(LIBSPECTRE_LIBS)
|
||||
endif
|
||||
|
||||
if CAIRO_CAN_TEST_PDF_SURFACE
|
||||
|
|
@ -1147,7 +1161,9 @@ check_PROGRAMS += pdf2png
|
|||
pdf2png_CFLAGS = $(AM_CFLAGS) $(POPPLER_CFLAGS)
|
||||
# add LDADD, so poppler uses "our" cairo
|
||||
pdf2png_LDFLAGS = $(AM_LDFLAGS) $(CAIRO_TEST_UNDEFINED_LDFLAGS)
|
||||
pdf2png_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(POPPLER_LIBS)
|
||||
pdf2png_LDADD = $(top_builddir)/src/libcairo.la \
|
||||
$(CAIRO_LDADD) \
|
||||
$(POPPLER_LIBS)
|
||||
endif
|
||||
|
||||
if CAIRO_CAN_TEST_SVG_SURFACE
|
||||
|
|
@ -1155,7 +1171,9 @@ check_PROGRAMS += svg2png
|
|||
svg2png_CFLAGS = $(AM_CFLAGS) $(LIBRSVG_CFLAGS)
|
||||
# add LDADD, so librsvg uses "our" cairo
|
||||
svg2png_LDFLAGS = $(AM_LDFLAGS) $(CAIRO_TEST_UNDEFINED_LDFLAGS)
|
||||
svg2png_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(LIBRSVG_LIBS)
|
||||
svg2png_LDADD = $(top_builddir)/src/libcairo.la \
|
||||
$(CAIRO_LDADD) \
|
||||
$(LIBRSVG_LIBS)
|
||||
endif
|
||||
|
||||
if CAIRO_HAS_SPECTRE
|
||||
|
|
@ -1163,7 +1181,9 @@ check_PROGRAMS += ps2png
|
|||
ps2png_CFLAGS = $(AM_CFLAGS) $(LIBSPECTRE_CFLAGS)
|
||||
# add LDADD, so ps2png uses "our" cairo
|
||||
ps2png_LDFLAGS = $(AM_LDFLAGS) $(CAIRO_TEST_UNDEFINED_LDFLAGS)
|
||||
ps2png_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(LIBSPECTRE_LIBS)
|
||||
ps2png_LDADD = $(top_builddir)/src/libcairo.la \
|
||||
$(CAIRO_LDADD) \
|
||||
$(LIBSPECTRE_LIBS)
|
||||
endif
|
||||
|
||||
EXTRA_PROGRAMS += $(TESTS)
|
||||
|
|
|
|||
|
|
@ -150,7 +150,8 @@ test_sources = \
|
|||
png.c \
|
||||
push-group.c \
|
||||
radial-gradient.c \
|
||||
random-intersections.c \
|
||||
random-intersections-eo.c \
|
||||
random-intersections-nonzero.c \
|
||||
rectangle-rounding-error.c \
|
||||
rectilinear-fill.c \
|
||||
rectilinear-miter-limit.c \
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.5 KiB |
BIN
test/caps-joins-alpha.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 5.6 KiB |
BIN
test/caps-joins-curve.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 5 KiB |
BIN
test/clear.pdf.argb32.ref.png
Normal file
|
After Width: | Height: | Size: 790 B |
BIN
test/clear.ps.argb32.ref.png
Normal file
|
After Width: | Height: | Size: 790 B |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 310 B After Width: | Height: | Size: 334 B |
BIN
test/clipped-trapezoids-ref.png
Normal file
|
After Width: | Height: | Size: 1 KiB |
95
test/clipped-trapezoids.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2008 Chris Wilson
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of
|
||||
* Chris Wilson not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Chris Wilson makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Chris Wilson <chris@chris-wilson.co.uk>
|
||||
*/
|
||||
|
||||
#include "cairo-test.h"
|
||||
|
||||
static cairo_test_status_t
|
||||
draw (cairo_t *cr, int width, int height)
|
||||
{
|
||||
double dash[2] = { 8, 4 };
|
||||
double radius;
|
||||
|
||||
radius = width;
|
||||
if (height > radius)
|
||||
radius = height;
|
||||
|
||||
/* fill the background using a big circle */
|
||||
cairo_arc (cr, 0, 0, 4 * radius, 0, 2 * M_PI);
|
||||
cairo_fill (cr);
|
||||
|
||||
/* a rotated square - overlapping the corners */
|
||||
cairo_save (cr);
|
||||
cairo_save (cr);
|
||||
cairo_translate (cr, width/2, height/2);
|
||||
cairo_rotate (cr, M_PI/4);
|
||||
cairo_scale (cr, M_SQRT2, M_SQRT2);
|
||||
cairo_rectangle (cr, -width/2, -height/2, width, height);
|
||||
cairo_restore (cr);
|
||||
cairo_set_source_rgba (cr, 0, 1, 0, .5);
|
||||
cairo_set_line_width (cr, radius/2);
|
||||
cairo_stroke (cr);
|
||||
cairo_restore (cr);
|
||||
|
||||
/* and put some circles in the corners */
|
||||
cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
cairo_new_sub_path (cr);
|
||||
cairo_arc (cr, 0, 0, radius/4, 0, 2 * M_PI);
|
||||
cairo_new_sub_path (cr);
|
||||
cairo_arc (cr, width, 0, radius/4, 0, 2 * M_PI);
|
||||
cairo_new_sub_path (cr);
|
||||
cairo_arc (cr, width, height, radius/4, 0, 2 * M_PI);
|
||||
cairo_new_sub_path (cr);
|
||||
cairo_arc (cr, 0, height, radius/4, 0, 2 * M_PI);
|
||||
cairo_fill (cr);
|
||||
|
||||
/* a couple of pixel-aligned lines */
|
||||
cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
cairo_move_to (cr, width/2, -height);
|
||||
cairo_rel_line_to (cr, 0, 3*height);
|
||||
cairo_move_to (cr, -width, height/2);
|
||||
cairo_rel_line_to (cr, 3*width, 0);
|
||||
cairo_stroke (cr);
|
||||
|
||||
/* a couple of dashed diagonals */
|
||||
cairo_save (cr);
|
||||
cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
cairo_set_dash (cr, dash, 2, 0);
|
||||
cairo_set_line_width (cr, 4.);
|
||||
cairo_move_to (cr, -width, -height);
|
||||
cairo_line_to (cr, width+width, height+height);
|
||||
cairo_move_to (cr, width+width, -height);
|
||||
cairo_line_to (cr, -width, height+height);
|
||||
cairo_stroke (cr);
|
||||
cairo_restore (cr);
|
||||
|
||||
return CAIRO_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
CAIRO_TEST (clipped_trapezoids,
|
||||
"Tests clipping of trapezoids larger than the surface",
|
||||
"clip", /* keywords */
|
||||
NULL, /* requirements */
|
||||
40, 40,
|
||||
NULL, draw)
|
||||
BIN
test/clipped-trapezoids.ref.png
Normal file
|
After Width: | Height: | Size: 963 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 40 KiB |
BIN
test/dash-curve.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 646 B |
|
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2 KiB |
BIN
test/degenerate-dash.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
test/degenerate-path.argb32.ref.png
Normal file
|
After Width: | Height: | Size: 240 B |
|
Before Width: | Height: | Size: 257 B |
|
Before Width: | Height: | Size: 224 B After Width: | Height: | Size: 210 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 997 B |
BIN
test/degenerate-pen.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 997 B |
|
Before Width: | Height: | Size: 275 B After Width: | Height: | Size: 275 B |
|
Before Width: | Height: | Size: 591 B After Width: | Height: | Size: 562 B |
|
Before Width: | Height: | Size: 614 B After Width: | Height: | Size: 631 B |
|
Before Width: | Height: | Size: 519 B After Width: | Height: | Size: 515 B |
BIN
test/fill-and-stroke.argb32.ref.png
Normal file
|
After Width: | Height: | Size: 313 B |
|
Before Width: | Height: | Size: 279 B |
|
Before Width: | Height: | Size: 257 B After Width: | Height: | Size: 287 B |
BIN
test/fill-and-stroke.xlib.argb32.ref.png
Normal file
|
After Width: | Height: | Size: 322 B |
BIN
test/fill-and-stroke.xlib.rgb24.ref.png
Normal file
|
After Width: | Height: | Size: 291 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 482 B After Width: | Height: | Size: 488 B |
BIN
test/ft-text-vertical-layout-type1.ps.ref.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.6 KiB |
BIN
test/ft-text-vertical-layout-type3.ps.ref.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 520 B After Width: | Height: | Size: 522 B |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 347 B After Width: | Height: | Size: 347 B |
BIN
test/leaky-dashed-rectangle.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 347 B |
|
Before Width: | Height: | Size: 9 KiB After Width: | Height: | Size: 9.2 KiB |
BIN
test/leaky-dashed-stroke.xlib.ref.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.7 KiB |
BIN
test/new-sub-path.argb32.ref.png
Normal file
|
After Width: | Height: | Size: 421 B |
BIN
test/new-sub-path.pdf.argb32.ref.png
Normal file
|
After Width: | Height: | Size: 512 B |
|
Before Width: | Height: | Size: 386 B |
|
Before Width: | Height: | Size: 355 B After Width: | Height: | Size: 381 B |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 585 B After Width: | Height: | Size: 576 B |
|
|
@ -69,7 +69,7 @@ draw (cairo_t *cr, int width, int height)
|
|||
return CAIRO_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
CAIRO_TEST (random_intersections,
|
||||
CAIRO_TEST (random_intersections_eo,
|
||||
"Tests the tessellator trapezoid generation and intersection computation",
|
||||
"trap", /* keywords */
|
||||
NULL, /* requirements */
|
||||
BIN
test/random-intersections-eo.ps.ref.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 193 KiB |
BIN
test/random-intersections-eo.ref.png
Normal file
|
After Width: | Height: | Size: 133 KiB |