[cairo-commit] 12 commits - src/cairo-bentley-ottmann.c src/cairo-compositor.c src/cairoint.h src/cairo-path-stroke.c src/cairo-path-stroke-polygon.c src/cairo-pen.c src/cairo-xlib-surface.c
Chris Wilson
ickle at kemper.freedesktop.org
Sun Aug 26 03:44:56 PDT 2012
src/cairo-bentley-ottmann.c | 73 ++++---------
src/cairo-compositor.c | 4
src/cairo-path-stroke-polygon.c | 214 +++++++++++++++++++--------------------
src/cairo-path-stroke.c | 215 ++++++++++++++++++++++++----------------
src/cairo-pen.c | 115 +++++++++++++++++----
src/cairo-xlib-surface.c | 4
src/cairoint.h | 17 +++
7 files changed, 374 insertions(+), 268 deletions(-)
New commits:
commit 637659fb511824eb8ac31ef85db10406295734e6
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sun Aug 26 00:39:43 2012 +0100
bentley-ottmann: hint that the insertion compare function should be inlined
Albeit it too large for gcc to automatically inline, it is only used
from within a single function. Hopefully gcc can optimise better with
the hint.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index 7820dad..4f5df2d 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -561,7 +561,7 @@ _line_equal (const cairo_line_t *a, const cairo_line_t *b)
a->p2.x == b->p2.x && a->p2.y == b->p2.y;
}
-static int
+static inline int
_cairo_bo_sweep_line_compare_edges (const cairo_bo_sweep_line_t *sweep_line,
const cairo_bo_edge_t *a,
const cairo_bo_edge_t *b)
commit 3c6e4311fb3b9fe400555a8d97193fc87974899b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sun Aug 26 00:35:52 2012 +0100
bentley-ottmann: Only check the pairs of coordinates for equality.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index fdb2744..7820dad 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -1329,7 +1329,7 @@ edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
*/
if (p != 0) {
/* colinear if either end-point are coincident */
- return ((p >> 1) & p) != 0;
+ return ((p >> 1) & p) & 5;
} else if (a->edge.line.p1.y < b->edge.line.p1.y) {
return edge_compare_for_y_against_x (b,
a->edge.line.p1.y,
commit 535b4e970cdbb459be621cecafd7f91ca4698396
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sun Aug 26 00:16:33 2012 +0100
bentley-ottman: Remove a few superfluous status propagation
For the traps it is simpler if we report the status at the end, and
no-op the accumulation of the trap after hitting the error condition.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index 38fe463..fdb2744 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -562,7 +562,7 @@ _line_equal (const cairo_line_t *a, const cairo_line_t *b)
}
static int
-_cairo_bo_sweep_line_compare_edges (cairo_bo_sweep_line_t *sweep_line,
+_cairo_bo_sweep_line_compare_edges (const cairo_bo_sweep_line_t *sweep_line,
const cairo_bo_edge_t *a,
const cairo_bo_edge_t *b)
{
@@ -1118,7 +1118,7 @@ _cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line)
sweep_line->current_edge = NULL;
}
-static cairo_status_t
+static void
_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t *edge)
{
@@ -1175,8 +1175,6 @@ _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
}
sweep_line->current_edge = edge;
-
- return CAIRO_STATUS_SUCCESS;
}
static void
@@ -1344,7 +1342,7 @@ edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
}
/* Adds the trapezoid, if any, of the left edge to the #cairo_traps_t */
-static cairo_status_t
+static void
_cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
int32_t bot,
cairo_traps_t *traps)
@@ -1376,8 +1374,6 @@ _cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
}
trap->right = NULL;
-
- return _cairo_traps_status (traps);
}
@@ -1386,16 +1382,14 @@ _cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
-static inline cairo_status_t
+static inline void
_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
cairo_bo_edge_t *right,
int top,
cairo_traps_t *traps)
{
- cairo_status_t status;
-
if (left->deferred_trap.right == right)
- return CAIRO_STATUS_SUCCESS;
+ return;
assert (right);
if (left->deferred_trap.right != NULL) {
@@ -1403,12 +1397,10 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
{
/* continuation on right, so just swap edges */
left->deferred_trap.right = right;
- return CAIRO_STATUS_SUCCESS;
+ return;
}
- status = _cairo_bo_edge_end_trap (left, top, traps);
- if (unlikely (status))
- return status;
+ _cairo_bo_edge_end_trap (left, top, traps);
}
if (! edges_colinear (left, right)) {
@@ -1422,18 +1414,15 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
top);
#endif
}
-
- return CAIRO_STATUS_SUCCESS;
}
-static inline cairo_status_t
+static inline void
_active_edges_to_traps (cairo_bo_edge_t *pos,
int32_t top,
unsigned mask,
cairo_traps_t *traps)
{
cairo_bo_edge_t *left;
- cairo_status_t status;
int in_out;
@@ -1457,9 +1446,7 @@ _active_edges_to_traps (cairo_bo_edge_t *pos,
}
else
{
- status = _cairo_bo_edge_end_trap (pos, top, traps);
- if (unlikely (status))
- return status;
+ _cairo_bo_edge_end_trap (pos, top, traps);
}
}
@@ -1467,22 +1454,15 @@ _active_edges_to_traps (cairo_bo_edge_t *pos,
if ((in_out & mask) == 0) {
/* skip co-linear edges */
if (pos->next == NULL || ! edges_colinear (pos, pos->next)) {
- status = _cairo_bo_edge_start_or_continue_trap (left, pos,
- top, traps);
- if (unlikely (status))
- return status;
-
+ _cairo_bo_edge_start_or_continue_trap (left, pos, top, traps);
left = pos->next;
}
}
pos = pos->next;
}
-
- return CAIRO_STATUS_SUCCESS;
}
-
/* Execute a single pass of the Bentley-Ottmann algorithm on edges,
* generating trapezoids according to the fill_rule and appending them
* to traps. */
@@ -1493,7 +1473,7 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events,
cairo_traps_t *traps,
int *num_intersections)
{
- cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence compiler */
+ cairo_status_t status;
int intersection_count = 0;
cairo_bo_event_queue_t event_queue;
cairo_bo_sweep_line_t sweep_line;
@@ -1534,20 +1514,16 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events,
if (event->point.y != sweep_line.current_y) {
for (e1 = sweep_line.stopped; e1; e1 = e1->next) {
if (e1->deferred_trap.right != NULL) {
- status = _cairo_bo_edge_end_trap (e1,
- e1->edge.bottom,
- traps);
- if (unlikely (status))
- goto unwind;
+ _cairo_bo_edge_end_trap (e1,
+ e1->edge.bottom,
+ traps);
}
}
sweep_line.stopped = NULL;
- status = _active_edges_to_traps (sweep_line.head,
- sweep_line.current_y,
- fill_rule, traps);
- if (unlikely (status))
- goto unwind;
+ _active_edges_to_traps (sweep_line.head,
+ sweep_line.current_y,
+ fill_rule, traps);
sweep_line.current_y = event->point.y;
}
@@ -1565,9 +1541,7 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events,
case CAIRO_BO_EVENT_TYPE_START:
e1 = &((cairo_bo_start_event_t *) event)->edge;
- status = _cairo_bo_sweep_line_insert (&sweep_line, e1);
- if (unlikely (status))
- goto unwind;
+ _cairo_bo_sweep_line_insert (&sweep_line, e1);
status = _cairo_bo_event_queue_insert_stop (&event_queue, e1);
if (unlikely (status))
@@ -1670,11 +1644,10 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events,
*num_intersections = intersection_count;
for (e1 = sweep_line.stopped; e1; e1 = e1->next) {
if (e1->deferred_trap.right != NULL) {
- status = _cairo_bo_edge_end_trap (e1, e1->edge.bottom, traps);
- if (unlikely (status))
- break;
+ _cairo_bo_edge_end_trap (e1, e1->edge.bottom, traps);
}
}
+ status = traps->status;
unwind:
_cairo_bo_event_queue_fini (&event_queue);
@@ -1691,7 +1664,6 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
int intersections;
- cairo_status_t status;
cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)];
cairo_bo_start_event_t *events;
cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
@@ -1699,6 +1671,7 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
cairo_bo_start_event_t *stack_event_y[64];
cairo_bo_start_event_t **event_y = NULL;
int i, num_events, y, ymin, ymax;
+ cairo_status_t status;
num_events = polygon->num_edges;
if (unlikely (0 == num_events))
commit b66065537cec5f03b33f7513f06e26630c28b5f1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sun Aug 26 10:21:22 2012 +0100
stroke: Compute bounds for fallback stroker (typically dashing)
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 8f9fa92..5ef212c 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -90,10 +90,13 @@ typedef struct cairo_stroker {
static cairo_status_t
_cairo_stroker_init (cairo_stroker_t *stroker,
+ const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
- double tolerance)
+ double tolerance,
+ const cairo_box_t *limits,
+ int num_limits)
{
cairo_status_t status;
@@ -111,8 +114,6 @@ _cairo_stroker_init (cairo_stroker_t *stroker,
if (unlikely (status))
return status;
- stroker->has_bounds = FALSE;
-
stroker->has_current_face = FALSE;
stroker->has_first_face = FALSE;
stroker->has_initial_sub_path = FALSE;
@@ -121,6 +122,31 @@ _cairo_stroker_init (cairo_stroker_t *stroker,
stroker->add_external_edge = NULL;
+ stroker->has_bounds = num_limits;
+ if (stroker->has_bounds) {
+ /* Extend the bounds in each direction to account for the maximum area
+ * we might generate trapezoids, to capture line segments that are
+ * outside of the bounds but which might generate rendering that's
+ * within bounds.
+ */
+ double dx, dy;
+ cairo_fixed_t fdx, fdy;
+ int i;
+
+ stroker->bounds = limits[0];
+ for (i = 1; i < num_limits; i++)
+ _cairo_box_add_box (&stroker->bounds, &limits[i]);
+
+ _cairo_stroke_style_max_distance_from_path (stroke_style, path, ctm, &dx, &dy);
+ fdx = _cairo_fixed_from_double (dx);
+ fdy = _cairo_fixed_from_double (dy);
+
+ stroker->bounds.p1.x -= fdx;
+ stroker->bounds.p2.x += fdx;
+ stroker->bounds.p1.y -= fdy;
+ stroker->bounds.p2.y += fdy;
+ }
+
return CAIRO_STATUS_SUCCESS;
}
@@ -1261,8 +1287,9 @@ _cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path,
cairo_stroker_t stroker;
cairo_status_t status;
- status = _cairo_stroker_init (&stroker, stroke_style,
- ctm, ctm_inverse, tolerance);
+ status = _cairo_stroker_init (&stroker, path, stroke_style,
+ ctm, ctm_inverse, tolerance,
+ NULL, 0);
if (unlikely (status))
return status;
@@ -1303,8 +1330,9 @@ _cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t *path,
cairo_stroker_t stroker;
cairo_status_t status;
- status = _cairo_stroker_init (&stroker, stroke_style,
- ctm, ctm_inverse, tolerance);
+ status = _cairo_stroker_init (&stroker, path, stroke_style,
+ ctm, ctm_inverse, tolerance,
+ polygon->limits, polygon->num_limits);
if (unlikely (status))
return status;
commit 99593538a9d054aa1bb9fa620fced8c8b8ccdc9d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sun Aug 26 10:50:50 2012 +0100
stroke: Convert fallback stroker to new pen vertex finder
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index bae66dc..8f9fa92 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -220,100 +220,117 @@ _tessellate_fan (cairo_stroker_t *stroker,
cairo_bool_t clockwise)
{
cairo_point_t stack_points[64], *points = stack_points;
- int start, stop, step, i, npoints;
+ cairo_pen_t *pen = &stroker->pen;
+ int start, stop, num_points = 0;
cairo_status_t status;
+ if (stroker->has_bounds &&
+ ! _cairo_box_contains_point (&stroker->bounds, midpt))
+ goto BEVEL;
+
+ assert (stroker->pen.num_vertices);
+
if (clockwise) {
- step = -1;
-
- start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
- in_vector);
- if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
- in_vector) < 0)
- start = _range_step (start, -1, stroker->pen.num_vertices);
-
- stop = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
- out_vector);
- if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
- out_vector) > 0)
- {
- stop = _range_step (stop, 1, stroker->pen.num_vertices);
- if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
- in_vector) < 0)
- {
- goto BEVEL;
- }
- }
+ _cairo_pen_find_active_ccw_vertices (pen,
+ in_vector, out_vector,
+ &start, &stop);
+ if (stroker->add_external_edge) {
+ cairo_point_t last;
+ last = *inpt;
+ while (start != stop) {
+ cairo_point_t p = *midpt;
+ _translate_point (&p, &pen->vertices[start].point);
- npoints = start - stop;
- } else {
- step = 1;
-
- start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
- in_vector);
- if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
- in_vector) < 0)
- start = _range_step (start, 1, stroker->pen.num_vertices);
-
- stop = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
- out_vector);
- if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
- out_vector) > 0)
- {
- stop = _range_step (stop, -1, stroker->pen.num_vertices);
- if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
- in_vector) < 0)
- {
+ status = stroker->add_external_edge (stroker->closure,
+ &last, &p);
+ if (unlikely (status))
+ return status;
+ last = p;
+
+ if (start-- == 0)
+ start += pen->num_vertices;
+ }
+ status = stroker->add_external_edge (stroker->closure,
+ &last, outpt);
+ } else {
+ if (start == stop)
goto BEVEL;
+
+ num_points = stop - start;
+ if (num_points < 0)
+ num_points += pen->num_vertices;
+ num_points += 2;
+ if (num_points > ARRAY_LENGTH(stack_points)) {
+ points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
+ if (unlikely (points == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- }
- npoints = stop - start;
- }
- stop = _range_step (stop, step, stroker->pen.num_vertices);
+ points[0] = *inpt;
+ num_points = 1;
+ while (start != stop) {
+ points[num_points] = *midpt;
+ _translate_point (&points[num_points], &pen->vertices[start].point);
+ num_points++;
- if (npoints < 0)
- npoints += stroker->pen.num_vertices;
- npoints += 3;
+ if (start-- == 0)
+ start += pen->num_vertices;
+ }
+ points[num_points++] = *outpt;
+ }
+ } else {
+ _cairo_pen_find_active_cw_vertices (pen,
+ in_vector, out_vector,
+ &start, &stop);
+ if (stroker->add_external_edge) {
+ cairo_point_t last;
+ last = *inpt;
+ while (start != stop) {
+ cairo_point_t p = *midpt;
+ _translate_point (&p, &pen->vertices[start].point);
- if (npoints <= 1)
- goto BEVEL;
+ status = stroker->add_external_edge (stroker->closure,
+ &p, &last);
+ if (unlikely (status))
+ return status;
+ last = p;
- if (npoints > ARRAY_LENGTH (stack_points)) {
- points = _cairo_malloc_ab (npoints, sizeof (cairo_point_t));
- if (unlikely (points == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
+ if (++start == pen->num_vertices)
+ start = 0;
+ }
+ status = stroker->add_external_edge (stroker->closure,
+ outpt, &last);
+ } else {
+ if (start == stop)
+ goto BEVEL;
+ num_points = stop - start;
+ if (num_points < 0)
+ num_points += pen->num_vertices;
+ num_points += 2;
+ if (num_points > ARRAY_LENGTH(stack_points)) {
+ points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
+ if (unlikely (points == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
- /* Construct the fan. */
- npoints = 0;
- points[npoints++] = *inpt;
- for (i = start;
- i != stop;
- i = _range_step (i, step, stroker->pen.num_vertices))
- {
- points[npoints] = *midpt;
- _translate_point (&points[npoints], &stroker->pen.vertices[i].point);
- npoints++;
- }
- points[npoints++] = *outpt;
+ points[0] = *inpt;
+ num_points = 1;
+ while (start != stop) {
+ points[num_points] = *midpt;
+ _translate_point (&points[num_points], &pen->vertices[start].point);
+ num_points++;
- if (stroker->add_external_edge != NULL) {
- for (i = 0; i < npoints - 1; i++) {
- if (clockwise) {
- status = stroker->add_external_edge (stroker->closure,
- &points[i], &points[i+1]);
- } else {
- status = stroker->add_external_edge (stroker->closure,
- &points[i+1], &points[i]);
+ if (++start == pen->num_vertices)
+ start = 0;
}
- if (unlikely (status))
- break;
+ points[num_points++] = *outpt;
}
- } else {
+ }
+
+ if (num_points) {
status = stroker->add_triangle_fan (stroker->closure,
- midpt, points, npoints);
+ midpt, points, num_points);
}
if (points != stack_points)
commit 4eb8e9f8618c5c5c002b7fd72c0370451ae1f511
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sat Aug 25 23:57:56 2012 +0100
stroke: Convert a very small round-join into a miter
Avoid adding a bevel join if the miter point is within tolerance.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index 350e436..f6e81e0 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -406,8 +406,8 @@ outer_close (struct stroker *stroker,
add_fan (stroker,
&in->dev_vector, &out->dev_vector, &in->point,
clockwise, outer);
+ break;
}
- break;
case CAIRO_LINE_JOIN_MITER:
default: {
commit fa93fc63b652f04bcf7d5340a13023819ecf2140
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sat Aug 25 23:54:36 2012 +0100
stroke: Precompute the line half-width
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index 61a782b..350e436 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -68,6 +68,7 @@ struct stroker {
const cairo_matrix_t *ctm_inverse;
double tolerance;
double spline_cusp_tolerance;
+ double half_line_width;
cairo_bool_t ctm_det_positive;
cairo_pen_t pen;
@@ -378,6 +379,7 @@ outer_close (struct stroker *stroker,
{
return;
}
+
clockwise = join_is_clockwise (in, out);
if (clockwise) {
inpt = &in->cw;
@@ -410,8 +412,8 @@ outer_close (struct stroker *stroker,
case CAIRO_LINE_JOIN_MITER:
default: {
/* dot product of incoming slope vector with outgoing slope vector */
- double in_dot_out = -in->usr_vector.x * out->usr_vector.x +
- -in->usr_vector.y * out->usr_vector.y;
+ double in_dot_out = in->dev_slope.x * out->dev_slope.x +
+ in->dev_slope.y * out->dev_slope.y;
double ml = stroker->style.miter_limit;
/* Check the miter limit -- lines meeting at an acute angle
@@ -471,7 +473,7 @@ outer_close (struct stroker *stroker,
* 2 <= ml² (1 - in · out)
*
*/
- if (2 <= ml * ml * (1 - in_dot_out)) {
+ if (2 <= ml * ml * (1 + in_dot_out)) {
double x1, y1, x2, y2;
double mx, my;
double dx1, dx2, dy1, dy2;
@@ -488,16 +490,14 @@ outer_close (struct stroker *stroker,
/* outer point of incoming line face */
x1 = _cairo_fixed_to_double (inpt->x);
y1 = _cairo_fixed_to_double (inpt->y);
- dx1 = in->usr_vector.x;
- dy1 = in->usr_vector.y;
- cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
+ dx1 = in->dev_slope.x;
+ dy1 = in->dev_slope.y;
/* outer point of outgoing line face */
x2 = _cairo_fixed_to_double (outpt->x);
y2 = _cairo_fixed_to_double (outpt->y);
- dx2 = out->usr_vector.x;
- dy2 = out->usr_vector.y;
- cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+ dx2 = out->dev_slope.x;
+ dy2 = out->dev_slope.y;
/*
* Compute the location of the outer corner of the miter.
@@ -596,8 +596,8 @@ outer_join (struct stroker *stroker,
case CAIRO_LINE_JOIN_MITER:
default: {
/* dot product of incoming slope vector with outgoing slope vector */
- double in_dot_out = -in->usr_vector.x * out->usr_vector.x +
- -in->usr_vector.y * out->usr_vector.y;
+ double in_dot_out = in->dev_slope.x * out->dev_slope.x +
+ in->dev_slope.y * out->dev_slope.y;
double ml = stroker->style.miter_limit;
/* Check the miter limit -- lines meeting at an acute angle
@@ -657,7 +657,7 @@ outer_join (struct stroker *stroker,
* 2 <= ml² (1 - in · out)
*
*/
- if (2 <= ml * ml * (1 - in_dot_out)) {
+ if (2 <= ml * ml * (1 + in_dot_out)) {
double x1, y1, x2, y2;
double mx, my;
double dx1, dx2, dy1, dy2;
@@ -674,16 +674,14 @@ outer_join (struct stroker *stroker,
/* outer point of incoming line face */
x1 = _cairo_fixed_to_double (inpt->x);
y1 = _cairo_fixed_to_double (inpt->y);
- dx1 = in->usr_vector.x;
- dy1 = in->usr_vector.y;
- cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
+ dx1 = in->dev_slope.x;
+ dy1 = in->dev_slope.y;
/* outer point of outgoing line face */
x2 = _cairo_fixed_to_double (outpt->x);
y2 = _cairo_fixed_to_double (outpt->y);
- dx2 = out->usr_vector.x;
- dy2 = out->usr_vector.y;
- cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+ dx2 = out->dev_slope.x;
+ dy2 = out->dev_slope.y;
/*
* Compute the location of the outer corner of the miter.
@@ -763,27 +761,25 @@ add_cap (struct stroker *stroker,
}
case CAIRO_LINE_CAP_SQUARE: {
+ cairo_slope_t fvector;
+ cairo_point_t p;
double dx, dy;
- cairo_slope_t fvector;
- cairo_point_t quad[4];
dx = f->usr_vector.x;
dy = f->usr_vector.y;
- dx *= stroker->style.line_width / 2.0;
- dy *= stroker->style.line_width / 2.0;
+ dx *= stroker->half_line_width;
+ dy *= stroker->half_line_width;
cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
fvector.dx = _cairo_fixed_from_double (dx);
fvector.dy = _cairo_fixed_from_double (dy);
- quad[0] = f->ccw;
- quad[1].x = f->ccw.x + fvector.dx;
- quad[1].y = f->ccw.y + fvector.dy;
- quad[2].x = f->cw.x + fvector.dx;
- quad[2].y = f->cw.y + fvector.dy;
- quad[3] = f->cw;
+ p.x = f->ccw.x + fvector.dx;
+ p.y = f->ccw.y + fvector.dy;
+ contour_add_point (stroker, c, &p);
- contour_add_point (stroker, c, &quad[1]);
- contour_add_point (stroker, c, &quad[2]);
+ p.x = f->cw.x + fvector.dx;
+ p.y = f->cw.y + fvector.dy;
+ contour_add_point (stroker, c, &p);
}
case CAIRO_LINE_CAP_BUTT:
@@ -888,22 +884,19 @@ compute_face (const cairo_point_t *point,
&slope_dx, &slope_dy);
normalize_slope (&slope_dx, &slope_dy);
- if (stroker->ctm_det_positive)
- {
- face_dx = - slope_dy * (stroker->style.line_width / 2.0);
- face_dy = slope_dx * (stroker->style.line_width / 2.0);
- }
- else
- {
- face_dx = slope_dy * (stroker->style.line_width / 2.0);
- face_dy = - slope_dx * (stroker->style.line_width / 2.0);
+ if (stroker->ctm_det_positive) {
+ face_dx = - slope_dy * stroker->half_line_width;
+ face_dy = slope_dx * stroker->half_line_width;
+ } else {
+ face_dx = slope_dy * stroker->half_line_width;
+ face_dy = - slope_dx * stroker->half_line_width;
}
/* back to device space */
cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
} else {
- face_dx = - slope_dy * (stroker->style.line_width / 2.0);
- face_dy = slope_dx * (stroker->style.line_width / 2.0);
+ face_dx = - slope_dy * stroker->half_line_width;
+ face_dy = slope_dx * stroker->half_line_width;
}
offset_ccw.x = _cairo_fixed_from_double (face_dx);
@@ -1089,7 +1082,7 @@ spline_to (void *closure,
#if DEBUG
_cairo_contour_add_point (&stroker->path, point);
#endif
- if (tangent->dx == 0 && tangent->dy == 0) {
+ if ((tangent->dx | tangent->dy) == 0) {
const cairo_point_t *inpt, *outpt;
struct stroke_contour *outer;
cairo_point_t t;
@@ -1307,6 +1300,7 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
stroker.ctm = ctm;
stroker.ctm_inverse = ctm_inverse;
stroker.tolerance = tolerance;
+ stroker.half_line_width = style->line_width / 2.;
/* To test whether we need to join two segments of a spline using
* a round-join or a bevel-join, we can inspect the angle between the
* two segments. If the difference between the chord distance
@@ -1314,7 +1308,7 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
* half-line-width itself is greater than tolerance then we need to
* inject a point.
*/
- stroker.spline_cusp_tolerance = 1 - 2 * tolerance / style->line_width;
+ stroker.spline_cusp_tolerance = 1 - tolerance / stroker.half_line_width;
stroker.spline_cusp_tolerance *= stroker.spline_cusp_tolerance;
stroker.spline_cusp_tolerance *= 2;
stroker.spline_cusp_tolerance -= 1;
@@ -1326,7 +1320,7 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
style->line_join == CAIRO_LINE_JOIN_ROUND ||
style->line_cap == CAIRO_LINE_CAP_ROUND) {
status = _cairo_pen_init (&stroker.pen,
- style->line_width / 2.0,
+ stroker.half_line_width,
tolerance, ctm);
if (unlikely (status))
return status;
commit 3cf6551ac71bac4d0ae1d0938bc0205dfc03f65c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sat Aug 25 23:42:45 2012 +0100
stroke: Use new pen vertex range finders
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index 242fb24..61a782b 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -161,12 +161,11 @@ add_fan (struct stroker *stroker,
const cairo_slope_t *in_vector,
const cairo_slope_t *out_vector,
const cairo_point_t *midpt,
- const cairo_point_t *inpt,
- const cairo_point_t *outpt,
cairo_bool_t clockwise,
struct stroke_contour *c)
{
- int start, stop, step, i, npoints;
+ cairo_pen_t *pen = &stroker->pen;
+ int start, stop;
if (stroker->has_bounds &&
! _cairo_box_contains_point (&stroker->bounds, midpt))
@@ -175,61 +174,29 @@ add_fan (struct stroker *stroker,
assert (stroker->pen.num_vertices);
if (clockwise) {
- step = 1;
-
- start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
- in_vector);
- if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
- in_vector) < 0)
- start = range_step (start, 1, stroker->pen.num_vertices);
-
- stop = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
- out_vector);
- if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
- out_vector) > 0)
- {
- stop = range_step (stop, -1, stroker->pen.num_vertices);
- if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
- in_vector) < 0)
- return;
+ _cairo_pen_find_active_cw_vertices (pen,
+ in_vector, out_vector,
+ &start, &stop);
+ while (start != stop) {
+ cairo_point_t p = *midpt;
+ translate_point (&p, &pen->vertices[start].point);
+ contour_add_point (stroker, c, &p);
+
+ if (++start == pen->num_vertices)
+ start = 0;
}
-
- npoints = stop - start;
} else {
- step = -1;
-
- start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
- in_vector);
- if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
- in_vector) < 0)
- start = range_step (start, -1, stroker->pen.num_vertices);
-
- stop = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
- out_vector);
- if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
- out_vector) > 0)
- {
- stop = range_step (stop, 1, stroker->pen.num_vertices);
- if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
- in_vector) < 0)
- return;
+ _cairo_pen_find_active_ccw_vertices (pen,
+ in_vector, out_vector,
+ &start, &stop);
+ while (start != stop) {
+ cairo_point_t p = *midpt;
+ translate_point (&p, &pen->vertices[start].point);
+ contour_add_point (stroker, c, &p);
+
+ if (start-- == 0)
+ start += pen->num_vertices;
}
-
- npoints = start - stop;
- }
- stop = range_step (stop, step, stroker->pen.num_vertices);
- if (npoints < 0)
- npoints += stroker->pen.num_vertices;
- if (npoints <= 1)
- return;
-
- for (i = start;
- i != stop;
- i = range_step (i, step, stroker->pen.num_vertices))
- {
- cairo_point_t p = *midpt;
- translate_point (&p, &stroker->pen.vertices[i].point);
- contour_add_point (stroker, c, &p);
}
}
@@ -435,9 +402,7 @@ outer_close (struct stroker *stroker,
in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
{
add_fan (stroker,
- &in->dev_vector,
- &out->dev_vector,
- &in->point, inpt, outpt,
+ &in->dev_vector, &out->dev_vector, &in->point,
clockwise, outer);
}
break;
@@ -624,9 +589,7 @@ outer_join (struct stroker *stroker,
case CAIRO_LINE_JOIN_ROUND:
/* construct a fan around the common midpoint */
add_fan (stroker,
- &in->dev_vector,
- &out->dev_vector,
- &in->point, inpt, outpt,
+ &in->dev_vector, &out->dev_vector, &in->point,
clockwise, outer);
break;
@@ -795,9 +758,7 @@ add_cap (struct stroker *stroker,
slope.dx = -f->dev_vector.dx;
slope.dy = -f->dev_vector.dy;
- add_fan (stroker, &f->dev_vector, &slope,
- &f->point, &f->ccw, &f->cw,
- FALSE, c);
+ add_fan (stroker, &f->dev_vector, &slope, &f->point, FALSE, c);
break;
}
@@ -1159,7 +1120,7 @@ spline_to (void *closure,
add_fan (stroker,
&stroker->current_face.dev_vector,
&face.dev_vector,
- &stroker->current_face.point, inpt, outpt,
+ &stroker->current_face.point,
clockwise, outer);
} else {
compute_face (point, tangent, stroker, &face);
@@ -1191,7 +1152,7 @@ spline_to (void *closure,
add_fan (stroker,
&stroker->current_face.dev_vector,
&face.dev_vector,
- &stroker->current_face.point, inpt, outpt,
+ &stroker->current_face.point,
clockwise, outer);
}
commit 74e9ae8cdff31e9a039b17f7dbe6e80f98e2c047
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sat Aug 25 23:29:21 2012 +0100
pen: Use bisection to speed up vertex finding
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index d70a064..cf441c4 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -388,3 +388,84 @@ _cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
return i;
}
+
+void
+_cairo_pen_find_active_cw_vertices (const cairo_pen_t *pen,
+ const cairo_slope_t *in,
+ const cairo_slope_t *out,
+ int *start, int *stop)
+{
+
+ int lo = 0, hi = pen->num_vertices;
+ int i;
+
+ i = (lo + hi) >> 1;
+ do {
+ if (_cairo_slope_compare (&pen->vertices[i].slope_cw, in) < 0)
+ lo = i;
+ else
+ hi = i;
+ i = (lo + hi) >> 1;
+ } while (hi - lo > 1);
+ if (_cairo_slope_compare (&pen->vertices[i].slope_cw, in) < 0)
+ if (++i == pen->num_vertices)
+ i = 0;
+ *start = i;
+
+ lo = i;
+ hi = i + pen->num_vertices;
+ i = (lo + hi) >> 1;
+ do {
+ int j = i;
+ if (j >= pen->num_vertices)
+ j -= pen->num_vertices;
+ if (_cairo_slope_compare (&pen->vertices[j].slope_cw, out) > 0)
+ hi = i;
+ else
+ lo = i;
+ i = (lo + hi) >> 1;
+ } while (hi - lo > 1);
+ if (i >= pen->num_vertices)
+ i -= pen->num_vertices;
+ *stop = i;
+}
+
+void
+_cairo_pen_find_active_ccw_vertices (const cairo_pen_t *pen,
+ const cairo_slope_t *in,
+ const cairo_slope_t *out,
+ int *start, int *stop)
+{
+ int lo = 0, hi = pen->num_vertices;
+ int i;
+
+ i = (lo + hi) >> 1;
+ do {
+ if (_cairo_slope_compare (in, &pen->vertices[i].slope_ccw) < 0)
+ lo = i;
+ else
+ hi = i;
+ i = (lo + hi) >> 1;
+ } while (hi - lo > 1);
+ if (_cairo_slope_compare (in, &pen->vertices[i].slope_ccw) < 0)
+ if (++i == pen->num_vertices)
+ i = 0;
+ *start = i;
+
+ lo = i;
+ hi = i + pen->num_vertices;
+ i = (lo + hi) >> 1;
+ do {
+ int j = i;
+ if (j >= pen->num_vertices)
+ j -= pen->num_vertices;
+ if (_cairo_slope_compare (out, &pen->vertices[j].slope_ccw) > 0)
+ hi = i;
+ else
+ lo = i;
+ i = (lo + hi) >> 1;
+ } while (hi - lo > 1);
+ if (i >= pen->num_vertices)
+ i -= pen->num_vertices;
+ *stop = i;
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 68b25be..7463595 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1555,6 +1555,18 @@ cairo_private int
_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
const cairo_slope_t *slope);
+cairo_private void
+_cairo_pen_find_active_cw_vertices (const cairo_pen_t *pen,
+ const cairo_slope_t *in,
+ const cairo_slope_t *out,
+ int *start, int *stop);
+
+cairo_private void
+_cairo_pen_find_active_ccw_vertices (const cairo_pen_t *pen,
+ const cairo_slope_t *in,
+ const cairo_slope_t *out,
+ int *start, int *stop);
+
/* cairo-polygon.c */
cairo_private void
_cairo_polygon_init (cairo_polygon_t *polygon,
commit aeb039b16dc302192113a7f10c4b86e7d13eb221
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sat Aug 25 12:57:01 2012 +0100
stroke: Skip spline evaluation when stroking to a polygon
If the spline is wholly outside the clip region, accounting for the
stroke width and additional rendering, then we can simplify that spline
with a straight line.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index b7c18b7..242fb24 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -81,6 +81,9 @@ struct stroker {
cairo_bool_t has_first_face;
cairo_stroke_face_t first_face;
+
+ cairo_bool_t has_bounds;
+ cairo_box_t bounds;
};
static inline double
@@ -165,6 +168,10 @@ add_fan (struct stroker *stroker,
{
int start, stop, step, i, npoints;
+ if (stroker->has_bounds &&
+ ! _cairo_box_contains_point (&stroker->bounds, midpt))
+ return;
+
assert (stroker->pen.num_vertices);
if (clockwise) {
@@ -1207,6 +1214,11 @@ curve_to (void *closure,
cairo_spline_t spline;
cairo_stroke_face_t face;
+ if (stroker->has_bounds &&
+ ! _cairo_spline_intersects (&stroker->current_face.point, b, c, b,
+ &stroker->bounds))
+ return line_to (closure, d);
+
if (! _cairo_spline_init (&spline, spline_to, stroker,
&stroker->current_face.point, b, c, d))
return line_to (closure, d);
@@ -1305,6 +1317,31 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
polygon);
}
+ stroker.has_bounds = polygon->num_limits;
+ if (stroker.has_bounds) {
+ /* Extend the bounds in each direction to account for the maximum area
+ * we might generate trapezoids, to capture line segments that are
+ * outside of the bounds but which might generate rendering that's
+ * within bounds.
+ */
+ double dx, dy;
+ cairo_fixed_t fdx, fdy;
+ int i;
+
+ stroker.bounds = polygon->limits[0];
+ for (i = 1; i < polygon->num_limits; i++)
+ _cairo_box_add_box (&stroker.bounds, &polygon->limits[i]);
+
+ _cairo_stroke_style_max_distance_from_path (style, path, ctm, &dx, &dy);
+ fdx = _cairo_fixed_from_double (dx);
+ fdy = _cairo_fixed_from_double (dy);
+
+ stroker.bounds.p1.x -= fdx;
+ stroker.bounds.p2.x += fdx;
+ stroker.bounds.p1.y -= fdy;
+ stroker.bounds.p2.y += fdy;
+ }
+
stroker.style = *style;
stroker.ctm = ctm;
stroker.ctm_inverse = ctm_inverse;
commit bdf83008f4b2c723fd8e65e2a92bc47a2e7bc442
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sat Aug 25 08:39:30 2012 +0100
compositor: Skip invisible strokes
If the pen is reduced to a single point, it is effectively invisible
when rasterised, so skip the stroke composition.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-compositor.c b/src/cairo-compositor.c
index a633aa2..b31413b 100644
--- a/src/cairo-compositor.c
+++ b/src/cairo-compositor.c
@@ -139,6 +139,10 @@ _cairo_compositor_stroke (const cairo_compositor_t *compositor,
cairo_int_status_t status;
TRACE ((stderr, "%s\n", __FUNCTION__));
+
+ if (_cairo_pen_vertices_needed (tolerance, style->line_width/2, ctm) <= 1)
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
status = _cairo_composite_rectangles_init_for_stroke (&extents, surface,
op, source,
path, style, ctm,
diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index e71f7b5..d70a064 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -41,11 +41,6 @@
#include "cairo-error-private.h"
#include "cairo-slope-private.h"
-static int
-_cairo_pen_vertices_needed (double tolerance,
- double radius,
- const cairo_matrix_t *matrix);
-
static void
_cairo_pen_compute_slopes (cairo_pen_t *pen);
@@ -88,10 +83,12 @@ _cairo_pen_init (cairo_pen_t *pen,
* is reflecting
*/
for (i=0; i < pen->num_vertices; i++) {
- double theta = 2 * M_PI * i / (double) pen->num_vertices;
- double dx = radius * cos (reflect ? -theta : theta);
- double dy = radius * sin (reflect ? -theta : theta);
cairo_pen_vertex_t *v = &pen->vertices[i];
+ double theta = 2 * M_PI * i / (double) pen->num_vertices, dx, dy;
+ if (reflect)
+ theta = -theta;
+ dx = radius * cos (theta);
+ dy = radius * sin (theta);
cairo_matrix_transform_distance (ctm, &dx, &dy);
v->point.x = _cairo_fixed_from_double (dx);
v->point.y = _cairo_fixed_from_double (dy);
@@ -273,7 +270,7 @@ Note that this also equation works for M == m (a circle) as it
doesn't matter where on the circle the error is computed.
*/
-static int
+int
_cairo_pen_vertices_needed (double tolerance,
double radius,
const cairo_matrix_t *matrix)
@@ -283,21 +280,16 @@ _cairo_pen_vertices_needed (double tolerance,
* compute major axis length for a pen with the specified radius.
* we don't need the minor axis length.
*/
+ double major_axis = _cairo_matrix_transformed_circle_major_axis (matrix,
+ radius);
+ int num_vertices;
- double major_axis = _cairo_matrix_transformed_circle_major_axis (matrix,
- radius);
-
- /*
- * compute number of vertices needed
- */
- int num_vertices;
-
- /* Where tolerance / M is > 1, we use 4 points */
- if (tolerance >= major_axis) {
+ if (tolerance >= 2*major_axis) {
+ num_vertices = 1;
+ } else if (tolerance >= major_axis) {
num_vertices = 4;
} else {
- double delta = acos (1 - tolerance / major_axis);
- num_vertices = ceil (M_PI / delta);
+ num_vertices = ceil (2*M_PI / acos (1 - tolerance / major_axis));
/* number of vertices must be even */
if (num_vertices % 2)
diff --git a/src/cairoint.h b/src/cairoint.h
index 26a8de1..68b25be 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1524,6 +1524,11 @@ cairo_private cairo_image_color_t
_cairo_image_analyze_color (cairo_image_surface_t *image);
/* cairo-pen.c */
+cairo_private int
+_cairo_pen_vertices_needed (double tolerance,
+ double radius,
+ const cairo_matrix_t *matrix);
+
cairo_private cairo_status_t
_cairo_pen_init (cairo_pen_t *pen,
double radius,
commit fc38d7375d4f0342ece91596d71f0ce56aa2c975
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Aug 24 17:39:08 2012 +0100
xlib/shm: Add missing release of the display after GetImage
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 6127e07..a35ea43 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -779,8 +779,10 @@ _get_image_surface (cairo_xlib_surface_t *surface,
AllPlanes);
XSetErrorHandler (old_handler);
- if (success)
+ if (success) {
+ cairo_device_release (&display->base);
return &image->base;
+ }
cairo_surface_destroy (&image->base);
}
More information about the cairo-commit
mailing list