/src/cairo/subprojects/pixman-0.44.2/pixman/pixman-conical-gradient.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2000 SuSE, Inc. |
3 | | * Copyright © 2007 Red Hat, Inc. |
4 | | * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. |
5 | | * 2005 Lars Knoll & Zack Rusin, Trolltech |
6 | | * |
7 | | * Permission to use, copy, modify, distribute, and sell this software and its |
8 | | * documentation for any purpose is hereby granted without fee, provided that |
9 | | * the above copyright notice appear in all copies and that both that |
10 | | * copyright notice and this permission notice appear in supporting |
11 | | * documentation, and that the name of Keith Packard not be used in |
12 | | * advertising or publicity pertaining to distribution of the software without |
13 | | * specific, written prior permission. Keith Packard makes no |
14 | | * representations about the suitability of this software for any purpose. It |
15 | | * is provided "as is" without express or implied warranty. |
16 | | * |
17 | | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
18 | | * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
19 | | * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
20 | | * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
21 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN |
22 | | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
23 | | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
24 | | * SOFTWARE. |
25 | | */ |
26 | | |
27 | | #ifdef HAVE_CONFIG_H |
28 | | #include <pixman-config.h> |
29 | | #endif |
30 | | |
31 | | #include <stdlib.h> |
32 | | #include <math.h> |
33 | | #include "pixman-private.h" |
34 | | |
35 | | static force_inline double |
36 | | coordinates_to_parameter (double x, double y, double angle) |
37 | 0 | { |
38 | 0 | double t; |
39 | |
|
40 | 0 | t = atan2 (y, x) + angle; |
41 | |
|
42 | 0 | while (t < 0) |
43 | 0 | t += 2 * M_PI; |
44 | |
|
45 | 0 | while (t >= 2 * M_PI) |
46 | 0 | t -= 2 * M_PI; |
47 | |
|
48 | 0 | return 1 - t * (1 / (2 * M_PI)); /* Scale t to [0, 1] and |
49 | | * make rotation CCW |
50 | | */ |
51 | 0 | } |
52 | | |
53 | | static uint32_t * |
54 | | conical_get_scanline (pixman_iter_t *iter, |
55 | | const uint32_t *mask, |
56 | | int Bpp, |
57 | | pixman_gradient_walker_write_t write_pixel) |
58 | 0 | { |
59 | 0 | pixman_image_t *image = iter->image; |
60 | 0 | int x = iter->x; |
61 | 0 | int y = iter->y; |
62 | 0 | int width = iter->width; |
63 | 0 | uint32_t *buffer = iter->buffer; |
64 | |
|
65 | 0 | gradient_t *gradient = (gradient_t *)image; |
66 | 0 | conical_gradient_t *conical = (conical_gradient_t *)image; |
67 | 0 | uint32_t *end = buffer + width * (Bpp / 4); |
68 | 0 | pixman_gradient_walker_t walker; |
69 | 0 | pixman_bool_t affine = TRUE; |
70 | 0 | double cx = 1.; |
71 | 0 | double cy = 0.; |
72 | 0 | double cz = 0.; |
73 | 0 | double rx = x + 0.5; |
74 | 0 | double ry = y + 0.5; |
75 | 0 | double rz = 1.; |
76 | |
|
77 | 0 | _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); |
78 | |
|
79 | 0 | if (image->common.transform) |
80 | 0 | { |
81 | 0 | pixman_vector_t v; |
82 | | |
83 | | /* reference point is the center of the pixel */ |
84 | 0 | v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; |
85 | 0 | v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; |
86 | 0 | v.vector[2] = pixman_fixed_1; |
87 | |
|
88 | 0 | if (!pixman_transform_point_3d (image->common.transform, &v)) |
89 | 0 | return iter->buffer; |
90 | | |
91 | 0 | cx = image->common.transform->matrix[0][0] / 65536.; |
92 | 0 | cy = image->common.transform->matrix[1][0] / 65536.; |
93 | 0 | cz = image->common.transform->matrix[2][0] / 65536.; |
94 | |
|
95 | 0 | rx = v.vector[0] / 65536.; |
96 | 0 | ry = v.vector[1] / 65536.; |
97 | 0 | rz = v.vector[2] / 65536.; |
98 | |
|
99 | 0 | affine = |
100 | 0 | image->common.transform->matrix[2][0] == 0 && |
101 | 0 | v.vector[2] == pixman_fixed_1; |
102 | 0 | } |
103 | | |
104 | 0 | if (affine) |
105 | 0 | { |
106 | 0 | rx -= conical->center.x / 65536.; |
107 | 0 | ry -= conical->center.y / 65536.; |
108 | |
|
109 | 0 | while (buffer < end) |
110 | 0 | { |
111 | 0 | if (!mask || *mask++) |
112 | 0 | { |
113 | 0 | double t = coordinates_to_parameter (rx, ry, conical->angle); |
114 | |
|
115 | 0 | write_pixel (&walker, |
116 | 0 | (pixman_fixed_48_16_t)pixman_double_to_fixed (t), |
117 | 0 | buffer); |
118 | 0 | } |
119 | |
|
120 | 0 | buffer += (Bpp / 4); |
121 | |
|
122 | 0 | rx += cx; |
123 | 0 | ry += cy; |
124 | 0 | } |
125 | 0 | } |
126 | 0 | else |
127 | 0 | { |
128 | 0 | while (buffer < end) |
129 | 0 | { |
130 | 0 | double x, y; |
131 | |
|
132 | 0 | if (!mask || *mask++) |
133 | 0 | { |
134 | 0 | double t; |
135 | |
|
136 | 0 | if (rz != 0) |
137 | 0 | { |
138 | 0 | x = rx / rz; |
139 | 0 | y = ry / rz; |
140 | 0 | } |
141 | 0 | else |
142 | 0 | { |
143 | 0 | x = y = 0.; |
144 | 0 | } |
145 | |
|
146 | 0 | x -= conical->center.x / 65536.; |
147 | 0 | y -= conical->center.y / 65536.; |
148 | |
|
149 | 0 | t = coordinates_to_parameter (x, y, conical->angle); |
150 | |
|
151 | 0 | write_pixel (&walker, |
152 | 0 | (pixman_fixed_48_16_t)pixman_double_to_fixed (t), |
153 | 0 | buffer); |
154 | 0 | } |
155 | |
|
156 | 0 | buffer += (Bpp / 4); |
157 | |
|
158 | 0 | rx += cx; |
159 | 0 | ry += cy; |
160 | 0 | rz += cz; |
161 | 0 | } |
162 | 0 | } |
163 | |
|
164 | 0 | iter->y++; |
165 | 0 | return iter->buffer; |
166 | 0 | } |
167 | | |
168 | | static uint32_t * |
169 | | conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) |
170 | 0 | { |
171 | 0 | return conical_get_scanline (iter, mask, 4, |
172 | 0 | _pixman_gradient_walker_write_narrow); |
173 | 0 | } |
174 | | |
175 | | static uint32_t * |
176 | | conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) |
177 | 0 | { |
178 | 0 | return conical_get_scanline (iter, NULL, 16, |
179 | 0 | _pixman_gradient_walker_write_wide); |
180 | 0 | } |
181 | | |
182 | | void |
183 | | _pixman_conical_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
184 | 0 | { |
185 | 0 | if (iter->iter_flags & ITER_NARROW) |
186 | 0 | iter->get_scanline = conical_get_scanline_narrow; |
187 | 0 | else |
188 | 0 | iter->get_scanline = conical_get_scanline_wide; |
189 | 0 | } |
190 | | |
191 | | PIXMAN_EXPORT pixman_image_t * |
192 | | pixman_image_create_conical_gradient (const pixman_point_fixed_t * center, |
193 | | pixman_fixed_t angle, |
194 | | const pixman_gradient_stop_t *stops, |
195 | | int n_stops) |
196 | 0 | { |
197 | 0 | pixman_image_t *image = _pixman_image_allocate (); |
198 | 0 | conical_gradient_t *conical; |
199 | |
|
200 | 0 | if (!image) |
201 | 0 | return NULL; |
202 | | |
203 | 0 | conical = &image->conical; |
204 | |
|
205 | 0 | if (!_pixman_init_gradient (&conical->common, stops, n_stops)) |
206 | 0 | { |
207 | 0 | free (image); |
208 | 0 | return NULL; |
209 | 0 | } |
210 | | |
211 | 0 | angle = MOD (angle, pixman_int_to_fixed (360)); |
212 | |
|
213 | 0 | image->type = CONICAL; |
214 | |
|
215 | 0 | conical->center = *center; |
216 | 0 | conical->angle = (pixman_fixed_to_double (angle) / 180.0) * M_PI; |
217 | |
|
218 | 0 | return image; |
219 | 0 | } |
220 | | |