Add qemu 2.4.0
[kvmfornfv.git] / qemu / pixman / pixman / pixman-gradient-walker.c
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 _pixman_gradient_walker_init (pixman_gradient_walker_t *walker,
33                               gradient_t *              gradient,
34                               pixman_repeat_t           repeat)
35 {
36     walker->num_stops = gradient->n_stops;
37     walker->stops     = gradient->stops;
38     walker->left_x    = 0;
39     walker->right_x   = 0x10000;
40     walker->a_s       = 0.0f;
41     walker->a_b       = 0.0f;
42     walker->r_s       = 0.0f;
43     walker->r_b       = 0.0f;
44     walker->g_s       = 0.0f;
45     walker->g_b       = 0.0f;
46     walker->b_s       = 0.0f;
47     walker->b_b       = 0.0f;
48     walker->repeat    = repeat;
49
50     walker->need_reset = TRUE;
51 }
52
53 static void
54 gradient_walker_reset (pixman_gradient_walker_t *walker,
55                        pixman_fixed_48_16_t      pos)
56 {
57     int32_t x, left_x, right_x;
58     pixman_color_t *left_c, *right_c;
59     int n, count = walker->num_stops;
60     pixman_gradient_stop_t *stops = walker->stops;
61     float la, lr, lg, lb;
62     float ra, rr, rg, rb;
63     float lx, rx;
64
65     if (walker->repeat == PIXMAN_REPEAT_NORMAL)
66     {
67         x = (int32_t)pos & 0xffff;
68     }
69     else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
70     {
71         x = (int32_t)pos & 0xffff;
72         if ((int32_t)pos & 0x10000)
73             x = 0x10000 - x;
74     }
75     else
76     {
77         x = pos;
78     }
79     
80     for (n = 0; n < count; n++)
81     {
82         if (x < stops[n].x)
83             break;
84     }
85     
86     left_x =  stops[n - 1].x;
87     left_c = &stops[n - 1].color;
88     
89     right_x =  stops[n].x;
90     right_c = &stops[n].color;
91
92     if (walker->repeat == PIXMAN_REPEAT_NORMAL)
93     {
94         left_x  += (pos - x);
95         right_x += (pos - x);
96     }
97     else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
98     {
99         if ((int32_t)pos & 0x10000)
100         {
101             pixman_color_t  *tmp_c;
102             int32_t tmp_x;
103
104             tmp_x   = 0x10000 - right_x;
105             right_x = 0x10000 - left_x;
106             left_x  = tmp_x;
107
108             tmp_c   = right_c;
109             right_c = left_c;
110             left_c  = tmp_c;
111
112             x = 0x10000 - x;
113         }
114         left_x  += (pos - x);
115         right_x += (pos - x);
116     }
117     else if (walker->repeat == PIXMAN_REPEAT_NONE)
118     {
119         if (n == 0)
120             right_c = left_c;
121         else if (n == count)
122             left_c = right_c;
123     }
124
125     /* The alpha channel is scaled to be in the [0, 255] interval,
126      * and the red/green/blue channels are scaled to be in [0, 1].
127      * This ensures that after premultiplication all channels will
128      * be in the [0, 255] interval.
129      */
130     la = (left_c->alpha * (1.0f/257.0f));
131     lr = (left_c->red * (1.0f/257.0f));
132     lg = (left_c->green * (1.0f/257.0f));
133     lb = (left_c->blue * (1.0f/257.0f));
134
135     ra = (right_c->alpha * (1.0f/257.0f));
136     rr = (right_c->red * (1.0f/257.0f));
137     rg = (right_c->green * (1.0f/257.0f));
138     rb = (right_c->blue * (1.0f/257.0f));
139     
140     lx = left_x * (1.0f/65536.0f);
141     rx = right_x * (1.0f/65536.0f);
142     
143     if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX)
144     {
145         walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f;
146         walker->a_b = (la + ra) / 2.0f;
147         walker->r_b = (lr + rr) / 510.0f;
148         walker->g_b = (lg + rg) / 510.0f;
149         walker->b_b = (lb + rb) / 510.0f;
150     }
151     else
152     {
153         float w_rec = 1.0f / (rx - lx);
154
155         walker->a_b = (la * rx - ra * lx) * w_rec;
156         walker->r_b = (lr * rx - rr * lx) * w_rec * (1.0f/255.0f);
157         walker->g_b = (lg * rx - rg * lx) * w_rec * (1.0f/255.0f);
158         walker->b_b = (lb * rx - rb * lx) * w_rec * (1.0f/255.0f);
159
160         walker->a_s = (ra - la) * w_rec;
161         walker->r_s = (rr - lr) * w_rec * (1.0f/255.0f);
162         walker->g_s = (rg - lg) * w_rec * (1.0f/255.0f);
163         walker->b_s = (rb - lb) * w_rec * (1.0f/255.0f);
164     }
165    
166     walker->left_x = left_x;
167     walker->right_x = right_x;
168
169     walker->need_reset = FALSE;
170 }
171
172 uint32_t
173 _pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker,
174                                pixman_fixed_48_16_t      x)
175 {
176     float a, r, g, b;
177     uint8_t a8, r8, g8, b8;
178     uint32_t v;
179     float y;
180
181     if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
182         gradient_walker_reset (walker, x);
183
184     y = x * (1.0f / 65536.0f);
185
186     a = walker->a_s * y + walker->a_b;
187     r = a * (walker->r_s * y + walker->r_b);
188     g = a * (walker->g_s * y + walker->g_b);
189     b = a * (walker->b_s * y + walker->b_b);
190
191     a8 = a + 0.5f;
192     r8 = r + 0.5f;
193     g8 = g + 0.5f;
194     b8 = b + 0.5f;
195
196     v = ((a8 << 24) & 0xff000000) |
197         ((r8 << 16) & 0x00ff0000) |
198         ((g8 <<  8) & 0x0000ff00) |
199         ((b8 >>  0) & 0x000000ff);
200
201     return v;
202 }