diff options
author | Owen Taylor <otaylor@redhat.com> | 2005-03-06 12:05:23 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@redhat.com> | 2005-03-06 12:05:23 +0000 |
commit | e7607bb379641f1f07a08e02214db63c0ed637a4 (patch) | |
tree | 74ed11fa98f056a41867425e61c5f94705241e3d | |
parent | 023d91123229dfb7db1c9e28b3981037660cc5a6 (diff) |
Comment and clean up the gradient computation. (_cairo_linear_pattern_classify): Determine if a linear gradient is horizontal or vertical. (_cairo_pattern_acquire_surface_for_gradient): Optimize horizontal/vertical gradients with a repeating surface.
Test case for linear gradients at angles and with a rotated pattern matrix.
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | src/cairo-pattern.c | 119 | ||||
-rw-r--r-- | src/cairo_pattern.c | 119 | ||||
-rw-r--r-- | test/Makefile.am | 3 | ||||
-rw-r--r-- | test/linear-gradient-ref.png | bin | 0 -> 12724 bytes | |||
-rw-r--r-- | test/linear-gradient.c | 141 | ||||
-rw-r--r-- | test/linear_gradient-ref.png | bin | 0 -> 12724 bytes | |||
-rw-r--r-- | test/linear_gradient.c | 141 |
8 files changed, 497 insertions, 38 deletions
@@ -1,3 +1,15 @@ +2005-03-06 Owen Taylor <otaylor@redhat.com> + + * src/cairo_pattern.c (_cairo_image_data_set_linear): Comment + and clean up the gradient computation. + (_cairo_linear_pattern_classify): Determine if a linear + gradient is horizontal or vertical. + (_cairo_pattern_acquire_surface_for_gradient): Optimize + horizontal/vertical gradients with a repeating surface. + + * test/linear_gradient.c: Test case for linear gradients + at angles and with a rotated pattern matrix. + 2005-03-06 David Reveman <davidr@novell.com> * src/cairo_glitz_surface.c (_cairo_glitz_pattern_acquire_surface): diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 49c878cd1..283c36dbd 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -642,9 +642,8 @@ _cairo_image_data_set_linear (cairo_linear_pattern_t *pattern, { int x, y; cairo_point_double_t point0, point1; - double px, py, ex, ey; double a, b, c, d, tx, ty; - double length, start, angle, fx, fy, factor; + double scale, start, dx, dy, factor; cairo_shader_op_t op; cairo_status_t status; @@ -652,6 +651,16 @@ _cairo_image_data_set_linear (cairo_linear_pattern_t *pattern, if (status) return status; + /* We compute the position in the linear gradient for + * a point q as: + * + * [q . (p1 - p0) - p0 . (p1 - p0)] / (p1 - p0) ^ 2 + * + * The computation is done in pattern space. The + * calculation could be heavily optimized by using the + * fact that 'factor' increases linearly in both + * directions. + */ point0.x = pattern->point0.x; point0.y = pattern->point0.y; point1.x = pattern->point1.x; @@ -659,28 +668,24 @@ _cairo_image_data_set_linear (cairo_linear_pattern_t *pattern, cairo_matrix_get_affine (&pattern->base.base.matrix, &a, &b, &c, &d, &tx, &ty); - - length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) + - (point1.y - point0.y) * (point1.y - point0.y)); - length = (length) ? 1.0 / length : CAIRO_MAXSHORT; - angle = -atan2 (point1.y - point0.y, point1.x - point0.x); - fx = cos (angle); - fy = -sin (angle); - - start = fx * point0.x; - start += fy * point0.y; + dx = point1.x - point0.x; + dy = point1.y - point0.y; + scale = dx * dx + dy * dy; + scale = (scale) ? 1.0 / scale : 1.0; + + start = dx * point0.x + dy * point0.y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { - px = x + offset_x; - py = y + offset_y; + double qx_device = x + offset_x; + double qy_device = y + offset_y; - /* transform fragment */ - ex = a * px + c * py + tx; - ey = b * px + d * py + ty; + /* transform fragment into pattern space */ + double qx = a * qx_device + c * qy_device + tx; + double qy = b * qx_device + d * qy_device + ty; - factor = ((fx * ex + fy * ey) - start) * length; + factor = ((dx * qx + dy * qy) - start) * scale; _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++); } @@ -691,6 +696,64 @@ _cairo_image_data_set_linear (cairo_linear_pattern_t *pattern, return CAIRO_STATUS_SUCCESS; } +static void +_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern, + double offset_x, + double offset_y, + int width, + int height, + cairo_bool_t *is_horizontal, + cairo_bool_t *is_vertical) +{ + cairo_point_double_t point0, point1; + double a, b, c, d, tx, ty; + double scale, start, dx, dy; + cairo_fixed_t factors[3]; + int i; + + /* To classidy a pattern as horizontal or vertical, we first + * compute the (fixed point) factors at the corners of the + * pattern. We actually only need 3/4 corners, so we skip the + * fourth. + */ + point0.x = pattern->point0.x; + point0.y = pattern->point0.y; + point1.x = pattern->point1.x; + point1.y = pattern->point1.y; + + cairo_matrix_get_affine (&pattern->base.base.matrix, + &a, &b, &c, &d, &tx, &ty); + + dx = point1.x - point0.x; + dy = point1.y - point0.y; + scale = dx * dx + dy * dy; + scale = (scale) ? 1.0 / scale : 1.0; + + start = dx * point0.x + dy * point0.y; + + for (i = 0; i < 3; i++) { + double qx_device = (i % 2) * (width - 1) + offset_x; + double qy_device = (i / 2) * (height - 1) + offset_y; + + /* transform fragment into pattern space */ + double qx = a * qx_device + c * qy_device + tx; + double qy = b * qx_device + d * qy_device + ty; + + factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale); + } + + /* We consider a pattern to be vertical if the fixed point factor + * at the two upper corners is the same. We could accept a small + * change, but determining what change is acceptable would require + * sorting the stops in the pattern and looking at the differences. + * + * Horizontal works the same way with the two left corners. + */ + + *is_vertical = factors[1] == factors[0]; + *is_horizontal = factors[2] == factors[0]; +} + static cairo_status_t _cairo_image_data_set_radial (cairo_radial_pattern_t *pattern, double offset_x, @@ -828,6 +891,24 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, cairo_image_surface_t *image; cairo_status_t status; uint32_t *data; + cairo_bool_t repeat = FALSE; + + if (pattern->base.type == CAIRO_PATTERN_LINEAR) { + cairo_bool_t is_horizontal; + cairo_bool_t is_vertical; + + _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern, + x, y, width, height, + &is_horizontal, &is_vertical); + if (is_horizontal) { + height = 1; + repeat = TRUE; + } + if (is_vertical) { + width = 1; + repeat = TRUE; + } + } data = malloc (width * height * 4); if (!data) @@ -873,7 +954,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, attr->x_offset = -x; attr->y_offset = -y; cairo_matrix_set_identity (&attr->matrix); - attr->extend = CAIRO_EXTEND_NONE; + attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE; attr->filter = CAIRO_FILTER_NEAREST; attr->acquired = FALSE; diff --git a/src/cairo_pattern.c b/src/cairo_pattern.c index 49c878cd1..283c36dbd 100644 --- a/src/cairo_pattern.c +++ b/src/cairo_pattern.c @@ -642,9 +642,8 @@ _cairo_image_data_set_linear (cairo_linear_pattern_t *pattern, { int x, y; cairo_point_double_t point0, point1; - double px, py, ex, ey; double a, b, c, d, tx, ty; - double length, start, angle, fx, fy, factor; + double scale, start, dx, dy, factor; cairo_shader_op_t op; cairo_status_t status; @@ -652,6 +651,16 @@ _cairo_image_data_set_linear (cairo_linear_pattern_t *pattern, if (status) return status; + /* We compute the position in the linear gradient for + * a point q as: + * + * [q . (p1 - p0) - p0 . (p1 - p0)] / (p1 - p0) ^ 2 + * + * The computation is done in pattern space. The + * calculation could be heavily optimized by using the + * fact that 'factor' increases linearly in both + * directions. + */ point0.x = pattern->point0.x; point0.y = pattern->point0.y; point1.x = pattern->point1.x; @@ -659,28 +668,24 @@ _cairo_image_data_set_linear (cairo_linear_pattern_t *pattern, cairo_matrix_get_affine (&pattern->base.base.matrix, &a, &b, &c, &d, &tx, &ty); - - length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) + - (point1.y - point0.y) * (point1.y - point0.y)); - length = (length) ? 1.0 / length : CAIRO_MAXSHORT; - angle = -atan2 (point1.y - point0.y, point1.x - point0.x); - fx = cos (angle); - fy = -sin (angle); - - start = fx * point0.x; - start += fy * point0.y; + dx = point1.x - point0.x; + dy = point1.y - point0.y; + scale = dx * dx + dy * dy; + scale = (scale) ? 1.0 / scale : 1.0; + + start = dx * point0.x + dy * point0.y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { - px = x + offset_x; - py = y + offset_y; + double qx_device = x + offset_x; + double qy_device = y + offset_y; - /* transform fragment */ - ex = a * px + c * py + tx; - ey = b * px + d * py + ty; + /* transform fragment into pattern space */ + double qx = a * qx_device + c * qy_device + tx; + double qy = b * qx_device + d * qy_device + ty; - factor = ((fx * ex + fy * ey) - start) * length; + factor = ((dx * qx + dy * qy) - start) * scale; _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++); } @@ -691,6 +696,64 @@ _cairo_image_data_set_linear (cairo_linear_pattern_t *pattern, return CAIRO_STATUS_SUCCESS; } +static void +_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern, + double offset_x, + double offset_y, + int width, + int height, + cairo_bool_t *is_horizontal, + cairo_bool_t *is_vertical) +{ + cairo_point_double_t point0, point1; + double a, b, c, d, tx, ty; + double scale, start, dx, dy; + cairo_fixed_t factors[3]; + int i; + + /* To classidy a pattern as horizontal or vertical, we first + * compute the (fixed point) factors at the corners of the + * pattern. We actually only need 3/4 corners, so we skip the + * fourth. + */ + point0.x = pattern->point0.x; + point0.y = pattern->point0.y; + point1.x = pattern->point1.x; + point1.y = pattern->point1.y; + + cairo_matrix_get_affine (&pattern->base.base.matrix, + &a, &b, &c, &d, &tx, &ty); + + dx = point1.x - point0.x; + dy = point1.y - point0.y; + scale = dx * dx + dy * dy; + scale = (scale) ? 1.0 / scale : 1.0; + + start = dx * point0.x + dy * point0.y; + + for (i = 0; i < 3; i++) { + double qx_device = (i % 2) * (width - 1) + offset_x; + double qy_device = (i / 2) * (height - 1) + offset_y; + + /* transform fragment into pattern space */ + double qx = a * qx_device + c * qy_device + tx; + double qy = b * qx_device + d * qy_device + ty; + + factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale); + } + + /* We consider a pattern to be vertical if the fixed point factor + * at the two upper corners is the same. We could accept a small + * change, but determining what change is acceptable would require + * sorting the stops in the pattern and looking at the differences. + * + * Horizontal works the same way with the two left corners. + */ + + *is_vertical = factors[1] == factors[0]; + *is_horizontal = factors[2] == factors[0]; +} + static cairo_status_t _cairo_image_data_set_radial (cairo_radial_pattern_t *pattern, double offset_x, @@ -828,6 +891,24 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, cairo_image_surface_t *image; cairo_status_t status; uint32_t *data; + cairo_bool_t repeat = FALSE; + + if (pattern->base.type == CAIRO_PATTERN_LINEAR) { + cairo_bool_t is_horizontal; + cairo_bool_t is_vertical; + + _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern, + x, y, width, height, + &is_horizontal, &is_vertical); + if (is_horizontal) { + height = 1; + repeat = TRUE; + } + if (is_vertical) { + width = 1; + repeat = TRUE; + } + } data = malloc (width * height * 4); if (!data) @@ -873,7 +954,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, attr->x_offset = -x; attr->y_offset = -y; cairo_matrix_set_identity (&attr->matrix); - attr->extend = CAIRO_EXTEND_NONE; + attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE; attr->filter = CAIRO_FILTER_NEAREST; attr->acquired = FALSE; diff --git a/test/Makefile.am b/test/Makefile.am index aa3d0604a..252dcbca9 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -3,6 +3,7 @@ TESTS = \ fill_rule \ leaky_polygon \ line_width \ +linear_gradient \ move_to_show_surface \ text_cache_crash \ text_rotate \ @@ -17,6 +18,7 @@ EXTRA_DIST = \ fill_rule-ref.png \ leaky_polygon-ref.png \ line_width-ref.png \ +linear_gradient-ref.png \ move_to_show_surface-ref.png \ coverage-ref.png \ clip_twice-ref.png \ @@ -68,6 +70,7 @@ xmalloc.h fill_rule_SOURCES = fill_rule.c $(cairo_test_lib) leaky_polygon_SOURCES = leaky_polygon.c $(cairo_test_lib) line_width_SOURCES = line_width.c $(cairo_test_lib) +linear_gradient_SOURCES = linear_gradient.c $(cairo_test_lib) move_to_show_surface_SOURCES = move_to_show_surface.c $(cairo_test_lib) text_cache_crash_SOURCES = text_cache_crash.c $(cairo_test_lib) text_rotate_SOURCES = text_rotate.c $(cairo_test_lib) diff --git a/test/linear-gradient-ref.png b/test/linear-gradient-ref.png Binary files differnew file mode 100644 index 000000000..77904144d --- /dev/null +++ b/test/linear-gradient-ref.png diff --git a/test/linear-gradient.c b/test/linear-gradient.c new file mode 100644 index 000000000..189b50065 --- /dev/null +++ b/test/linear-gradient.c @@ -0,0 +1,141 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor <otaylor@redhat.com> + */ + +#include "cairo_test.h" +#include "stdio.h" + +/* The test matrix is + * + * A) Horizontal B) 5° C) 45° D) Vertical + * 1) Rotated 0° 2) Rotated 45° C) Rotated 90° + * a) 2 stop b) 3 stop + * + * A1a B1a C1a D1a + * A2a B2a C2a D2a + * A3a B3a C3a D3a + * A1b B1b C1b D1b + * A2b B2b C2b D2b + * A3b B3b C3b D3b + */ + +static const double gradient_angles[] = { 0, 45, 90 }; +#define N_GRADIENT_ANGLES 3 +static const double rotate_angles[] = { 0, 45, 90 }; +#define N_ROTATE_ANGLES 3 +static const int n_stops[] = { 2, 3 }; +#define N_N_STOPS 2 + +#define UNIT_SIZE 75 +#define UNIT_SIZE 75 +#define PAD 5 + +#define WIDTH N_GRADIENT_ANGLES * UNIT_SIZE + (N_GRADIENT_ANGLES + 1) * PAD +#define HEIGHT N_N_STOPS * N_ROTATE_ANGLES * UNIT_SIZE + (N_N_STOPS * N_ROTATE_ANGLES + 1) * PAD + +cairo_test_t test = { + "linear_gradient", + "Tests the drawing of linear gradients", + WIDTH, HEIGHT +}; + +static void +draw_unit (cairo_t *cr, + double gradient_angle, + double rotate_angle, + int n_stops) +{ + cairo_pattern_t *pattern; + + cairo_rectangle (cr, 0, 0, 1, 1); + cairo_clip (cr); + cairo_new_path(cr); + + cairo_set_rgb_color (cr, 0.0, 0.0, 0.0); + cairo_rectangle (cr, 0, 0, 1, 1); + cairo_fill (cr); + + cairo_translate (cr, 0.5, 0.5); + cairo_scale (cr, 1 / 1.5, 1 / 1.5); + cairo_rotate (cr, rotate_angle); + + pattern = cairo_pattern_create_linear (-0.5 * cos (gradient_angle), -0.5 * sin (gradient_angle), + 0.5 * cos (gradient_angle), 0.5 * sin (gradient_angle)); + + if (n_stops == 2) { + cairo_pattern_add_color_stop (pattern, 0., + 0.3, 0.3, 0.3, + 1.0); + cairo_pattern_add_color_stop (pattern, 1., + 1.0, 1.0, 1.0, + 1.0); + } else { + cairo_pattern_add_color_stop (pattern, 0., + 1.0, 0.0, 0.0, + 1.0); + cairo_pattern_add_color_stop (pattern, 0.5, + 1.0, 1.0, 1.0, + 1.0); + cairo_pattern_add_color_stop (pattern, 1., + 0.0, 0.0, 1.0, + 1.0); + } + + cairo_set_pattern (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_rectangle (cr, -0.5, -0.5, 1, 1); + cairo_fill (cr); +} + +static void +draw (cairo_t *cr, int width, int height) +{ + int i, j, k; + + cairo_set_rgb_color (cr, 0.5, 0.5, 0.5); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + + for (i = 0; i < N_GRADIENT_ANGLES; i++) + for (j = 0; j < N_ROTATE_ANGLES; j++) + for (k = 0; k < N_N_STOPS; k++) { + cairo_save (cr); + cairo_translate (cr, + PAD + (PAD + UNIT_SIZE) * i, + PAD + (PAD + UNIT_SIZE) * (N_ROTATE_ANGLES * k + j)); + cairo_scale (cr, UNIT_SIZE, UNIT_SIZE); + + draw_unit (cr, + gradient_angles[i] * M_PI / 180., + rotate_angles[j] * M_PI / 180., + n_stops[k]); + cairo_restore (cr); + } +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/linear_gradient-ref.png b/test/linear_gradient-ref.png Binary files differnew file mode 100644 index 000000000..77904144d --- /dev/null +++ b/test/linear_gradient-ref.png diff --git a/test/linear_gradient.c b/test/linear_gradient.c new file mode 100644 index 000000000..189b50065 --- /dev/null +++ b/test/linear_gradient.c @@ -0,0 +1,141 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor <otaylor@redhat.com> + */ + +#include "cairo_test.h" +#include "stdio.h" + +/* The test matrix is + * + * A) Horizontal B) 5° C) 45° D) Vertical + * 1) Rotated 0° 2) Rotated 45° C) Rotated 90° + * a) 2 stop b) 3 stop + * + * A1a B1a C1a D1a + * A2a B2a C2a D2a + * A3a B3a C3a D3a + * A1b B1b C1b D1b + * A2b B2b C2b D2b + * A3b B3b C3b D3b + */ + +static const double gradient_angles[] = { 0, 45, 90 }; +#define N_GRADIENT_ANGLES 3 +static const double rotate_angles[] = { 0, 45, 90 }; +#define N_ROTATE_ANGLES 3 +static const int n_stops[] = { 2, 3 }; +#define N_N_STOPS 2 + +#define UNIT_SIZE 75 +#define UNIT_SIZE 75 +#define PAD 5 + +#define WIDTH N_GRADIENT_ANGLES * UNIT_SIZE + (N_GRADIENT_ANGLES + 1) * PAD +#define HEIGHT N_N_STOPS * N_ROTATE_ANGLES * UNIT_SIZE + (N_N_STOPS * N_ROTATE_ANGLES + 1) * PAD + +cairo_test_t test = { + "linear_gradient", + "Tests the drawing of linear gradients", + WIDTH, HEIGHT +}; + +static void +draw_unit (cairo_t *cr, + double gradient_angle, + double rotate_angle, + int n_stops) +{ + cairo_pattern_t *pattern; + + cairo_rectangle (cr, 0, 0, 1, 1); + cairo_clip (cr); + cairo_new_path(cr); + + cairo_set_rgb_color (cr, 0.0, 0.0, 0.0); + cairo_rectangle (cr, 0, 0, 1, 1); + cairo_fill (cr); + + cairo_translate (cr, 0.5, 0.5); + cairo_scale (cr, 1 / 1.5, 1 / 1.5); + cairo_rotate (cr, rotate_angle); + + pattern = cairo_pattern_create_linear (-0.5 * cos (gradient_angle), -0.5 * sin (gradient_angle), + 0.5 * cos (gradient_angle), 0.5 * sin (gradient_angle)); + + if (n_stops == 2) { + cairo_pattern_add_color_stop (pattern, 0., + 0.3, 0.3, 0.3, + 1.0); + cairo_pattern_add_color_stop (pattern, 1., + 1.0, 1.0, 1.0, + 1.0); + } else { + cairo_pattern_add_color_stop (pattern, 0., + 1.0, 0.0, 0.0, + 1.0); + cairo_pattern_add_color_stop (pattern, 0.5, + 1.0, 1.0, 1.0, + 1.0); + cairo_pattern_add_color_stop (pattern, 1., + 0.0, 0.0, 1.0, + 1.0); + } + + cairo_set_pattern (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_rectangle (cr, -0.5, -0.5, 1, 1); + cairo_fill (cr); +} + +static void +draw (cairo_t *cr, int width, int height) +{ + int i, j, k; + + cairo_set_rgb_color (cr, 0.5, 0.5, 0.5); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + + for (i = 0; i < N_GRADIENT_ANGLES; i++) + for (j = 0; j < N_ROTATE_ANGLES; j++) + for (k = 0; k < N_N_STOPS; k++) { + cairo_save (cr); + cairo_translate (cr, + PAD + (PAD + UNIT_SIZE) * i, + PAD + (PAD + UNIT_SIZE) * (N_ROTATE_ANGLES * k + j)); + cairo_scale (cr, UNIT_SIZE, UNIT_SIZE); + + draw_unit (cr, + gradient_angles[i] * M_PI / 180., + rotate_angles[j] * M_PI / 180., + n_stops[k]); + cairo_restore (cr); + } +} + +int +main (void) +{ + return cairo_test (&test, draw); +} |