Coverage Report

Created: 2025-07-23 08:13

/src/cairo/subprojects/pixman-0.44.2/pixman/pixman-general.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2009 Red Hat, Inc.
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
7
 *             2008 Aaron Plattner, NVIDIA Corporation
8
 *
9
 * Permission to use, copy, modify, distribute, and sell this software and its
10
 * documentation for any purpose is hereby granted without fee, provided that
11
 * the above copyright notice appear in all copies and that both that
12
 * copyright notice and this permission notice appear in supporting
13
 * documentation, and that the name of Red Hat not be used in advertising or
14
 * publicity pertaining to distribution of the software without specific,
15
 * written prior permission.  Red Hat makes no representations about the
16
 * suitability of this software for any purpose.  It is provided "as is"
17
 * without express or implied warranty.
18
 *
19
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
20
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
21
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
22
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
24
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
25
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26
 * SOFTWARE.
27
 */
28
#ifdef HAVE_CONFIG_H
29
#include <pixman-config.h>
30
#endif
31
#include <stdlib.h>
32
#include <string.h>
33
#include <math.h>
34
#include <limits.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include "pixman-private.h"
39
40
static void
41
general_iter_init (pixman_iter_t *iter, const pixman_iter_info_t *info)
42
174
{
43
174
    pixman_image_t *image = iter->image;
44
45
174
    switch (image->type)
46
174
    {
47
2
    case BITS:
48
2
        if ((iter->iter_flags & ITER_SRC) == ITER_SRC)
49
0
            _pixman_bits_image_src_iter_init (image, iter);
50
2
        else
51
2
            _pixman_bits_image_dest_iter_init (image, iter);
52
2
        break;
53
54
172
    case LINEAR:
55
172
        _pixman_linear_gradient_iter_init (image, iter);
56
172
        break;
57
58
0
    case RADIAL:
59
0
  _pixman_radial_gradient_iter_init (image, iter);
60
0
        break;
61
62
0
    case CONICAL:
63
0
  _pixman_conical_gradient_iter_init (image, iter);
64
0
        break;
65
66
0
    case SOLID:
67
0
        _pixman_log_error (FUNC, "Solid image not handled by noop");
68
0
        break;
69
70
0
    default:
71
0
  _pixman_log_error (FUNC, "Pixman bug: unknown image type\n");
72
0
        break;
73
174
    }
74
174
}
75
76
static const pixman_iter_info_t general_iters[] =
77
{
78
    { PIXMAN_any, 0, 0, general_iter_init, NULL, NULL },
79
    { PIXMAN_null },
80
};
81
82
typedef struct op_info_t op_info_t;
83
struct op_info_t
84
{
85
    uint8_t src, dst;
86
};
87
88
#define ITER_IGNORE_BOTH            \
89
    (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB | ITER_LOCALIZED_ALPHA)
90
91
static const op_info_t op_flags[PIXMAN_N_OPERATORS] =
92
{
93
    /* Src                   Dst                   */
94
    { ITER_IGNORE_BOTH,      ITER_IGNORE_BOTH      }, /* CLEAR */
95
    { ITER_LOCALIZED_ALPHA,  ITER_IGNORE_BOTH      }, /* SRC */
96
    { ITER_IGNORE_BOTH,      ITER_LOCALIZED_ALPHA  }, /* DST */
97
    { 0,                     ITER_LOCALIZED_ALPHA  }, /* OVER */
98
    { ITER_LOCALIZED_ALPHA,  0                     }, /* OVER_REVERSE */
99
    { ITER_LOCALIZED_ALPHA,  ITER_IGNORE_RGB       }, /* IN */
100
    { ITER_IGNORE_RGB,       ITER_LOCALIZED_ALPHA  }, /* IN_REVERSE */
101
    { ITER_LOCALIZED_ALPHA,  ITER_IGNORE_RGB       }, /* OUT */
102
    { ITER_IGNORE_RGB,       ITER_LOCALIZED_ALPHA  }, /* OUT_REVERSE */
103
    { 0,                     0                     }, /* ATOP */
104
    { 0,                     0                     }, /* ATOP_REVERSE */
105
    { 0,                     0                     }, /* XOR */
106
    { ITER_LOCALIZED_ALPHA,  ITER_LOCALIZED_ALPHA  }, /* ADD */
107
    { 0,                     0                     }, /* SATURATE */
108
};
109
110
#define SCANLINE_BUFFER_LENGTH 8192
111
112
static pixman_bool_t
113
operator_needs_division (pixman_op_t op)
114
174
{
115
174
    static const uint8_t needs_division[] =
116
174
    {
117
174
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* SATURATE */
118
174
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, /* DISJOINT */
119
174
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, /* CONJOINT */
120
174
  0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, /* blend ops */
121
174
    };
122
123
174
    return needs_division[op];
124
174
}
125
126
static void
127
general_composite_rect  (pixman_implementation_t *imp,
128
                         pixman_composite_info_t *info)
