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 40static void 41general_iter_init (pixman_iter_t *iter, const pixman_iter_info_t *info) 42{ 43 pixman_image_t *image = iter->image; 44 45 switch (image->type) 46 { 47 case BITS: 48 if ((iter->iter_flags & ITER_SRC) == ITER_SRC) 49 _pixman_bits_image_src_iter_init (image, iter); 50 else 51 _pixman_bits_image_dest_iter_init (image, iter); 52 break; 53 54 case LINEAR: 55 _pixman_linear_gradient_iter_init (image, iter); 56 break; 57 58 case RADIAL: 59 _pixman_radial_gradient_iter_init (image, iter); 60 break; 61 62 case CONICAL: 63 _pixman_conical_gradient_iter_init (image, iter); 64 break; 65 66 case SOLID: 67 _pixman_log_error (FUNC, "Solid image not handled by noop"); 68 break; 69 70 default: 71 _pixman_log_error (FUNC, "Pixman bug: unknown image type\n"); 72 break; 73 } 74} 75 76static const pixman_iter_info_t general_iters[] = 77{ 78 { PIXMAN_any, 0, 0, general_iter_init, NULL, NULL }, 79 { PIXMAN_null }, 80}; 81 82typedef struct op_info_t op_info_t; 83struct 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 91static 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 112static pixman_bool_t 113operator_needs_division (pixman_op_t op) 114{ 115 static const uint8_t needs_division[] = 116 { 117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* SATURATE */ 118 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, /* DISJOINT */ 119 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, /* CONJOINT */ 120 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, /* blend ops */ 121 }; 122 123 return needs_division[op]; 124} 125 126static void 127general_composite_rect (pixman_implementation_t *imp, 128 pixman_composite_info_t *info) 129{ 130 PIXMAN_COMPOSITE_ARGS (info); 131 uint8_t stack_scanline_buffer[3 * SCANLINE_BUFFER_LENGTH]; 132 uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer; 133 uint8_t *src_buffer, *mask_buffer, *dest_buffer; 134 pixman_iter_t src_iter, mask_iter, dest_iter; 135 pixman_combine_32_func_t compose; 136 pixman_bool_t component_alpha; 137 iter_flags_t width_flag, src_iter_flags; 138 int Bpp; 139 int i; 140 141 if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT) && 142 (!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) && 143 (dest_image->common.flags & FAST_PATH_NARROW_FORMAT) && 144 !(operator_needs_division (op)) && 145 (dest_image->bits.dither == PIXMAN_DITHER_NONE)) 146 { 147 width_flag = ITER_NARROW; 148 Bpp = 4; 149 } 150 else 151 { 152 width_flag = ITER_WIDE; 153 Bpp = 16; 154 } 155 156#define ALIGN(addr) \ 157 ((uint8_t *)((((uintptr_t)(addr)) + 15) & (~15))) 158 159 if (width <= 0 || _pixman_multiply_overflows_int (width, Bpp * 3)) 160 return; 161 162 if (width * Bpp * 3 > sizeof (stack_scanline_buffer) - 15 * 3) 163 { 164 scanline_buffer = pixman_malloc_ab_plus_c (width, Bpp * 3, 15 * 3); 165 166 if (!scanline_buffer) 167 return; 168 169 memset (scanline_buffer, 0, width * Bpp * 3 + 15 * 3); 170 } 171 else 172 { 173 memset (stack_scanline_buffer, 0, sizeof (stack_scanline_buffer)); 174 } 175 176 src_buffer = ALIGN (scanline_buffer); 177 mask_buffer = ALIGN (src_buffer + width * Bpp); 178 dest_buffer = ALIGN (mask_buffer + width * Bpp); 179 180 if (width_flag == ITER_WIDE) 181 { 182 /* To make sure there aren't any NANs in the buffers */ 183 memset (src_buffer, 0, width * Bpp); 184 memset (mask_buffer, 0, width * Bpp); 185 memset (dest_buffer, 0, width * Bpp); 186 } 187 188 /* src iter */ 189 src_iter_flags = width_flag | op_flags[op].src | ITER_SRC; 190 191 _pixman_implementation_iter_init (imp->toplevel, &src_iter, src_image, 192 src_x, src_y, width, height, 193 src_buffer, src_iter_flags, 194 info->src_flags); 195 196 /* mask iter */ 197 if ((src_iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) == 198 (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) 199 { 200 /* If it doesn't matter what the source is, then it doesn't matter 201 * what the mask is 202 */ 203 mask_image = NULL; 204 } 205 206 component_alpha = mask_image && mask_image->common.component_alpha; 207 208 _pixman_implementation_iter_init ( 209 imp->toplevel, &mask_iter, 210 mask_image, mask_x, mask_y, width, height, mask_buffer, 211 ITER_SRC | width_flag | (component_alpha? 0 : ITER_IGNORE_RGB), 212 info->mask_flags); 213 214 /* dest iter */ 215 _pixman_implementation_iter_init ( 216 imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height, 217 dest_buffer, ITER_DEST | width_flag | op_flags[op].dst, info->dest_flags); 218 219 compose = _pixman_implementation_lookup_combiner ( 220 imp->toplevel, op, component_alpha, width_flag != ITER_WIDE); 221 222 for (i = 0; i < height; ++i) 223 { 224 uint32_t *s, *m, *d; 225 226 m = mask_iter.get_scanline (&mask_iter, NULL); 227 s = src_iter.get_scanline (&src_iter, m); 228 d = dest_iter.get_scanline (&dest_iter, NULL); 229 230 compose (imp->toplevel, op, d, s, m, width); 231 232 dest_iter.write_back (&dest_iter); 233 } 234 235 if (src_iter.fini) 236 src_iter.fini (&src_iter); 237 if (mask_iter.fini) 238 mask_iter.fini (&mask_iter); 239 if (dest_iter.fini) 240 dest_iter.fini (&dest_iter); 241 242 if (scanline_buffer != (uint8_t *) stack_scanline_buffer) 243 free (scanline_buffer); 244} 245 246static 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 252pixman_implementation_t * 253_pixman_implementation_create_general (void) 254{ 255 pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path); 256 257 _pixman_setup_combiner_functions_32 (imp); 258 _pixman_setup_combiner_functions_float (imp); 259 260 imp->iter_info = general_iters; 261 262 return imp; 263} 264 265