1 /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
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
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.
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
32 #include "pixman-private.h"
35 linear_gradient_is_horizontal (pixman_image_t
*image
,
41 linear_gradient_t
*linear
= (linear_gradient_t
*)image
;
43 pixman_fixed_32_32_t l
;
44 pixman_fixed_48_16_t dx
, dy
;
47 if (image
->common
.transform
)
49 /* projective transformation */
50 if (image
->common
.transform
->matrix
[2][0] != 0 ||
51 image
->common
.transform
->matrix
[2][1] != 0 ||
52 image
->common
.transform
->matrix
[2][2] == 0)
57 v
.vector
[0] = image
->common
.transform
->matrix
[0][1];
58 v
.vector
[1] = image
->common
.transform
->matrix
[1][1];
59 v
.vector
[2] = image
->common
.transform
->matrix
[2][2];
64 v
.vector
[1] = pixman_fixed_1
;
65 v
.vector
[2] = pixman_fixed_1
;
68 dx
= linear
->p2
.x
- linear
->p1
.x
;
69 dy
= linear
->p2
.y
- linear
->p1
.y
;
71 l
= dx
* dx
+ dy
* dy
;
77 * compute how much the input of the gradient walked changes
78 * when moving vertically through the whole image
80 inc
= height
* (double) pixman_fixed_1
* pixman_fixed_1
*
81 (dx
* v
.vector
[0] + dy
* v
.vector
[1]) /
82 (v
.vector
[2] * (double) l
);
84 /* check that casting to integer would result in 0 */
85 if (-1 < inc
&& inc
< 1)
92 linear_get_scanline_narrow (pixman_iter_t
*iter
,
95 pixman_image_t
*image
= iter
->image
;
98 int width
= iter
->width
;
99 uint32_t * buffer
= iter
->buffer
;
101 pixman_vector_t v
, unit
;
102 pixman_fixed_32_32_t l
;
103 pixman_fixed_48_16_t dx
, dy
;
104 gradient_t
*gradient
= (gradient_t
*)image
;
105 linear_gradient_t
*linear
= (linear_gradient_t
*)image
;
106 uint32_t *end
= buffer
+ width
;
107 pixman_gradient_walker_t walker
;
109 _pixman_gradient_walker_init (&walker
, gradient
, image
->common
.repeat
);
111 /* reference point is the center of the pixel */
112 v
.vector
[0] = pixman_int_to_fixed (x
) + pixman_fixed_1
/ 2;
113 v
.vector
[1] = pixman_int_to_fixed (y
) + pixman_fixed_1
/ 2;
114 v
.vector
[2] = pixman_fixed_1
;
116 if (image
->common
.transform
)
118 if (!pixman_transform_point_3d (image
->common
.transform
, &v
))
121 unit
.vector
[0] = image
->common
.transform
->matrix
[0][0];
122 unit
.vector
[1] = image
->common
.transform
->matrix
[1][0];
123 unit
.vector
[2] = image
->common
.transform
->matrix
[2][0];
127 unit
.vector
[0] = pixman_fixed_1
;
132 dx
= linear
->p2
.x
- linear
->p1
.x
;
133 dy
= linear
->p2
.y
- linear
->p1
.y
;
135 l
= dx
* dx
+ dy
* dy
;
137 if (l
== 0 || unit
.vector
[2] == 0)
139 /* affine transformation only */
140 pixman_fixed_32_32_t t
, next_inc
;
143 if (l
== 0 || v
.vector
[2] == 0)
152 invden
= pixman_fixed_1
* (double) pixman_fixed_1
/
153 (l
* (double) v
.vector
[2]);
154 v2
= v
.vector
[2] * (1. / pixman_fixed_1
);
155 t
= ((dx
* v
.vector
[0] + dy
* v
.vector
[1]) -
156 (dx
* linear
->p1
.x
+ dy
* linear
->p1
.y
) * v2
) * invden
;
157 inc
= (dx
* unit
.vector
[0] + dy
* unit
.vector
[1]) * invden
;
161 if (((pixman_fixed_32_32_t
)(inc
* width
)) == 0)
163 register uint32_t color
;
165 color
= _pixman_gradient_walker_pixel (&walker
, t
);
176 if (!mask
|| *mask
++)
178 *buffer
= _pixman_gradient_walker_pixel (&walker
,
189 /* projective transformation */
196 if (!mask
|| *mask
++)
198 if (v
.vector
[2] != 0)
202 invden
= pixman_fixed_1
* (double) pixman_fixed_1
/
203 (l
* (double) v
.vector
[2]);
204 v2
= v
.vector
[2] * (1. / pixman_fixed_1
);
205 t
= ((dx
* v
.vector
[0] + dy
* v
.vector
[1]) -
206 (dx
* linear
->p1
.x
+ dy
* linear
->p1
.y
) * v2
) * invden
;
209 *buffer
= _pixman_gradient_walker_pixel (&walker
, t
);
214 v
.vector
[0] += unit
.vector
[0];
215 v
.vector
[1] += unit
.vector
[1];
216 v
.vector
[2] += unit
.vector
[2];
226 linear_get_scanline_wide (pixman_iter_t
*iter
, const uint32_t *mask
)
228 uint32_t *buffer
= linear_get_scanline_narrow (iter
, NULL
);
230 pixman_expand_to_float (
231 (argb_t
*)buffer
, buffer
, PIXMAN_a8r8g8b8
, iter
->width
);
237 _pixman_linear_gradient_iter_init (pixman_image_t
*image
, pixman_iter_t
*iter
)
239 if (linear_gradient_is_horizontal (
240 iter
->image
, iter
->x
, iter
->y
, iter
->width
, iter
->height
))
242 if (iter
->iter_flags
& ITER_NARROW
)
243 linear_get_scanline_narrow (iter
, NULL
);
245 linear_get_scanline_wide (iter
, NULL
);
247 iter
->get_scanline
= _pixman_iter_get_scanline_noop
;
251 if (iter
->iter_flags
& ITER_NARROW
)
252 iter
->get_scanline
= linear_get_scanline_narrow
;
254 iter
->get_scanline
= linear_get_scanline_wide
;
258 PIXMAN_EXPORT pixman_image_t
*
259 pixman_image_create_linear_gradient (const pixman_point_fixed_t
* p1
,
260 const pixman_point_fixed_t
* p2
,
261 const pixman_gradient_stop_t
*stops
,
264 pixman_image_t
*image
;
265 linear_gradient_t
*linear
;
267 image
= _pixman_image_allocate ();
272 linear
= &image
->linear
;
274 if (!_pixman_init_gradient (&linear
->common
, stops
, n_stops
))
283 image
->type
= LINEAR
;