Use MAKE_ACCESSORS() to generate accessors for the a1 format.
[profile/ivi/pixman.git] / pixman / pixman-gradient-walker.c
1 /*
2  *
3  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
4  *             2005 Lars Knoll & Zack Rusin, Trolltech
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes no
13  * representations about the suitability of this software for any purpose.  It
14  * is provided "as is" without express or implied warranty.
15  *
16  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
21  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
22  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23  * SOFTWARE.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 #include "pixman-private.h"
30
31 void
32 _pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
33                               gradient_t *              gradient,
34                               unsigned int              spread)
35 {
36     walker->num_stops = gradient->n_stops;
37     walker->stops     = gradient->stops;
38     walker->left_x    = 0;
39     walker->right_x   = 0x10000;
40     walker->stepper   = 0;
41     walker->left_ag   = 0;
42     walker->left_rb   = 0;
43     walker->right_ag  = 0;
44     walker->right_rb  = 0;
45     walker->spread    = spread;
46
47     walker->need_reset = TRUE;
48 }
49
50 void
51 _pixman_gradient_walker_reset (pixman_gradient_walker_t *walker,
52                                pixman_fixed_32_32_t      pos)
53 {
54     int32_t x, left_x, right_x;
55     pixman_color_t          *left_c, *right_c;
56     int n, count = walker->num_stops;
57     pixman_gradient_stop_t *      stops = walker->stops;
58
59     static const pixman_color_t transparent_black = { 0, 0, 0, 0 };
60
61     switch (walker->spread)
62     {
63     case PIXMAN_REPEAT_NORMAL:
64         x = (int32_t)pos & 0xFFFF;
65         for (n = 0; n < count; n++)
66             if (x < stops[n].x)
67                 break;
68         if (n == 0)
69         {
70             left_x =  stops[count - 1].x - 0x10000;
71             left_c = &stops[count - 1].color;
72         }
73         else
74         {
75             left_x =  stops[n - 1].x;
76             left_c = &stops[n - 1].color;
77         }
78
79         if (n == count)
80         {
81             right_x =  stops[0].x + 0x10000;
82             right_c = &stops[0].color;
83         }
84         else
85         {
86             right_x =  stops[n].x;
87             right_c = &stops[n].color;
88         }
89         left_x  += (pos - x);
90         right_x += (pos - x);
91         break;
92
93     case PIXMAN_REPEAT_PAD:
94         for (n = 0; n < count; n++)
95             if (pos < stops[n].x)
96                 break;
97
98         if (n == 0)
99         {
100             left_x =  INT32_MIN;
101             left_c = &stops[0].color;
102         }
103         else
104         {
105             left_x =  stops[n - 1].x;
106             left_c = &stops[n - 1].color;
107         }
108
109         if (n == count)
110         {
111             right_x =  INT32_MAX;
112             right_c = &stops[n - 1].color;
113         }
114         else
115         {
116             right_x =  stops[n].x;
117             right_c = &stops[n].color;
118         }
119         break;
120
121     case PIXMAN_REPEAT_REFLECT:
122         x = (int32_t)pos & 0xFFFF;
123         if ((int32_t)pos & 0x10000)
124             x = 0x10000 - x;
125         for (n = 0; n < count; n++)
126             if (x < stops[n].x)
127                 break;
128
129         if (n == 0)
130         {
131             left_x =  -stops[0].x;
132             left_c = &stops[0].color;
133         }
134         else
135         {
136             left_x =  stops[n - 1].x;
137             left_c = &stops[n - 1].color;
138         }
139
140         if (n == count)
141         {
142             right_x = 0x20000 - stops[n - 1].x;
143             right_c = &stops[n - 1].color;
144         }
145         else
146         {
147             right_x =  stops[n].x;
148             right_c = &stops[n].color;
149         }
150
151         if ((int32_t)pos & 0x10000)
152         {
153             pixman_color_t  *tmp_c;
154             int32_t tmp_x;
155
156             tmp_x   = 0x10000 - right_x;
157             right_x = 0x10000 - left_x;
158             left_x  = tmp_x;
159
160             tmp_c   = right_c;
161             right_c = left_c;
162             left_c  = tmp_c;
163
164             x = 0x10000 - x;
165         }
166         left_x  += (pos - x);
167         right_x += (pos - x);
168         break;
169
170     default:  /* REPEAT_NONE */
171         for (n = 0; n < count; n++)
172             if (pos < stops[n].x)
173                 break;
174
175         if (n == 0)
176         {
177             left_x  =  INT32_MIN;
178             right_x =  stops[0].x;
179             left_c  = right_c = (pixman_color_t*) &transparent_black;
180         }
181         else if (n == count)
182         {
183             left_x  = stops[n - 1].x;
184             right_x = INT32_MAX;
185             left_c  = right_c = (pixman_color_t*) &transparent_black;
186         }
187         else
188         {
189             left_x  =  stops[n - 1].x;
190             right_x =  stops[n].x;
191             left_c  = &stops[n - 1].color;
192             right_c = &stops[n].color;
193         }
194     }
195
196     walker->left_x   = left_x;
197     walker->right_x  = right_x;
198     walker->left_ag  = ((left_c->alpha >> 8) << 16)   | (left_c->green >> 8);
199     walker->left_rb  = ((left_c->red & 0xff00) << 8)  | (left_c->blue >> 8);
200     walker->right_ag = ((right_c->alpha >> 8) << 16)  | (right_c->green >> 8);
201     walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8);
202
203     if (walker->left_x == walker->right_x                ||
204         ( walker->left_ag == walker->right_ag &&
205           walker->left_rb == walker->right_rb )   )
206     {
207         walker->stepper = 0;
208     }
209     else
210     {
211         int32_t width = right_x - left_x;
212         walker->stepper = ((1 << 24) + width / 2) / width;
213     }
214
215     walker->need_reset = FALSE;
216 }
217
218 #define  PIXMAN_GRADIENT_WALKER_NEED_RESET(w, x)                         \
219     ( (w)->need_reset || (x) < (w)->left_x || (x) >= (w)->right_x)
220
221
222 /* the following assumes that PIXMAN_GRADIENT_WALKER_NEED_RESET(w,x) is FALSE */
223 uint32_t
224 _pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
225                                pixman_fixed_32_32_t      x)
226 {
227     int dist, idist;
228     uint32_t t1, t2, a, color;
229
230     if (PIXMAN_GRADIENT_WALKER_NEED_RESET (walker, x))
231         _pixman_gradient_walker_reset (walker, x);
232
233     dist  = ((int)(x - walker->left_x) * walker->stepper) >> 16;
234     idist = 256 - dist;
235
236     /* combined INTERPOLATE and premultiply */
237     t1 = walker->left_rb * idist + walker->right_rb * dist;
238     t1 = (t1 >> 8) & 0xff00ff;
239
240     t2  = walker->left_ag * idist + walker->right_ag * dist;
241     t2 &= 0xff00ff00;
242
243     color = t2 & 0xff000000;
244     a     = t2 >> 24;
245
246     t1  = t1 * a + 0x800080;
247     t1  = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8;
248
249     t2  = (t2 >> 8) * a + 0x800080;
250     t2  = (t2 + ((t2 >> 8) & 0xff00ff));
251
252     return (color | (t1 & 0xff00ff) | (t2 & 0xff00));
253 }
254