|
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 <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 { |
|
38 double t; |
|
39 |
|
40 t = atan2 (y, x) + angle; |
|
41 |
|
42 while (t < 0) |
|
43 t += 2 * M_PI; |
|
44 |
|
45 while (t >= 2 * M_PI) |
|
46 t -= 2 * M_PI; |
|
47 |
|
48 return 1 - t * (1 / (2 * M_PI)); /* Scale t to [0, 1] and |
|
49 * make rotation CCW |
|
50 */ |
|
51 } |
|
52 |
|
53 static uint32_t * |
|
54 conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask) |
|
55 { |
|
56 pixman_image_t *image = iter->image; |
|
57 int x = iter->x; |
|
58 int y = iter->y; |
|
59 int width = iter->width; |
|
60 uint32_t *buffer = iter->buffer; |
|
61 |
|
62 gradient_t *gradient = (gradient_t *)image; |
|
63 conical_gradient_t *conical = (conical_gradient_t *)image; |
|
64 uint32_t *end = buffer + width; |
|
65 pixman_gradient_walker_t walker; |
|
66 pixman_bool_t affine = TRUE; |
|
67 double cx = 1.; |
|
68 double cy = 0.; |
|
69 double cz = 0.; |
|
70 double rx = x + 0.5; |
|
71 double ry = y + 0.5; |
|
72 double rz = 1.; |
|
73 |
|
74 _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); |
|
75 |
|
76 if (image->common.transform) |
|
77 { |
|
78 pixman_vector_t v; |
|
79 |
|
80 /* reference point is the center of the pixel */ |
|
81 v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; |
|
82 v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; |
|
83 v.vector[2] = pixman_fixed_1; |
|
84 |
|
85 if (!pixman_transform_point_3d (image->common.transform, &v)) |
|
86 return iter->buffer; |
|
87 |
|
88 cx = image->common.transform->matrix[0][0] / 65536.; |
|
89 cy = image->common.transform->matrix[1][0] / 65536.; |
|
90 cz = image->common.transform->matrix[2][0] / 65536.; |
|
91 |
|
92 rx = v.vector[0] / 65536.; |
|
93 ry = v.vector[1] / 65536.; |
|
94 rz = v.vector[2] / 65536.; |
|
95 |
|
96 affine = |
|
97 image->common.transform->matrix[2][0] == 0 && |
|
98 v.vector[2] == pixman_fixed_1; |
|
99 } |
|
100 |
|
101 if (affine) |
|
102 { |
|
103 rx -= conical->center.x / 65536.; |
|
104 ry -= conical->center.y / 65536.; |
|
105 |
|
106 while (buffer < end) |
|
107 { |
|
108 if (!mask || *mask++) |
|
109 { |
|
110 double t = coordinates_to_parameter (rx, ry, conical->angle); |
|
111 |
|
112 *buffer = _pixman_gradient_walker_pixel ( |
|
113 &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t)); |
|
114 } |
|
115 |
|
116 ++buffer; |
|
117 |
|
118 rx += cx; |
|
119 ry += cy; |
|
120 } |
|
121 } |
|
122 else |
|
123 { |
|
124 while (buffer < end) |
|
125 { |
|
126 double x, y; |
|
127 |
|
128 if (!mask || *mask++) |
|
129 { |
|
130 double t; |
|
131 |
|
132 if (rz != 0) |
|
133 { |
|
134 x = rx / rz; |
|
135 y = ry / rz; |
|
136 } |
|
137 else |
|
138 { |
|
139 x = y = 0.; |
|
140 } |
|
141 |
|
142 x -= conical->center.x / 65536.; |
|
143 y -= conical->center.y / 65536.; |
|
144 |
|
145 t = coordinates_to_parameter (x, y, conical->angle); |
|
146 |
|
147 *buffer = _pixman_gradient_walker_pixel ( |
|
148 &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t)); |
|
149 } |
|
150 |
|
151 ++buffer; |
|
152 |
|
153 rx += cx; |
|
154 ry += cy; |
|
155 rz += cz; |
|
156 } |
|
157 } |
|
158 |
|
159 iter->y++; |
|
160 return iter->buffer; |
|
161 } |
|
162 |
|
163 static uint32_t * |
|
164 conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) |
|
165 { |
|
166 uint32_t *buffer = conical_get_scanline_narrow (iter, NULL); |
|
167 |
|
168 pixman_expand_to_float ( |
|
169 (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); |
|
170 |
|
171 return buffer; |
|
172 } |
|
173 |
|
174 void |
|
175 _pixman_conical_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
|
176 { |
|
177 if (iter->iter_flags & ITER_NARROW) |
|
178 iter->get_scanline = conical_get_scanline_narrow; |
|
179 else |
|
180 iter->get_scanline = conical_get_scanline_wide; |
|
181 } |
|
182 |
|
183 PIXMAN_EXPORT pixman_image_t * |
|
184 pixman_image_create_conical_gradient (const pixman_point_fixed_t * center, |
|
185 pixman_fixed_t angle, |
|
186 const pixman_gradient_stop_t *stops, |
|
187 int n_stops) |
|
188 { |
|
189 pixman_image_t *image = _pixman_image_allocate (); |
|
190 conical_gradient_t *conical; |
|
191 |
|
192 if (!image) |
|
193 return NULL; |
|
194 |
|
195 conical = &image->conical; |
|
196 |
|
197 if (!_pixman_init_gradient (&conical->common, stops, n_stops)) |
|
198 { |
|
199 free (image); |
|
200 return NULL; |
|
201 } |
|
202 |
|
203 angle = MOD (angle, pixman_int_to_fixed (360)); |
|
204 |
|
205 image->type = CONICAL; |
|
206 |
|
207 conical->center = *center; |
|
208 conical->angle = (pixman_fixed_to_double (angle) / 180.0) * M_PI; |
|
209 |
|
210 return image; |
|
211 } |
|
212 |