Line data Source code
1 : /*
2 : *
3 : * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
4 : * 2005 Lars Knoll & Zack Rusin, Trolltech
5 : *
6 : * Permission to use, copy, modify, distribute, and sell this software and its
7 : * documentation for any purpose is hereby granted without fee, provided that
8 : * the above copyright notice appear in all copies and that both that
9 : * copyright notice and this permission notice appear in supporting
10 : * documentation, and that the name of Keith Packard not be used in
11 : * advertising or publicity pertaining to distribution of the software without
12 : * specific, written prior permission. Keith Packard makes no
13 : * representations about the suitability of this software for any purpose. It
14 : * is provided "as is" without express or implied warranty.
15 : *
16 : * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17 : * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 : * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 : * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
21 : * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
22 : * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23 : * SOFTWARE.
24 : */
25 :
26 : #ifdef HAVE_CONFIG_H
27 : #include <config.h>
28 : #endif
29 : #include "pixman-private.h"
30 :
31 : void
32 0 : _pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
33 : gradient_t * gradient,
34 : pixman_repeat_t repeat)
35 : {
36 0 : walker->num_stops = gradient->n_stops;
37 0 : walker->stops = gradient->stops;
38 0 : walker->left_x = 0;
39 0 : walker->right_x = 0x10000;
40 0 : walker->stepper = 0;
41 0 : walker->left_ag = 0;
42 0 : walker->left_rb = 0;
43 0 : walker->right_ag = 0;
44 0 : walker->right_rb = 0;
45 0 : walker->repeat = repeat;
46 :
47 0 : walker->need_reset = TRUE;
48 0 : }
49 :
50 : static void
51 0 : gradient_walker_reset (pixman_gradient_walker_t *walker,
52 : pixman_fixed_48_16_t pos)
53 : {
54 : int32_t x, left_x, right_x;
55 : pixman_color_t *left_c, *right_c;
56 0 : int n, count = walker->num_stops;
57 0 : pixman_gradient_stop_t *stops = walker->stops;
58 :
59 0 : if (walker->repeat == PIXMAN_REPEAT_NORMAL)
60 : {
61 0 : x = (int32_t)pos & 0xffff;
62 : }
63 0 : else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
64 : {
65 0 : x = (int32_t)pos & 0xffff;
66 0 : if ((int32_t)pos & 0x10000)
67 0 : x = 0x10000 - x;
68 : }
69 : else
70 : {
71 0 : x = pos;
72 : }
73 :
74 0 : for (n = 0; n < count; n++)
75 : {
76 0 : if (x < stops[n].x)
77 0 : break;
78 : }
79 :
80 0 : left_x = stops[n - 1].x;
81 0 : left_c = &stops[n - 1].color;
82 :
83 0 : right_x = stops[n].x;
84 0 : right_c = &stops[n].color;
85 :
86 0 : if (walker->repeat == PIXMAN_REPEAT_NORMAL)
87 : {
88 0 : left_x += (pos - x);
89 0 : right_x += (pos - x);
90 : }
91 0 : else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
92 : {
93 0 : if ((int32_t)pos & 0x10000)
94 : {
95 : pixman_color_t *tmp_c;
96 : int32_t tmp_x;
97 :
98 0 : tmp_x = 0x10000 - right_x;
99 0 : right_x = 0x10000 - left_x;
100 0 : left_x = tmp_x;
101 :
102 0 : tmp_c = right_c;
103 0 : right_c = left_c;
104 0 : left_c = tmp_c;
105 :
106 0 : x = 0x10000 - x;
107 : }
108 0 : left_x += (pos - x);
109 0 : right_x += (pos - x);
110 : }
111 0 : else if (walker->repeat == PIXMAN_REPEAT_NONE)
112 : {
113 0 : if (n == 0)
114 0 : right_c = left_c;
115 0 : else if (n == count)
116 0 : left_c = right_c;
117 : }
118 :
119 0 : walker->left_x = left_x;
120 0 : walker->right_x = right_x;
121 0 : walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8);
122 0 : walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8);
123 0 : walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8);
124 0 : walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8);
125 :
126 0 : if (walker->left_x == walker->right_x ||
127 0 : (walker->left_ag == walker->right_ag &&
128 0 : walker->left_rb == walker->right_rb))
129 : {
130 0 : walker->stepper = 0;
131 : }
132 : else
133 : {
134 0 : int32_t width = right_x - left_x;
135 0 : walker->stepper = ((1 << 24) + width / 2) / width;
136 : }
137 :
138 0 : walker->need_reset = FALSE;
139 0 : }
140 :
141 : uint32_t
142 0 : _pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
143 : pixman_fixed_48_16_t x)
144 : {
145 : int dist, idist;
146 : uint32_t t1, t2, a, color;
147 :
148 0 : if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
149 0 : gradient_walker_reset (walker, x);
150 :
151 0 : dist = ((int)(x - walker->left_x) * walker->stepper) >> 16;
152 0 : idist = 256 - dist;
153 :
154 : /* combined INTERPOLATE and premultiply */
155 0 : t1 = walker->left_rb * idist + walker->right_rb * dist;
156 0 : t1 = (t1 >> 8) & 0xff00ff;
157 :
158 0 : t2 = walker->left_ag * idist + walker->right_ag * dist;
159 0 : t2 &= 0xff00ff00;
160 :
161 0 : color = t2 & 0xff000000;
162 0 : a = t2 >> 24;
163 :
164 0 : t1 = t1 * a + 0x800080;
165 0 : t1 = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8;
166 :
167 0 : t2 = (t2 >> 8) * a + 0x800080;
168 0 : t2 = (t2 + ((t2 >> 8) & 0xff00ff));
169 :
170 0 : return (color | (t1 & 0xff00ff) | (t2 & 0xff00));
171 : }
172 :
|