Coverage Report

Created: 2025-02-19 06:30

/src/cairo/subprojects/pixman-0.43.4/pixman/pixman-gradient-walker.c
Line
Count
Source (jump to first uncovered line)
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 <pixman-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
2.11k
{
36
2.11k
    walker->num_stops = gradient->n_stops;
37
2.11k
    walker->stops     = gradient->stops;
38
2.11k
    walker->left_x    = 0;
39
2.11k
    walker->right_x   = 0x10000;
40
2.11k
    walker->a_s       = 0.0f;
41
2.11k
    walker->a_b       = 0.0f;
42
2.11k
    walker->r_s       = 0.0f;
43
2.11k
    walker->r_b       = 0.0f;
44
2.11k
    walker->g_s       = 0.0f;
45
2.11k
    walker->g_b       = 0.0f;
46
2.11k
    walker->b_s       = 0.0f;
47
2.11k
    walker->b_b       = 0.0f;
48
2.11k
    walker->repeat    = repeat;
49
50
2.11k
    walker->need_reset = TRUE;
51
2.11k
}
52
53
static void
54
gradient_walker_reset (pixman_gradient_walker_t *walker,
55
           pixman_fixed_48_16_t      pos)
56
2.11k
{
57
2.11k
    int64_t x, left_x, right_x;
58
2.11k
    pixman_color_t *left_c, *right_c;
59
2.11k
    int n, count = walker->num_stops;
60
2.11k
    pixman_gradient_stop_t *stops = walker->stops;
61
2.11k
    float la, lr, lg, lb;
62
2.11k
    float ra, rr, rg, rb;
63
2.11k
    float lx, rx;
64
65
2.11k
    if (walker->repeat == PIXMAN_REPEAT_NORMAL)
66
0
    {
67
0
  x = (int32_t)pos & 0xffff;
68
0
    }
69
2.11k
    else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
70
0
    {
71
0
  x = (int32_t)pos & 0xffff;
72
0
  if ((int32_t)pos & 0x10000)
73
0
      x = 0x10000 - x;
74
0
    }
75
2.11k
    else
76
2.11k
    {
77
2.11k
  x = pos;
78
2.11k
    }
79
    
80
5.44k
    for (n = 0; n < count; n++)
81
3.34k
    {
82
3.34k
  if (x < stops[n].x)
83
15
      break;
84
3.34k
    }
85
    
86
2.11k
    left_x =  stops[n - 1].x;
87
2.11k
    left_c = &stops[n - 1].color;
88
    
89
2.11k
    right_x =  stops[n].x;
90
2.11k
    right_c = &stops[n].color;
91
92
2.11k
    if (walker->repeat == PIXMAN_REPEAT_NORMAL)
93
0
    {
94
0
  left_x  += (pos - x);
95
0
  right_x += (pos - x);
96
0
    }
97
2.11k
    else if (walker->repeat == PIXMAN_REPEAT_REFLECT)
98
0
    {
99
0
  if ((int32_t)pos & 0x10000)
100
0
  {
101
0
      pixman_color_t  *tmp_c;
102
0
      int32_t tmp_x;
103
104
0
      tmp_x   = 0x10000 - right_x;
105
0
      right_x = 0x10000 - left_x;
106
0
      left_x  = tmp_x;
107
108
0
      tmp_c   = right_c;
109
0
      right_c = left_c;
110
0
      left_c  = tmp_c;
111
112
0
      x = 0x10000 - x;
113
0
  }
114
0
  left_x  += (pos - x);
115
0
  right_x += (pos - x);
116
0
    }
117
2.11k
    else if (walker->repeat == PIXMAN_REPEAT_NONE)
118
0
    {
119
0
  if (n == 0)
120
0
      right_c = left_c;
121
0
  else if (n == count)
122
0
      left_c = right_c;
123
0
    }
124
125
    /* The alpha/red/green/blue channels are scaled to be in [0, 1].
126
     * This ensures that after premultiplication all channels will
127
     * be in the [0, 1] interval.
128
     */
129
2.11k
    la = (left_c->alpha * (1.0f/257.0f));
130
2.11k
    lr = (left_c->red * (1.0f/257.0f));
131
2.11k
    lg = (left_c->green * (1.0f/257.0f));
132
2.11k
    lb = (left_c->blue * (1.0f/257.0f));
133
134
2.11k
    ra = (right_c->alpha * (1.0f/257.0f));
135
2.11k
    rr = (right_c->red * (1.0f/257.0f));
136
2.11k
    rg = (right_c->green * (1.0f/257.0f));
137
2.11k
    rb = (right_c->blue * (1.0f/257.0f));
138
    
139
2.11k
    lx = left_x * (1.0f/65536.0f);
140
2.11k
    rx = right_x * (1.0f/65536.0f);
141
    
142
2.11k
    if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX)
143
2.11k
    {
144
2.11k
  walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f;
145
2.11k
  walker->a_b = (la + ra) / 510.0f;
146
2.11k
  walker->r_b = (lr + rr) / 510.0f;
147
2.11k
  walker->g_b = (lg + rg) / 510.0f;
148
2.11k
  walker->b_b = (lb + rb) / 510.0f;
149
2.11k
    }
150
0
    else
