/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 | | |