[cairo-commit] 6 commits - pixman/src src/cairo-pattern.c
src/cairo-pdf-surface.c src/cairo-svg-surface.c
test/.gitignore test/Makefile.am test/radial-gradient.c
test/radial-gradient-ref.png
Carl Worth
cworth at kemper.freedesktop.org
Thu Mar 1 17:09:37 PST 2007
pixman/src/fbcompose.c | 213 ++++++++++++++++++++++++++++++++-----------
pixman/src/icimage.c | 22 +---
pixman/src/icimage.h | 13 +-
pixman/src/icint.h | 1
pixman/src/pixman.h | 4
src/cairo-pattern.c | 36 +++----
src/cairo-pdf-surface.c | 12 +-
src/cairo-svg-surface.c | 43 ++++++--
test/.gitignore | 1
test/Makefile.am | 1
test/radial-gradient-ref.png |binary
test/radial-gradient.c | 110 ++++++++++++++++++++++
12 files changed, 346 insertions(+), 110 deletions(-)
New commits:
diff-tree df2d42ac7fb71997abd406fb5716c0bd85037c04 (from parents)
Merge: ec11ca33a7ebcc752218e63c57f861de6e23a86a 97dbbae62182c2e40f5f98278e08c92e14b92731
Author: Carl Worth <cworth at cworth.org>
Date: Thu Mar 1 17:08:03 2007 -0800
Merge branch 'radial-gradient-fixes' into cairo
diff-tree 97dbbae62182c2e40f5f98278e08c92e14b92731 (from fe68e8aa32cc5a9f4d9f9302644ca66d8b691d65)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Mar 1 15:17:19 2007 -0800
SVG: Support CAIRO_EXTEND_NONE for radial gradients.
This is as simple as adding transparent color stops on either end.
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index fefe2d4..b9c9f60 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1280,11 +1280,14 @@ emit_radial_pattern (cairo_svg_surface_t
/* SVG doesn't have a start radius, so computing now SVG focal coordinates
* and emulating start radius by translating color stops.
- * FIXME: We also need to emulate cairo behaviour inside start circle when
- * extend != CAIRO_EXTEND_NONE.
* FIXME: Handle radius1 <= radius0 */
- fx = (r1 * x0 - r0 * x1) / (r1 - r0);
- fy = (r1 * y0 - r0 * y1) / (r1 - r0);
+ if (pattern->base.base.extend == CAIRO_EXTEND_NONE) {
+ fx = x0;
+ fy = y0;
+ } else {
+ fx = (r1 * x0 - r0 * x1) / (r1 - r0);
+ fy = (r1 * y0 - r0 * y1) / (r1 - r0);
+ }
_cairo_output_stream_printf (document->xml_node_defs,
"<radialGradient id=\"radial%d\" "
@@ -1300,7 +1303,27 @@ emit_radial_pattern (cairo_svg_surface_t
cairo_matrix_invert (&p2u);
emit_transform (document->xml_node_defs, "gradientTransform", ">\n", &p2u);
+ /* To support cairo's EXTEND_NONE, (for which SVG has no similar
+ * notion), we add transparent color stops on either end of the
+ * user-provided stops. */
+ if (pattern->base.base.extend == CAIRO_EXTEND_NONE) {
+ _cairo_output_stream_printf (document->xml_node_defs,
+ "<stop offset=\"0\" style=\""
+ "stop-color: rgb(0%%,0%%,0%%); "
+ "stop-opacity: 0;\"/>\n");
+ if (r0 != 0.0)
+ _cairo_output_stream_printf (document->xml_node_defs,
+ "<stop offset=\"%f\" style=\""
+ "stop-color: rgb(0%%,0%%,0%%); "
+ "stop-opacity: 0;\"/>\n",
+ r0 / r1);
+ }
emit_pattern_stops (document->xml_node_defs, &pattern->base, r0 / r1);
+ if (pattern->base.base.extend == CAIRO_EXTEND_NONE)
+ _cairo_output_stream_printf (document->xml_node_defs,
+ "<stop offset=\"1.0\" style=\""
+ "stop-color: rgb(0%%,0%%,0%%); "
+ "stop-opacity: 0;\"/>\n");
_cairo_output_stream_printf (document->xml_node_defs,
"</radialGradient>\n");
diff-tree fe68e8aa32cc5a9f4d9f9302644ca66d8b691d65 (from 9a5dfe1415dce9d726c93cd08c532f26512a70ee)
Author: Carl Worth <cworth at cworth.org>
Date: Wed Feb 28 00:41:47 2007 -0800
Fix gradient walker to not reset needlessly
Previously the gradient walker was doing excessive resets, (such
as on every pixel in constant-colored regions or outside the
gradient with CAIRO_EXTEND_NONE). Don't do that.
diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c
index 8d45ea2..233b90c 100644
--- a/pixman/src/fbcompose.c
+++ b/pixman/src/fbcompose.c
@@ -2740,12 +2740,13 @@ typedef struct
CARD32 right_rb;
int32_t left_x;
int32_t right_x;
- int32_t width_x;
int32_t stepper;
pixman_gradient_stop_t *stops;
int num_stops;
unsigned int spread;
+
+ int need_reset;
} GradientWalker;
static void
@@ -2757,13 +2758,14 @@ _gradient_walker_init (GradientWalker *
walker->stops = pGradient->gradient.stops;
walker->left_x = 0;
walker->right_x = 0x10000;
- walker->width_x = 0; /* will force a reset */
walker->stepper = 0;
walker->left_ag = 0;
walker->left_rb = 0;
walker->right_ag = 0;
walker->right_rb = 0;
walker->spread = spread;
+
+ walker->need_reset = TRUE;
}
static void
@@ -2895,27 +2897,28 @@ _gradient_walker_reset (GradientWalker
walker->left_x = left_x;
walker->right_x = right_x;
- walker->width_x = right_x - left_x;
walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8);
walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8);
walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8);
walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8);
- if ( walker->width_x == 0 ||
+ if ( walker->left_x == walker->right_x ||
( walker->left_ag == walker->right_ag &&
walker->left_rb == walker->right_rb ) )
{
- walker->width_x = 1;
walker->stepper = 0;
}
else
{
- walker->stepper = ((1 << 24) + walker->width_x/2)/walker->width_x;
+ int32_t width = right_x - left_x;
+ walker->stepper = ((1 << 24) + width/2)/width;
}
+
+ walker->need_reset = FALSE;
}
#define GRADIENT_WALKER_NEED_RESET(w,x) \
- ( (x) < (w)->left_x || (x) - (w)->left_x >= (w)->width_x )
+ ( (w)->need_reset || (x) < (w)->left_x || (x) >= (w)->right_x)
/* the following assumes that GRADIENT_WALKER_NEED_RESET(w,x) is FALSE */
static CARD32
diff-tree 9a5dfe1415dce9d726c93cd08c532f26512a70ee (from 0439f4c4f7e7374b4f9699f664fc0e157628b190)
Author: Carl Worth <cworth at cworth.org>
Date: Thu Mar 1 14:53:48 2007 -0800
Fix implementation of radial gradients for inner radius != 0
The previous implementation fell apart quite badly when neither radius
value was equal to 0.0. I derived the math from scratch, (much thanks to
Vincent Torri <vtorri at univ-evry.fr> for guiding me to a simpler derivation
than I was doing originally), and it's working much better now without
being any slower, (in fact, cairo-perf shows speedup of 1.05x to 1.58x on
my laptop here).
This work also provides groundwork for defining the behavior of radial
gradients where neither circle is wholly contained within the other, (though
we haven't done that definition yet---it will require a new test case and a
very little bit of work on the implementation).
This is a fix for the following bug report:
Radial Gradients with nonzero inner radius misplace stops
https://bugs.freedesktop.org/show_bug.cgi?id=7685
diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c
index 7d7ac00..8d45ea2 100644
--- a/pixman/src/fbcompose.c
+++ b/pixman/src/fbcompose.c
@@ -37,6 +37,7 @@
#define _USE_MATH_DEFINES
#endif
+#include <assert.h>
#include <math.h>
#ifndef M_PI
@@ -2949,8 +2950,6 @@ _gradient_walker_pixel (GradientWalker
return (color | (t1 & 0xff00ff) | (t2 & 0xff00));
}
-
-
static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *buffer, CARD32 *mask, CARD32 maskBits)
{
SourcePictPtr pGradient = pict->pSourcePict;
@@ -3082,13 +3081,128 @@ static void fbFetchSourcePict(PicturePtr
}
}
} else {
+
+/*
+ * In the radial gradient problem we are given two circles (câ,râ) and
+ * (câ,râ) that define the gradient itself. Then, for any point p, we
+ * must compute the value(s) of t within [0.0, 1.0] representing the
+ * circle(s) that would color the point.
+ *
+ * There are potentially two values of t since the point p can be
+ * colored by both sides of the circle, (which happens whenever one
+ * circle is not entirely contained within the other).
+ *
+ * If we solve for a value of t that is outside of [0.0, 1.0] then we
+ * use the extend mode (NONE, REPEAT, REFLECT, or PAD) to map to a
+ * value within [0.0, 1.0].
+ *
+ * Here is an illustration of the problem:
+ *
+ * pâ
+ * p â¢
+ * ⢠â²
+ * · â²râ
+ * pâ · â²
+ * ⢠θâ²
+ * â² âââ¢
+ * â²râ · câ
+ * θⲠ·
+ * âââ¢
+ * câ
+ *
+ * Given (câ,râ), (câ,râ) and p, we must find an angle θ such that two
+ * points pâ and pâ on the two circles are collinear with p. Then, the
+ * desired value of t is the ratio of the length of pâp to the length
+ * of pâpâ.
+ *
+ * So, we have six unknown values: (pâx, pây), (pâx, pây), θ and t.
+ * We can also write six equations that constrain the problem:
+ *
+ * Point pâ is a distance râ from câ at an angle of θ:
+ *
+ * 1. pâx = câx + râ·cos θ
+ * 2. pây = cây + râ·sin θ
+ *
+ * Point pâ is a distance râ from câ at an angle of θ:
+ *
+ * 3. pâx = câx + r2·cos θ
+ * 4. pây = cây + r2·sin θ
+ *
+ * Point p lies at a fraction t along the line segment pâpâ:
+ *
+ * 5. px = t·pâx + (1-t)·pâx
+ * 6. py = t·pây + (1-t)·pây
+ *
+ * To solve, first subtitute 1-4 into 5 and 6:
+ *
+ * px = t·(câx + râ·cos θ) + (1-t)·(câx + râ·cos θ)
+ * py = t·(cây + râ·sin θ) + (1-t)·(cây + râ·sin θ)
+ *
+ * Then solve each for cos θ and sin θ expressed as a function of t:
+ *
+ * cos θ = (-(câx - câx)·t + (px - câx)) / ((râ-râ)·t + râ)
+ * sin θ = (-(cây - cây)·t + (py - cây)) / ((râ-râ)·t + râ)
+ *
+ * To simplify this a bit, we define new variables for several of the
+ * common terms as shown below:
+ *
+ * pâ
+ * p â¢
+ * ⢠â²
+ * · â â²râ
+ * pâ · â â²
+ * ⢠pdyâ â²
+ * â² â â¢câ
+ * â²râ â · â
+ * Ⲡ·â âcdy
+ * â¢âââââ´ââââââââ
+ * câ pdx cdx
+ *
+ * cdx = (câx - câx)
+ * cdy = (cây - cây)
+ * dr = râ-râ
+ * pdx = px - câx
+ * pdy = py - cây
+ *
+ * Note that cdx, cdy, and dr do not depend on point p at all, so can
+ * be pre-computed for the entire gradient. The simplifed equations
+ * are now:
+ *
+ * cos θ = (-cdx·t + pdx) / (dr·t + râ)
+ * sin θ = (-cdy·t + pdy) / (dr·t + râ)
+ *
+ * Finally, to get a single function of t and eliminate the last
+ * unknown θ, we use the identity sin²θ + cos²θ = 1. First, square
+ * each equation, (we knew a quadratic was coming since it must be
+ * possible to obtain two solutions in some cases):
+ *
+ * cos²θ = (cdx²t² - 2·cdx·pdx·t + pdx²) / (dr²·t² + 2·râ·dr·t + râ²)
+ * sin²θ = (cdy²t² - 2·cdy·pdy·t + pdy²) / (dr²·t² + 2·râ·dr·t + râ²)
+ *
+ * Then add both together, set the result equal to 1, and express as a
+ * standard quadratic equation in t of the form At² + Bt + C = 0
+ *
+ * (cdx² + cdy² - dr²)·t² - 2·(cdx·pdx + cdy·pdy + râ·dr)·t + (pdx² + pdy² - râ²) = 0
+ *
+ * In other words:
+ *
+ * A = cdx² + cdy² - dr²
+ * B = -2·(pdx·cdx + pdy·cdy + râ·dr)
+ * C = pdx² + pdy² - râ²
+ *
+ * And again, notice that A does not depend on p, so can be
+ * precomputed. From here we just use the quadratic formula to solve
+ * for t:
+ *
+ * t = (-2·B ± â·(B² - 4·A·C)) / 2·A
+ */
/* radial or conical */
Bool projective = FALSE;
double cx = 1.;
double cy = 0.;
double cz = 0.;
- double rx = x;
- double ry = y;
+ double rx = x + 0.5;
+ double ry = y + 0.5;
double rz = 1.;
if (pict->transform) {
@@ -3110,23 +3224,36 @@ static void fbFetchSourcePict(PicturePtr
}
if (pGradient->type == SourcePictTypeRadial) {
+ pixman_radial_gradient_image_t *radial;
+ radial = &pGradient->radial;
if (!projective) {
- rx -= pGradient->radial.fx;
- ry -= pGradient->radial.fy;
-
while (buffer < end) {
- double b, c, det, s;
-
if (!mask || *mask++ & maskBits)
{
- xFixed_48_16 t;
-
- b = 2*(rx*pGradient->radial.dx + ry*pGradient->radial.dy);
- c = -(rx*rx + ry*ry);
- det = (b * b) - (4 * pGradient->radial.a * c);
- s = (-b + sqrt(det))/(2. * pGradient->radial.a);
-
- t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536);
+ double pdx, pdy;
+ double B, C;
+ double det;
+ double c1x = xFixedToDouble (radial->c1.x);
+ double c1y = xFixedToDouble (radial->c1.y);
+ double r1 = xFixedToDouble (radial->c1.radius);
+ xFixed_48_16 t;
+
+ pdx = rx - c1x;
+ pdy = ry - c1y;
+
+ B = -2 * ( pdx * radial->cdx
+ + pdy * radial->cdy
+ + r1 * radial->dr);
+ C = (pdx * pdx + pdy * pdy - r1 * r1);
+
+ det = (B * B) - (4 * radial->A * C);
+ if (det < 0.0)
+ det = 0.0;
+
+ if (radial->A < 0)
+ t = (xFixed_48_16) ((- B - sqrt(det)) / (2.0 * radial->A) * 65536);
+ else
+ t = (xFixed_48_16) ((- B + sqrt(det)) / (2.0 * radial->A) * 65536);
*buffer = _gradient_walker_pixel (&walker, t);
}
@@ -3135,35 +3262,12 @@ static void fbFetchSourcePict(PicturePtr
ry += cy;
}
} else {
- while (buffer < end) {
- double x, y;
- double b, c, det, s;
-
- if (!mask || *mask++ & maskBits)
- {
- xFixed_48_16 t;
-
- if (rz != 0) {
- x = rx/rz;
- y = ry/rz;
- } else {
- x = y = 0.;
- }
- x -= pGradient->radial.fx;
- y -= pGradient->radial.fy;
- b = 2*(x*pGradient->radial.dx + y*pGradient->radial.dy);
- c = -(x*x + y*y);
- det = (b * b) - (4 * pGradient->radial.a * c);
- s = (-b + sqrt(det))/(2. * pGradient->radial.a);
- t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536);
-
- *buffer = _gradient_walker_pixel (&walker, t);
- }
- ++buffer;
- rx += cx;
- ry += cy;
- rz += cz;
- }
+ /* In cairo, we don't have projective transformed
+ * radial gradients---so I'm not going to bother
+ * implementing something untested and broken
+ * here. Instead, someone trying to get this code into
+ * shape for use in the X server can fix this here. */
+ assert (0);
}
} else /* SourcePictTypeConical */ {
double a = pGradient->conical.angle/(180.*65536);
diff --git a/pixman/src/icimage.c b/pixman/src/icimage.c
index e97b4c8..4d957a0 100644
--- a/pixman/src/icimage.c
+++ b/pixman/src/icimage.c
@@ -247,7 +247,6 @@ pixman_image_create_radial_gradient (con
{
pixman_radial_gradient_image_t *radial;
pixman_image_t *image;
- double x;
if (n_stops < 2)
return NULL;
@@ -270,19 +269,14 @@ pixman_image_create_radial_gradient (con
memcpy (radial->stops, stops, sizeof (pixman_gradient_stop_t) * n_stops);
radial->type = SourcePictTypeRadial;
- x = (double) gradient->c1.radius / (double) gradient->c2.radius;
- radial->dx = (gradient->c2.x - gradient->c1.x);
- radial->dy = (gradient->c2.y - gradient->c1.y);
- radial->fx = (gradient->c1.x) - x * radial->dx;
- radial->fy = (gradient->c1.y) - x * radial->dy;
- radial->m = 1. / (1 + x);
- radial->b = -x * radial->m;
- radial->dx /= 65536.;
- radial->dy /= 65536.;
- radial->fx /= 65536.;
- radial->fy /= 65536.;
- x = gradient->c2.radius / 65536.;
- radial->a = x * x - radial->dx * radial->dx - radial->dy * radial->dy;
+ radial->c1 = gradient->c1;
+ radial->c2 = gradient->c2;
+ radial->cdx = xFixedToDouble (gradient->c2.x - gradient->c1.x);
+ radial->cdy = xFixedToDouble (gradient->c2.y - gradient->c1.y);
+ radial->dr = xFixedToDouble (gradient->c2.radius - gradient->c1.radius);
+ radial->A = ( radial->cdx * radial->cdx
+ + radial->cdy * radial->cdy
+ - radial->dr * radial->dr);
image->pSourcePict = (pixman_source_image_t *) radial;
diff --git a/pixman/src/icimage.h b/pixman/src/icimage.h
index 82202a7..bbf41b9 100644
--- a/pixman/src/icimage.h
+++ b/pixman/src/icimage.h
@@ -101,13 +101,12 @@ typedef struct _pixman_radial_gradient_i
int stopRange;
uint32_t *colorTable;
int colorTableSize;
- double fx;
- double fy;
- double dx;
- double dy;
- double a;
- double m;
- double b;
+ pixman_circle_t c1;
+ pixman_circle_t c2;
+ double cdx;
+ double cdy;
+ double dr;
+ double A;
} pixman_radial_gradient_image_t;
typedef struct _pixman_conical_gradient_image {
diff --git a/pixman/src/icint.h b/pixman/src/icint.h
index 93795b0..47a2220 100644
--- a/pixman/src/icint.h
+++ b/pixman/src/icint.h
@@ -1026,6 +1026,7 @@ typedef xFixed_16_16 xFixed;
#define IntToxFixed(i) ((xFixed) (i) << XFIXED_BITS)
#define xFixedE ((xFixed) 1)
#define xFixed1 (IntToxFixed(1))
+#define xFixedToDouble(f) (double) ((f) / (double) xFixed1)
#define xFixed1MinusE (xFixed1 - xFixedE)
#define xFixedFrac(f) ((f) & xFixed1MinusE)
#define xFixedFloor(f) ((f) & ~xFixed1MinusE)
diff-tree 0439f4c4f7e7374b4f9699f664fc0e157628b190 (from d65455ed3800f9ec3115bbed96a5b2328ee60b57)
Author: Carl Worth <cworth at cworth.org>
Date: Sun Feb 25 16:01:10 2007 +0100
Rename radial gradient inner/outer to c1/c2
The inner/outer names were totally bogus. It is quite
legitimate to have the first circle's radius be larger than
that of the second.
diff --git a/pixman/src/icimage.c b/pixman/src/icimage.c
index 44c4c8b..e97b4c8 100644
--- a/pixman/src/icimage.c
+++ b/pixman/src/icimage.c
@@ -270,18 +270,18 @@ pixman_image_create_radial_gradient (con
memcpy (radial->stops, stops, sizeof (pixman_gradient_stop_t) * n_stops);
radial->type = SourcePictTypeRadial;
- x = (double) gradient->inner.radius / (double) gradient->outer.radius;
- radial->dx = (gradient->outer.x - gradient->inner.x);
- radial->dy = (gradient->outer.y - gradient->inner.y);
- radial->fx = (gradient->inner.x) - x * radial->dx;
- radial->fy = (gradient->inner.y) - x * radial->dy;
+ x = (double) gradient->c1.radius / (double) gradient->c2.radius;
+ radial->dx = (gradient->c2.x - gradient->c1.x);
+ radial->dy = (gradient->c2.y - gradient->c1.y);
+ radial->fx = (gradient->c1.x) - x * radial->dx;
+ radial->fy = (gradient->c1.y) - x * radial->dy;
radial->m = 1. / (1 + x);
radial->b = -x * radial->m;
radial->dx /= 65536.;
radial->dy /= 65536.;
radial->fx /= 65536.;
radial->fy /= 65536.;
- x = gradient->outer.radius / 65536.;
+ x = gradient->c2.radius / 65536.;
radial->a = x * x - radial->dx * radial->dx - radial->dy * radial->dy;
image->pSourcePict = (pixman_source_image_t *) radial;
diff --git a/pixman/src/pixman.h b/pixman/src/pixman.h
index 309e5e6..7f0ef32 100644
--- a/pixman/src/pixman.h
+++ b/pixman/src/pixman.h
@@ -364,8 +364,8 @@ typedef struct pixman_linear_gradient {
} pixman_linear_gradient_t;
typedef struct pixman_radial_gradient {
- pixman_circle_t inner;
- pixman_circle_t outer;
+ pixman_circle_t c1;
+ pixman_circle_t c2;
} pixman_radial_gradient_t;
typedef enum {
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index ae271f8..f613f0e 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -238,12 +238,12 @@ _cairo_pattern_init_radial (cairo_radial
{
_cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL);
- pattern->gradient.inner.x = _cairo_fixed_from_double (cx0);
- pattern->gradient.inner.y = _cairo_fixed_from_double (cy0);
- pattern->gradient.inner.radius = _cairo_fixed_from_double (fabs (radius0));
- pattern->gradient.outer.x = _cairo_fixed_from_double (cx1);
- pattern->gradient.outer.y = _cairo_fixed_from_double (cy1);
- pattern->gradient.outer.radius = _cairo_fixed_from_double (fabs (radius1));
+ pattern->gradient.c1.x = _cairo_fixed_from_double (cx0);
+ pattern->gradient.c1.y = _cairo_fixed_from_double (cy0);
+ pattern->gradient.c1.radius = _cairo_fixed_from_double (fabs (radius0));
+ pattern->gradient.c2.x = _cairo_fixed_from_double (cx1);
+ pattern->gradient.c2.y = _cairo_fixed_from_double (cy1);
+ pattern->gradient.c2.radius = _cairo_fixed_from_double (fabs (radius1));
}
cairo_pattern_t *
@@ -1771,12 +1771,12 @@ cairo_pattern_get_linear_points (cairo_p
/**
* cairo_pattern_get_radial_circles
* @pattern: a #cairo_pattern_t
- * @x0: return value for the x coordinate of the center of the first (inner) circle, or %NULL
- * @y0: return value for the y coordinate of the center of the first (inner) circle, or %NULL
- * @r0: return value for the radius of the first (inner) circle, or %NULL
- * @x1: return value for the x coordinate of the center of the second (outer) circle, or %NULL
- * @y1: return value for the y coordinate of the center of the second (outer) circle, or %NULL
- * @r1: return value for the radius of the second (outer) circle, or %NULL
+ * @x0: return value for the x coordinate of the center of the first circle, or %NULL
+ * @y0: return value for the y coordinate of the center of the first circle, or %NULL
+ * @r0: return value for the radius of the first circle, or %NULL
+ * @x1: return value for the x coordinate of the center of the second circle, or %NULL
+ * @y1: return value for the y coordinate of the center of the second circle, or %NULL
+ * @r1: return value for the radius of the second circle, or %NULL
*
* Gets the gradient endpoint circles for a radial gradient, each
* specified as a center coordinate and a radius.
@@ -1798,17 +1798,17 @@ cairo_pattern_get_radial_circles (cairo_
return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
if (x0)
- *x0 = _cairo_fixed_to_double (radial->gradient.inner.x);
+ *x0 = _cairo_fixed_to_double (radial->gradient.c1.x);
if (y0)
- *y0 = _cairo_fixed_to_double (radial->gradient.inner.y);
+ *y0 = _cairo_fixed_to_double (radial->gradient.c1.y);
if (r0)
- *r0 = _cairo_fixed_to_double (radial->gradient.inner.radius);
+ *r0 = _cairo_fixed_to_double (radial->gradient.c1.radius);
if (x1)
- *x1 = _cairo_fixed_to_double (radial->gradient.outer.x);
+ *x1 = _cairo_fixed_to_double (radial->gradient.c2.x);
if (y1)
- *y1 = _cairo_fixed_to_double (radial->gradient.outer.y);
+ *y1 = _cairo_fixed_to_double (radial->gradient.c2.y);
if (r1)
- *r1 = _cairo_fixed_to_double (radial->gradient.outer.radius);
+ *r1 = _cairo_fixed_to_double (radial->gradient.c2.radius);
return CAIRO_STATUS_SUCCESS;
}
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index fa6c830..104c339 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1257,13 +1257,13 @@ emit_radial_pattern (cairo_pdf_surface_t
p2u = pattern->base.base.matrix;
cairo_matrix_invert (&p2u);
- x0 = _cairo_fixed_to_double (pattern->gradient.inner.x);
- y0 = _cairo_fixed_to_double (pattern->gradient.inner.y);
- r0 = _cairo_fixed_to_double (pattern->gradient.inner.radius);
+ x0 = _cairo_fixed_to_double (pattern->gradient.c1.x);
+ y0 = _cairo_fixed_to_double (pattern->gradient.c1.y);
+ r0 = _cairo_fixed_to_double (pattern->gradient.c1.radius);
cairo_matrix_transform_point (&p2u, &x0, &y0);
- x1 = _cairo_fixed_to_double (pattern->gradient.outer.x);
- y1 = _cairo_fixed_to_double (pattern->gradient.outer.y);
- r1 = _cairo_fixed_to_double (pattern->gradient.outer.radius);
+ x1 = _cairo_fixed_to_double (pattern->gradient.c2.x);
+ y1 = _cairo_fixed_to_double (pattern->gradient.c2.y);
+ r1 = _cairo_fixed_to_double (pattern->gradient.c2.radius);
cairo_matrix_transform_point (&p2u, &x1, &y1);
/* FIXME: This is surely crack, but how should you scale a radius
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 1788a99..fefe2d4 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1271,12 +1271,12 @@ emit_radial_pattern (cairo_svg_surface_t
double x0, y0, x1, y1, r0, r1;
double fx, fy;
- x0 = _cairo_fixed_to_double (pattern->gradient.inner.x);
- y0 = _cairo_fixed_to_double (pattern->gradient.inner.y);
- r0 = _cairo_fixed_to_double (pattern->gradient.inner.radius);
- x1 = _cairo_fixed_to_double (pattern->gradient.outer.x);
- y1 = _cairo_fixed_to_double (pattern->gradient.outer.y);
- r1 = _cairo_fixed_to_double (pattern->gradient.outer.radius);
+ x0 = _cairo_fixed_to_double (pattern->gradient.c1.x);
+ y0 = _cairo_fixed_to_double (pattern->gradient.c1.y);
+ r0 = _cairo_fixed_to_double (pattern->gradient.c1.radius);
+ x1 = _cairo_fixed_to_double (pattern->gradient.c2.x);
+ y1 = _cairo_fixed_to_double (pattern->gradient.c2.y);
+ r1 = _cairo_fixed_to_double (pattern->gradient.c2.radius);
/* SVG doesn't have a start radius, so computing now SVG focal coordinates
* and emulating start radius by translating color stops.
diff-tree d65455ed3800f9ec3115bbed96a5b2328ee60b57 (from 1bc1f8ef46a27aa21f8d29b39e645ee5a0e95cda)
Author: Carl Worth <cworth at cworth.org>
Date: Fri Feb 23 07:12:03 2007 +0100
Add radial-gradient test case
Embarrassingly enough, the test suite previously never called
into cairo_pattern_create_radial at all. Unsurprisingly, this
has led to bugs creeping into the radial gradient implementation.
diff --git a/test/.gitignore b/test/.gitignore
index 3bac973..0b5ae98 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -96,6 +96,7 @@ png-flatten
ps-features
ps-features.ps
push-group
+radial-gradient
random-intersections
svg2png
svg-clip
diff --git a/test/Makefile.am b/test/Makefile.am
index 3382cf4..9462e30 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -71,6 +71,7 @@ paint-with-alpha \
pattern-get-type \
pattern-getters \
pixman-rotate \
+radial-gradient \
random-intersections \
rectangle-rounding-error \
rectilinear-stroke \
diff --git a/test/radial-gradient-ref.png b/test/radial-gradient-ref.png
new file mode 100644
index 0000000..ab10858
Binary files /dev/null and b/test/radial-gradient-ref.png differ
diff --git a/test/radial-gradient.c b/test/radial-gradient.c
new file mode 100644
index 0000000..1207943
--- /dev/null
+++ b/test/radial-gradient.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2005, 2007 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth at cworth.org>
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_draw_function_t draw;
+
+#define NUM_GRADIENTS 4
+#define NUM_EXTEND 4
+#define SIZE 60
+#define WIDTH (SIZE * NUM_GRADIENTS)
+#define HEIGHT (SIZE * NUM_EXTEND)
+
+cairo_test_t test = {
+ "radial-gradient",
+ "Simple test of radial gradients",
+ WIDTH, HEIGHT,
+ draw
+};
+
+static void
+draw_gradient (cairo_t *cr,
+ int x,
+ int y,
+ int size,
+ double offset,
+ double inner_radius,
+ cairo_extend_t extend)
+{
+ cairo_pattern_t *pattern;
+
+ cairo_save (cr);
+
+ pattern = cairo_pattern_create_radial (x + size/2.0 + offset,
+ y + size/2.0 + offset, inner_radius,
+ x + size/2.0,
+ y + size/2.0, size/3.0);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0,
+ 1.0, 0.0, 0.0, 1.0);
+ cairo_pattern_add_color_stop_rgba (pattern, sqrt (1.0 / 2.0),
+ 0.0, 1.0, 0.0, 0.0);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0,
+ 0.0, 0.0, 1.0, 0.5);
+ cairo_pattern_set_extend (pattern, extend);
+
+ cairo_rectangle (cr, x, y, size, size);
+ cairo_clip (cr);
+
+ cairo_set_source (cr, pattern);
+ cairo_paint (cr);
+
+ cairo_pattern_destroy (pattern);
+
+ cairo_restore (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ int i, j;
+ double inner_radius, offset;
+ cairo_extend_t extend[NUM_EXTEND] = {
+ CAIRO_EXTEND_NONE,
+ CAIRO_EXTEND_REPEAT,
+ CAIRO_EXTEND_REFLECT,
+ CAIRO_EXTEND_PAD
+ };
+
+ cairo_test_paint_checkered (cr);
+
+ for (j = 0; j < NUM_EXTEND; j++) {
+ for (i = 0; i < NUM_GRADIENTS; i++) {
+ offset = i % 2 ? SIZE / 12.0 : 0.0;
+ inner_radius = i >= NUM_EXTEND / 2 ? SIZE / 6.0 : 0.0;
+ draw_gradient (cr, i * SIZE, j * SIZE, SIZE,
+ offset, inner_radius, extend[j]);
+ }
+ }
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test);
+}
More information about the cairo-commit
mailing list