No subject
Tue Feb 3 09:21:25 PST 2009
device extents and each try different tricks to achieve this.
The attached patch adds cairo_(stroke|fill|path)_device_extents() which
act the same as the current api but do not transform the extents back
into userspace. The patch is large because it refactors the existing
implementation to share a common device_extents implementation.
Comments welcome,
-Jeff
--cNdxnHkX5QqsyA0e
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="extents.patch"
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 9ee31b0..98dfc4d 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -787,30 +787,6 @@ _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)
-{
- double px1, py1, px2, py2;
-
- _cairo_path_fixed_bounds (path,
- &px1, &py1, &px2, &py2);
-
- _cairo_gstate_backend_to_user_rectangle (gstate,
- &px1, &py1, &px2, &py2,
- NULL);
- if (x1)
- *x1 = px1;
- if (y1)
- *y1 = py1;
- if (x2)
- *x2 = px2;
- if (y2)
- *y2 = py2;
-}
-
static cairo_status_t
_cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
cairo_pattern_t **pattern,
@@ -1109,7 +1085,7 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate)
}
static void
-_cairo_gstate_traps_extents_to_user_rectangle (cairo_gstate_t *gstate,
+_cairo_gstate_traps_extents_to_device_rectangle (cairo_gstate_t *gstate,
cairo_traps_t *traps,
double *x1, double *y1,
double *x2, double *y2)
@@ -1118,40 +1094,18 @@ _cairo_gstate_traps_extents_to_user_rectangle (cairo_gstate_t *gstate,
if (traps->num_traps == 0) {
/* no traps, so we actually won't draw anything */
- if (x1)
- *x1 = 0.0;
- if (y1)
- *y1 = 0.0;
- if (x2)
- *x2 = 0.0;
- if (y2)
- *y2 = 0.0;
} else {
- double px1, py1, px2, py2;
-
_cairo_traps_extents (traps, &extents);
- px1 = _cairo_fixed_to_double (extents.p1.x);
- py1 = _cairo_fixed_to_double (extents.p1.y);
- px2 = _cairo_fixed_to_double (extents.p2.x);
- py2 = _cairo_fixed_to_double (extents.p2.y);
-
- _cairo_gstate_backend_to_user_rectangle (gstate,
- &px1, &py1, &px2, &py2,
- NULL);
- if (x1)
- *x1 = px1;
- if (y1)
- *y1 = py1;
- if (x2)
- *x2 = px2;
- if (y2)
- *y2 = py2;
+ *x1 = _cairo_fixed_to_double (extents.p1.x);
+ *y1 = _cairo_fixed_to_double (extents.p1.y);
+ *x2 = _cairo_fixed_to_double (extents.p2.x);
+ *y2 = _cairo_fixed_to_double (extents.p2.y);
}
}
cairo_status_t
-_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
+_cairo_gstate_stroke_device_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
@@ -1160,14 +1114,6 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
cairo_traps_t traps;
if (gstate->stroke_style.line_width <= 0.0) {
- if (x1)
- *x1 = 0.0;
- if (y1)
- *y1 = 0.0;
- if (x2)
- *x2 = 0.0;
- if (y2)
- *y2 = 0.0;
return CAIRO_STATUS_SUCCESS;
}
@@ -1180,7 +1126,7 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
gstate->tolerance,
&traps);
if (status == CAIRO_STATUS_SUCCESS) {
- _cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
+ _cairo_gstate_traps_extents_to_device_rectangle (gstate, &traps,
x1, y1, x2, y2);
}
@@ -1190,7 +1136,7 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
}
cairo_status_t
-_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
+_cairo_gstate_fill_device_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
@@ -1205,7 +1151,7 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
gstate->tolerance,
&traps);
if (status == CAIRO_STATUS_SUCCESS) {
- _cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
+ _cairo_gstate_traps_extents_to_device_rectangle (gstate, &traps,
x1, y1, x2, y2);
}
@@ -1214,6 +1160,7 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
return status;
}
+
cairo_status_t
_cairo_gstate_reset_clip (cairo_gstate_t *gstate)
{
@@ -1246,37 +1193,23 @@ _cairo_gstate_int_clip_extents (cairo_gstate_t *gstate,
}
cairo_status_t
-_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
- double *x1,
- double *y1,
- double *x2,
- double *y2)
+_cairo_gstate_clip_device_extents (cairo_gstate_t *gstate,
+ double *x1,
+ double *y1,
+ double *x2,
+ double *y2)
{
cairo_rectangle_int_t extents;
- double px1, py1, px2, py2;
cairo_status_t status;
status = _cairo_gstate_int_clip_extents (gstate, &extents);
if (unlikely (status))
return status;
- px1 = extents.x;
- py1 = extents.y;
- px2 = extents.x + (int) extents.width;
- py2 = extents.y + (int) extents.height;
-
- _cairo_gstate_backend_to_user_rectangle (gstate,
- &px1, &py1, &px2, &py2,
- NULL);
-
- if (x1)
- *x1 = px1;
- if (y1)
- *y1 = py1;
- if (x2)
- *x2 = px2;
- if (y2)
- *y2 = py2;
+ *x1 = extents.x;
+ *y1 = extents.y;
+ *x2 = extents.x + (int) extents.width;
+ *y2 = extents.y + (int) extents.height;
return CAIRO_STATUS_SUCCESS;
}
diff --git a/src/cairo.c b/src/cairo.c
index 4cdf685..181c8e6 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1941,24 +1941,62 @@ void
cairo_path_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
- if (cr->status) {
- if (x1)
- *x1 = 0.0;
- if (y1)
- *y1 = 0.0;
- if (x2)
- *x2 = 0.0;
- if (y2)
- *y2 = 0.0;
+ double px1 = 0.0, py1 = 0.0, px2 = 0.0, py2 = 0.0;
+ if (!cr->status) {
+ _cairo_path_fixed_bounds (cr->path,
+ &px1, &py1, &px2, &py2);
+ _cairo_gstate_backend_to_user_rectangle (cr->gstate,
+ &px1, &py1, &px2, &py2,
+ NULL);
+ }
- return;
+ if (x1)
+ *x1 = px1;
+ if (y1)
+ *y1 = py1;
+ if (x2)
+ *x2 = px2;
+ if (y2)
+ *y2 = py2;
+}
+
+/**
+ * cairo_path_device_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 device-space coordinates covering the
+ * points on the current path. The computation is similar to
+ * cairo_path_extents() however the results are not transformed back into
+ * user space
+ *
+ * Since: 1.10
+ **/
+void
+cairo_path_device_extents (cairo_t *cr,
+ double *x1, double *y1, double *x2, double *y2)
+{
+ double px1 = 0.0, py1 = 0.0, px2 = 0.0, py2 = 0.0;
+
+ if (!cr->status) {
+ _cairo_path_fixed_bounds (cr->path,
+ &px1, &py1, &px2, &py2);
}
- _cairo_gstate_path_extents (cr->gstate,
- cr->path,
- x1, y1, x2, y2);
+ if (x1)
+ *x1 = px1;
+ if (y1)
+ *y1 = py1;
+ if (x2)
+ *x2 = px2;
+ if (y2)
+ *y2 = py2;
}
+
/**
* cairo_paint:
* @cr: a cairo context
@@ -2349,25 +2387,83 @@ cairo_stroke_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
cairo_status_t status;
-
- if (cr->status) {
- if (x1)
- *x1 = 0.0;
- if (y1)
- *y1 = 0.0;
- if (x2)
- *x2 = 0.0;
- if (y2)
- *y2 = 0.0;
-
- return;
+ double px1 = 0.0, py1 = 0.0, px2 = 0.0, py2 = 0.0;
+
+ if (!cr->status) {
+ status = _cairo_gstate_stroke_device_extents (cr->gstate,
+ cr->path,
+ &px1, &py1, &px2, &py2);
+ if (likely(!status)) {
+ _cairo_gstate_backend_to_user_rectangle (cr->gstate,
+ &px1, &py1, &px2, &py2,
+ NULL);
+ } else {
+ _cairo_set_error (cr, status);
+ }
}
+ if (x1)
+ *x1 = px1;
+ if (y1)
+ *y1 = py1;
+ if (x2)
+ *x2 = px2;
+ if (y2)
+ *y2 = py2;
+}
- status = _cairo_gstate_stroke_extents (cr->gstate,
- cr->path,
- x1, y1, x2, y2);
- if (unlikely (status))
- _cairo_set_error (cr, status);
+/**
+ * cairo_stroke_device_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 area that
+ * 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.
+ *
+ * Note that cairo_stroke_extents() must necessarily do more work to
+ * compute the precise inked areas in light of the stroke parameters,
+ * so cairo_path_extents() may be more desirable for sake of
+ * performance if non-inked path extents are desired.
+ *
+ * See cairo_stroke(), cairo_set_line_width(), cairo_set_line_join(),
+ * cairo_set_line_cap(), cairo_set_dash(), and
+ * cairo_stroke_preserve().
+ *
+ * Since: 1.10
+ **/
+void
+cairo_stroke_device_extents (cairo_t *cr,
+ double *x1, double *y1, double *x2, double *y2)
+{
+ cairo_status_t status;
+ double px1 = 0.0, py1 = 0.0, px2 = 0.0, py2 = 0.0;
+
+ if (!cr->status) {
+ status = _cairo_gstate_stroke_device_extents (cr->gstate,
+ cr->path,
+ &px1, &py1, &px2, &py2);
+ if (unlikely (status))
+ _cairo_set_error (cr, status);
+ }
+ if (x1)
+ *x1 = px1;
+ if (y1)
+ *y1 = py1;
+ if (x2)
+ *x2 = px2;
+ if (y2)
+ *y2 = py2;
}
/**
@@ -2400,25 +2496,80 @@ cairo_fill_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
cairo_status_t status;
+ double px1 = 0.0, py1 = 0.0, px2 = 0.0, py2 = 0.0;
+
+ if (!cr->status) {
+ status = _cairo_gstate_fill_device_extents (cr->gstate,
+ cr->path,
+ &px1, &py1, &px2, &py2);
+ if (likely(!status)) {
+ _cairo_gstate_backend_to_user_rectangle (cr->gstate,
+ &px1, &py1, &px2, &py2,
+ NULL);
+ } else {
+ _cairo_set_error (cr, status);
+ }
+ }
- if (cr->status) {
- if (x1)
- *x1 = 0.0;
- if (y1)
- *y1 = 0.0;
- if (x2)
- *x2 = 0.0;
- if (y2)
- *y2 = 0.0;
+ if (x1)
+ *x1 = px1;
+ if (y1)
+ *y1 = py1;
+ if (x2)
+ *x2 = px2;
+ if (y2)
+ *y2 = py2;
+}
- return;
+/**
+ * cairo_fill_device_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 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.
+ *
+ * Contrast with cairo_path_extents(), which is similar, but returns
+ * non-zero extents for some paths with no inked area, (such as a
+ * simple line segment).
+ *
+ * Note that cairo_fill_extents() must necessarily do more work to
+ * compute the precise inked areas in light of the fill rule, so
+ * cairo_path_extents() may be more desirable for sake of performance
+ * if the non-inked path extents are desired.
+ *
+ * See cairo_fill(), cairo_set_fill_rule() and cairo_fill_preserve().
+ *
+ * Since: 1.10
+ **/
+void
+cairo_fill_device_extents (cairo_t *cr,
+ double *x1, double *y1, double *x2, double *y2)
+{
+ cairo_status_t status;
+ double px1 = 0.0, py1 = 0.0, px2 = 0.0, py2 = 0.0;
+
+ if (!cr->status) {
+ status = _cairo_gstate_fill_device_extents (cr->gstate,
+ cr->path,
+ &px1, &py1, &px2, &py2);
+ if (unlikely (status))
+ _cairo_set_error (cr, status);
}
-
- status = _cairo_gstate_fill_extents (cr->gstate,
- cr->path,
- x1, y1, x2, y2);
- if (unlikely (status))
- _cairo_set_error (cr, status);
+ if (x1)
+ *x1 = px1;
+ if (y1)
+ *y1 = py1;
+ if (x2)
+ *x2 = px2;
+ if (y2)
+ *y2 = py2;
}
/**
@@ -2535,25 +2686,68 @@ cairo_clip_extents (cairo_t *cr,
double *x2, double *y2)
{
cairo_status_t status;
+ double px1 = 0.0, py1 = 0.0, px2 = 0.0, py2 = 0.0;
+
+ if (!cr->status) {
+ status = _cairo_gstate_clip_device_extents (cr->gstate, &px1, &py1, &px2, &py2);
+ if (likely(!status)) {
+ _cairo_gstate_backend_to_user_rectangle (cr->gstate,
+ &px1, &py1, &px2, &py2,
+ NULL);
+ } else {
+ _cairo_set_error (cr, status);
+ }
+ }
- if (cr->status) {
- if (x1)
- *x1 = 0.0;
- if (y1)
- *y1 = 0.0;
- if (x2)
- *x2 = 0.0;
- if (y2)
- *y2 = 0.0;
+ if (x1)
+ *x1 = px1;
+ if (y1)
+ *y1 = py1;
+ if (x2)
+ *x2 = px2;
+ if (y2)
+ *y2 = py2;
+}
- return;
+/**
+ * cairo_clip_device_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 area inside the
+ * current clip.
+ *
+ * Since: 1.10
+ **/
+void
+cairo_clip_device_extents (cairo_t *cr,
+ double *x1, double *y1,
+ double *x2, double *y2)
+{
+ cairo_status_t status;
+ double px1 = 0.0, py1 = 0.0, px2 = 0.0, py2 = 0.0;
+
+ if (!cr->status) {
+ status = _cairo_gstate_clip_device_extents (cr->gstate, &px1, &py1, &px2, &py2);
+ if (unlikely(status)) {
+ _cairo_set_error (cr, status);
+ }
}
- status = _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2);
- if (unlikely (status))
- _cairo_set_error (cr, status);
+ if (x1)
+ *x1 = px1;
+ if (y1)
+ *y1 = py1;
+ if (x2)
+ *x2 = px2;
+ if (y2)
+ *y2 = py2;
}
+
static cairo_rectangle_list_t *
_cairo_rectangle_list_create_in_error (cairo_status_t status)
{
diff --git a/src/cairo.h b/src/cairo.h
index 856f7af..a6077c1 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -686,6 +686,12 @@ cairo_path_extents (cairo_t *cr,
double *x1, double *y1,
double *x2, double *y2);
+cairo_public void
+cairo_path_device_extents (cairo_t *cr,
+ double *x1, double *y1,
+ double *x2, double *y2);
+
+
/* Painting functions */
cairo_public void
cairo_paint (cairo_t *cr);
@@ -740,6 +746,16 @@ cairo_fill_extents (cairo_t *cr,
double *x1, double *y1,
double *x2, double *y2);
+cairo_public void
+cairo_stroke_device_extents (cairo_t *cr,
+ double *x1, double *y1,
+ double *x2, double *y2);
+
+cairo_public void
+cairo_fill_device_extents (cairo_t *cr,
+ double *x1, double *y1,
+ double *x2, double *y2);
+
/* Clipping */
cairo_public void
cairo_reset_clip (cairo_t *cr);
@@ -755,6 +771,12 @@ cairo_clip_extents (cairo_t *cr,
double *x1, double *y1,
double *x2, double *y2);
+cairo_public void
+cairo_clip_device_extents (cairo_t *cr,
+ double *x1, double *y1,
+ double *x2, double *y2);
+
+
/**
* cairo_rectangle_t:
* @x: X coordinate of the left side of the rectangle
diff --git a/src/cairoint.h b/src/cairoint.h
index 8115c81..5eed1cf 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1160,12 +1160,6 @@ _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);
@@ -1186,16 +1180,16 @@ cairo_private cairo_status_t
_cairo_gstate_show_page (cairo_gstate_t *gstate);
cairo_private cairo_status_t
-_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
- cairo_path_fixed_t *path,
- double *x1, double *y1,
- double *x2, double *y2);
+_cairo_gstate_stroke_device_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_fill_extents (cairo_gstate_t *gstate,
- cairo_path_fixed_t *path,
- double *x1, double *y1,
- double *x2, double *y2);
+_cairo_gstate_fill_device_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_in_stroke (cairo_gstate_t *gstate,
@@ -1218,11 +1212,11 @@ cairo_private cairo_status_t
_cairo_gstate_reset_clip (cairo_gstate_t *gstate);
cairo_private cairo_status_t
-_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
- double *x1,
- double *y1,
- double *x2,
- double *y2);
+_cairo_gstate_clip_device_extents (cairo_gstate_t *gstate,
+ double *x1,
+ double *y1,
+ double *x2,
+ double *y2);
cairo_private cairo_rectangle_list_t*
_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate);
--cNdxnHkX5QqsyA0e--
More information about the cairo
mailing list