Merge branch 'radial-gradient-fixes' into cairo

This commit is contained in:
Carl Worth 2007-03-01 17:08:03 -08:00
commit df2d42ac7f
12 changed files with 344 additions and 108 deletions

View file

@ -37,6 +37,7 @@
#define _USE_MATH_DEFINES
#endif
#include <assert.h>
#include <math.h>
#ifndef M_PI
@ -2739,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
@ -2756,13 +2758,14 @@ _gradient_walker_init (GradientWalker *walker,
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
@ -2894,27 +2897,28 @@ _gradient_walker_reset (GradientWalker *walker,
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
@ -2949,8 +2953,6 @@ _gradient_walker_pixel (GradientWalker *walker,
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 +3084,128 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *
}
}
} 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 pp to the length
* of pp.
*
* So, we have six unknown values: (px, py), (px, py), θ 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. px = cx + r·cos θ
* 2. py = cy + r·sin θ
*
* Point p is a distance r from c at an angle of θ:
*
* 3. px = cx + r2·cos θ
* 4. py = cy + r2·sin θ
*
* Point p lies at a fraction t along the line segment pp:
*
* 5. px = t·px + (1-t)·px
* 6. py = t·py + (1-t)·py
*
* To solve, first subtitute 1-4 into 5 and 6:
*
* px = t·(cx + r·cos θ) + (1-t)·(cx + r·cos θ)
* py = t·(cy + r·sin θ) + (1-t)·(cy + r·sin θ)
*
* Then solve each for cos θ and sin θ expressed as a function of t:
*
* cos θ = (-(cx - cx)·t + (px - cx)) / ((r-r)·t + r)
* sin θ = (-(cy - cy)·t + (py - cy)) / ((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 = (cx - cx)
* cdy = (cy - cy)
* dr = r-r
* pdx = px - cx
* pdy = py - cy
*
* 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 +3227,36 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *
}
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;
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;
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);
pdx = rx - c1x;
pdy = ry - c1y;
t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536);
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 +3265,12 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *
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);

View file

@ -247,7 +247,6 @@ pixman_image_create_radial_gradient (const pixman_radial_gradient_t *gradient,
{
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 (const pixman_radial_gradient_t *gradient,
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;
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.;
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;

View file

@ -101,13 +101,12 @@ typedef struct _pixman_radial_gradient_image {
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 {

View file

@ -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)

View file

@ -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 {

View file

@ -244,12 +244,12 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
{
_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 *
@ -1855,12 +1855,12 @@ cairo_pattern_get_linear_points (cairo_pattern_t *pattern,
/**
* 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.
@ -1882,17 +1882,17 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
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;
}

View file

@ -1263,13 +1263,13 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte
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

View file

@ -1280,20 +1280,23 @@ emit_radial_pattern (cairo_svg_surface_t *surface,
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.
* 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\" "
@ -1309,7 +1312,27 @@ emit_radial_pattern (cairo_svg_surface_t *surface,
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");

1
test/.gitignore vendored
View file

@ -97,6 +97,7 @@ png-flatten
ps-features
ps-features.ps
push-group
radial-gradient
random-intersections
svg2png
svg-clip

View file

@ -72,6 +72,7 @@ paint-with-alpha \
pattern-get-type \
pattern-getters \
pixman-rotate \
radial-gradient \
random-intersections \
rectangle-rounding-error \
rectilinear-stroke \

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

110
test/radial-gradient.c Normal file
View file

@ -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@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);
}