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 0 : _pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
33 : gradient_t * gradient,
34 : unsigned int spread)
35 : {
36 0 : walker->num_stops = gradient->n_stops;
37 0 : walker->stops = gradient->stops;
38 0 : walker->left_x = 0;
39 0 : walker->right_x = 0x10000;
40 0 : walker->stepper = 0;
41 0 : walker->left_ag = 0;
42 0 : walker->left_rb = 0;
43 0 : walker->right_ag = 0;
44 0 : walker->right_rb = 0;
45 0 : walker->spread = spread;
46 :
47 0 : walker->need_reset = TRUE;
48 0 : }
49 :
50 : void
51 0 : _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 0 : int n, count = walker->num_stops;
57 0 : pixman_gradient_stop_t * stops = walker->stops;
58 :
59 : static const pixman_color_t transparent_black = { 0, 0, 0, 0 };
60 :
61 0 : switch (walker->spread)
62 : {
63 : case PIXMAN_REPEAT_NORMAL:
64 0 : x = (int32_t)pos & 0xFFFF;
65 0 : for (n = 0; n < count; n++)
66 0 : if (x < stops[n].x)
67 0 : break;
68 0 : if (n == 0)
69 : {
70 0 : left_x = stops[count - 1].x - 0x10000;
71 0 : left_c = &stops[count - 1].color;
72 : }
73 : else
74 : {
75 0 : left_x = stops[n - 1].x;
76 0 : left_c = &stops[n - 1].color;
77 : }
78 :
79 0 : if (n == count)
80 : {
81 0 : right_x = stops[0].x + 0x10000;
82 0 : right_c = &stops[0].color;
83 : }
84 : else
85 : {
86 0 : right_x = stops[n].x;
87 0 : right_c = &stops[n].color;
88 : }
89 0 : left_x += (pos - x);
90 0 : right_x += (pos - x);
91 0 : break;
92 :
93 : case PIXMAN_REPEAT_PAD:
94 0 : for (n = 0; n < count; n++)
95 0 : if (pos < stops[n].x)
96 0 : break;
97 :
98 0 : if (n == 0)
99 : {
100 0 : left_x = INT32_MIN;
101 0 : left_c = &stops[0].color;
102 : }
103 : else
104 : {
105 0 : left_x = stops[n - 1].x;
106 0 : left_c = &stops[n - 1].color;
107 : }
108 :
109 0 : if (n == count)
110 : {
111 0 : right_x = INT32_MAX;
112 0 : right_c = &stops[n - 1].color;
113 : }
114 : else
115 : {
116 0 : right_x = stops[n].x;
117 0 : right_c = &stops[n].color;
118 : }
119 0 : break;
120 :
121 : case PIXMAN_REPEAT_REFLECT:
122 0 : x = (int32_t)pos & 0xFFFF;
123 0 : if ((int32_t)pos & 0x10000)
124 0 : x = 0x10000 - x;
125 0 : for (n = 0; n < count; n++)
126 0 : if (x < stops[n].x)
127 0 : break;
128 :
129 0 : if (n == 0)
130 : {
131 0 : left_x = -stops[0].x;
132 0 : left_c = &stops[0].color;
133 : }
134 : else
135 : {
136 0 : left_x = stops[n - 1].x;
137 0 : left_c = &stops[n - 1].color;
138 : }
139 :
140 0 : if (n == count)
141 : {
142 0 : right_x = 0x20000 - stops[n - 1].x;
143 0 : right_c = &stops[n - 1].color;
144 : }
145 : else
146 : {
147 0 : right_x = stops[n].x;
148 0 : right_c = &stops[n].color;
149 : }
150 :
151 0 : if ((int32_t)pos & 0x10000)
152 : {
153 : pixman_color_t *tmp_c;
154 : int32_t tmp_x;
155 :
156 0 : tmp_x = 0x10000 - right_x;
157 0 : right_x = 0x10000 - left_x;
158 0 : left_x = tmp_x;
159 :
160 0 : tmp_c = right_c;
161 0 : right_c = left_c;
162 0 : left_c = tmp_c;
163 :
164 0 : x = 0x10000 - x;
165 : }
166 0 : left_x += (pos - x);
167 0 : right_x += (pos - x);
168 0 : break;
169 :
170 : default: /* REPEAT_NONE */
171 0 : for (n = 0; n < count; n++)
172 0 : if (pos < stops[n].x)
173 0 : break;
174 :
175 0 : if (n == 0)
176 : {
177 0 : left_x = INT32_MIN;
178 0 : right_x = stops[0].x;
179 0 : left_c = right_c = (pixman_color_t*) &transparent_black;
180 : }
181 0 : else if (n == count)
182 : {
183 0 : left_x = stops[n - 1].x;
184 0 : right_x = INT32_MAX;
185 0 : left_c = right_c = (pixman_color_t*) &transparent_black;
186 : }
187 : else
188 : {
189 0 : left_x = stops[n - 1].x;
190 0 : right_x = stops[n].x;
191 0 : left_c = &stops[n - 1].color;
192 0 : right_c = &stops[n].color;
193 : }
194 : }
195 :
196 0 : walker->left_x = left_x;
197 0 : walker->right_x = right_x;
198 0 : walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8);
199 0 : walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8);
200 0 : walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8);
201 0 : walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8);
202 :
203 0 : if (walker->left_x == walker->right_x ||
204 0 : ( walker->left_ag == walker->right_ag &&
205 0 : walker->left_rb == walker->right_rb ) )
206 : {
207 0 : walker->stepper = 0;
208 : }
209 : else
210 : {
211 0 : int32_t width = right_x - left_x;
212 0 : walker->stepper = ((1 << 24) + width / 2) / width;
213 : }
214 :
215 0 : walker->need_reset = FALSE;
216 0 : }
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 0 : _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 0 : if (PIXMAN_GRADIENT_WALKER_NEED_RESET (walker, x))
231 0 : _pixman_gradient_walker_reset (walker, x);
232 :
233 0 : dist = ((int)(x - walker->left_x) * walker->stepper) >> 16;
234 0 : idist = 256 - dist;
235 :
236 : /* combined INTERPOLATE and premultiply */
237 0 : t1 = walker->left_rb * idist + walker->right_rb * dist;
238 0 : t1 = (t1 >> 8) & 0xff00ff;
239 :
240 0 : t2 = walker->left_ag * idist + walker->right_ag * dist;
241 0 : t2 &= 0xff00ff00;
242 :
243 0 : color = t2 & 0xff000000;
244 0 : a = t2 >> 24;
245 :
246 0 : t1 = t1 * a + 0x800080;
247 0 : t1 = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8;
248 :
249 0 : t2 = (t2 >> 8) * a + 0x800080;
250 0 : t2 = (t2 + ((t2 >> 8) & 0xff00ff));
251 :
252 0 : return (color | (t1 & 0xff00ff) | (t2 & 0xff00));
253 : }
254 :
|