Constify the mask argument to scanline fetchers.
[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 #include <config.h>
28 #include <stdlib.h>
29 #include "pixman-private.h"
30
31 static source_pict_class_t
32 linear_gradient_classify (pixman_image_t *image,
33                           int             x,
34                           int             y,
35                           int             width,
36                           int             height)
37 {
38     linear_gradient_t *linear = (linear_gradient_t *)image;
39     pixman_vector_t   v;
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];
43     int      i;
44     
45     image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
46     
47     dx = linear->p2.x - linear->p1.x;
48     dy = linear->p2.y - linear->p1.y;
49     l = dx * dx + dy * dy;
50     if (l)
51     {
52         a = (dx << 32) / l;
53         b = (dy << 32) / l;
54     }
55     else
56     {
57         a = b = 0;
58     }
59     
60     off = (-a * linear->p1.x
61            -b * linear->p1.y) >> 16;
62     
63     for (i = 0; i < 3; i++)
64     {
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;
68         
69         if (image->common.transform)
70         {
71             if (!pixman_transform_point_3d (image->common.transform, &v))
72             {
73                 image->source.class = SOURCE_IMAGE_CLASS_UNKNOWN;
74                 
75                 return image->source.class;
76             }
77         }
78         
79         factors[i] = ((a * v.vector[0] + b * v.vector[1]) >> 16) + off;
80     }
81     
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;
86     
87     return image->source.class;
88 }
89
90 static void
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)
93 {
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;
102     
103     _pixman_gradient_walker_init (&walker, gradient, source->common.repeat);
104     
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))
111             return;
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];
115     } else {
116         unit.vector[0] = pixman_fixed_1;
117         unit.vector[1] = 0;
118         unit.vector[2] = 0;
119     }
120     
121     dx = linear->p2.x - linear->p1.x;
122     dy = linear->p2.y - linear->p1.y;
123     l = dx*dx + dy*dy;
124     if (l != 0) {
125         a = (dx << 32) / l;
126         b = (dy << 32) / l;
127         off = (-a*linear->p1.x - b*linear->p1.y)>>16;
128     }
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 */
132         if (l == 0) {
133             t = 0;
134             inc = 0;
135         } else {
136             t = ((a*v.vector[0] + b*v.vector[1]) >> 16) + off;
137             inc = (a * unit.vector[0] + b * unit.vector[1]) >> 16;
138         }
139         
140         if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
141         {
142             register uint32_t color;
143             
144             color = _pixman_gradient_walker_pixel( &walker, t );
145             while (buffer < end)
146                 *(buffer++) = color;
147         }
148         else
149         {
150             if (!mask) {
151                 while (buffer < end)
152                 {
153                     *(buffer) = _pixman_gradient_walker_pixel (&walker, t);
154                     buffer += 1;
155                     t      += inc;
156                 }
157             } else {
158                 while (buffer < end) {
159                     if (*mask++ & maskBits)
160                     {
161                         *(buffer) = _pixman_gradient_walker_pixel (&walker, t);
162                     }
163                     buffer += 1;
164                     t      += inc;
165                 }
166             }
167         }
168     }
169     else /* projective transformation */
170     {
171         pixman_fixed_48_16_t t;
172         
173         if (source->class == SOURCE_IMAGE_CLASS_VERTICAL)
174         {
175             register uint32_t color;
176             
177             if (v.vector[2] == 0)
178             {
179                 t = 0;
180             }
181             else
182             {
183                 pixman_fixed_48_16_t x, y;
184                 
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;
188             }
189             
190             color = _pixman_gradient_walker_pixel( &walker, t );
191             while (buffer < end)
192                 *(buffer++) = color;
193         }
194         else
195         {
196             while (buffer < end)
197             {
198                 if (!mask || *mask++ & maskBits)
199                 {
200                     if (v.vector[2] == 0) {
201                         t = 0;
202                     } else {
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;
207                     }
208                     *(buffer) = _pixman_gradient_walker_pixel (&walker, t);
209                 }
210                 ++buffer;
211                 v.vector[0] += unit.vector[0];
212                 v.vector[1] += unit.vector[1];
213                 v.vector[2] += unit.vector[2];
214             }
215         }
216     }
217 }
218
219 static void
220 linear_gradient_property_changed (pixman_image_t *image)
221 {
222     image->common.get_scanline_32 = linear_gradient_get_scanline_32;
223     image->common.get_scanline_64 = _pixman_image_get_scanline_64_generic;
224 }
225
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,
230                                      int                           n_stops)
231 {
232     pixman_image_t *image;
233     linear_gradient_t *linear;
234     
235     return_val_if_fail (n_stops >= 2, NULL);
236     
237     image = _pixman_image_allocate();
238     
239     if (!image)
240         return NULL;
241     
242     linear = &image->linear;
243     
244     if (!_pixman_init_gradient (&linear->common, stops, n_stops))
245     {
246         free (image);
247         return NULL;
248     }
249     
250     linear->p1 = *p1;
251     linear->p2 = *p2;
252     
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;
257     
258     linear_gradient_property_changed (image);
259     
260     return image;
261 }