Rename source_pict_class_t to source_image_class_t
[profile/ivi/pixman.git] / pixman / pixman-linear-gradient.c
1 /*
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
6  *
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.
16  *
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
24  * SOFTWARE.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 #include <stdlib.h>
31 #include "pixman-private.h"
32
33 static source_image_class_t
34 linear_gradient_classify (pixman_image_t *image,
35                           int             x,
36                           int             y,
37                           int             width,
38                           int             height)
39 {
40     linear_gradient_t *linear = (linear_gradient_t *)image;
41     pixman_vector_t v;
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];
45     int i;
46
47     image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
48
49     dx = linear->p2.x - linear->p1.x;
50     dy = linear->p2.y - linear->p1.y;
51
52     l = dx * dx + dy * dy;
53
54     if (l)
55     {
56         a = (dx << 32) / l;
57         b = (dy << 32) / l;
58     }
59     else
60     {
61         a = b = 0;
62     }
63
64     off = (-a * linear->p1.x
65            -b * linear->p1.y) >> 16;
66
67     for (i = 0; i < 3; i++)
68     {
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;
72
73         if (image->common.transform)
74         {
75             if (!pixman_transform_point_3d (image->common.transform, &v))
76             {
77                 image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
78
79                 return image->source.class;
80             }
81         }
82
83         factors[i] = ((a * v.vector[0] + b * v.vector[1]) >> 16) + off;
84     }
85
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;
90
91     return image->source.class;
92 }
93
94 static void
95 linear_gradient_get_scanline_32 (pixman_image_t *image,
96                                  int             x,
97                                  int             y,
98                                  int             width,
99                                  uint32_t *      buffer,
100                                  const uint32_t *mask,
101                                  uint32_t        mask_bits)
102 {
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;
111
112     _pixman_gradient_walker_init (&walker, gradient, source->common.repeat);
113
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;
118
119     if (source->common.transform)
120     {
121         if (!pixman_transform_point_3d (source->common.transform, &v))
122             return;
123         
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];
127     }
128     else
129     {
130         unit.vector[0] = pixman_fixed_1;
131         unit.vector[1] = 0;
132         unit.vector[2] = 0;
133     }
134
135     dx = linear->p2.x - linear->p1.x;
136     dy = linear->p2.y - linear->p1.y;
137
138     l = dx * dx + dy * dy;
139
140     if (l != 0)
141     {
142         a = (dx << 32) / l;
143         b = (dy << 32) / l;
144         off = (-a * linear->p1.x
145                -b * linear->p1.y) >> 16;
146     }
147
148     if (l == 0 || (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1))
149     {
150         pixman_fixed_48_16_t inc, t;
151
152         /* affine transformation only */
153         if (l == 0)
154         {
155             t = 0;
156             inc = 0;
157         }
158         else
159         {
160             t = ((a * v.vector[0] + b * v.vector[1]) >> 16) + off;
161             inc = (a * unit.vector[0] + b * unit.vector[1]) >> 16;
162         }
163
164         if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
165         {
166             register uint32_t color;
167
168             color = _pixman_gradient_walker_pixel (&walker, t);
169             while (buffer < end)
170                 *buffer++ = color;
171         }
172         else
173         {
174             if (!mask)
175             {
176                 while (buffer < end)
177                 {
178                     *buffer++ = _pixman_gradient_walker_pixel (&walker, t);
179                     
180                     t += inc;
181                 }
182             }
183             else
184             {
185                 while (buffer < end)
186                 {
187                     if (*mask++ & mask_bits)
188                         *buffer = _pixman_gradient_walker_pixel (&walker, t);
189
190                     buffer++;
191                     t += inc;
192                 }
193             }
194         }
195     }
196     else
197     {
198         /* projective transformation */
199         pixman_fixed_48_16_t t;
200
201         if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
202         {
203             register uint32_t color;
204
205             if (v.vector[2] == 0)
206             {
207                 t = 0;
208             }
209             else
210             {
211                 pixman_fixed_48_16_t x, y;
212
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;
216             }
217
218             color = _pixman_gradient_walker_pixel (&walker, t);
219             while (buffer < end)
220                 *buffer++ = color;
221         }
222         else
223         {
224             while (buffer < end)
225             {
226                 if (!mask || *mask++ & mask_bits)
227                 {
228                     if (v.vector[2] == 0)
229                     {
230                         t = 0;
231                     }
232                     else
233                     {
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;
238                     }
239                     
240                     *buffer = _pixman_gradient_walker_pixel (&walker, t);
241                 }
242                 
243                 ++buffer;
244                 
245                 v.vector[0] += unit.vector[0];
246                 v.vector[1] += unit.vector[1];
247                 v.vector[2] += unit.vector[2];
248             }
249         }
250     }
251 }
252
253 static void
254 linear_gradient_property_changed (pixman_image_t *image)
255 {
256     image->common.get_scanline_32 = linear_gradient_get_scanline_32;
257     image->common.get_scanline_64 = _pixman_image_get_scanline_generic_64;
258 }
259
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,
264                                      int                           n_stops)
265 {
266     pixman_image_t *image;
267     linear_gradient_t *linear;
268
269     return_val_if_fail (n_stops >= 2, NULL);
270
271     image = _pixman_image_allocate ();
272
273     if (!image)
274         return NULL;
275
276     linear = &image->linear;
277
278     if (!_pixman_init_gradient (&linear->common, stops, n_stops))
279     {
280         free (image);
281         return NULL;
282     }
283
284     linear->p1 = *p1;
285     linear->p2 = *p2;
286
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;
291
292     linear_gradient_property_changed (image);
293
294     return image;
295 }
296