/src/cairo/subprojects/pixman-0.43.4/pixman/pixman-gradient-walker.c
Line | Count | Source (jump to first uncovered line) |
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 <pixman-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 | 2.11k | { |
36 | 2.11k | walker->num_stops = gradient->n_stops; |
37 | 2.11k | walker->stops = gradient->stops; |
38 | 2.11k | walker->left_x = 0; |
39 | 2.11k | walker->right_x = 0x10000; |
40 | 2.11k | walker->a_s = 0.0f; |
41 | 2.11k | walker->a_b = 0.0f; |
42 | 2.11k | walker->r_s = 0.0f; |
43 | 2.11k | walker->r_b = 0.0f; |
44 | 2.11k | walker->g_s = 0.0f; |
45 | 2.11k | walker->g_b = 0.0f; |
46 | 2.11k | walker->b_s = 0.0f; |
47 | 2.11k | walker->b_b = 0.0f; |
48 | 2.11k | walker->repeat = repeat; |
49 | | |
50 | 2.11k | walker->need_reset = TRUE; |
51 | 2.11k | } |
52 | | |
53 | | static void |
54 | | gradient_walker_reset (pixman_gradient_walker_t *walker, |
55 | | pixman_fixed_48_16_t pos) |
56 | 2.11k | { |
57 | 2.11k | int64_t x, left_x, right_x; |
58 | 2.11k | pixman_color_t *left_c, *right_c; |
59 | 2.11k | int n, count = walker->num_stops; |
60 | 2.11k | pixman_gradient_stop_t *stops = walker->stops; |
61 | 2.11k | float la, lr, lg, lb; |
62 | 2.11k | float ra, rr, rg, rb; |
63 | 2.11k | float lx, rx; |
64 | | |
65 | 2.11k | if (walker->repeat == PIXMAN_REPEAT_NORMAL) |
66 | 0 | { |
67 | 0 | x = (int32_t)pos & 0xffff; |
68 | 0 | } |
69 | 2.11k | else if (walker->repeat == PIXMAN_REPEAT_REFLECT) |
70 | 0 | { |
71 | 0 | x = (int32_t)pos & 0xffff; |
72 | 0 | if ((int32_t)pos & 0x10000) |
73 | 0 | x = 0x10000 - x; |
74 | 0 | } |
75 | 2.11k | else |
76 | 2.11k | { |
77 | 2.11k | x = pos; |
78 | 2.11k | } |
79 | | |
80 | 5.44k | for (n = 0; n < count; n++) |
81 | 3.34k | { |
82 | 3.34k | if (x < stops[n].x) |
83 | 15 | break; |
84 | 3.34k | } |
85 | | |
86 | 2.11k | left_x = stops[n - 1].x; |
87 | 2.11k | left_c = &stops[n - 1].color; |
88 | | |
89 | 2.11k | right_x = stops[n].x; |
90 | 2.11k | right_c = &stops[n].color; |
91 | | |
92 | 2.11k | if (walker->repeat == PIXMAN_REPEAT_NORMAL) |
93 | 0 | { |
94 | 0 | left_x += (pos - x); |
95 | 0 | right_x += (pos - x); |
96 | 0 | } |
97 | 2.11k | else if (walker->repeat == PIXMAN_REPEAT_REFLECT) |
98 | 0 | { |
99 | 0 | if ((int32_t)pos & 0x10000) |
100 | 0 | { |
101 | 0 | pixman_color_t *tmp_c; |
102 | 0 | int32_t tmp_x; |
103 | |
|
104 | 0 | tmp_x = 0x10000 - right_x; |
105 | 0 | right_x = 0x10000 - left_x; |
106 | 0 | left_x = tmp_x; |
107 | |
|
108 | 0 | tmp_c = right_c; |
109 | 0 | right_c = left_c; |
110 | 0 | left_c = tmp_c; |
111 | |
|
112 | 0 | x = 0x10000 - x; |
113 | 0 | } |
114 | 0 | left_x += (pos - x); |
115 | 0 | right_x += (pos - x); |
116 | 0 | } |
117 | 2.11k | else if (walker->repeat == PIXMAN_REPEAT_NONE) |
118 | 0 | { |
119 | 0 | if (n == 0) |
120 | 0 | right_c = left_c; |
121 | 0 | else if (n == count) |
122 | 0 | left_c = right_c; |
123 | 0 | } |
124 | | |
125 | | /* The alpha/red/green/blue channels are scaled to be in [0, 1]. |
126 | | * This ensures that after premultiplication all channels will |
127 | | * be in the [0, 1] interval. |
128 | | */ |
129 | 2.11k | la = (left_c->alpha * (1.0f/257.0f)); |
130 | 2.11k | lr = (left_c->red * (1.0f/257.0f)); |
131 | 2.11k | lg = (left_c->green * (1.0f/257.0f)); |
132 | 2.11k | lb = (left_c->blue * (1.0f/257.0f)); |
133 | | |
134 | 2.11k | ra = (right_c->alpha * (1.0f/257.0f)); |
135 | 2.11k | rr = (right_c->red * (1.0f/257.0f)); |
136 | 2.11k | rg = (right_c->green * (1.0f/257.0f)); |
137 | 2.11k | rb = (right_c->blue * (1.0f/257.0f)); |
138 | | |
139 | 2.11k | lx = left_x * (1.0f/65536.0f); |
140 | 2.11k | rx = right_x * (1.0f/65536.0f); |
141 | | |
142 | 2.11k | if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX) |
143 | 2.11k | { |
144 | 2.11k | walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f; |
145 | 2.11k | walker->a_b = (la + ra) / 510.0f; |
146 | 2.11k | walker->r_b = (lr + rr) / 510.0f; |
147 | 2.11k | walker->g_b = (lg + rg) / 510.0f; |
148 | 2.11k | walker->b_b = (lb + rb) / 510.0f; |
149 | 2.11k | } |
150 | 0 | else |
151 | 0 | { |
152 | 0 | float w_rec = 1.0f / (rx - lx); |
153 | |
|
154 | 0 | walker->a_b = (la * rx - ra * lx) * w_rec * (1.0f/255.0f); |
155 | 0 | walker->r_b = (lr * rx - rr * lx) * w_rec * (1.0f/255.0f); |
156 | 0 | walker->g_b = (lg * rx - rg * lx) * w_rec * (1.0f/255.0f); |
157 | 0 | walker->b_b = (lb * rx - rb * lx) * w_rec * (1.0f/255.0f); |
158 | |
|
159 | 0 | walker->a_s = (ra - la) * w_rec * (1.0f/255.0f); |
160 | 0 | walker->r_s = (rr - lr) * w_rec * (1.0f/255.0f); |
161 | 0 | walker->g_s = (rg - lg) * w_rec * (1.0f/255.0f); |
162 | 0 | walker->b_s = (rb - lb) * w_rec * (1.0f/255.0f); |
163 | 0 | } |
164 | | |
165 | 2.11k | walker->left_x = left_x; |
166 | 2.11k | walker->right_x = right_x; |
167 | | |
168 | 2.11k | walker->need_reset = FALSE; |
169 | 2.11k | } |
170 | | |
171 | | static argb_t |
172 | | pixman_gradient_walker_pixel_float (pixman_gradient_walker_t *walker, |
173 | | pixman_fixed_48_16_t x) |
174 | 0 | { |
175 | 0 | argb_t f; |
176 | 0 | float y; |
177 | |
|
178 | 0 | if (walker->need_reset || x < walker->left_x || x >= walker->right_x) |
179 | 0 | gradient_walker_reset (walker, x); |
180 | |
|
181 | 0 | y = x * (1.0f / 65536.0f); |
182 | |
|
183 | 0 | f.a = walker->a_s * y + walker->a_b; |
184 | 0 | f.r = f.a * (walker->r_s * y + walker->r_b); |
185 | 0 | f.g = f.a * (walker->g_s * y + walker->g_b); |
186 | 0 | f.b = f.a * (walker->b_s * y + walker->b_b); |
187 | |
|
188 | 0 | return f; |
189 | 0 | } |
190 | | |
191 | | static uint32_t |
192 | | pixman_gradient_walker_pixel_32 (pixman_gradient_walker_t *walker, |
193 | | pixman_fixed_48_16_t x) |
194 | 2.11k | { |
195 | 2.11k | argb_t f; |
196 | 2.11k | float y; |
197 | | |
198 | 2.11k | if (walker->need_reset || x < walker->left_x || x >= walker->right_x) |
199 | 2.11k | gradient_walker_reset (walker, x); |
200 | | |
201 | 2.11k | y = x * (1.0f / 65536.0f); |
202 | | |
203 | | /* Instead of [0...1] for ARGB, we want [0...255], |
204 | | * multiply alpha with 255 and the color channels |
205 | | * also get multiplied by the alpha multiplier. |
206 | | * |
207 | | * We don't use pixman_contract_from_float because it causes a 2x |
208 | | * slowdown to do so, and the values are already normalized, |
209 | | * so we don't have to worry about values < 0.f or > 1.f |
210 | | */ |
211 | 2.11k | f.a = 255.f * (walker->a_s * y + walker->a_b); |
212 | 2.11k | f.r = f.a * (walker->r_s * y + walker->r_b); |
213 | 2.11k | f.g = f.a * (walker->g_s * y + walker->g_b); |
214 | 2.11k | f.b = f.a * (walker->b_s * y + walker->b_b); |
215 | | |
216 | 2.11k | return (((uint32_t)(f.a + .5f) << 24) & 0xff000000) | |
217 | 2.11k | (((uint32_t)(f.r + .5f) << 16) & 0x00ff0000) | |
218 | 2.11k | (((uint32_t)(f.g + .5f) << 8) & 0x0000ff00) | |
219 | 2.11k | (((uint32_t)(f.b + .5f) >> 0) & 0x000000ff); |
220 | 2.11k | } |
221 | | |
222 | | void |
223 | | _pixman_gradient_walker_write_narrow (pixman_gradient_walker_t *walker, |
224 | | pixman_fixed_48_16_t x, |
225 | | uint32_t *buffer) |
226 | 2.11k | { |
227 | 2.11k | *buffer = pixman_gradient_walker_pixel_32 (walker, x); |
228 | 2.11k | } |
229 | | |
230 | | void |
231 | | _pixman_gradient_walker_write_wide (pixman_gradient_walker_t *walker, |
232 | | pixman_fixed_48_16_t x, |
233 | | uint32_t *buffer) |
234 | 0 | { |
235 | 0 | *(argb_t *)buffer = pixman_gradient_walker_pixel_float (walker, x); |
236 | 0 | } |
237 | | |
238 | | void |
239 | | _pixman_gradient_walker_fill_narrow (pixman_gradient_walker_t *walker, |
240 | | pixman_fixed_48_16_t x, |
241 | | uint32_t *buffer, |
242 | | uint32_t *end) |
243 | 0 | { |
244 | 0 | register uint32_t color; |
245 | |
|
246 | 0 | color = pixman_gradient_walker_pixel_32 (walker, x); |
247 | 0 | while (buffer < end) |
248 | 0 | *buffer++ = color; |
249 | 0 | } |
250 | | |
251 | | void |
252 | | _pixman_gradient_walker_fill_wide (pixman_gradient_walker_t *walker, |
253 | | pixman_fixed_48_16_t x, |
254 | | uint32_t *buffer, |
255 | | uint32_t *end) |
256 | 0 | { |
257 | 0 | register argb_t color; |
258 | 0 | argb_t *buffer_wide = (argb_t *)buffer; |
259 | 0 | argb_t *end_wide = (argb_t *)end; |
260 | |
|
261 | 0 | color = pixman_gradient_walker_pixel_float (walker, x); |
262 | 0 | while (buffer_wide < end_wide) |
263 | 0 | *buffer_wide++ = color; |
264 | 0 | } |