151
0
    {
152
0
  float w_rec = 1.0f / (rx - lx);
153
154
0
  walker->a_b = (la * rx - ra * lx) * w_rec * (1.0f/255.0f);
155
0
  walker->r_b = (lr * rx - rr * lx) * w_rec * (1.0f/255.0f);
156
0
  walker->g_b = (lg * rx - rg * lx) * w_rec * (1.0f/255.0f);
157
0
  walker->b_b = (lb * rx - rb * lx) * w_rec * (1.0f/255.0f);
158
159
0
  walker->a_s = (ra - la) * w_rec * (1.0f/255.0f);
160
0
  walker->r_s = (rr - lr) * w_rec * (1.0f/255.0f);
161
0
  walker->g_s = (rg - lg) * w_rec * (1.0f/255.0f);
162
0
  walker->b_s = (rb - lb) * w_rec * (1.0f/255.0f);
163
0
    }
164
   
165
2.11k
    walker->left_x = left_x;
166
2.11k
    walker->right_x = right_x;
167
168
2.11k
    walker->need_reset = FALSE;
169
2.11k
}
170
171
static argb_t
172
pixman_gradient_walker_pixel_float (pixman_gradient_walker_t *walker,
173
            pixman_fixed_48_16_t      x)
174
0
{
175
0
    argb_t f;
176
0
    float y;
177
178
0
    if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
179
0
  gradient_walker_reset (walker, x);
180
181
0
    y = x * (1.0f / 65536.0f);
182
183
0
    f.a = walker->a_s * y + walker->a_b;
184
0
    f.r = f.a * (walker->r_s * y + walker->r_b);
185
0
    f.g = f.a * (walker->g_s * y + walker->g_b);
186
0
    f.b = f.a * (walker->b_s * y + walker->b_b);
187
188
0
    return f;
189
0
}
190
191
static uint32_t
192
pixman_gradient_walker_pixel_32 (pixman_gradient_walker_t *walker,
193
         pixman_fixed_48_16_t      x)
194
2.11k
{
195
2.11k
    argb_t f;
196
2.11k
    float y;
197
198
2.11k
    if (walker->need_reset || x < walker->left_x || x >= walker->right_x)
199
2.11k
  gradient_walker_reset (walker, x);
200
201
2.11k
    y = x * (1.0f / 65536.0f);
202
203
    /* Instead of [0...1] for ARGB, we want [0...255],
204
     * multiply alpha with 255 and the color channels
205
     * also get multiplied by the alpha multiplier.
206
     *
207
     * We don't use pixman_contract_from_float because it causes a 2x
208
     * slowdown to do so, and the values are already normalized,
209
     * so we don't have to worry about values < 0.f or > 1.f
210
     */
211
2.11k
    f.a = 255.f * (walker->a_s * y + walker->a_b);
212
2.11k
    f.r = f.a * (walker->r_s * y + walker->r_b);
213
2.11k
    f.g = f.a * (walker->g_s * y + walker->g_b);
214
2.11k
    f.b = f.a * (walker->b_s * y + walker->b_b);
215
216
2.11k
    return (((uint32_t)(f.a + .5f) << 24) & 0xff000000) |
217
2.11k
           (((uint32_t)(f.r + .5f) << 16) & 0x00ff0000) |
218
2.11k
           (((uint32_t)(f.g + .5f) <<  8) & 0x0000ff00) |
219
2.11k
           (((uint32_t)(f.b + .5f) >>  0) & 0x000000ff);
220
2.11k
}
221
222
void
223
_pixman_gradient_walker_write_narrow (pixman_gradient_walker_t *walker,
224
              pixman_fixed_48_16_t      x,
225
              uint32_t                 *buffer)
226
2.11k
{
227
2.11k
    *buffer = pixman_gradient_walker_pixel_32 (walker, x);
228
2.11k
}
229
230
void
231
_pixman_gradient_walker_write_wide (pixman_gradient_walker_t *walker,
232
            pixman_fixed_48_16_t      x,
233
            uint32_t                 *buffer)
234
0
{
235
0
    *(argb_t *)buffer = pixman_gradient_walker_pixel_float (walker, x);
236
0
}
237
238
void
239
_pixman_gradient_walker_fill_narrow (pixman_gradient_walker_t *walker,
240
             pixman_fixed_48_16_t      x,
241
             uint32_t                 *buffer,
242
             uint32_t                 *end)
243
0
{
244
0
    register uint32_t color;
245
246
0
    color = pixman_gradient_walker_pixel_32 (walker, x);
247
0
    while (buffer < end)
248
0
  *buffer++ = color;
249
0
}
250
251
void
252
_pixman_gradient_walker_fill_wide (pixman_gradient_walker_t *walker,
253
           pixman_fixed_48_16_t      x,
254
           uint32_t                 *buffer,
255
           uint32_t                 *end)
256
0
{
257
0
    register argb_t color;
258
0
    argb_t *buffer_wide = (argb_t *)buffer;
259
0
    argb_t *end_wide    = (argb_t *)end;
260
261
0
    color = pixman_gradient_walker_pixel_float (walker, x);
262
0
    while (buffer_wide < end_wide)
263
0
  *buffer_wide++ = color;
264
0
}