129
174
{
130
174
    PIXMAN_COMPOSITE_ARGS (info);
131
174
    uint8_t stack_scanline_buffer[3 * SCANLINE_BUFFER_LENGTH];
132
174
    uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer;
133
174
    uint8_t *src_buffer, *mask_buffer, *dest_buffer;
134
174
    pixman_iter_t src_iter, mask_iter, dest_iter;
135
174
    pixman_combine_32_func_t compose;
136
174
    pixman_bool_t component_alpha;
137
174
    iter_flags_t width_flag, src_iter_flags;
138
174
    int Bpp;
139
174
    int i;
140
141
174
    if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT)        &&
142
174
  (!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT)  &&
143
174
  (dest_image->common.flags & FAST_PATH_NARROW_FORMAT)        &&
144
174
  !(operator_needs_division (op))                                      &&
145
174
  (dest_image->bits.dither == PIXMAN_DITHER_NONE))
146
174
    {
147
174
  width_flag = ITER_NARROW;
148
174
  Bpp = 4;
149
174
    }
150
0
    else
151
0
    {
152
0
  width_flag = ITER_WIDE;
153
0
  Bpp = 16;
154
0
    }
155
156
174
#define ALIGN(addr)             \
157
522
    ((uint8_t *)((((uintptr_t)(addr)) + 15) & (~15)))
158
159
174
    if (width <= 0 || _pixman_multiply_overflows_int (width, Bpp * 3))
160
0
  return;
161
162
174
    if (width * Bpp * 3 > sizeof (stack_scanline_buffer) - 15 * 3)
163
0
    {
164
0
  scanline_buffer = pixman_malloc_ab_plus_c (width, Bpp * 3, 15 * 3);
165
166
0
  if (!scanline_buffer)
167
0
      return;
168
169
0
  memset (scanline_buffer, 0, width * Bpp * 3 + 15 * 3);
170
0
    }
171
174
    else
172
174
    {
173
174
  memset (stack_scanline_buffer, 0, sizeof (stack_scanline_buffer));
174
174
    }
175
176
174
    src_buffer = ALIGN (scanline_buffer);
177
174
    mask_buffer = ALIGN (src_buffer + width * Bpp);
178
174
    dest_buffer = ALIGN (mask_buffer + width * Bpp);
179
180
174
    if (width_flag == ITER_WIDE)
181
0
    {
182
  /* To make sure there aren't any NANs in the buffers */
183
0
  memset (src_buffer, 0, width * Bpp);
184
0
  memset (mask_buffer, 0, width * Bpp);
185
0
  memset (dest_buffer, 0, width * Bpp);
186
0
    }
187
    
188
    /* src iter */
189
174
    src_iter_flags = width_flag | op_flags[op].src | ITER_SRC;
190
191
174
    _pixman_implementation_iter_init (imp->toplevel, &src_iter, src_image,
192
174
                                      src_x, src_y, width, height,
193
174
                                      src_buffer, src_iter_flags,
194
174
                                      info->src_flags);
195
196
    /* mask iter */
197
174
    if ((src_iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) ==
198
174
  (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB))
199
0
    {
200
  /* If it doesn't matter what the source is, then it doesn't matter
201
   * what the mask is
202
   */
203
0
  mask_image = NULL;
204
0
    }
205
206
174
    component_alpha = mask_image && mask_image->common.component_alpha;
207
208
174
    _pixman_implementation_iter_init (
209
174
  imp->toplevel, &mask_iter,
210
174
  mask_image, mask_x, mask_y, width, height, mask_buffer,
211
174
  ITER_SRC | width_flag | (component_alpha? 0 : ITER_IGNORE_RGB),
212
174
  info->mask_flags);
213
214
    /* dest iter */
215
174
    _pixman_implementation_iter_init (
216
174
  imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height,
217
174
  dest_buffer, ITER_DEST | width_flag | op_flags[op].dst, info->dest_flags);
218
219
174
    compose = _pixman_implementation_lookup_combiner (
220
174
  imp->toplevel, op, component_alpha, width_flag != ITER_WIDE);
221
222
381
    for (i = 0; i < height; ++i)
223
207
    {
224
207
  uint32_t *s, *m, *d;
225
226
207
  m = mask_iter.get_scanline (&mask_iter, NULL);
227
207
  s = src_iter.get_scanline (&src_iter, m);
228
207
  d = dest_iter.get_scanline (&dest_iter, NULL);
229
230
207
  compose (imp->toplevel, op, d, s, m, width);
231
232
207
  dest_iter.write_back (&dest_iter);
233
207
    }
234
235
174
    if (src_iter.fini)
236
0
  src_iter.fini (&src_iter);
237
174
    if (mask_iter.fini)
238
0
  mask_iter.fini (&mask_iter);
239
174
    if (dest_iter.fini)
240
0
  dest_iter.fini (&dest_iter);
241
    
242
174
    if (scanline_buffer != (uint8_t *) stack_scanline_buffer)
243
0
  free (scanline_buffer);
244
174
}
245
246
static const pixman_fast_path_t general_fast_path[] =
247
{
248
    { PIXMAN_OP_any, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, general_composite_rect },
249
    { PIXMAN_OP_NONE }
250
};
251
252
pixman_implementation_t *
253
_pixman_implementation_create_general (void)
254
12
{
255
12
    pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path);
256
257
12
    _pixman_setup_combiner_functions_32 (imp);
258
12
    _pixman_setup_combiner_functions_float (imp);
259
260
12
    imp->iter_info = general_iters;
261
262
12
    return imp;
263
12
}
264