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,
103 pixman_vector_t v, unit;
104 pixman_fixed_32_32_t l;
105 pixman_fixed_48_16_t dx, dy, a, b, off;
106 gradient_t *gradient = (gradient_t *)image;
107 source_image_t *source = (source_image_t *)image;
108 linear_gradient_t *linear = (linear_gradient_t *)image;
109 uint32_t *end = buffer + width;
110 pixman_gradient_walker_t walker;
112 _pixman_gradient_walker_init (&walker, gradient, source->common.repeat);
114 /* reference point is the center of the pixel */
115 v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
116 v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
117 v.vector[2] = pixman_fixed_1;
119 if (source->common.transform)
121 if (!pixman_transform_point_3d (source->common.transform, &v))
124 unit.vector[0] = source->common.transform->matrix[0][0];
125 unit.vector[1] = source->common.transform->matrix[1][0];
126 unit.vector[2] = source->common.transform->matrix[2][0];
130 unit.vector[0] = pixman_fixed_1;
135 dx = linear->p2.x - linear->p1.x;
136 dy = linear->p2.y - linear->p1.y;
138 l = dx * dx + dy * dy;
144 off = (-a * linear->p1.x
145 -b * linear->p1.y) >> 16;
148 if (l == 0 || (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1))
150 pixman_fixed_48_16_t inc, t;
152 /* affine transformation only */
160 t = ((a * v.vector[0] + b * v.vector[1]) >> 16) + off;
161 inc = (a * unit.vector[0] + b * unit.vector[1]) >> 16;
164 if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
166 register uint32_t color;
168 color = _pixman_gradient_walker_pixel (&walker, t);
178 *buffer++ = _pixman_gradient_walker_pixel (&walker, t);
187 if (*mask++ & mask_bits)
188 *buffer = _pixman_gradient_walker_pixel (&walker, t);
198 /* projective transformation */
199 pixman_fixed_48_16_t t;
201 if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
203 register uint32_t color;
205 if (v.vector[2] == 0)
211 pixman_fixed_48_16_t x, y;
213 x = ((pixman_fixed_48_16_t) v.vector[0] << 16) / v.vector[2];
214 y = ((pixman_fixed_48_16_t) v.vector[1] << 16) / v.vector[2];
215 t = ((a * x + b * y) >> 16) + off;
218 color = _pixman_gradient_walker_pixel (&walker, t);
226 if (!mask || *mask++ & mask_bits)
228 if (v.vector[2] == 0)
234 pixman_fixed_48_16_t x, y;
235 x = ((pixman_fixed_48_16_t)v.vector[0] << 16) / v.vector[2];
236 y = ((pixman_fixed_48_16_t)v.vector[1] << 16) / v.vector[2];
237 t = ((a * x + b * y) >> 16) + off;
240 *buffer = _pixman_gradient_walker_pixel (&walker, t);
245 v.vector[0] += unit.vector[0];
246 v.vector[1] += unit.vector[1];
247 v.vector[2] += unit.vector[2];
254 linear_gradient_property_changed (pixman_image_t *image)
256 image->common.get_scanline_32 = linear_gradient_get_scanline_32;
257 image->common.get_scanline_64 = _pixman_image_get_scanline_generic_64;
260 PIXMAN_EXPORT pixman_image_t *
261 pixman_image_create_linear_gradient (pixman_point_fixed_t * p1,
262 pixman_point_fixed_t * p2,
263 const pixman_gradient_stop_t *stops,
266 pixman_image_t *image;
267 linear_gradient_t *linear;
269 return_val_if_fail (n_stops >= 2, NULL);
271 image = _pixman_image_allocate ();
276 linear = &image->linear;
278 if (!_pixman_init_gradient (&linear->common, stops, n_stops))
287 image->type = LINEAR;
288 image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
289 image->common.classify = linear_gradient_classify;
290 image->common.property_changed = linear_gradient_property_changed;
292 linear_gradient_property_changed (image);