Coverage Report

Created: 2025-07-23 08:13

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