/src/cairo/subprojects/pixman-0.44.2/pixman/pixman-linear-gradient.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */ |
2 | | /* |
3 | | * Copyright © 2000 SuSE, Inc. |
4 | | * Copyright © 2007 Red Hat, Inc. |
5 | | * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. |
6 | | * 2005 Lars Knoll & Zack Rusin, Trolltech |
7 | | * |
8 | | * Permission to use, copy, modify, distribute, and sell this software and its |
9 | | * documentation for any purpose is hereby granted without fee, provided that |
10 | | * the above copyright notice appear in all copies and that both that |
11 | | * copyright notice and this permission notice appear in supporting |
12 | | * documentation, and that the name of Keith Packard not be used in |
13 | | * advertising or publicity pertaining to distribution of the software without |
14 | | * specific, written prior permission. Keith Packard makes no |
15 | | * representations about the suitability of this software for any purpose. It |
16 | | * is provided "as is" without express or implied warranty. |
17 | | * |
18 | | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
19 | | * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | | * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
21 | | * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
22 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN |
23 | | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
24 | | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
25 | | * SOFTWARE. |
26 | | */ |
27 | | |
28 | | #ifdef HAVE_CONFIG_H |
29 | | #include <pixman-config.h> |
30 | | #endif |
31 | | #include <stdlib.h> |
32 | | #include "pixman-private.h" |
33 | | |
34 | | static pixman_bool_t |
35 | | linear_gradient_is_horizontal (pixman_image_t *image, |
36 | | int x, |
37 | | int y, |
38 | | int width, |
39 | | int height) |
40 | 172 | { |
41 | 172 | linear_gradient_t *linear = (linear_gradient_t *)image; |
42 | 172 | pixman_vector_t v; |
43 | 172 | pixman_fixed_32_32_t l; |
44 | 172 | pixman_fixed_48_16_t dx, dy; |
45 | 172 | double inc; |
46 | | |
47 | 172 | if (image->common.transform) |
48 | 172 | { |
49 | | /* projective transformation */ |
50 | 172 | if (image->common.transform->matrix[2][0] != 0 || |
51 | 172 | image->common.transform->matrix[2][1] != 0 || |
52 | 172 | image->common.transform->matrix[2][2] == 0) |
53 | 0 | { |
54 | 0 | return FALSE; |
55 | 0 | } |
56 | | |
57 | 172 | v.vector[0] = image->common.transform->matrix[0][1]; |
58 | 172 | v.vector[1] = image->common.transform->matrix[1][1]; |
59 | 172 | v.vector[2] = image->common.transform->matrix[2][2]; |
60 | 172 | } |
61 | 0 | else |
62 | 0 | { |
63 | 0 | v.vector[0] = 0; |
64 | 0 | v.vector[1] = pixman_fixed_1; |
65 | 0 | v.vector[2] = pixman_fixed_1; |
66 | 0 | } |
67 | | |
68 | 172 | dx = linear->p2.x - linear->p1.x; |
69 | 172 | dy = linear->p2.y - linear->p1.y; |
70 | | |
71 | 172 | l = dx * dx + dy * dy; |
72 | | |
73 | 172 | if (l == 0) |
74 | 0 | return FALSE; |
75 | | |
76 | | /* |
77 | | * compute how much the input of the gradient walked changes |
78 | | * when moving vertically through the whole image |
79 | | */ |
80 | 172 | inc = height * (double) pixman_fixed_1 * pixman_fixed_1 * |
81 | 172 | (dx * v.vector[0] + dy * v.vector[1]) / |
82 | 172 | (v.vector[2] * (double) l); |
83 | | |
84 | | /* check that casting to integer would result in 0 */ |
85 | 172 | if (-1 < inc && inc < 1) |
86 | 0 | return TRUE; |
87 | | |
88 | 172 | return FALSE; |
89 | 172 | } |
90 | | |
91 | | static uint32_t * |
92 | | linear_get_scanline (pixman_iter_t *iter, |
93 | | const uint32_t *mask, |
94 | | int Bpp, |
95 | | pixman_gradient_walker_write_t write_pixel, |
96 | | pixman_gradient_walker_fill_t fill_pixel) |
97 | 172 | { |
98 | 172 | pixman_image_t *image = iter->image; |
99 | 172 | int x = iter->x; |
100 | 172 | int y = iter->y; |
101 | 172 | int width = iter->width; |
102 | 172 | uint32_t * buffer = iter->buffer; |
103 | | |
104 | 172 | pixman_vector_t v, unit; |
105 | 172 | pixman_fixed_32_32_t l; |
106 | 172 | pixman_fixed_48_16_t dx, dy; |
107 | 172 | gradient_t *gradient = (gradient_t *)image; |
108 | 172 | linear_gradient_t *linear = (linear_gradient_t *)image; |
109 | 172 | uint32_t *end = buffer + width * (Bpp / 4); |
110 | 172 | pixman_gradient_walker_t walker; |
111 | | |
112 | 172 | _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); |
113 | | |
114 | | /* reference point is the center of the pixel */ |
115 | 172 | v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; |
116 | 172 | v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; |
117 | 172 | v.vector[2] = pixman_fixed_1; |
118 | | |
119 | 172 | if (image->common.transform) |
120 | 172 | { |
121 | 172 | if (!pixman_transform_point_3d (image->common.transform, &v)) |
122 | 0 | return iter->buffer; |
123 | | |
124 | 172 | unit.vector[0] = image->common.transform->matrix[0][0]; |
125 | 172 | unit.vector[1] = image->common.transform->matrix[1][0]; |
126 | 172 | unit.vector[2] = image->common.transform->matrix[2][0]; |
127 | 172 | } |
128 | 0 | else |
129 | 0 | { |
130 | 0 | unit.vector[0] = pixman_fixed_1; |
131 | 0 | unit.vector[1] = 0; |
132 | 0 | unit.vector[2] = 0; |
133 | 0 | } |
134 | | |
135 | 172 | dx = linear->p2.x - linear->p1.x; |
136 | 172 | dy = linear->p2.y - linear->p1.y; |
137 | | |
138 | 172 | l = dx * dx + dy * dy; |
139 | | |
140 | 172 | if (l == 0 || unit.vector[2] == 0) |
141 | 172 | { |
142 | | /* affine transformation only */ |
143 | 172 | pixman_fixed_32_32_t t, next_inc; |
144 | 172 | double inc; |
145 | | |
146 | 172 | if (l == 0 || v.vector[2] == 0) |
147 | 0 | { |
148 | 0 | t = 0; |
149 | 0 | inc = 0; |
150 | 0 | } |
151 | 172 | else |
152 | 172 | { |
153 | 172 | double invden, v2; |
154 | | |
155 | 172 | invden = pixman_fixed_1 * (double) pixman_fixed_1 / |
156 | 172 | (l * (double) v.vector[2]); |
157 | 172 | v2 = v.vector[2] * (1. / pixman_fixed_1); |
158 | 172 | t = ((dx * v.vector[0] + dy * v.vector[1]) - |
159 | 172 | (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; |
160 | 172 | inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden; |
161 | 172 | } |
162 | 172 | next_inc = 0; |
163 | | |
164 | 172 | if (((pixman_fixed_32_32_t )(inc * width)) == 0) |
165 | 35 | { |
166 | 35 | fill_pixel (&walker, t, buffer, end); |
167 | 35 | } |
168 | 137 | else |
169 | 137 | { |
170 | 137 | int i; |
171 | | |
172 | 137 | i = 0; |
173 | 3.82k | while (buffer < end) |
174 | 3.68k | { |
175 | 3.68k | if (!mask || *mask++) |
176 | 3.68k | { |
177 | 3.68k | write_pixel (&walker, t + next_inc, buffer); |
178 | 3.68k | } |
179 | 3.68k | i++; |
180 | 3.68k | next_inc = inc * i; |
181 | 3.68k | buffer += (Bpp / 4); |
182 | 3.68k | } |
183 | 137 | } |
184 | 172 | } |
185 | 0 | else |
186 | 0 | { |
187 | | /* projective transformation */ |
188 | 0 | double t; |
189 | |
|
190 | 0 | t = 0; |
191 | |
|
192 | 0 | while (buffer < end) |
193 | 0 | { |
194 | 0 | if (!mask || *mask++) |
195 | 0 | { |
196 | 0 | if (v.vector[2] != 0) |
197 | 0 | { |
198 | 0 | double invden, v2; |
199 | |
|
200 | 0 | invden = pixman_fixed_1 * (double) pixman_fixed_1 / |
201 | 0 | (l * (double) v.vector[2]); |
202 | 0 | v2 = v.vector[2] * (1. / pixman_fixed_1); |
203 | 0 | t = ((dx * v.vector[0] + dy * v.vector[1]) - |
204 | 0 | (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden; |
205 | 0 | } |
206 | |
|
207 | 0 | write_pixel (&walker, t, buffer); |
208 | 0 | } |
209 | |
|
210 | 0 | buffer += (Bpp / 4); |
211 | |
|
212 | 0 | v.vector[0] += unit.vector[0]; |
213 | 0 | v.vector[1] += unit.vector[1]; |
214 | 0 | v.vector[2] += unit.vector[2]; |
215 | 0 | } |
216 | 0 | } |
217 | | |
218 | 172 | iter->y++; |
219 | | |
220 | 172 | return iter->buffer; |
221 | 172 | } |
222 | | |
223 | | static uint32_t * |
224 | | linear_get_scanline_narrow (pixman_iter_t *iter, |
225 | | const uint32_t *mask) |
226 | 172 | { |
227 | 172 | return linear_get_scanline (iter, mask, 4, |
228 | 172 | _pixman_gradient_walker_write_narrow, |
229 | 172 | _pixman_gradient_walker_fill_narrow); |
230 | 172 | } |
231 | | |
232 | | |
233 | | static uint32_t * |
234 | | linear_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) |
235 | 0 | { |
236 | 0 | return linear_get_scanline (iter, NULL, 16, |
237 | 0 | _pixman_gradient_walker_write_wide, |
238 | 0 | _pixman_gradient_walker_fill_wide); |
239 | 0 | } |
240 | | |
241 | | void |
242 | | _pixman_linear_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
243 | 172 | { |
244 | 172 | if (linear_gradient_is_horizontal ( |
245 | 172 | iter->image, iter->x, iter->y, iter->width, iter->height)) |
246 | 0 | { |
247 | 0 | if (iter->iter_flags & ITER_NARROW) |
248 | 0 | linear_get_scanline_narrow (iter, NULL); |
249 | 0 | else |
250 | 0 | linear_get_scanline_wide (iter, NULL); |
251 | |
|
252 | 0 | iter->get_scanline = _pixman_iter_get_scanline_noop; |
253 | 0 | } |
254 | 172 | else |
255 | 172 | { |
256 | 172 | if (iter->iter_flags & ITER_NARROW) |
257 | 172 | iter->get_scanline = linear_get_scanline_narrow; |
258 | 0 | else |
259 | 0 | iter->get_scanline = linear_get_scanline_wide; |
260 | 172 | } |
261 | 172 | } |
262 | | |
263 | | PIXMAN_EXPORT pixman_image_t * |
264 | | pixman_image_create_linear_gradient (const pixman_point_fixed_t * p1, |
265 | | const pixman_point_fixed_t * p2, |
266 | | const pixman_gradient_stop_t *stops, |
267 | | int n_stops) |
268 | 4 | { |
269 | 4 | pixman_image_t *image; |
270 | 4 | linear_gradient_t *linear; |
271 | | |
272 | 4 | image = _pixman_image_allocate (); |
273 | | |
274 | 4 | if (!image) |
275 | 0 | return NULL; |
276 | | |
277 | 4 | linear = &image->linear; |
278 | | |
279 | 4 | if (!_pixman_init_gradient (&linear->common, stops, n_stops)) |
280 | 0 | { |
281 | 0 | free (image); |
282 | 0 | return NULL; |
283 | 0 | } |
284 | | |
285 | 4 | linear->p1 = *p1; |
286 | 4 | linear->p2 = *p2; |
287 | | |
288 | 4 | image->type = LINEAR; |
289 | | |
290 | 4 | return image; |
291 | 4 | } |
292 | | |