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
31 #include "pixman-private.h"
33 static source_image_class_t
34 linear_gradient_classify (pixman_image_t *image,
40 linear_gradient_t *linear = (linear_gradient_t *)image;
42 pixman_fixed_32_32_t l;
43 pixman_fixed_48_16_t dx, dy, a, b, off;
44 pixman_fixed_48_16_t factors[4];
47 image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
49 dx = linear->p2.x - linear->p1.x;
50 dy = linear->p2.y - linear->p1.y;
52 l = dx * dx + dy * dy;
64 off = (-a * linear->p1.x
65 -b * linear->p1.y) >> 16;
67 for (i = 0; i < 3; i++)
69 v.vector[0] = pixman_int_to_fixed ((i % 2) * (width - 1) + x);
70 v.vector[1] = pixman_int_to_fixed ((i / 2) * (height - 1) + y);
71 v.vector[2] = pixman_fixed_1;
73 if (image->common.transform)
75 if (!pixman_transform_point_3d (image->common.transform, &v))
77 image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
79 return image->source.class;
83 factors[i] = ((a * v.vector[0] + b * v.vector[1]) >> 16) + off;
86 if (factors[2] == factors[0])
87 image->source.class = SOURCE_IMAGE_CLASS_HORIZONTAL;
88 else if (factors[1] == factors[0])
89 image->source.class = SOURCE_IMAGE_CLASS_VERTICAL;
91 return image->source.class;
95 linear_gradient_get_scanline_32 (pixman_image_t *image,
100 const uint32_t *mask)
102 pixman_vector_t v, unit;
103 pixman_fixed_32_32_t l;
104 pixman_fixed_48_16_t dx, dy, a, b, off;
105 gradient_t *gradient = (gradient_t *)image;
106 source_image_t *source = (source_image_t *)image;
107 linear_gradient_t *linear = (linear_gradient_t *)image;
108 uint32_t *end = buffer + width;
109 pixman_gradient_walker_t walker;
111 _pixman_gradient_walker_init (&walker, gradient, source->common.repeat);
113 /* reference point is the center of the pixel */
114 v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
115 v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
116 v.vector[2] = pixman_fixed_1;
118 if (source->common.transform)
120 if (!pixman_transform_point_3d (source->common.transform, &v))
123 unit.vector[0] = source->common.transform->matrix[0][0];
124 unit.vector[1] = source->common.transform->matrix[1][0];
125 unit.vector[2] = source->common.transform->matrix[2][0];
129 unit.vector[0] = pixman_fixed_1;
134 dx = linear->p2.x - linear->p1.x;
135 dy = linear->p2.y - linear->p1.y;
137 l = dx * dx + dy * dy;
143 off = (-a * linear->p1.x
144 -b * linear->p1.y) >> 16;
147 if (l == 0 || (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1))
149 pixman_fixed_48_16_t inc, t;
151 /* affine transformation only */
159 t = ((a * v.vector[0] + b * v.vector[1]) >> 16) + off;
160 inc = (a * unit.vector[0] + b * unit.vector[1]) >> 16;
163 if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
165 register uint32_t color;
167 color = _pixman_gradient_walker_pixel (&walker, t);
177 *buffer++ = _pixman_gradient_walker_pixel (&walker, t);
187 *buffer = _pixman_gradient_walker_pixel (&walker, t);
197 /* projective transformation */
198 pixman_fixed_48_16_t t;
200 if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
202 register uint32_t color;
204 if (v.vector[2] == 0)
210 pixman_fixed_48_16_t x, y;
212 x = ((pixman_fixed_48_16_t) v.vector[0] << 16) / v.vector[2];
213 y = ((pixman_fixed_48_16_t) v.vector[1] << 16) / v.vector[2];
214 t = ((a * x + b * y) >> 16) + off;
217 color = _pixman_gradient_walker_pixel (&walker, t);
225 if (!mask || *mask++)
227 if (v.vector[2] == 0)
233 pixman_fixed_48_16_t x, y;
234 x = ((pixman_fixed_48_16_t)v.vector[0] << 16) / v.vector[2];
235 y = ((pixman_fixed_48_16_t)v.vector[1] << 16) / v.vector[2];
236 t = ((a * x + b * y) >> 16) + off;
239 *buffer = _pixman_gradient_walker_pixel (&walker, t);
244 v.vector[0] += unit.vector[0];
245 v.vector[1] += unit.vector[1];
246 v.vector[2] += unit.vector[2];
253 linear_gradient_property_changed (pixman_image_t *image)
255 image->common.get_scanline_32 = linear_gradient_get_scanline_32;
256 image->common.get_scanline_64 = _pixman_image_get_scanline_generic_64;
259 PIXMAN_EXPORT pixman_image_t *
260 pixman_image_create_linear_gradient (pixman_point_fixed_t * p1,
261 pixman_point_fixed_t * p2,
262 const pixman_gradient_stop_t *stops,
265 pixman_image_t *image;
266 linear_gradient_t *linear;
268 image = _pixman_image_allocate ();
273 linear = &image->linear;
275 if (!_pixman_init_gradient (&linear->common, stops, n_stops))
284 image->type = LINEAR;
285 image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
286 image->common.classify = linear_gradient_classify;
287 image->common.property_changed = linear_gradient_property_changed;