[cairo-commit] 12 commits - doc/public src/cairo-analysis-surface.c src/cairo.c src/cairo-gstate.c src/cairo.h src/cairoint.h src/cairo-path-bounds.c src/cairo-path.c src/cairo-path-fixed.c test/get-path-extents.c
Carl Worth
cworth at kemper.freedesktop.org
Mon Jan 21 15:26:04 PST 2008
doc/public/cairo-sections.txt | 1
doc/public/tmpl/cairo-paths.sgml | 10 +++
src/cairo-analysis-surface.c | 2
src/cairo-gstate.c | 11 +++
src/cairo-path-bounds.c | 66 ++++++++++------------
src/cairo-path-fixed.c | 99 ++++++++++++++++++++++++++++++++++
src/cairo-path.c | 112 ++++++++++-----------------------------
src/cairo.c | 70 +++++++++++++++++++++---
src/cairo.h | 5 +
src/cairoint.h | 19 ++++++
test/get-path-extents.c | 83 ++++++++++++++++++++++------
11 files changed, 333 insertions(+), 145 deletions(-)
New commits:
commit 326342962daa694d876c03194e8a6c1b13f9a8d2
Author: Carl Worth <cworth at cworth.org>
Date: Mon Jan 21 15:20:07 2008 -0800
Rename trailing_move_to_point to move_to_point
And prefer TRUE and FALSE literals over 1 and 0.
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index b945c40..581244b 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -37,9 +37,9 @@
#include "cairoint.h"
typedef struct cairo_path_bounder {
- cairo_point_t trailing_move_to_point;
- int has_trailing_move_to;
- int has_point;
+ cairo_point_t move_to_point;
+ cairo_bool_t has_move_to_point;
+ cairo_bool_t has_point;
cairo_fixed_t min_x;
cairo_fixed_t min_y;
@@ -68,13 +68,15 @@ _cairo_path_bounder_close_path (void *closure);
static void
_cairo_path_bounder_init (cairo_path_bounder_t *bounder)
{
- bounder->has_point = 0;
+ bounder->has_move_to_point = FALSE;
+ bounder->has_point = FALSE;
}
static void
_cairo_path_bounder_fini (cairo_path_bounder_t *bounder)
{
- bounder->has_point = 0;
+ bounder->has_move_to_point = FALSE;
+ bounder->has_point = FALSE;
}
static void
@@ -98,7 +100,7 @@ _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *poi
bounder->max_x = point->x;
bounder->max_y = point->y;
- bounder->has_point = 1;
+ bounder->has_point = TRUE;
}
}
@@ -107,8 +109,8 @@ _cairo_path_bounder_move_to (void *closure, cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
- bounder->trailing_move_to_point = *point;
- bounder->has_trailing_move_to = 1;
+ bounder->move_to_point = *point;
+ bounder->has_move_to_point = TRUE;
return CAIRO_STATUS_SUCCESS;
}
@@ -118,10 +120,10 @@ _cairo_path_bounder_line_to (void *closure, cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
- if (bounder->has_trailing_move_to) {
+ if (bounder->has_move_to_point) {
_cairo_path_bounder_add_point (bounder,
- &bounder->trailing_move_to_point);
- bounder->has_trailing_move_to = 0;
+ &bounder->move_to_point);
+ bounder->has_move_to_point = FALSE;
}
_cairo_path_bounder_add_point (bounder, point);
commit c480eedbb58dd03dd4b9b87b3985758ffbce7113
Author: Carl Worth <cworth at cworth.org>
Date: Mon Jan 21 14:56:21 2008 -0800
Test and document extents of degenerate "dots"
It's a common idiom to stroke degenerate sub-paths made with
cairo_move_to(x,y);cairo_rel_line_to(0,0) to draw dots. Test
that we get the desired extents from cairo_fill_extents,
cairo_stroke_extents, and cairo_path_extents for these cases.
Also document that the cairo_path_extents result is equivalent
to the limit of stroking with CAIRO_LINE_CAP_ROUND, (so that
these "dot" points are included), as the line width
approaches 0.0 .
diff --git a/src/cairo.c b/src/cairo.c
index f5b92a7..3011125 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1887,9 +1887,9 @@ slim_hidden_def(cairo_close_path);
* the corresponding drawing operations.
*
* The result of cairo_path_extents() is defined as equivalent to the
- * limit of cairo_stroke_extents() as the line width approaches 0.0,
- * (but never reaching the empty-rectangle returned by
- * cairo_stroke_extents() for a line width of 0.0).
+ * limit of cairo_stroke_extents() with CAIRO_LINE_CAP_ROUND as the
+ * line width approaches 0.0, (but never reaching the empty-rectangle
+ * returned by cairo_stroke_extents() for a line width of 0.0).
*
* Specifically, this means that zero-area sub-paths such as
* cairo_move_to();cairo_line_to() segments, (even degenerate cases
diff --git a/test/get-path-extents.c b/test/get-path-extents.c
index 0be57a7..5e82c1e 100644
--- a/test/get-path-extents.c
+++ b/test/get-path-extents.c
@@ -166,6 +166,34 @@ draw (cairo_t *cr, int width, int height)
cairo_new_path (cr2);
cairo_restore (cr2);
+ /* Test that with CAIRO_LINE_CAP_ROUND, we get "dots" from
+ * cairo_move_to; cairo_rel_line_to(0,0) */
+ cairo_save (cr2);
+
+ cairo_set_line_cap (cr2, CAIRO_LINE_CAP_ROUND);
+ cairo_set_line_width (cr2, 20);
+
+ cairo_move_to (cr2, 200, 400);
+ cairo_rel_line_to (cr2, 0, 0);
+ phase = "Single 'dot'";
+ if (!check_extents (phase, cr2, FILL, EQUALS, 0, 0, 0, 0) ||
+ !check_extents (phase, cr2, STROKE, EQUALS, 190, 390, 20, 20) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 200, 400, 0, 0))
+ ret = CAIRO_TEST_FAILURE;
+
+ /* Add another dot without starting a new path */
+ cairo_move_to (cr2, 100, 500);
+ cairo_rel_line_to (cr2, 0, 0);
+ phase = "Multiple 'dots'";
+ if (!check_extents (phase, cr2, FILL, EQUALS, 0, 0, 0, 0) ||
+ !check_extents (phase, cr2, STROKE, EQUALS, 90, 390, 120, 120) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 100, 400, 100, 100))
+ ret = CAIRO_TEST_FAILURE;
+
+ cairo_new_path (cr2);
+
+ cairo_restore (cr2);
+
/* http://bugs.freedesktop.org/show_bug.cgi?id=7965 */
phase = "A vertical, open path";
cairo_save (cr2);
commit 55e0dddf0408046ea0ded419ebe45099a4eb563e
Author: Carl Worth <cworth at cworth.org>
Date: Mon Jan 21 14:45:06 2008 -0800
Add cairo_path_extents testing to several cases missing it
With these degenerate shapes, cairo_path_extents still returns
a zero-area rectangle, but with a non-zero offset.
diff --git a/test/get-path-extents.c b/test/get-path-extents.c
index 5520b39..0be57a7 100644
--- a/test/get-path-extents.c
+++ b/test/get-path-extents.c
@@ -134,7 +134,8 @@ draw (cairo_t *cr, int width, int height)
cairo_rel_line_to (cr2, 0., 0.);
phase = "Degenerate line";
if (!check_extents (phase, cr2, FILL, EQUALS, 0, 0, 0, 0) ||
- !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 0, 0))
+ !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 0, 0) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 200, 400, 0, 0))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
@@ -142,21 +143,24 @@ draw (cairo_t *cr, int width, int height)
cairo_rel_curve_to (cr2, 0., 0., 0., 0., 0., 0.);
phase = "Degenerate curve";
if (!check_extents (phase, cr2, FILL, EQUALS, 0, 0, 0, 0) ||
- !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 0, 0))
+ !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 0, 0) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 200, 400, 0, 0))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
cairo_arc (cr2, 200, 400, 0., 0, 2 * M_PI);
phase = "Degenerate arc (R=0)";
if (!check_extents (phase, cr2, FILL, EQUALS, 0, 0, 0, 0) ||
- !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 0, 0))
+ !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 0, 0) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 200, 400, 0, 0))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
cairo_arc (cr2, 200, 400, 10., 0, 0);
phase = "Degenerate arc (Î=0)";
if (!check_extents (phase, cr2, FILL, EQUALS, 0, 0, 0, 0) ||
- !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 0, 0))
+ !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 0, 0) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 200, 400, 0, 0))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
commit 63df3a82a3a4a035edf89152995a324449616059
Author: Carl Worth <cworth at cworth.org>
Date: Mon Jan 21 13:47:05 2008 -0800
Fix cairo_path_extents to ignore lone cairo_move_to points.
Update the documentation as well.
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index f996977..b945c40 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -37,6 +37,8 @@
#include "cairoint.h"
typedef struct cairo_path_bounder {
+ cairo_point_t trailing_move_to_point;
+ int has_trailing_move_to;
int has_point;
cairo_fixed_t min_x;
@@ -105,7 +107,8 @@ _cairo_path_bounder_move_to (void *closure, cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
- _cairo_path_bounder_add_point (bounder, point);
+ bounder->trailing_move_to_point = *point;
+ bounder->has_trailing_move_to = 1;
return CAIRO_STATUS_SUCCESS;
}
@@ -115,6 +118,12 @@ _cairo_path_bounder_line_to (void *closure, cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
+ if (bounder->has_trailing_move_to) {
+ _cairo_path_bounder_add_point (bounder,
+ &bounder->trailing_move_to_point);
+ bounder->has_trailing_move_to = 0;
+ }
+
_cairo_path_bounder_add_point (bounder, point);
return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo.c b/src/cairo.c
index 9e71c81..f5b92a7 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1877,16 +1877,26 @@ slim_hidden_def(cairo_close_path);
* @x2: right of the resulting extents
* @y2: bottom of the resulting extents
*
- * Computes a bounding box in user coordinates covering the points
- * on the current path. If the current path is empty,
- * returns an empty rectangle (0,0, 0,0). Stroke parameters,
- * surface dimensions and clipping are not taken into account.
+ * Computes a bounding box in user-space coordinates covering the
+ * points on the current path. If the current path is empty, returns
+ * an empty rectangle ((0,0), (0,0)). Stroke parameters, surface
+ * dimensions and clipping are not taken into account.
*
* Contrast with cairo_fill_extents() and cairo_stroke_extents() which
- * return the extents of the area that would be "inked" by drawing
- * operations. The results of cairo_path_extent() and
- * cairo_fill_extents() are identical unless there are one or more
- * sub-paths with zero area.
+ * return the extents of only the area that would be "inked" by
+ * the corresponding drawing operations.
+ *
+ * The result of cairo_path_extents() is defined as equivalent to the
+ * limit of cairo_stroke_extents() as the line width approaches 0.0,
+ * (but never reaching the empty-rectangle returned by
+ * cairo_stroke_extents() for a line width of 0.0).
+ *
+ * Specifically, this means that zero-area sub-paths such as
+ * cairo_move_to();cairo_line_to() segments, (even degenerate cases
+ * where the coordinates to both calls are identical), will be
+ * considered as contributing to the extents. However, a lone
+ * cairo_move_to() will not contribute to the results of
+ * cairo_path_extents().
*
* Since: 1.6
**/
@@ -2273,8 +2283,8 @@ cairo_in_fill (cairo_t *cr, double x, double y)
* would be affected, (the "inked" area), by a cairo_stroke()
* operation operation given the current path and stroke
* parameters. If the current path is empty, returns an empty
- * rectangle (0,0, 0,0). Surface dimensions and clipping are not taken
- * into account.
+ * rectangle ((0,0), (0,0)). Surface dimensions and clipping are not
+ * taken into account.
*
* Note that if the line width is set to exactly zero, then
* cairo_stroke_extents will return an empty rectangle. Contrast with
@@ -2312,12 +2322,12 @@ cairo_stroke_extents (cairo_t *cr,
* Computes a bounding box in user coordinates covering the area that
* would be affected, (the "inked" area), by a cairo_fill() operation
* given the current path and fill parameters. If the current path is
- * empty, returns an empty rectangle (0,0, 0,0). Surface dimensions
- * and clipping are not taken into account.
+ * empty, returns an empty rectangle ((0,0), (0,0)). Surface
+ * dimensions and clipping are not taken into account.
*
- * Contrast with cairo_path_extents(), which is similar, but will
- * return non-zero extents for a path with no inked area, (such as a
- * simple line segment).
+ * Contrast with cairo_path_extents(), which is similar, but returns
+ * non-zero extents for some paths no inked area, (such as a simple
+ * line segment).
*
* See cairo_fill(), cairo_set_fill_rule() and cairo_fill_preserve().
**/
commit c15cab8b6855540436e457465c4766812c6def55
Author: Carl Worth <cworth at cworth.org>
Date: Mon Jan 21 13:34:53 2008 -0800
Correct near-pangram to be an actual pangram
This wasn't affecting the test quality at all, but it did annoy
me to see this mistake.
diff --git a/test/get-path-extents.c b/test/get-path-extents.c
index 0ba761c..5520b39 100644
--- a/test/get-path-extents.c
+++ b/test/get-path-extents.c
@@ -106,7 +106,7 @@ draw (cairo_t *cr, int width, int height)
cairo_surface_t *surface;
cairo_t *cr2;
const char *phase;
- const char string[] = "The quick brown fox jumped over the lazy dog.";
+ const char string[] = "The quick brown fox jumps over the lazy dog.";
cairo_text_extents_t extents, scaled_font_extents;
cairo_test_status_t ret = CAIRO_TEST_SUCCESS;
commit ed695bdb9b1e4500f796c7f07a7cc2f3832b2a39
Author: Carl Worth <cworth at cworth.org>
Date: Mon Jan 21 13:33:46 2008 -0800
Define repeated string literal once
diff --git a/test/get-path-extents.c b/test/get-path-extents.c
index a06e301..0ba761c 100644
--- a/test/get-path-extents.c
+++ b/test/get-path-extents.c
@@ -106,6 +106,7 @@ draw (cairo_t *cr, int width, int height)
cairo_surface_t *surface;
cairo_t *cr2;
const char *phase;
+ const char string[] = "The quick brown fox jumped over the lazy dog.";
cairo_text_extents_t extents, scaled_font_extents;
cairo_test_status_t ret = CAIRO_TEST_SUCCESS;
@@ -223,15 +224,16 @@ draw (cairo_t *cr, int width, int height)
phase = "Text";
cairo_save (cr2);
+ cairo_set_tolerance (cr2, 100.0);
cairo_select_font_face (cr2, "Bitstream Vera Sans",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr2, 12);
- cairo_text_extents (cr2, "The quick brown fox jumped over the lazy dog.", &extents);
+ cairo_text_extents (cr2, string, &extents);
/* double check that the two methods of measuring the text agree... */
cairo_scaled_font_text_extents (cairo_get_scaled_font (cr2),
- "The quick brown fox jumped over the lazy dog.",
- &scaled_font_extents);
+ string,
+ &scaled_font_extents);
if (memcmp (&extents, &scaled_font_extents, sizeof (extents))) {
cairo_test_log ("Error: cairo_text_extents() does not match cairo_scaled_font_text_extents() - font extents (%f, %f) x (%f, %f) should be (%f, %f) x (%f, %f)\n",
scaled_font_extents.x_bearing,
@@ -246,7 +248,7 @@ draw (cairo_t *cr, int width, int height)
}
cairo_move_to (cr2, -extents.x_bearing, -extents.y_bearing);
- cairo_text_path (cr2, "The quick brown fox jumped over the lazy dog.");
+ cairo_text_path (cr2, string);
cairo_set_line_width (cr2, 2.0);
if (!check_extents (phase, cr2, FILL, EQUALS, 0, 0, extents.width, extents.height) ||
!check_extents (phase, cr2, STROKE, EQUALS, -1, -1, extents.width+2, extents.height+2) ||
commit 80df194b77a4caac1d58132341f034596e500bda
Author: Carl Worth <cworth at cworth.org>
Date: Mon Jan 21 12:14:49 2008 -0800
Clarify documentation of cairo_{fill,stroke,path}_extents
Mostly just adding more cross-references between the documentation
of these three similar functions.
diff --git a/src/cairo.c b/src/cairo.c
index 42411ce..9e71c81 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1880,9 +1880,13 @@ slim_hidden_def(cairo_close_path);
* Computes a bounding box in user coordinates covering the points
* on the current path. If the current path is empty,
* returns an empty rectangle (0,0, 0,0). Stroke parameters,
- * surface dimensions and clipping are not taken into account. This
- * will be the same as the value returned by cairo_fill_extents()
- * unless the area enclosed by the path is empty.
+ * surface dimensions and clipping are not taken into account.
+ *
+ * Contrast with cairo_fill_extents() and cairo_stroke_extents() which
+ * return the extents of the area that would be "inked" by drawing
+ * operations. The results of cairo_path_extent() and
+ * cairo_fill_extents() are identical unless there are one or more
+ * sub-paths with zero area.
*
* Since: 1.6
**/
@@ -2266,10 +2270,16 @@ cairo_in_fill (cairo_t *cr, double x, double y)
* @y2: bottom of the resulting extents
*
* Computes a bounding box in user coordinates covering the area that
- * would be affected by a cairo_stroke() operation operation given the
- * current path and stroke parameters. If the current path is empty,
- * returns an empty rectangle (0,0, 0,0). Surface dimensions and
- * clipping are not taken into account.
+ * would be affected, (the "inked" area), by a cairo_stroke()
+ * operation operation given the current path and stroke
+ * parameters. If the current path is empty, returns an empty
+ * rectangle (0,0, 0,0). Surface dimensions and clipping are not taken
+ * into account.
+ *
+ * Note that if the line width is set to exactly zero, then
+ * cairo_stroke_extents will return an empty rectangle. Contrast with
+ * cairo_path_extents() which can be used to compute the non-empty
+ * bounds as the line width approaches zero.
*
* See cairo_stroke(), cairo_set_line_width(), cairo_set_line_join(),
* cairo_set_line_cap(), cairo_set_dash(), and
@@ -2300,10 +2310,14 @@ cairo_stroke_extents (cairo_t *cr,
* @y2: bottom of the resulting extents
*
* Computes a bounding box in user coordinates covering the area that
- * would be affected by a cairo_fill() operation given the current path
- * and fill parameters. If the current path is empty, returns an empty
- * rectangle (0,0, 0,0). Surface dimensions and clipping are not taken
- * into account.
+ * would be affected, (the "inked" area), by a cairo_fill() operation
+ * given the current path and fill parameters. If the current path is
+ * empty, returns an empty rectangle (0,0, 0,0). Surface dimensions
+ * and clipping are not taken into account.
+ *
+ * Contrast with cairo_path_extents(), which is similar, but will
+ * return non-zero extents for a path with no inked area, (such as a
+ * simple line segment).
*
* See cairo_fill(), cairo_set_fill_rule() and cairo_fill_preserve().
**/
commit eba04b7fbcc7fdbf075ad1372208908634459178
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date: Sun Jan 20 03:22:12 2008 +0000
[path] use new interpret_flat infrastructure for path_populate
refactor to reduce duplication of flattening code.
diff --git a/src/cairo-path.c b/src/cairo-path.c
index 605ba05..96ecbb3 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -237,40 +237,6 @@ _cpp_curve_to (void *closure,
}
static cairo_status_t
-_cpp_curve_to_flatten (void *closure,
- cairo_point_t *p1,
- cairo_point_t *p2,
- cairo_point_t *p3)
-{
- cpp_t *cpp = closure;
- cairo_status_t status;
- cairo_spline_t spline;
- int i;
-
- cairo_point_t *p0 = &cpp->current_point;
-
- status = _cairo_spline_init (&spline, p0, p1, p2, p3);
- if (status == CAIRO_INT_STATUS_DEGENERATE)
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_spline_decompose (&spline,
- _cairo_gstate_get_tolerance (cpp->gstate));
- if (status)
- goto out;
-
- for (i=1; i < spline.num_points; i++)
- _cpp_line_to (cpp, &spline.points[i]);
-
- cpp->current_point = *p3;
-
- status = CAIRO_STATUS_SUCCESS;
-
- out:
- _cairo_spline_fini (&spline);
- return status;
-}
-
-static cairo_status_t
_cpp_close_path (void *closure)
{
cpp_t *cpp = closure;
@@ -298,15 +264,25 @@ _cairo_path_populate (cairo_path_t *path,
cpp.current_point.x = 0;
cpp.current_point.y = 0;
- status = _cairo_path_fixed_interpret (path_fixed,
+ if (flatten) {
+ double tolerance = _cairo_gstate_get_tolerance (gstate);
+ status = _cairo_path_fixed_interpret_flat (path_fixed,
+ CAIRO_DIRECTION_FORWARD,
+ _cpp_move_to,
+ _cpp_line_to,
+ _cpp_close_path,
+ &cpp,
+ tolerance);
+ } else {
+ status = _cairo_path_fixed_interpret (path_fixed,
CAIRO_DIRECTION_FORWARD,
_cpp_move_to,
_cpp_line_to,
- flatten ?
- _cpp_curve_to_flatten :
_cpp_curve_to,
_cpp_close_path,
&cpp);
+ }
+
if (status)
return status;
commit 3270ae6a65105787942da8309fa874ee65bc79fe
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date: Sun Jan 20 03:21:41 2008 +0000
[path] Use new interpret_flat infrastructure for path_count.
Refactor to reduce duplication of path flattening code.
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index 9652934..f996977 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -61,12 +61,6 @@ static cairo_status_t
_cairo_path_bounder_line_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_path_bounder_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d);
-
-static cairo_status_t
_cairo_path_bounder_close_path (void *closure);
static void
diff --git a/src/cairo-path.c b/src/cairo-path.c
index b9086c4..605ba05 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -44,7 +44,6 @@ static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
/* Closure for path interpretation. */
typedef struct cairo_path_count {
int count;
- double tolerance;
cairo_point_t current_point;
} cpc_t;
@@ -88,39 +87,6 @@ _cpc_curve_to (void *closure,
}
static cairo_status_t
-_cpc_curve_to_flatten (void *closure,
- cairo_point_t *p1,
- cairo_point_t *p2,
- cairo_point_t *p3)
-{
- cpc_t *cpc = closure;
- cairo_status_t status;
- cairo_spline_t spline;
- int i;
-
- cairo_point_t *p0 = &cpc->current_point;
-
- status = _cairo_spline_init (&spline, p0, p1, p2, p3);
- if (status == CAIRO_INT_STATUS_DEGENERATE)
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_spline_decompose (&spline, cpc->tolerance);
- if (status)
- goto out;
-
- for (i=1; i < spline.num_points; i++)
- _cpc_line_to (cpc, &spline.points[i]);
-
- cpc->current_point = *p3;
-
- status = CAIRO_STATUS_SUCCESS;
-
- out:
- _cairo_spline_fini (&spline);
- return status;
-}
-
-static cairo_status_t
_cpc_close_path (void *closure)
{
cpc_t *cpc = closure;
@@ -140,19 +106,27 @@ _cairo_path_count (cairo_path_t *path,
cpc_t cpc;
cpc.count = 0;
- cpc.tolerance = tolerance;
cpc.current_point.x = 0;
cpc.current_point.y = 0;
- status = _cairo_path_fixed_interpret (path_fixed,
- CAIRO_DIRECTION_FORWARD,
- _cpc_move_to,
- _cpc_line_to,
- flatten ?
- _cpc_curve_to_flatten :
- _cpc_curve_to,
- _cpc_close_path,
- &cpc);
+ if (flatten) {
+ status = _cairo_path_fixed_interpret_flat (path_fixed,
+ CAIRO_DIRECTION_FORWARD,
+ _cpc_move_to,
+ _cpc_line_to,
+ _cpc_close_path,
+ &cpc,
+ tolerance);
+ } else {
+ status = _cairo_path_fixed_interpret (path_fixed,
+ CAIRO_DIRECTION_FORWARD,
+ _cpc_move_to,
+ _cpc_line_to,
+ _cpc_curve_to,
+ _cpc_close_path,
+ &cpc);
+ }
+
if (status)
return -1;
commit 4177208be63caa3128eaf07428f3d4617fcd18e0
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date: Fri Nov 16 22:43:43 2007 +0000
[cairo] Add cairo_path_extents()
This new function gets the extents of the current path, whether
or not they would be inked by a 'fill'. It differs from
cairo_fill_extents() when the area enclosed by the path is 0.
Includes documentation and updated test.
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 4484271..88e9c8a 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -326,6 +326,7 @@ cairo_text_path
cairo_rel_curve_to
cairo_rel_line_to
cairo_rel_move_to
+cairo_path_extents
</SECTION>
<SECTION>
diff --git a/doc/public/tmpl/cairo-paths.sgml b/doc/public/tmpl/cairo-paths.sgml
index 3be71a4..3d68342 100644
--- a/doc/public/tmpl/cairo-paths.sgml
+++ b/doc/public/tmpl/cairo-paths.sgml
@@ -236,3 +236,13 @@ Creating paths and manipulating path data
@dy:
+<!-- ##### FUNCTION cairo_path_extents ##### -->
+<para>
+
+</para>
+
+ at cr:
+ at x1:
+ at y1:
+ at x2:
+ at y2:
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 3577d84..a00a52c 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -818,6 +818,17 @@ _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
}
*/
+void
+_cairo_gstate_path_extents (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
+ double *x1, double *y1,
+ double *x2, double *y2)
+{
+ _cairo_path_fixed_bounds (path, x1, y1, x2, y2, gstate->tolerance);
+
+ _cairo_gstate_backend_to_user_rectangle (gstate, x1, y1, x2, y2, NULL);
+}
+
static cairo_status_t
_cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
cairo_pattern_t *pattern,
diff --git a/src/cairo.c b/src/cairo.c
index 4a7aec1..42411ce 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1870,6 +1870,36 @@ cairo_close_path (cairo_t *cr)
slim_hidden_def(cairo_close_path);
/**
+ * cairo_path_extents:
+ * @cr: a cairo context
+ * @x1: left of the resulting extents
+ * @y1: top of the resulting extents
+ * @x2: right of the resulting extents
+ * @y2: bottom of the resulting extents
+ *
+ * Computes a bounding box in user coordinates covering the points
+ * on the current path. If the current path is empty,
+ * returns an empty rectangle (0,0, 0,0). Stroke parameters,
+ * surface dimensions and clipping are not taken into account. This
+ * will be the same as the value returned by cairo_fill_extents()
+ * unless the area enclosed by the path is empty.
+ *
+ * Since: 1.6
+ **/
+void
+cairo_path_extents (cairo_t *cr,
+ double *x1, double *y1, double *x2, double *y2)
+{
+ if (cr->status)
+ return;
+
+ _cairo_gstate_path_extents (cr->gstate,
+ cr->path,
+ x1, y1, x2, y2);
+}
+slim_hidden_def (cairo_path_extents);
+
+/**
* cairo_paint:
* @cr: a cairo context
*
diff --git a/src/cairo.h b/src/cairo.h
index 4c58c14..157b6e1 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -584,6 +584,11 @@ cairo_stroke_to_path (cairo_t *cr);
cairo_public void
cairo_close_path (cairo_t *cr);
+cairo_public void
+cairo_path_extents (cairo_t *cr,
+ double *x1, double *y1,
+ double *x2, double *y2);
+
/* Painting functions */
cairo_public void
cairo_paint (cairo_t *cr);
diff --git a/src/cairoint.h b/src/cairoint.h
index ea3c2b6..7c1d2d5 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1005,6 +1005,12 @@ _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
double *x2, double *y2,
cairo_bool_t *is_tight);
+cairo_private void
+_cairo_gstate_path_extents (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
+ double *x1, double *y1,
+ double *x2, double *y2);
+
cairo_private cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate);
@@ -2220,6 +2226,7 @@ slim_hidden_proto (cairo_matrix_translate);
slim_hidden_proto (cairo_move_to);
slim_hidden_proto (cairo_new_path);
slim_hidden_proto (cairo_paint);
+slim_hidden_proto (cairo_path_extents);
slim_hidden_proto (cairo_pattern_create_for_surface);
slim_hidden_proto (cairo_pattern_create_rgb);
slim_hidden_proto (cairo_pattern_create_rgba);
diff --git a/test/get-path-extents.c b/test/get-path-extents.c
index b20b13f..a06e301 100644
--- a/test/get-path-extents.c
+++ b/test/get-path-extents.c
@@ -36,7 +36,7 @@ cairo_test_t test = {
draw
};
-enum ExtentsType { FILL, STROKE };
+enum ExtentsType { FILL, STROKE, PATH };
enum Relation { EQUALS, APPROX_EQUALS, CONTAINS };
@@ -59,6 +59,10 @@ check_extents (const char *message, cairo_t *cr, enum ExtentsType type,
type_string = "stroke";
cairo_stroke_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2);
break;
+ case PATH:
+ type_string = "path";
+ cairo_path_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2);
+ break;
}
/* let empty rects match */
@@ -118,7 +122,8 @@ draw (cairo_t *cr, int width, int height)
phase = "No path";
if (!check_extents (phase, cr2, FILL, EQUALS, 0, 0, 0, 0) ||
- !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 0, 0))
+ !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 0, 0) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 0, 0, 0, 0))
ret = CAIRO_TEST_FAILURE;
cairo_save (cr2);
@@ -164,7 +169,8 @@ draw (cairo_t *cr, int width, int height)
cairo_move_to (cr2, 0, 180);
cairo_line_to (cr2, 750, 180);
if (!check_extents (phase, cr2, FILL, EQUALS, 0, 0, 0, 0) ||
- !check_extents (phase, cr2, STROKE, EQUALS, -5, 175, 760, 10))
+ !check_extents (phase, cr2, STROKE, EQUALS, -5, 175, 760, 10) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 0, 180, 755, 0))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
cairo_restore (cr2);
@@ -173,7 +179,8 @@ draw (cairo_t *cr, int width, int height)
cairo_save (cr2);
cairo_rectangle (cr2, 10, 10, 80, 80);
if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 80, 80) ||
- !check_extents (phase, cr2, STROKE, EQUALS, 5, 5, 90, 90))
+ !check_extents (phase, cr2, STROKE, EQUALS, 5, 5, 90, 90) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 10, 10, 80, 80))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
cairo_restore (cr2);
@@ -183,7 +190,8 @@ draw (cairo_t *cr, int width, int height)
cairo_rectangle (cr2, 10, 10, 10, 10);
cairo_rectangle (cr2, 20, 20, 10, 10);
if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 20, 20) ||
- !check_extents (phase, cr2, STROKE, EQUALS, 5, 5, 30, 30))
+ !check_extents (phase, cr2, STROKE, EQUALS, 5, 5, 30, 30) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 10, 10, 20, 20))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
cairo_restore (cr2);
@@ -197,7 +205,8 @@ draw (cairo_t *cr, int width, int height)
/* miter joins protrude 5*(1+sqrt(2)) above the top-left corner and to
the right of the bottom-right corner */
if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 80, 80) ||
- !check_extents (phase, cr2, STROKE, CONTAINS, 0, 5, 95, 95))
+ !check_extents (phase, cr2, STROKE, CONTAINS, 0, 5, 95, 95) ||
+ !check_extents (phase, cr2, PATH, CONTAINS, 10, 10, 80, 80))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
cairo_restore (cr2);
@@ -240,7 +249,8 @@ draw (cairo_t *cr, int width, int height)
cairo_text_path (cr2, "The quick brown fox jumped over the lazy dog.");
cairo_set_line_width (cr2, 2.0);
if (!check_extents (phase, cr2, FILL, EQUALS, 0, 0, extents.width, extents.height) ||
- !check_extents (phase, cr2, STROKE, EQUALS, -1, -1, extents.width+2, extents.height+2))
+ !check_extents (phase, cr2, STROKE, EQUALS, -1, -1, extents.width+2, extents.height+2) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 0, 0, extents.width, extents.height))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
cairo_restore (cr2);
@@ -250,7 +260,8 @@ draw (cairo_t *cr, int width, int height)
cairo_scale (cr2, 2, 2);
cairo_rectangle (cr2, 5, 5, 40, 40);
if (!check_extents (phase, cr2, FILL, EQUALS, 5, 5, 40, 40) ||
- !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 50, 50))
+ !check_extents (phase, cr2, STROKE, EQUALS, 0, 0, 50, 50) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 5, 5, 40, 40))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
cairo_restore (cr2);
@@ -262,7 +273,8 @@ draw (cairo_t *cr, int width, int height)
cairo_rectangle (cr2, 5, 5, 40, 40);
cairo_restore (cr2);
if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 80, 80) ||
- !check_extents (phase, cr2, STROKE, EQUALS, 5, 5, 90, 90))
+ !check_extents (phase, cr2, STROKE, EQUALS, 5, 5, 90, 90) ||
+ !check_extents (phase, cr2, PATH, EQUALS, 10, 10, 80, 80))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
cairo_restore (cr2);
@@ -281,7 +293,8 @@ draw (cairo_t *cr, int width, int height)
the largest axis-aligned square is a bit over 38 on either side of
the axes. */
if (!check_extents (phase, cr2, FILL, CONTAINS, -35, -35, 35, 35) ||
- !check_extents (phase, cr2, STROKE, CONTAINS, -38, -38, 38, 38))
+ !check_extents (phase, cr2, STROKE, CONTAINS, -38, -38, 38, 38) ||
+ !check_extents (phase, cr2, PATH, CONTAINS, -35, -35, 35, 35))
ret = CAIRO_TEST_FAILURE;
cairo_new_path (cr2);
cairo_restore (cr2);
commit d923457c0f40c9b34ee75d4d47b9bd0c3edfe669
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date: Sat Jan 19 22:31:49 2008 +0000
[path-fixed] make _cairo_path_fixed_bounds use _cairo_path_fixed_interpret_flat
_cairo_path_fixed_bounds can use the new _interpret_flat mechanism; this
results in tighter bounds; previously the bounds followed the control
points of the beziers, whereas now they are the bounds of the curve.
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 509b5f2..a223086 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -228,7 +228,7 @@ _cairo_analysis_surface_intersect_clip_path (void *abstract_surface,
surface->current_clip.width = surface->width;
surface->current_clip.height = surface->height;
} else {
- _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2);
+ _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2, tolerance);
extent.x = floor (x1);
extent.y = floor (y1);
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index 55a64e5..9652934 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -127,21 +127,6 @@ _cairo_path_bounder_line_to (void *closure, cairo_point_t *point)
}
static cairo_status_t
-_cairo_path_bounder_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- cairo_path_bounder_t *bounder = closure;
-
- _cairo_path_bounder_add_point (bounder, b);
- _cairo_path_bounder_add_point (bounder, c);
- _cairo_path_bounder_add_point (bounder, d);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
_cairo_path_bounder_close_path (void *closure)
{
return CAIRO_STATUS_SUCCESS;
@@ -151,7 +136,8 @@ _cairo_path_bounder_close_path (void *closure)
void
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
double *x1, double *y1,
- double *x2, double *y2)
+ double *x2, double *y2,
+ double tolerance)
{
cairo_status_t status;
@@ -159,21 +145,24 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path,
_cairo_path_bounder_init (&bounder);
- status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
- _cairo_path_bounder_move_to,
- _cairo_path_bounder_line_to,
- _cairo_path_bounder_curve_to,
- _cairo_path_bounder_close_path,
- &bounder);
+ status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
+ _cairo_path_bounder_move_to,
+ _cairo_path_bounder_line_to,
+ _cairo_path_bounder_close_path,
+ &bounder,
+ tolerance);
assert (status == CAIRO_STATUS_SUCCESS);
- if (! bounder.has_point) {
- *x1 = *y1 = *x2 = *y2 = 0.;
- } else {
+ if (bounder.has_point) {
*x1 = _cairo_fixed_to_double (bounder.min_x);
*y1 = _cairo_fixed_to_double (bounder.min_y);
*x2 = _cairo_fixed_to_double (bounder.max_x);
*y2 = _cairo_fixed_to_double (bounder.max_y);
+ } else {
+ *x1 = 0.0;
+ *y1 = 0.0;
+ *x2 = 0.0;
+ *y2 = 0.0;
}
_cairo_path_bounder_fini (&bounder);
diff --git a/src/cairoint.h b/src/cairoint.h
index fe23259..ea3c2b6 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1359,7 +1359,8 @@ _cairo_path_fixed_interpret_flat (cairo_path_fixed_t *path,
cairo_private void
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
double *x1, double *y1,
- double *x2, double *y2);
+ double *x2, double *y2,
+ double tolerance);
cairo_private void
_cairo_path_fixed_device_transform (cairo_path_fixed_t *path,
commit 1471b3f00acddecdfc2617a62ab0e584f319dc1c
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date: Sat Jan 19 22:31:10 2008 +0000
[path-fixed] add _cairo_path_fixed_interpret_flat
_cairo_path_fixed_interpret_flat flattens the path as it
interprets it, meaning that a curve_to callback is not
required.
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index e18ecc3..91b8c0e 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -622,3 +622,102 @@ _cairo_path_fixed_is_equal (cairo_path_fixed_t *path,
}
return TRUE;
}
+
+/* Closure for path flattening */
+typedef struct cairo_path_flattener {
+ double tolerance;
+ cairo_point_t current_point;
+ cairo_path_fixed_move_to_func_t *move_to;
+ cairo_path_fixed_line_to_func_t *line_to;
+ cairo_path_fixed_close_path_func_t *close_path;
+ void *closure;
+} cpf_t;
+
+static cairo_status_t
+_cpf_move_to (void *closure, cairo_point_t *point)
+{
+ cpf_t *cpf = closure;
+
+ cpf->current_point = *point;
+
+ return cpf->move_to (cpf->closure, point);
+}
+
+static cairo_status_t
+_cpf_line_to (void *closure, cairo_point_t *point)
+{
+ cpf_t *cpf = closure;
+
+ cpf->current_point = *point;
+
+ return cpf->line_to (cpf->closure, point);
+}
+
+static cairo_status_t
+_cpf_curve_to (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ cpf_t *cpf = closure;
+ cairo_status_t status;
+ cairo_spline_t spline;
+ int i;
+
+ cairo_point_t *p0 = &cpf->current_point;
+
+ status = _cairo_spline_init (&spline, p0, p1, p2, p3);
+ if (status == CAIRO_INT_STATUS_DEGENERATE)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_spline_decompose (&spline, cpf->tolerance);
+ if (status)
+ goto out;
+
+ for (i=1; i < spline.num_points; i++) {
+ status = cpf->line_to (cpf->closure, &spline.points[i]);
+ if (status)
+ goto out;
+ }
+
+ cpf->current_point = *p3;
+
+ status = CAIRO_STATUS_SUCCESS;
+
+ out:
+ _cairo_spline_fini (&spline);
+ return status;
+}
+
+static cairo_status_t
+_cpf_close_path (void *closure)
+{
+ cpf_t *cpf = closure;
+
+ return cpf->close_path (cpf->closure);
+}
+
+
+cairo_status_t
+_cairo_path_fixed_interpret_flat (cairo_path_fixed_t *path,
+ cairo_direction_t dir,
+ cairo_path_fixed_move_to_func_t *move_to,
+ cairo_path_fixed_line_to_func_t *line_to,
+ cairo_path_fixed_close_path_func_t *close_path,
+ void *closure,
+ double tolerance)
+{
+ cpf_t flattener;
+
+ flattener.tolerance = tolerance;
+ flattener.move_to = move_to;
+ flattener.line_to = line_to;
+ flattener.close_path = close_path;
+ flattener.closure = closure;
+ return _cairo_path_fixed_interpret (path, dir,
+ _cpf_move_to,
+ _cpf_line_to,
+ _cpf_curve_to,
+ _cpf_close_path,
+ &flattener);
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index d8a31b5..fe23259 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1347,6 +1347,15 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path,
cairo_path_fixed_close_path_func_t *close_path,
void *closure);
+cairo_private cairo_status_t
+_cairo_path_fixed_interpret_flat (cairo_path_fixed_t *path,
+ cairo_direction_t dir,
+ cairo_path_fixed_move_to_func_t *move_to,
+ cairo_path_fixed_line_to_func_t *line_to,
+ cairo_path_fixed_close_path_func_t *close_path,
+ void *closure,
+ double tolerance);
+
cairo_private void
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
double *x1, double *y1,
More information about the cairo-commit
mailing list