2 * Copyright © 2000 SuSE, Inc.
3 * Copyright © 2007 Red Hat, Inc.
4 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
5 * 2005 Lars Knoll & Zack Rusin, Trolltech
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of Keith Packard not be used in
12 * advertising or publicity pertaining to distribution of the software without
13 * specific, written prior permission. Keith Packard makes no
14 * representations about the suitability of this software for any purpose. It
15 * is provided "as is" without express or implied warranty.
17 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
18 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
22 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
23 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 #include "pixman-private.h"
31 static source_pict_class_t
32 linear_gradient_classify (pixman_image_t *image,
38 linear_gradient_t *linear = (linear_gradient_t *)image;
40 pixman_fixed_32_32_t l;
41 pixman_fixed_48_16_t dx, dy, a, b, off;
42 pixman_fixed_48_16_t factors[4];
45 image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
47 dx = linear->p2.x - linear->p1.x;
48 dy = linear->p2.y - linear->p1.y;
49 l = dx * dx + dy * dy;
60 off = (-a * linear->p1.x
61 -b * linear->p1.y) >> 16;
63 for (i = 0; i < 3; i++)
65 v.vector[0] = pixman_int_to_fixed ((i % 2) * (width - 1) + x);
66 v.vector[1] = pixman_int_to_fixed ((i / 2) * (height - 1) + y);
67 v.vector[2] = pixman_fixed_1;
69 if (image->common.transform)
71 if (!pixman_transform_point_3d (image->common.transform, &v))
73 image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
75 return image->source.class;
79 factors[i] = ((a * v.vector[0] + b * v.vector[1]) >> 16) + off;
82 if (factors[2] == factors[0])
83 image->source.class = SOURCE_IMAGE_CLASS_HORIZONTAL;
84 else if (factors[1] == factors[0])
85 image->source.class = SOURCE_IMAGE_CLASS_VERTICAL;
87 return image->source.class;
91 linear_gradient_get_scanline_32 (pixman_image_t *image, int x, int y, int width, uint32_t *buffer,
92 const uint32_t *mask, uint32_t maskBits)
94 pixman_vector_t v, unit;
95 pixman_fixed_32_32_t l;
96 pixman_fixed_48_16_t dx, dy, a, b, off;
97 gradient_t *gradient = (gradient_t *)image;
98 source_image_t *source = (source_image_t *)image;
99 linear_gradient_t *linear = (linear_gradient_t *)image;
100 uint32_t *end = buffer + width;
101 pixman_gradient_walker_t walker;
103 _pixman_gradient_walker_init (&walker, gradient, source->common.repeat);
105 /* reference point is the center of the pixel */
106 v.vector[0] = pixman_int_to_fixed(x) + pixman_fixed_1/2;
107 v.vector[1] = pixman_int_to_fixed(y) + pixman_fixed_1/2;
108 v.vector[2] = pixman_fixed_1;
109 if (source->common.transform) {
110 if (!pixman_transform_point_3d (source->common.transform, &v))
112 unit.vector[0] = source->common.transform->matrix[0][0];
113 unit.vector[1] = source->common.transform->matrix[1][0];
114 unit.vector[2] = source->common.transform->matrix[2][0];
116 unit.vector[0] = pixman_fixed_1;
121 dx = linear->p2.x - linear->p1.x;
122 dy = linear->p2.y - linear->p1.y;
127 off = (-a*linear->p1.x - b*linear->p1.y)>>16;
129 if (l == 0 || (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)) {
130 pixman_fixed_48_16_t inc, t;
131 /* affine transformation only */
136 t = ((a*v.vector[0] + b*v.vector[1]) >> 16) + off;
137 inc = (a * unit.vector[0] + b * unit.vector[1]) >> 16;
140 if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
142 register uint32_t color;
144 color = _pixman_gradient_walker_pixel( &walker, t );
153 *(buffer) = _pixman_gradient_walker_pixel (&walker, t);
158 while (buffer < end) {
159 if (*mask++ & maskBits)
161 *(buffer) = _pixman_gradient_walker_pixel (&walker, t);
169 else /* projective transformation */
171 pixman_fixed_48_16_t t;
173 if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
175 register uint32_t color;
177 if (v.vector[2] == 0)
183 pixman_fixed_48_16_t x, y;
185 x = ((pixman_fixed_48_16_t) v.vector[0] << 16) / v.vector[2];
186 y = ((pixman_fixed_48_16_t) v.vector[1] << 16) / v.vector[2];
187 t = ((a * x + b * y) >> 16) + off;
190 color = _pixman_gradient_walker_pixel( &walker, t );
198 if (!mask || *mask++ & maskBits)
200 if (v.vector[2] == 0) {
203 pixman_fixed_48_16_t x, y;
204 x = ((pixman_fixed_48_16_t)v.vector[0] << 16) / v.vector[2];
205 y = ((pixman_fixed_48_16_t)v.vector[1] << 16) / v.vector[2];
206 t = ((a*x + b*y) >> 16) + off;
208 *(buffer) = _pixman_gradient_walker_pixel (&walker, t);
211 v.vector[0] += unit.vector[0];
212 v.vector[1] += unit.vector[1];
213 v.vector[2] += unit.vector[2];
220 linear_gradient_property_changed (pixman_image_t *image)
222 image->common.get_scanline_32 = linear_gradient_get_scanline_32;
223 image->common.get_scanline_64 = _pixman_image_get_scanline_generic_64;
226 PIXMAN_EXPORT pixman_image_t *
227 pixman_image_create_linear_gradient (pixman_point_fixed_t *p1,
228 pixman_point_fixed_t *p2,
229 const pixman_gradient_stop_t *stops,
232 pixman_image_t *image;
233 linear_gradient_t *linear;
235 return_val_if_fail (n_stops >= 2, NULL);
237 image = _pixman_image_allocate();
242 linear = &image->linear;
244 if (!_pixman_init_gradient (&linear->common, stops, n_stops))
253 image->type = LINEAR;
254 image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
255 image->common.classify = linear_gradient_classify;
256 image->common.property_changed = linear_gradient_property_changed;
258 linear_gradient_property_changed (image);