Add definitions of INT64_MIN and INT64_MAX
[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                               pixman_repeat_t           repeat)
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->repeat    = repeat;
46
47     walker->need_reset = TRUE;
48 }
49
50 static void
51 gradient_walker_reset (pixman_gradient_walker_t *walker,
52                        pixman_fixed_48_16_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     if (walker->repeat == PIXMAN_REPEAT_NORMAL)
60     {
61         x = (int32_t)pos & 0xffff;
62     }
63     else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
64     {
65         x = (int32_t)pos & 0xffff;
66         if ((int32_t)pos & 0x10000)
67             x = 0x10000 - x;
68     }
69     else
70     {
71         x = pos;
72     }
73     
74     for (n = 0; n < count; n++)
75     {
76         if (x < stops[n].x)
77             break;
78     }
79     
80     left_x =  stops[n - 1].x;
81     left_c = &stops[n - 1].color;
82     
83     right_x =  stops[n].x;
84     right_c = &stops[n].color;
85
86     if (walker->repeat == PIXMAN_REPEAT_NORMAL)
87     {
88         left_x  += (pos - x);
89         right_x += (pos - x);
90     }
91     else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
92     {
93         if ((int32_t)pos & 0x10000)
94         {
95             pixman_color_t  *tmp_c;
96             int32_t tmp_x;
97
98             tmp_x   = 0x10000 - right_x;
99             right_x = 0x10000 - left_x;
100             left_x  = tmp_x;
101
102             tmp_c   = right_c;
103             right_c = left_c;
104             left_c  = tmp_c;
105
106             x = 0x10000 - x;
107         }
108         left_x  += (pos - x);
109         right_x += (pos - x);
110     }
111
112     walker->left_x   = left_x;
113     walker->right_x  = right_x;
114     walker->left_ag  = ((left_c->alpha >> 8) << 16)   | (left_c->green >> 8);
115     walker->left_rb  = ((left_c->red & 0xff00) << 8)  | (left_c->blue >> 8);
116     walker->right_ag = ((right_c->alpha >> 8) << 16)  | (right_c->green >> 8);
117     walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8);
118
119     if (walker->left_x == walker->right_x                ||
120         (walker->left_ag == walker->right_ag &&
121          walker->left_rb == walker->right_rb))
122     {
123         walker->stepper = 0;
124     }
125     else
126     {
127         int32_t width = right_x - left_x;
128         walker->stepper = ((1 << 24) + width / 2) / width;
129     }
130
131     walker->need_reset = FALSE;
132 }
133
134 uint32_t
135 _pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
136                                pixman_fixed_48_16_t      x)
137 {
138     int dist, idist;
139     uint32_t t1, t2, a, color;
140
141     if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
142         gradient_walker_reset (walker, x);
143
144     dist  = ((int)(x - walker->left_x) * walker->stepper) >> 16;
145     idist = 256 - dist;
146
147     /* combined INTERPOLATE and premultiply */
148     t1 = walker->left_rb * idist + walker->right_rb * dist;
149     t1 = (t1 >> 8) & 0xff00ff;
150
151     t2  = walker->left_ag * idist + walker->right_ag * dist;
152     t2 &= 0xff00ff00;
153
154     color = t2 & 0xff000000;
155     a     = t2 >> 24;
156
157     t1  = t1 * a + 0x800080;
158     t1  = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8;
159
160     t2  = (t2 >> 8) * a + 0x800080;
161     t2  = (t2 + ((t2 >> 8) & 0xff00ff));
162
163     return (color | (t1 & 0xff00ff) | (t2 & 0xff00));
164 }
165