Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* |
michael@0 | 2 | * Copyright © 2009 Red Hat, Inc. |
michael@0 | 3 | * Copyright © 2000 SuSE, Inc. |
michael@0 | 4 | * Copyright © 2007 Red Hat, Inc. |
michael@0 | 5 | * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. |
michael@0 | 6 | * 2005 Lars Knoll & Zack Rusin, Trolltech |
michael@0 | 7 | * 2008 Aaron Plattner, NVIDIA Corporation |
michael@0 | 8 | * |
michael@0 | 9 | * Permission to use, copy, modify, distribute, and sell this software and its |
michael@0 | 10 | * documentation for any purpose is hereby granted without fee, provided that |
michael@0 | 11 | * the above copyright notice appear in all copies and that both that |
michael@0 | 12 | * copyright notice and this permission notice appear in supporting |
michael@0 | 13 | * documentation, and that the name of Red Hat not be used in advertising or |
michael@0 | 14 | * publicity pertaining to distribution of the software without specific, |
michael@0 | 15 | * written prior permission. Red Hat makes no representations about the |
michael@0 | 16 | * suitability of this software for any purpose. It is provided "as is" |
michael@0 | 17 | * without express or implied warranty. |
michael@0 | 18 | * |
michael@0 | 19 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
michael@0 | 20 | * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
michael@0 | 21 | * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
michael@0 | 22 | * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
michael@0 | 23 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN |
michael@0 | 24 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
michael@0 | 25 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
michael@0 | 26 | * SOFTWARE. |
michael@0 | 27 | */ |
michael@0 | 28 | #ifdef HAVE_CONFIG_H |
michael@0 | 29 | #include <config.h> |
michael@0 | 30 | #endif |
michael@0 | 31 | #include <stdlib.h> |
michael@0 | 32 | #include <string.h> |
michael@0 | 33 | #include <math.h> |
michael@0 | 34 | #include <limits.h> |
michael@0 | 35 | #include <stdio.h> |
michael@0 | 36 | #include <stdlib.h> |
michael@0 | 37 | #include <string.h> |
michael@0 | 38 | #include "pixman-private.h" |
michael@0 | 39 | |
michael@0 | 40 | static pixman_bool_t |
michael@0 | 41 | general_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) |
michael@0 | 42 | { |
michael@0 | 43 | pixman_image_t *image = iter->image; |
michael@0 | 44 | |
michael@0 | 45 | if (image->type == LINEAR) |
michael@0 | 46 | _pixman_linear_gradient_iter_init (image, iter); |
michael@0 | 47 | else if (image->type == RADIAL) |
michael@0 | 48 | _pixman_radial_gradient_iter_init (image, iter); |
michael@0 | 49 | else if (image->type == CONICAL) |
michael@0 | 50 | _pixman_conical_gradient_iter_init (image, iter); |
michael@0 | 51 | else if (image->type == BITS) |
michael@0 | 52 | _pixman_bits_image_src_iter_init (image, iter); |
michael@0 | 53 | else if (image->type == SOLID) |
michael@0 | 54 | _pixman_log_error (FUNC, "Solid image not handled by noop"); |
michael@0 | 55 | else |
michael@0 | 56 | _pixman_log_error (FUNC, "Pixman bug: unknown image type\n"); |
michael@0 | 57 | |
michael@0 | 58 | return TRUE; |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | static pixman_bool_t |
michael@0 | 62 | general_dest_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) |
michael@0 | 63 | { |
michael@0 | 64 | if (iter->image->type == BITS) |
michael@0 | 65 | { |
michael@0 | 66 | _pixman_bits_image_dest_iter_init (iter->image, iter); |
michael@0 | 67 | |
michael@0 | 68 | return TRUE; |
michael@0 | 69 | } |
michael@0 | 70 | else |
michael@0 | 71 | { |
michael@0 | 72 | _pixman_log_error (FUNC, "Trying to write to a non-writable image"); |
michael@0 | 73 | |
michael@0 | 74 | return FALSE; |
michael@0 | 75 | } |
michael@0 | 76 | } |
michael@0 | 77 | |
michael@0 | 78 | typedef struct op_info_t op_info_t; |
michael@0 | 79 | struct op_info_t |
michael@0 | 80 | { |
michael@0 | 81 | uint8_t src, dst; |
michael@0 | 82 | }; |
michael@0 | 83 | |
michael@0 | 84 | #define ITER_IGNORE_BOTH \ |
michael@0 | 85 | (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB | ITER_LOCALIZED_ALPHA) |
michael@0 | 86 | |
michael@0 | 87 | static const op_info_t op_flags[PIXMAN_N_OPERATORS] = |
michael@0 | 88 | { |
michael@0 | 89 | /* Src Dst */ |
michael@0 | 90 | { ITER_IGNORE_BOTH, ITER_IGNORE_BOTH }, /* CLEAR */ |
michael@0 | 91 | { ITER_LOCALIZED_ALPHA, ITER_IGNORE_BOTH }, /* SRC */ |
michael@0 | 92 | { ITER_IGNORE_BOTH, ITER_LOCALIZED_ALPHA }, /* DST */ |
michael@0 | 93 | { 0, ITER_LOCALIZED_ALPHA }, /* OVER */ |
michael@0 | 94 | { ITER_LOCALIZED_ALPHA, 0 }, /* OVER_REVERSE */ |
michael@0 | 95 | { ITER_LOCALIZED_ALPHA, ITER_IGNORE_RGB }, /* IN */ |
michael@0 | 96 | { ITER_IGNORE_RGB, ITER_LOCALIZED_ALPHA }, /* IN_REVERSE */ |
michael@0 | 97 | { ITER_LOCALIZED_ALPHA, ITER_IGNORE_RGB }, /* OUT */ |
michael@0 | 98 | { ITER_IGNORE_RGB, ITER_LOCALIZED_ALPHA }, /* OUT_REVERSE */ |
michael@0 | 99 | { 0, 0 }, /* ATOP */ |
michael@0 | 100 | { 0, 0 }, /* ATOP_REVERSE */ |
michael@0 | 101 | { 0, 0 }, /* XOR */ |
michael@0 | 102 | { ITER_LOCALIZED_ALPHA, ITER_LOCALIZED_ALPHA }, /* ADD */ |
michael@0 | 103 | { 0, 0 }, /* SATURATE */ |
michael@0 | 104 | }; |
michael@0 | 105 | |
michael@0 | 106 | #define SCANLINE_BUFFER_LENGTH 8192 |
michael@0 | 107 | |
michael@0 | 108 | static void |
michael@0 | 109 | general_composite_rect (pixman_implementation_t *imp, |
michael@0 | 110 | pixman_composite_info_t *info) |
michael@0 | 111 | { |
michael@0 | 112 | PIXMAN_COMPOSITE_ARGS (info); |
michael@0 | 113 | uint64_t stack_scanline_buffer[(SCANLINE_BUFFER_LENGTH * 3 + 7) / 8]; |
michael@0 | 114 | uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer; |
michael@0 | 115 | uint8_t *src_buffer, *mask_buffer, *dest_buffer; |
michael@0 | 116 | pixman_iter_t src_iter, mask_iter, dest_iter; |
michael@0 | 117 | pixman_combine_32_func_t compose; |
michael@0 | 118 | pixman_bool_t component_alpha; |
michael@0 | 119 | iter_flags_t narrow, src_iter_flags; |
michael@0 | 120 | iter_flags_t rgb16; |
michael@0 | 121 | int Bpp; |
michael@0 | 122 | int i; |
michael@0 | 123 | |
michael@0 | 124 | if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT) && |
michael@0 | 125 | (!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) && |
michael@0 | 126 | (dest_image->common.flags & FAST_PATH_NARROW_FORMAT)) |
michael@0 | 127 | { |
michael@0 | 128 | narrow = ITER_NARROW; |
michael@0 | 129 | Bpp = 4; |
michael@0 | 130 | } |
michael@0 | 131 | else |
michael@0 | 132 | { |
michael@0 | 133 | narrow = 0; |
michael@0 | 134 | Bpp = 16; |
michael@0 | 135 | } |
michael@0 | 136 | |
michael@0 | 137 | // XXX: This special casing is bad. Ideally, we'd keep the general code general perhaps |
michael@0 | 138 | // by having it deal more specifically with different intermediate formats |
michael@0 | 139 | if ( |
michael@0 | 140 | (dest_image->common.flags & FAST_PATH_16_FORMAT && (src_image->type == LINEAR || src_image->type == RADIAL)) && |
michael@0 | 141 | ( op == PIXMAN_OP_SRC || |
michael@0 | 142 | (op == PIXMAN_OP_OVER && (src_image->common.flags & FAST_PATH_IS_OPAQUE)) |
michael@0 | 143 | ) |
michael@0 | 144 | ) { |
michael@0 | 145 | rgb16 = ITER_16; |
michael@0 | 146 | } else { |
michael@0 | 147 | rgb16 = 0; |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | |
michael@0 | 151 | if (width * Bpp > SCANLINE_BUFFER_LENGTH) |
michael@0 | 152 | { |
michael@0 | 153 | scanline_buffer = pixman_malloc_abc (width, 3, Bpp); |
michael@0 | 154 | |
michael@0 | 155 | if (!scanline_buffer) |
michael@0 | 156 | return; |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | src_buffer = scanline_buffer; |
michael@0 | 160 | mask_buffer = src_buffer + width * Bpp; |
michael@0 | 161 | dest_buffer = mask_buffer + width * Bpp; |
michael@0 | 162 | |
michael@0 | 163 | if (!narrow) |
michael@0 | 164 | { |
michael@0 | 165 | /* To make sure there aren't any NANs in the buffers */ |
michael@0 | 166 | memset (src_buffer, 0, width * Bpp); |
michael@0 | 167 | memset (mask_buffer, 0, width * Bpp); |
michael@0 | 168 | memset (dest_buffer, 0, width * Bpp); |
michael@0 | 169 | } |
michael@0 | 170 | |
michael@0 | 171 | /* src iter */ |
michael@0 | 172 | src_iter_flags = narrow | op_flags[op].src | rgb16; |
michael@0 | 173 | |
michael@0 | 174 | _pixman_implementation_src_iter_init (imp->toplevel, &src_iter, src_image, |
michael@0 | 175 | src_x, src_y, width, height, |
michael@0 | 176 | src_buffer, src_iter_flags, info->src_flags); |
michael@0 | 177 | |
michael@0 | 178 | /* mask iter */ |
michael@0 | 179 | if ((src_iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) == |
michael@0 | 180 | (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) |
michael@0 | 181 | { |
michael@0 | 182 | /* If it doesn't matter what the source is, then it doesn't matter |
michael@0 | 183 | * what the mask is |
michael@0 | 184 | */ |
michael@0 | 185 | mask_image = NULL; |
michael@0 | 186 | } |
michael@0 | 187 | |
michael@0 | 188 | component_alpha = |
michael@0 | 189 | mask_image && |
michael@0 | 190 | mask_image->common.type == BITS && |
michael@0 | 191 | mask_image->common.component_alpha && |
michael@0 | 192 | PIXMAN_FORMAT_RGB (mask_image->bits.format); |
michael@0 | 193 | |
michael@0 | 194 | _pixman_implementation_src_iter_init ( |
michael@0 | 195 | imp->toplevel, &mask_iter, mask_image, mask_x, mask_y, width, height, |
michael@0 | 196 | mask_buffer, narrow | (component_alpha? 0 : ITER_IGNORE_RGB), info->mask_flags); |
michael@0 | 197 | |
michael@0 | 198 | /* dest iter */ |
michael@0 | 199 | _pixman_implementation_dest_iter_init ( |
michael@0 | 200 | imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height, |
michael@0 | 201 | dest_buffer, narrow | op_flags[op].dst | rgb16, info->dest_flags); |
michael@0 | 202 | |
michael@0 | 203 | compose = _pixman_implementation_lookup_combiner ( |
michael@0 | 204 | imp->toplevel, op, component_alpha, narrow, !!rgb16); |
michael@0 | 205 | |
michael@0 | 206 | for (i = 0; i < height; ++i) |
michael@0 | 207 | { |
michael@0 | 208 | uint32_t *s, *m, *d; |
michael@0 | 209 | |
michael@0 | 210 | m = mask_iter.get_scanline (&mask_iter, NULL); |
michael@0 | 211 | s = src_iter.get_scanline (&src_iter, m); |
michael@0 | 212 | d = dest_iter.get_scanline (&dest_iter, NULL); |
michael@0 | 213 | |
michael@0 | 214 | compose (imp->toplevel, op, d, s, m, width); |
michael@0 | 215 | |
michael@0 | 216 | dest_iter.write_back (&dest_iter); |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | if (scanline_buffer != (uint8_t *) stack_scanline_buffer) |
michael@0 | 220 | free (scanline_buffer); |
michael@0 | 221 | } |
michael@0 | 222 | |
michael@0 | 223 | static const pixman_fast_path_t general_fast_path[] = |
michael@0 | 224 | { |
michael@0 | 225 | { PIXMAN_OP_any, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, general_composite_rect }, |
michael@0 | 226 | { PIXMAN_OP_NONE } |
michael@0 | 227 | }; |
michael@0 | 228 | |
michael@0 | 229 | pixman_implementation_t * |
michael@0 | 230 | _pixman_implementation_create_general (void) |
michael@0 | 231 | { |
michael@0 | 232 | pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path); |
michael@0 | 233 | |
michael@0 | 234 | _pixman_setup_combiner_functions_16 (imp); |
michael@0 | 235 | _pixman_setup_combiner_functions_32 (imp); |
michael@0 | 236 | _pixman_setup_combiner_functions_float (imp); |
michael@0 | 237 | |
michael@0 | 238 | imp->src_iter_init = general_src_iter_init; |
michael@0 | 239 | imp->dest_iter_init = general_dest_iter_init; |
michael@0 | 240 | |
michael@0 | 241 | return imp; |
michael@0 | 242 | } |
michael@0 | 243 |