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