Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */ |
michael@0 | 2 | /* |
michael@0 | 3 | * Copyright © 2000 SuSE, Inc. |
michael@0 | 4 | * Copyright © 2007 Red Hat, Inc. |
michael@0 | 5 | * |
michael@0 | 6 | * Permission to use, copy, modify, distribute, and sell this software and its |
michael@0 | 7 | * documentation for any purpose is hereby granted without fee, provided that |
michael@0 | 8 | * the above copyright notice appear in all copies and that both that |
michael@0 | 9 | * copyright notice and this permission notice appear in supporting |
michael@0 | 10 | * documentation, and that the name of SuSE not be used in advertising or |
michael@0 | 11 | * publicity pertaining to distribution of the software without specific, |
michael@0 | 12 | * written prior permission. SuSE makes no representations about the |
michael@0 | 13 | * suitability of this software for any purpose. It is provided "as is" |
michael@0 | 14 | * without express or implied warranty. |
michael@0 | 15 | * |
michael@0 | 16 | * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL |
michael@0 | 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE |
michael@0 | 18 | * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
michael@0 | 19 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
michael@0 | 20 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
michael@0 | 21 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
michael@0 | 22 | * |
michael@0 | 23 | * Author: Keith Packard, SuSE, Inc. |
michael@0 | 24 | */ |
michael@0 | 25 | |
michael@0 | 26 | #ifdef HAVE_CONFIG_H |
michael@0 | 27 | #include <config.h> |
michael@0 | 28 | #endif |
michael@0 | 29 | #include "pixman-private.h" |
michael@0 | 30 | |
michael@0 | 31 | #include <stdlib.h> |
michael@0 | 32 | |
michael@0 | 33 | pixman_implementation_t *global_implementation; |
michael@0 | 34 | |
michael@0 | 35 | #ifdef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR |
michael@0 | 36 | static void __attribute__((constructor)) |
michael@0 | 37 | pixman_constructor (void) |
michael@0 | 38 | { |
michael@0 | 39 | global_implementation = _pixman_choose_implementation (); |
michael@0 | 40 | } |
michael@0 | 41 | #endif |
michael@0 | 42 | |
michael@0 | 43 | typedef struct operator_info_t operator_info_t; |
michael@0 | 44 | |
michael@0 | 45 | struct operator_info_t |
michael@0 | 46 | { |
michael@0 | 47 | uint8_t opaque_info[4]; |
michael@0 | 48 | }; |
michael@0 | 49 | |
michael@0 | 50 | #define PACK(neither, src, dest, both) \ |
michael@0 | 51 | {{ (uint8_t)PIXMAN_OP_ ## neither, \ |
michael@0 | 52 | (uint8_t)PIXMAN_OP_ ## src, \ |
michael@0 | 53 | (uint8_t)PIXMAN_OP_ ## dest, \ |
michael@0 | 54 | (uint8_t)PIXMAN_OP_ ## both }} |
michael@0 | 55 | |
michael@0 | 56 | static const operator_info_t operator_table[] = |
michael@0 | 57 | { |
michael@0 | 58 | /* Neither Opaque Src Opaque Dst Opaque Both Opaque */ |
michael@0 | 59 | PACK (CLEAR, CLEAR, CLEAR, CLEAR), |
michael@0 | 60 | PACK (SRC, SRC, SRC, SRC), |
michael@0 | 61 | PACK (DST, DST, DST, DST), |
michael@0 | 62 | PACK (OVER, SRC, OVER, SRC), |
michael@0 | 63 | PACK (OVER_REVERSE, OVER_REVERSE, DST, DST), |
michael@0 | 64 | PACK (IN, IN, SRC, SRC), |
michael@0 | 65 | PACK (IN_REVERSE, DST, IN_REVERSE, DST), |
michael@0 | 66 | PACK (OUT, OUT, CLEAR, CLEAR), |
michael@0 | 67 | PACK (OUT_REVERSE, CLEAR, OUT_REVERSE, CLEAR), |
michael@0 | 68 | PACK (ATOP, IN, OVER, SRC), |
michael@0 | 69 | PACK (ATOP_REVERSE, OVER_REVERSE, IN_REVERSE, DST), |
michael@0 | 70 | PACK (XOR, OUT, OUT_REVERSE, CLEAR), |
michael@0 | 71 | PACK (ADD, ADD, ADD, ADD), |
michael@0 | 72 | PACK (SATURATE, OVER_REVERSE, DST, DST), |
michael@0 | 73 | |
michael@0 | 74 | {{ 0 /* 0x0e */ }}, |
michael@0 | 75 | {{ 0 /* 0x0f */ }}, |
michael@0 | 76 | |
michael@0 | 77 | PACK (CLEAR, CLEAR, CLEAR, CLEAR), |
michael@0 | 78 | PACK (SRC, SRC, SRC, SRC), |
michael@0 | 79 | PACK (DST, DST, DST, DST), |
michael@0 | 80 | PACK (DISJOINT_OVER, DISJOINT_OVER, DISJOINT_OVER, DISJOINT_OVER), |
michael@0 | 81 | PACK (DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE, DISJOINT_OVER_REVERSE), |
michael@0 | 82 | PACK (DISJOINT_IN, DISJOINT_IN, DISJOINT_IN, DISJOINT_IN), |
michael@0 | 83 | PACK (DISJOINT_IN_REVERSE, DISJOINT_IN_REVERSE, DISJOINT_IN_REVERSE, DISJOINT_IN_REVERSE), |
michael@0 | 84 | PACK (DISJOINT_OUT, DISJOINT_OUT, DISJOINT_OUT, DISJOINT_OUT), |
michael@0 | 85 | PACK (DISJOINT_OUT_REVERSE, DISJOINT_OUT_REVERSE, DISJOINT_OUT_REVERSE, DISJOINT_OUT_REVERSE), |
michael@0 | 86 | PACK (DISJOINT_ATOP, DISJOINT_ATOP, DISJOINT_ATOP, DISJOINT_ATOP), |
michael@0 | 87 | PACK (DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE, DISJOINT_ATOP_REVERSE), |
michael@0 | 88 | PACK (DISJOINT_XOR, DISJOINT_XOR, DISJOINT_XOR, DISJOINT_XOR), |
michael@0 | 89 | |
michael@0 | 90 | {{ 0 /* 0x1c */ }}, |
michael@0 | 91 | {{ 0 /* 0x1d */ }}, |
michael@0 | 92 | {{ 0 /* 0x1e */ }}, |
michael@0 | 93 | {{ 0 /* 0x1f */ }}, |
michael@0 | 94 | |
michael@0 | 95 | PACK (CLEAR, CLEAR, CLEAR, CLEAR), |
michael@0 | 96 | PACK (SRC, SRC, SRC, SRC), |
michael@0 | 97 | PACK (DST, DST, DST, DST), |
michael@0 | 98 | PACK (CONJOINT_OVER, CONJOINT_OVER, CONJOINT_OVER, CONJOINT_OVER), |
michael@0 | 99 | PACK (CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE, CONJOINT_OVER_REVERSE), |
michael@0 | 100 | PACK (CONJOINT_IN, CONJOINT_IN, CONJOINT_IN, CONJOINT_IN), |
michael@0 | 101 | PACK (CONJOINT_IN_REVERSE, CONJOINT_IN_REVERSE, CONJOINT_IN_REVERSE, CONJOINT_IN_REVERSE), |
michael@0 | 102 | PACK (CONJOINT_OUT, CONJOINT_OUT, CONJOINT_OUT, CONJOINT_OUT), |
michael@0 | 103 | PACK (CONJOINT_OUT_REVERSE, CONJOINT_OUT_REVERSE, CONJOINT_OUT_REVERSE, CONJOINT_OUT_REVERSE), |
michael@0 | 104 | PACK (CONJOINT_ATOP, CONJOINT_ATOP, CONJOINT_ATOP, CONJOINT_ATOP), |
michael@0 | 105 | PACK (CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE, CONJOINT_ATOP_REVERSE), |
michael@0 | 106 | PACK (CONJOINT_XOR, CONJOINT_XOR, CONJOINT_XOR, CONJOINT_XOR), |
michael@0 | 107 | |
michael@0 | 108 | {{ 0 /* 0x2c */ }}, |
michael@0 | 109 | {{ 0 /* 0x2d */ }}, |
michael@0 | 110 | {{ 0 /* 0x2e */ }}, |
michael@0 | 111 | {{ 0 /* 0x2f */ }}, |
michael@0 | 112 | |
michael@0 | 113 | PACK (MULTIPLY, MULTIPLY, MULTIPLY, MULTIPLY), |
michael@0 | 114 | PACK (SCREEN, SCREEN, SCREEN, SCREEN), |
michael@0 | 115 | PACK (OVERLAY, OVERLAY, OVERLAY, OVERLAY), |
michael@0 | 116 | PACK (DARKEN, DARKEN, DARKEN, DARKEN), |
michael@0 | 117 | PACK (LIGHTEN, LIGHTEN, LIGHTEN, LIGHTEN), |
michael@0 | 118 | PACK (COLOR_DODGE, COLOR_DODGE, COLOR_DODGE, COLOR_DODGE), |
michael@0 | 119 | PACK (COLOR_BURN, COLOR_BURN, COLOR_BURN, COLOR_BURN), |
michael@0 | 120 | PACK (HARD_LIGHT, HARD_LIGHT, HARD_LIGHT, HARD_LIGHT), |
michael@0 | 121 | PACK (SOFT_LIGHT, SOFT_LIGHT, SOFT_LIGHT, SOFT_LIGHT), |
michael@0 | 122 | PACK (DIFFERENCE, DIFFERENCE, DIFFERENCE, DIFFERENCE), |
michael@0 | 123 | PACK (EXCLUSION, EXCLUSION, EXCLUSION, EXCLUSION), |
michael@0 | 124 | PACK (HSL_HUE, HSL_HUE, HSL_HUE, HSL_HUE), |
michael@0 | 125 | PACK (HSL_SATURATION, HSL_SATURATION, HSL_SATURATION, HSL_SATURATION), |
michael@0 | 126 | PACK (HSL_COLOR, HSL_COLOR, HSL_COLOR, HSL_COLOR), |
michael@0 | 127 | PACK (HSL_LUMINOSITY, HSL_LUMINOSITY, HSL_LUMINOSITY, HSL_LUMINOSITY), |
michael@0 | 128 | }; |
michael@0 | 129 | |
michael@0 | 130 | /* |
michael@0 | 131 | * Optimize the current operator based on opacity of source or destination |
michael@0 | 132 | * The output operator should be mathematically equivalent to the source. |
michael@0 | 133 | */ |
michael@0 | 134 | static pixman_op_t |
michael@0 | 135 | optimize_operator (pixman_op_t op, |
michael@0 | 136 | uint32_t src_flags, |
michael@0 | 137 | uint32_t mask_flags, |
michael@0 | 138 | uint32_t dst_flags) |
michael@0 | 139 | { |
michael@0 | 140 | pixman_bool_t is_source_opaque, is_dest_opaque; |
michael@0 | 141 | |
michael@0 | 142 | #define OPAQUE_SHIFT 13 |
michael@0 | 143 | |
michael@0 | 144 | COMPILE_TIME_ASSERT (FAST_PATH_IS_OPAQUE == (1 << OPAQUE_SHIFT)); |
michael@0 | 145 | |
michael@0 | 146 | is_dest_opaque = (dst_flags & FAST_PATH_IS_OPAQUE); |
michael@0 | 147 | is_source_opaque = ((src_flags & mask_flags) & FAST_PATH_IS_OPAQUE); |
michael@0 | 148 | |
michael@0 | 149 | is_dest_opaque >>= OPAQUE_SHIFT - 1; |
michael@0 | 150 | is_source_opaque >>= OPAQUE_SHIFT; |
michael@0 | 151 | |
michael@0 | 152 | return operator_table[op].opaque_info[is_dest_opaque | is_source_opaque]; |
michael@0 | 153 | } |
michael@0 | 154 | |
michael@0 | 155 | /* |
michael@0 | 156 | * Computing composite region |
michael@0 | 157 | */ |
michael@0 | 158 | static inline pixman_bool_t |
michael@0 | 159 | clip_general_image (pixman_region32_t * region, |
michael@0 | 160 | pixman_region32_t * clip, |
michael@0 | 161 | int dx, |
michael@0 | 162 | int dy) |
michael@0 | 163 | { |
michael@0 | 164 | if (pixman_region32_n_rects (region) == 1 && |
michael@0 | 165 | pixman_region32_n_rects (clip) == 1) |
michael@0 | 166 | { |
michael@0 | 167 | pixman_box32_t * rbox = pixman_region32_rectangles (region, NULL); |
michael@0 | 168 | pixman_box32_t * cbox = pixman_region32_rectangles (clip, NULL); |
michael@0 | 169 | int v; |
michael@0 | 170 | |
michael@0 | 171 | if (rbox->x1 < (v = cbox->x1 + dx)) |
michael@0 | 172 | rbox->x1 = v; |
michael@0 | 173 | if (rbox->x2 > (v = cbox->x2 + dx)) |
michael@0 | 174 | rbox->x2 = v; |
michael@0 | 175 | if (rbox->y1 < (v = cbox->y1 + dy)) |
michael@0 | 176 | rbox->y1 = v; |
michael@0 | 177 | if (rbox->y2 > (v = cbox->y2 + dy)) |
michael@0 | 178 | rbox->y2 = v; |
michael@0 | 179 | if (rbox->x1 >= rbox->x2 || rbox->y1 >= rbox->y2) |
michael@0 | 180 | { |
michael@0 | 181 | pixman_region32_init (region); |
michael@0 | 182 | return FALSE; |
michael@0 | 183 | } |
michael@0 | 184 | } |
michael@0 | 185 | else if (!pixman_region32_not_empty (clip)) |
michael@0 | 186 | { |
michael@0 | 187 | return FALSE; |
michael@0 | 188 | } |
michael@0 | 189 | else |
michael@0 | 190 | { |
michael@0 | 191 | if (dx || dy) |
michael@0 | 192 | pixman_region32_translate (region, -dx, -dy); |
michael@0 | 193 | |
michael@0 | 194 | if (!pixman_region32_intersect (region, region, clip)) |
michael@0 | 195 | return FALSE; |
michael@0 | 196 | |
michael@0 | 197 | if (dx || dy) |
michael@0 | 198 | pixman_region32_translate (region, dx, dy); |
michael@0 | 199 | } |
michael@0 | 200 | |
michael@0 | 201 | return pixman_region32_not_empty (region); |
michael@0 | 202 | } |
michael@0 | 203 | |
michael@0 | 204 | static inline pixman_bool_t |
michael@0 | 205 | clip_source_image (pixman_region32_t * region, |
michael@0 | 206 | pixman_image_t * image, |
michael@0 | 207 | int dx, |
michael@0 | 208 | int dy) |
michael@0 | 209 | { |
michael@0 | 210 | /* Source clips are ignored, unless they are explicitly turned on |
michael@0 | 211 | * and the clip in question was set by an X client. (Because if |
michael@0 | 212 | * the clip was not set by a client, then it is a hierarchy |
michael@0 | 213 | * clip and those should always be ignored for sources). |
michael@0 | 214 | */ |
michael@0 | 215 | if (!image->common.clip_sources || !image->common.client_clip) |
michael@0 | 216 | return TRUE; |
michael@0 | 217 | |
michael@0 | 218 | return clip_general_image (region, |
michael@0 | 219 | &image->common.clip_region, |
michael@0 | 220 | dx, dy); |
michael@0 | 221 | } |
michael@0 | 222 | |
michael@0 | 223 | /* |
michael@0 | 224 | * returns FALSE if the final region is empty. Indistinguishable from |
michael@0 | 225 | * an allocation failure, but rendering ignores those anyways. |
michael@0 | 226 | */ |
michael@0 | 227 | pixman_bool_t |
michael@0 | 228 | _pixman_compute_composite_region32 (pixman_region32_t * region, |
michael@0 | 229 | pixman_image_t * src_image, |
michael@0 | 230 | pixman_image_t * mask_image, |
michael@0 | 231 | pixman_image_t * dest_image, |
michael@0 | 232 | int32_t src_x, |
michael@0 | 233 | int32_t src_y, |
michael@0 | 234 | int32_t mask_x, |
michael@0 | 235 | int32_t mask_y, |
michael@0 | 236 | int32_t dest_x, |
michael@0 | 237 | int32_t dest_y, |
michael@0 | 238 | int32_t width, |
michael@0 | 239 | int32_t height) |
michael@0 | 240 | { |
michael@0 | 241 | region->extents.x1 = dest_x; |
michael@0 | 242 | region->extents.x2 = dest_x + width; |
michael@0 | 243 | region->extents.y1 = dest_y; |
michael@0 | 244 | region->extents.y2 = dest_y + height; |
michael@0 | 245 | |
michael@0 | 246 | region->extents.x1 = MAX (region->extents.x1, 0); |
michael@0 | 247 | region->extents.y1 = MAX (region->extents.y1, 0); |
michael@0 | 248 | region->extents.x2 = MIN (region->extents.x2, dest_image->bits.width); |
michael@0 | 249 | region->extents.y2 = MIN (region->extents.y2, dest_image->bits.height); |
michael@0 | 250 | |
michael@0 | 251 | region->data = 0; |
michael@0 | 252 | |
michael@0 | 253 | /* Check for empty operation */ |
michael@0 | 254 | if (region->extents.x1 >= region->extents.x2 || |
michael@0 | 255 | region->extents.y1 >= region->extents.y2) |
michael@0 | 256 | { |
michael@0 | 257 | region->extents.x1 = 0; |
michael@0 | 258 | region->extents.x2 = 0; |
michael@0 | 259 | region->extents.y1 = 0; |
michael@0 | 260 | region->extents.y2 = 0; |
michael@0 | 261 | return FALSE; |
michael@0 | 262 | } |
michael@0 | 263 | |
michael@0 | 264 | if (dest_image->common.have_clip_region) |
michael@0 | 265 | { |
michael@0 | 266 | if (!clip_general_image (region, &dest_image->common.clip_region, 0, 0)) |
michael@0 | 267 | return FALSE; |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | if (dest_image->common.alpha_map) |
michael@0 | 271 | { |
michael@0 | 272 | if (!pixman_region32_intersect_rect (region, region, |
michael@0 | 273 | dest_image->common.alpha_origin_x, |
michael@0 | 274 | dest_image->common.alpha_origin_y, |
michael@0 | 275 | dest_image->common.alpha_map->width, |
michael@0 | 276 | dest_image->common.alpha_map->height)) |
michael@0 | 277 | { |
michael@0 | 278 | return FALSE; |
michael@0 | 279 | } |
michael@0 | 280 | if (!pixman_region32_not_empty (region)) |
michael@0 | 281 | return FALSE; |
michael@0 | 282 | if (dest_image->common.alpha_map->common.have_clip_region) |
michael@0 | 283 | { |
michael@0 | 284 | if (!clip_general_image (region, &dest_image->common.alpha_map->common.clip_region, |
michael@0 | 285 | -dest_image->common.alpha_origin_x, |
michael@0 | 286 | -dest_image->common.alpha_origin_y)) |
michael@0 | 287 | { |
michael@0 | 288 | return FALSE; |
michael@0 | 289 | } |
michael@0 | 290 | } |
michael@0 | 291 | } |
michael@0 | 292 | |
michael@0 | 293 | /* clip against src */ |
michael@0 | 294 | if (src_image->common.have_clip_region) |
michael@0 | 295 | { |
michael@0 | 296 | if (!clip_source_image (region, src_image, dest_x - src_x, dest_y - src_y)) |
michael@0 | 297 | return FALSE; |
michael@0 | 298 | } |
michael@0 | 299 | if (src_image->common.alpha_map && src_image->common.alpha_map->common.have_clip_region) |
michael@0 | 300 | { |
michael@0 | 301 | if (!clip_source_image (region, (pixman_image_t *)src_image->common.alpha_map, |
michael@0 | 302 | dest_x - (src_x - src_image->common.alpha_origin_x), |
michael@0 | 303 | dest_y - (src_y - src_image->common.alpha_origin_y))) |
michael@0 | 304 | { |
michael@0 | 305 | return FALSE; |
michael@0 | 306 | } |
michael@0 | 307 | } |
michael@0 | 308 | /* clip against mask */ |
michael@0 | 309 | if (mask_image && mask_image->common.have_clip_region) |
michael@0 | 310 | { |
michael@0 | 311 | if (!clip_source_image (region, mask_image, dest_x - mask_x, dest_y - mask_y)) |
michael@0 | 312 | return FALSE; |
michael@0 | 313 | |
michael@0 | 314 | if (mask_image->common.alpha_map && mask_image->common.alpha_map->common.have_clip_region) |
michael@0 | 315 | { |
michael@0 | 316 | if (!clip_source_image (region, (pixman_image_t *)mask_image->common.alpha_map, |
michael@0 | 317 | dest_x - (mask_x - mask_image->common.alpha_origin_x), |
michael@0 | 318 | dest_y - (mask_y - mask_image->common.alpha_origin_y))) |
michael@0 | 319 | { |
michael@0 | 320 | return FALSE; |
michael@0 | 321 | } |
michael@0 | 322 | } |
michael@0 | 323 | } |
michael@0 | 324 | |
michael@0 | 325 | return TRUE; |
michael@0 | 326 | } |
michael@0 | 327 | |
michael@0 | 328 | typedef struct |
michael@0 | 329 | { |
michael@0 | 330 | pixman_fixed_48_16_t x1; |
michael@0 | 331 | pixman_fixed_48_16_t y1; |
michael@0 | 332 | pixman_fixed_48_16_t x2; |
michael@0 | 333 | pixman_fixed_48_16_t y2; |
michael@0 | 334 | } box_48_16_t; |
michael@0 | 335 | |
michael@0 | 336 | static pixman_bool_t |
michael@0 | 337 | compute_transformed_extents (pixman_transform_t *transform, |
michael@0 | 338 | const pixman_box32_t *extents, |
michael@0 | 339 | box_48_16_t *transformed) |
michael@0 | 340 | { |
michael@0 | 341 | pixman_fixed_48_16_t tx1, ty1, tx2, ty2; |
michael@0 | 342 | pixman_fixed_t x1, y1, x2, y2; |
michael@0 | 343 | int i; |
michael@0 | 344 | |
michael@0 | 345 | x1 = pixman_int_to_fixed (extents->x1) + pixman_fixed_1 / 2; |
michael@0 | 346 | y1 = pixman_int_to_fixed (extents->y1) + pixman_fixed_1 / 2; |
michael@0 | 347 | x2 = pixman_int_to_fixed (extents->x2) - pixman_fixed_1 / 2; |
michael@0 | 348 | y2 = pixman_int_to_fixed (extents->y2) - pixman_fixed_1 / 2; |
michael@0 | 349 | |
michael@0 | 350 | if (!transform) |
michael@0 | 351 | { |
michael@0 | 352 | transformed->x1 = x1; |
michael@0 | 353 | transformed->y1 = y1; |
michael@0 | 354 | transformed->x2 = x2; |
michael@0 | 355 | transformed->y2 = y2; |
michael@0 | 356 | |
michael@0 | 357 | return TRUE; |
michael@0 | 358 | } |
michael@0 | 359 | |
michael@0 | 360 | tx1 = ty1 = INT64_MAX; |
michael@0 | 361 | tx2 = ty2 = INT64_MIN; |
michael@0 | 362 | |
michael@0 | 363 | for (i = 0; i < 4; ++i) |
michael@0 | 364 | { |
michael@0 | 365 | pixman_fixed_48_16_t tx, ty; |
michael@0 | 366 | pixman_vector_t v; |
michael@0 | 367 | |
michael@0 | 368 | v.vector[0] = (i & 0x01)? x1 : x2; |
michael@0 | 369 | v.vector[1] = (i & 0x02)? y1 : y2; |
michael@0 | 370 | v.vector[2] = pixman_fixed_1; |
michael@0 | 371 | |
michael@0 | 372 | if (!pixman_transform_point (transform, &v)) |
michael@0 | 373 | return FALSE; |
michael@0 | 374 | |
michael@0 | 375 | tx = (pixman_fixed_48_16_t)v.vector[0]; |
michael@0 | 376 | ty = (pixman_fixed_48_16_t)v.vector[1]; |
michael@0 | 377 | |
michael@0 | 378 | if (tx < tx1) |
michael@0 | 379 | tx1 = tx; |
michael@0 | 380 | if (ty < ty1) |
michael@0 | 381 | ty1 = ty; |
michael@0 | 382 | if (tx > tx2) |
michael@0 | 383 | tx2 = tx; |
michael@0 | 384 | if (ty > ty2) |
michael@0 | 385 | ty2 = ty; |
michael@0 | 386 | } |
michael@0 | 387 | |
michael@0 | 388 | transformed->x1 = tx1; |
michael@0 | 389 | transformed->y1 = ty1; |
michael@0 | 390 | transformed->x2 = tx2; |
michael@0 | 391 | transformed->y2 = ty2; |
michael@0 | 392 | |
michael@0 | 393 | return TRUE; |
michael@0 | 394 | } |
michael@0 | 395 | |
michael@0 | 396 | #define IS_16BIT(x) (((x) >= INT16_MIN) && ((x) <= INT16_MAX)) |
michael@0 | 397 | #define ABS(f) (((f) < 0)? (-(f)) : (f)) |
michael@0 | 398 | #define IS_16_16(f) (((f) >= pixman_min_fixed_48_16 && ((f) <= pixman_max_fixed_48_16))) |
michael@0 | 399 | |
michael@0 | 400 | static pixman_bool_t |
michael@0 | 401 | analyze_extent (pixman_image_t *image, |
michael@0 | 402 | const pixman_box32_t *extents, |
michael@0 | 403 | uint32_t *flags) |
michael@0 | 404 | { |
michael@0 | 405 | pixman_transform_t *transform; |
michael@0 | 406 | pixman_fixed_t x_off, y_off; |
michael@0 | 407 | pixman_fixed_t width, height; |
michael@0 | 408 | pixman_fixed_t *params; |
michael@0 | 409 | box_48_16_t transformed; |
michael@0 | 410 | pixman_box32_t exp_extents; |
michael@0 | 411 | |
michael@0 | 412 | if (!image) |
michael@0 | 413 | return TRUE; |
michael@0 | 414 | |
michael@0 | 415 | /* Some compositing functions walk one step |
michael@0 | 416 | * outside the destination rectangle, so we |
michael@0 | 417 | * check here that the expanded-by-one source |
michael@0 | 418 | * extents in destination space fits in 16 bits |
michael@0 | 419 | */ |
michael@0 | 420 | if (!IS_16BIT (extents->x1 - 1) || |
michael@0 | 421 | !IS_16BIT (extents->y1 - 1) || |
michael@0 | 422 | !IS_16BIT (extents->x2 + 1) || |
michael@0 | 423 | !IS_16BIT (extents->y2 + 1)) |
michael@0 | 424 | { |
michael@0 | 425 | return FALSE; |
michael@0 | 426 | } |
michael@0 | 427 | |
michael@0 | 428 | transform = image->common.transform; |
michael@0 | 429 | if (image->common.type == BITS) |
michael@0 | 430 | { |
michael@0 | 431 | /* During repeat mode calculations we might convert the |
michael@0 | 432 | * width/height of an image to fixed 16.16, so we need |
michael@0 | 433 | * them to be smaller than 16 bits. |
michael@0 | 434 | */ |
michael@0 | 435 | if (image->bits.width >= 0x7fff || image->bits.height >= 0x7fff) |
michael@0 | 436 | return FALSE; |
michael@0 | 437 | |
michael@0 | 438 | if ((image->common.flags & FAST_PATH_ID_TRANSFORM) == FAST_PATH_ID_TRANSFORM && |
michael@0 | 439 | extents->x1 >= 0 && |
michael@0 | 440 | extents->y1 >= 0 && |
michael@0 | 441 | extents->x2 <= image->bits.width && |
michael@0 | 442 | extents->y2 <= image->bits.height) |
michael@0 | 443 | { |
michael@0 | 444 | *flags |= FAST_PATH_SAMPLES_COVER_CLIP_NEAREST; |
michael@0 | 445 | return TRUE; |
michael@0 | 446 | } |
michael@0 | 447 | |
michael@0 | 448 | switch (image->common.filter) |
michael@0 | 449 | { |
michael@0 | 450 | case PIXMAN_FILTER_CONVOLUTION: |
michael@0 | 451 | params = image->common.filter_params; |
michael@0 | 452 | x_off = - pixman_fixed_e - ((params[0] - pixman_fixed_1) >> 1); |
michael@0 | 453 | y_off = - pixman_fixed_e - ((params[1] - pixman_fixed_1) >> 1); |
michael@0 | 454 | width = params[0]; |
michael@0 | 455 | height = params[1]; |
michael@0 | 456 | break; |
michael@0 | 457 | |
michael@0 | 458 | case PIXMAN_FILTER_SEPARABLE_CONVOLUTION: |
michael@0 | 459 | params = image->common.filter_params; |
michael@0 | 460 | x_off = - pixman_fixed_e - ((params[0] - pixman_fixed_1) >> 1); |
michael@0 | 461 | y_off = - pixman_fixed_e - ((params[1] - pixman_fixed_1) >> 1); |
michael@0 | 462 | width = params[0]; |
michael@0 | 463 | height = params[1]; |
michael@0 | 464 | break; |
michael@0 | 465 | |
michael@0 | 466 | case PIXMAN_FILTER_GOOD: |
michael@0 | 467 | case PIXMAN_FILTER_BEST: |
michael@0 | 468 | case PIXMAN_FILTER_BILINEAR: |
michael@0 | 469 | x_off = - pixman_fixed_1 / 2; |
michael@0 | 470 | y_off = - pixman_fixed_1 / 2; |
michael@0 | 471 | width = pixman_fixed_1; |
michael@0 | 472 | height = pixman_fixed_1; |
michael@0 | 473 | break; |
michael@0 | 474 | |
michael@0 | 475 | case PIXMAN_FILTER_FAST: |
michael@0 | 476 | case PIXMAN_FILTER_NEAREST: |
michael@0 | 477 | x_off = - pixman_fixed_e; |
michael@0 | 478 | y_off = - pixman_fixed_e; |
michael@0 | 479 | width = 0; |
michael@0 | 480 | height = 0; |
michael@0 | 481 | break; |
michael@0 | 482 | |
michael@0 | 483 | default: |
michael@0 | 484 | return FALSE; |
michael@0 | 485 | } |
michael@0 | 486 | } |
michael@0 | 487 | else |
michael@0 | 488 | { |
michael@0 | 489 | x_off = 0; |
michael@0 | 490 | y_off = 0; |
michael@0 | 491 | width = 0; |
michael@0 | 492 | height = 0; |
michael@0 | 493 | } |
michael@0 | 494 | |
michael@0 | 495 | if (!compute_transformed_extents (transform, extents, &transformed)) |
michael@0 | 496 | return FALSE; |
michael@0 | 497 | |
michael@0 | 498 | /* Expand the source area by a tiny bit so account of different rounding that |
michael@0 | 499 | * may happen during sampling. Note that (8 * pixman_fixed_e) is very far from |
michael@0 | 500 | * 0.5 so this won't cause the area computed to be overly pessimistic. |
michael@0 | 501 | */ |
michael@0 | 502 | transformed.x1 -= 8 * pixman_fixed_e; |
michael@0 | 503 | transformed.y1 -= 8 * pixman_fixed_e; |
michael@0 | 504 | transformed.x2 += 8 * pixman_fixed_e; |
michael@0 | 505 | transformed.y2 += 8 * pixman_fixed_e; |
michael@0 | 506 | |
michael@0 | 507 | if (image->common.type == BITS) |
michael@0 | 508 | { |
michael@0 | 509 | if (pixman_fixed_to_int (transformed.x1) >= 0 && |
michael@0 | 510 | pixman_fixed_to_int (transformed.y1) >= 0 && |
michael@0 | 511 | pixman_fixed_to_int (transformed.x2) < image->bits.width && |
michael@0 | 512 | pixman_fixed_to_int (transformed.y2) < image->bits.height) |
michael@0 | 513 | { |
michael@0 | 514 | *flags |= FAST_PATH_SAMPLES_COVER_CLIP_NEAREST; |
michael@0 | 515 | } |
michael@0 | 516 | |
michael@0 | 517 | if (pixman_fixed_to_int (transformed.x1 - pixman_fixed_1 / 2) >= 0 && |
michael@0 | 518 | pixman_fixed_to_int (transformed.y1 - pixman_fixed_1 / 2) >= 0 && |
michael@0 | 519 | pixman_fixed_to_int (transformed.x2 + pixman_fixed_1 / 2) < image->bits.width && |
michael@0 | 520 | pixman_fixed_to_int (transformed.y2 + pixman_fixed_1 / 2) < image->bits.height) |
michael@0 | 521 | { |
michael@0 | 522 | *flags |= FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR; |
michael@0 | 523 | } |
michael@0 | 524 | } |
michael@0 | 525 | |
michael@0 | 526 | /* Check we don't overflow when the destination extents are expanded by one. |
michael@0 | 527 | * This ensures that compositing functions can simply walk the source space |
michael@0 | 528 | * using 16.16 variables without worrying about overflow. |
michael@0 | 529 | */ |
michael@0 | 530 | exp_extents = *extents; |
michael@0 | 531 | exp_extents.x1 -= 1; |
michael@0 | 532 | exp_extents.y1 -= 1; |
michael@0 | 533 | exp_extents.x2 += 1; |
michael@0 | 534 | exp_extents.y2 += 1; |
michael@0 | 535 | |
michael@0 | 536 | if (!compute_transformed_extents (transform, &exp_extents, &transformed)) |
michael@0 | 537 | return FALSE; |
michael@0 | 538 | |
michael@0 | 539 | if (!IS_16_16 (transformed.x1 + x_off - 8 * pixman_fixed_e) || |
michael@0 | 540 | !IS_16_16 (transformed.y1 + y_off - 8 * pixman_fixed_e) || |
michael@0 | 541 | !IS_16_16 (transformed.x2 + x_off + 8 * pixman_fixed_e + width) || |
michael@0 | 542 | !IS_16_16 (transformed.y2 + y_off + 8 * pixman_fixed_e + height)) |
michael@0 | 543 | { |
michael@0 | 544 | return FALSE; |
michael@0 | 545 | } |
michael@0 | 546 | |
michael@0 | 547 | return TRUE; |
michael@0 | 548 | } |
michael@0 | 549 | |
michael@0 | 550 | /* |
michael@0 | 551 | * Work around GCC bug causing crashes in Mozilla with SSE2 |
michael@0 | 552 | * |
michael@0 | 553 | * When using -msse, gcc generates movdqa instructions assuming that |
michael@0 | 554 | * the stack is 16 byte aligned. Unfortunately some applications, such |
michael@0 | 555 | * as Mozilla and Mono, end up aligning the stack to 4 bytes, which |
michael@0 | 556 | * causes the movdqa instructions to fail. |
michael@0 | 557 | * |
michael@0 | 558 | * The __force_align_arg_pointer__ makes gcc generate a prologue that |
michael@0 | 559 | * realigns the stack pointer to 16 bytes. |
michael@0 | 560 | * |
michael@0 | 561 | * On x86-64 this is not necessary because the standard ABI already |
michael@0 | 562 | * calls for a 16 byte aligned stack. |
michael@0 | 563 | * |
michael@0 | 564 | * See https://bugs.freedesktop.org/show_bug.cgi?id=15693 |
michael@0 | 565 | */ |
michael@0 | 566 | #if defined (USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) |
michael@0 | 567 | __attribute__((__force_align_arg_pointer__)) |
michael@0 | 568 | #endif |
michael@0 | 569 | PIXMAN_EXPORT void |
michael@0 | 570 | pixman_image_composite32 (pixman_op_t op, |
michael@0 | 571 | pixman_image_t * src, |
michael@0 | 572 | pixman_image_t * mask, |
michael@0 | 573 | pixman_image_t * dest, |
michael@0 | 574 | int32_t src_x, |
michael@0 | 575 | int32_t src_y, |
michael@0 | 576 | int32_t mask_x, |
michael@0 | 577 | int32_t mask_y, |
michael@0 | 578 | int32_t dest_x, |
michael@0 | 579 | int32_t dest_y, |
michael@0 | 580 | int32_t width, |
michael@0 | 581 | int32_t height) |
michael@0 | 582 | { |
michael@0 | 583 | pixman_format_code_t src_format, mask_format, dest_format; |
michael@0 | 584 | pixman_region32_t region; |
michael@0 | 585 | pixman_box32_t extents; |
michael@0 | 586 | pixman_implementation_t *imp; |
michael@0 | 587 | pixman_composite_func_t func; |
michael@0 | 588 | pixman_composite_info_t info; |
michael@0 | 589 | const pixman_box32_t *pbox; |
michael@0 | 590 | int n; |
michael@0 | 591 | |
michael@0 | 592 | _pixman_image_validate (src); |
michael@0 | 593 | if (mask) |
michael@0 | 594 | _pixman_image_validate (mask); |
michael@0 | 595 | _pixman_image_validate (dest); |
michael@0 | 596 | |
michael@0 | 597 | src_format = src->common.extended_format_code; |
michael@0 | 598 | info.src_flags = src->common.flags; |
michael@0 | 599 | |
michael@0 | 600 | if (mask && !(mask->common.flags & FAST_PATH_IS_OPAQUE)) |
michael@0 | 601 | { |
michael@0 | 602 | mask_format = mask->common.extended_format_code; |
michael@0 | 603 | info.mask_flags = mask->common.flags; |
michael@0 | 604 | } |
michael@0 | 605 | else |
michael@0 | 606 | { |
michael@0 | 607 | mask_format = PIXMAN_null; |
michael@0 | 608 | info.mask_flags = FAST_PATH_IS_OPAQUE; |
michael@0 | 609 | } |
michael@0 | 610 | |
michael@0 | 611 | dest_format = dest->common.extended_format_code; |
michael@0 | 612 | info.dest_flags = dest->common.flags; |
michael@0 | 613 | |
michael@0 | 614 | /* Check for pixbufs */ |
michael@0 | 615 | if ((mask_format == PIXMAN_a8r8g8b8 || mask_format == PIXMAN_a8b8g8r8) && |
michael@0 | 616 | (src->type == BITS && src->bits.bits == mask->bits.bits) && |
michael@0 | 617 | (src->common.repeat == mask->common.repeat) && |
michael@0 | 618 | (info.src_flags & info.mask_flags & FAST_PATH_ID_TRANSFORM) && |
michael@0 | 619 | (src_x == mask_x && src_y == mask_y)) |
michael@0 | 620 | { |
michael@0 | 621 | if (src_format == PIXMAN_x8b8g8r8) |
michael@0 | 622 | src_format = mask_format = PIXMAN_pixbuf; |
michael@0 | 623 | else if (src_format == PIXMAN_x8r8g8b8) |
michael@0 | 624 | src_format = mask_format = PIXMAN_rpixbuf; |
michael@0 | 625 | } |
michael@0 | 626 | |
michael@0 | 627 | pixman_region32_init (®ion); |
michael@0 | 628 | |
michael@0 | 629 | if (!_pixman_compute_composite_region32 ( |
michael@0 | 630 | ®ion, src, mask, dest, |
michael@0 | 631 | src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height)) |
michael@0 | 632 | { |
michael@0 | 633 | goto out; |
michael@0 | 634 | } |
michael@0 | 635 | |
michael@0 | 636 | extents = *pixman_region32_extents (®ion); |
michael@0 | 637 | |
michael@0 | 638 | extents.x1 -= dest_x - src_x; |
michael@0 | 639 | extents.y1 -= dest_y - src_y; |
michael@0 | 640 | extents.x2 -= dest_x - src_x; |
michael@0 | 641 | extents.y2 -= dest_y - src_y; |
michael@0 | 642 | |
michael@0 | 643 | if (!analyze_extent (src, &extents, &info.src_flags)) |
michael@0 | 644 | goto out; |
michael@0 | 645 | |
michael@0 | 646 | extents.x1 -= src_x - mask_x; |
michael@0 | 647 | extents.y1 -= src_y - mask_y; |
michael@0 | 648 | extents.x2 -= src_x - mask_x; |
michael@0 | 649 | extents.y2 -= src_y - mask_y; |
michael@0 | 650 | |
michael@0 | 651 | if (!analyze_extent (mask, &extents, &info.mask_flags)) |
michael@0 | 652 | goto out; |
michael@0 | 653 | |
michael@0 | 654 | /* If the clip is within the source samples, and the samples are |
michael@0 | 655 | * opaque, then the source is effectively opaque. |
michael@0 | 656 | */ |
michael@0 | 657 | #define NEAREST_OPAQUE (FAST_PATH_SAMPLES_OPAQUE | \ |
michael@0 | 658 | FAST_PATH_NEAREST_FILTER | \ |
michael@0 | 659 | FAST_PATH_SAMPLES_COVER_CLIP_NEAREST) |
michael@0 | 660 | #define BILINEAR_OPAQUE (FAST_PATH_SAMPLES_OPAQUE | \ |
michael@0 | 661 | FAST_PATH_BILINEAR_FILTER | \ |
michael@0 | 662 | FAST_PATH_SAMPLES_COVER_CLIP_BILINEAR) |
michael@0 | 663 | |
michael@0 | 664 | if ((info.src_flags & NEAREST_OPAQUE) == NEAREST_OPAQUE || |
michael@0 | 665 | (info.src_flags & BILINEAR_OPAQUE) == BILINEAR_OPAQUE) |
michael@0 | 666 | { |
michael@0 | 667 | info.src_flags |= FAST_PATH_IS_OPAQUE; |
michael@0 | 668 | } |
michael@0 | 669 | |
michael@0 | 670 | if ((info.mask_flags & NEAREST_OPAQUE) == NEAREST_OPAQUE || |
michael@0 | 671 | (info.mask_flags & BILINEAR_OPAQUE) == BILINEAR_OPAQUE) |
michael@0 | 672 | { |
michael@0 | 673 | info.mask_flags |= FAST_PATH_IS_OPAQUE; |
michael@0 | 674 | } |
michael@0 | 675 | |
michael@0 | 676 | /* |
michael@0 | 677 | * Check if we can replace our operator by a simpler one |
michael@0 | 678 | * if the src or dest are opaque. The output operator should be |
michael@0 | 679 | * mathematically equivalent to the source. |
michael@0 | 680 | */ |
michael@0 | 681 | info.op = optimize_operator (op, info.src_flags, info.mask_flags, info.dest_flags); |
michael@0 | 682 | |
michael@0 | 683 | _pixman_implementation_lookup_composite ( |
michael@0 | 684 | get_implementation (), info.op, |
michael@0 | 685 | src_format, info.src_flags, |
michael@0 | 686 | mask_format, info.mask_flags, |
michael@0 | 687 | dest_format, info.dest_flags, |
michael@0 | 688 | &imp, &func); |
michael@0 | 689 | |
michael@0 | 690 | info.src_image = src; |
michael@0 | 691 | info.mask_image = mask; |
michael@0 | 692 | info.dest_image = dest; |
michael@0 | 693 | |
michael@0 | 694 | pbox = pixman_region32_rectangles (®ion, &n); |
michael@0 | 695 | |
michael@0 | 696 | while (n--) |
michael@0 | 697 | { |
michael@0 | 698 | info.src_x = pbox->x1 + src_x - dest_x; |
michael@0 | 699 | info.src_y = pbox->y1 + src_y - dest_y; |
michael@0 | 700 | info.mask_x = pbox->x1 + mask_x - dest_x; |
michael@0 | 701 | info.mask_y = pbox->y1 + mask_y - dest_y; |
michael@0 | 702 | info.dest_x = pbox->x1; |
michael@0 | 703 | info.dest_y = pbox->y1; |
michael@0 | 704 | info.width = pbox->x2 - pbox->x1; |
michael@0 | 705 | info.height = pbox->y2 - pbox->y1; |
michael@0 | 706 | |
michael@0 | 707 | func (imp, &info); |
michael@0 | 708 | |
michael@0 | 709 | pbox++; |
michael@0 | 710 | } |
michael@0 | 711 | |
michael@0 | 712 | out: |
michael@0 | 713 | pixman_region32_fini (®ion); |
michael@0 | 714 | } |
michael@0 | 715 | |
michael@0 | 716 | PIXMAN_EXPORT void |
michael@0 | 717 | pixman_image_composite (pixman_op_t op, |
michael@0 | 718 | pixman_image_t * src, |
michael@0 | 719 | pixman_image_t * mask, |
michael@0 | 720 | pixman_image_t * dest, |
michael@0 | 721 | int16_t src_x, |
michael@0 | 722 | int16_t src_y, |
michael@0 | 723 | int16_t mask_x, |
michael@0 | 724 | int16_t mask_y, |
michael@0 | 725 | int16_t dest_x, |
michael@0 | 726 | int16_t dest_y, |
michael@0 | 727 | uint16_t width, |
michael@0 | 728 | uint16_t height) |
michael@0 | 729 | { |
michael@0 | 730 | pixman_image_composite32 (op, src, mask, dest, src_x, src_y, |
michael@0 | 731 | mask_x, mask_y, dest_x, dest_y, width, height); |
michael@0 | 732 | } |
michael@0 | 733 | |
michael@0 | 734 | PIXMAN_EXPORT pixman_bool_t |
michael@0 | 735 | pixman_blt (uint32_t *src_bits, |
michael@0 | 736 | uint32_t *dst_bits, |
michael@0 | 737 | int src_stride, |
michael@0 | 738 | int dst_stride, |
michael@0 | 739 | int src_bpp, |
michael@0 | 740 | int dst_bpp, |
michael@0 | 741 | int src_x, |
michael@0 | 742 | int src_y, |
michael@0 | 743 | int dest_x, |
michael@0 | 744 | int dest_y, |
michael@0 | 745 | int width, |
michael@0 | 746 | int height) |
michael@0 | 747 | { |
michael@0 | 748 | return _pixman_implementation_blt (get_implementation(), |
michael@0 | 749 | src_bits, dst_bits, src_stride, dst_stride, |
michael@0 | 750 | src_bpp, dst_bpp, |
michael@0 | 751 | src_x, src_y, |
michael@0 | 752 | dest_x, dest_y, |
michael@0 | 753 | width, height); |
michael@0 | 754 | } |
michael@0 | 755 | |
michael@0 | 756 | PIXMAN_EXPORT pixman_bool_t |
michael@0 | 757 | pixman_fill (uint32_t *bits, |
michael@0 | 758 | int stride, |
michael@0 | 759 | int bpp, |
michael@0 | 760 | int x, |
michael@0 | 761 | int y, |
michael@0 | 762 | int width, |
michael@0 | 763 | int height, |
michael@0 | 764 | uint32_t filler) |
michael@0 | 765 | { |
michael@0 | 766 | return _pixman_implementation_fill ( |
michael@0 | 767 | get_implementation(), bits, stride, bpp, x, y, width, height, filler); |
michael@0 | 768 | } |
michael@0 | 769 | |
michael@0 | 770 | static uint32_t |
michael@0 | 771 | color_to_uint32 (const pixman_color_t *color) |
michael@0 | 772 | { |
michael@0 | 773 | return |
michael@0 | 774 | (color->alpha >> 8 << 24) | |
michael@0 | 775 | (color->red >> 8 << 16) | |
michael@0 | 776 | (color->green & 0xff00) | |
michael@0 | 777 | (color->blue >> 8); |
michael@0 | 778 | } |
michael@0 | 779 | |
michael@0 | 780 | static pixman_bool_t |
michael@0 | 781 | color_to_pixel (const pixman_color_t *color, |
michael@0 | 782 | uint32_t * pixel, |
michael@0 | 783 | pixman_format_code_t format) |
michael@0 | 784 | { |
michael@0 | 785 | uint32_t c = color_to_uint32 (color); |
michael@0 | 786 | |
michael@0 | 787 | if (!(format == PIXMAN_a8r8g8b8 || |
michael@0 | 788 | format == PIXMAN_x8r8g8b8 || |
michael@0 | 789 | format == PIXMAN_a8b8g8r8 || |
michael@0 | 790 | format == PIXMAN_x8b8g8r8 || |
michael@0 | 791 | format == PIXMAN_b8g8r8a8 || |
michael@0 | 792 | format == PIXMAN_b8g8r8x8 || |
michael@0 | 793 | format == PIXMAN_r8g8b8a8 || |
michael@0 | 794 | format == PIXMAN_r8g8b8x8 || |
michael@0 | 795 | format == PIXMAN_r5g6b5 || |
michael@0 | 796 | format == PIXMAN_b5g6r5 || |
michael@0 | 797 | format == PIXMAN_a8 || |
michael@0 | 798 | format == PIXMAN_a1)) |
michael@0 | 799 | { |
michael@0 | 800 | return FALSE; |
michael@0 | 801 | } |
michael@0 | 802 | |
michael@0 | 803 | if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) |
michael@0 | 804 | { |
michael@0 | 805 | c = ((c & 0xff000000) >> 0) | |
michael@0 | 806 | ((c & 0x00ff0000) >> 16) | |
michael@0 | 807 | ((c & 0x0000ff00) >> 0) | |
michael@0 | 808 | ((c & 0x000000ff) << 16); |
michael@0 | 809 | } |
michael@0 | 810 | if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) |
michael@0 | 811 | { |
michael@0 | 812 | c = ((c & 0xff000000) >> 24) | |
michael@0 | 813 | ((c & 0x00ff0000) >> 8) | |
michael@0 | 814 | ((c & 0x0000ff00) << 8) | |
michael@0 | 815 | ((c & 0x000000ff) << 24); |
michael@0 | 816 | } |
michael@0 | 817 | if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_RGBA) |
michael@0 | 818 | c = ((c & 0xff000000) >> 24) | (c << 8); |
michael@0 | 819 | |
michael@0 | 820 | if (format == PIXMAN_a1) |
michael@0 | 821 | c = c >> 31; |
michael@0 | 822 | else if (format == PIXMAN_a8) |
michael@0 | 823 | c = c >> 24; |
michael@0 | 824 | else if (format == PIXMAN_r5g6b5 || |
michael@0 | 825 | format == PIXMAN_b5g6r5) |
michael@0 | 826 | c = convert_8888_to_0565 (c); |
michael@0 | 827 | |
michael@0 | 828 | #if 0 |
michael@0 | 829 | printf ("color: %x %x %x %x\n", color->alpha, color->red, color->green, color->blue); |
michael@0 | 830 | printf ("pixel: %x\n", c); |
michael@0 | 831 | #endif |
michael@0 | 832 | |
michael@0 | 833 | *pixel = c; |
michael@0 | 834 | return TRUE; |
michael@0 | 835 | } |
michael@0 | 836 | |
michael@0 | 837 | PIXMAN_EXPORT pixman_bool_t |
michael@0 | 838 | pixman_image_fill_rectangles (pixman_op_t op, |
michael@0 | 839 | pixman_image_t * dest, |
michael@0 | 840 | const pixman_color_t * color, |
michael@0 | 841 | int n_rects, |
michael@0 | 842 | const pixman_rectangle16_t *rects) |
michael@0 | 843 | { |
michael@0 | 844 | pixman_box32_t stack_boxes[6]; |
michael@0 | 845 | pixman_box32_t *boxes; |
michael@0 | 846 | pixman_bool_t result; |
michael@0 | 847 | int i; |
michael@0 | 848 | |
michael@0 | 849 | if (n_rects > 6) |
michael@0 | 850 | { |
michael@0 | 851 | boxes = pixman_malloc_ab (sizeof (pixman_box32_t), n_rects); |
michael@0 | 852 | if (boxes == NULL) |
michael@0 | 853 | return FALSE; |
michael@0 | 854 | } |
michael@0 | 855 | else |
michael@0 | 856 | { |
michael@0 | 857 | boxes = stack_boxes; |
michael@0 | 858 | } |
michael@0 | 859 | |
michael@0 | 860 | for (i = 0; i < n_rects; ++i) |
michael@0 | 861 | { |
michael@0 | 862 | boxes[i].x1 = rects[i].x; |
michael@0 | 863 | boxes[i].y1 = rects[i].y; |
michael@0 | 864 | boxes[i].x2 = boxes[i].x1 + rects[i].width; |
michael@0 | 865 | boxes[i].y2 = boxes[i].y1 + rects[i].height; |
michael@0 | 866 | } |
michael@0 | 867 | |
michael@0 | 868 | result = pixman_image_fill_boxes (op, dest, color, n_rects, boxes); |
michael@0 | 869 | |
michael@0 | 870 | if (boxes != stack_boxes) |
michael@0 | 871 | free (boxes); |
michael@0 | 872 | |
michael@0 | 873 | return result; |
michael@0 | 874 | } |
michael@0 | 875 | |
michael@0 | 876 | PIXMAN_EXPORT pixman_bool_t |
michael@0 | 877 | pixman_image_fill_boxes (pixman_op_t op, |
michael@0 | 878 | pixman_image_t * dest, |
michael@0 | 879 | const pixman_color_t *color, |
michael@0 | 880 | int n_boxes, |
michael@0 | 881 | const pixman_box32_t *boxes) |
michael@0 | 882 | { |
michael@0 | 883 | pixman_image_t *solid; |
michael@0 | 884 | pixman_color_t c; |
michael@0 | 885 | int i; |
michael@0 | 886 | |
michael@0 | 887 | _pixman_image_validate (dest); |
michael@0 | 888 | |
michael@0 | 889 | if (color->alpha == 0xffff) |
michael@0 | 890 | { |
michael@0 | 891 | if (op == PIXMAN_OP_OVER) |
michael@0 | 892 | op = PIXMAN_OP_SRC; |
michael@0 | 893 | } |
michael@0 | 894 | |
michael@0 | 895 | if (op == PIXMAN_OP_CLEAR) |
michael@0 | 896 | { |
michael@0 | 897 | c.red = 0; |
michael@0 | 898 | c.green = 0; |
michael@0 | 899 | c.blue = 0; |
michael@0 | 900 | c.alpha = 0; |
michael@0 | 901 | |
michael@0 | 902 | color = &c; |
michael@0 | 903 | |
michael@0 | 904 | op = PIXMAN_OP_SRC; |
michael@0 | 905 | } |
michael@0 | 906 | |
michael@0 | 907 | if (op == PIXMAN_OP_SRC) |
michael@0 | 908 | { |
michael@0 | 909 | uint32_t pixel; |
michael@0 | 910 | |
michael@0 | 911 | if (color_to_pixel (color, &pixel, dest->bits.format)) |
michael@0 | 912 | { |
michael@0 | 913 | pixman_region32_t fill_region; |
michael@0 | 914 | int n_rects, j; |
michael@0 | 915 | pixman_box32_t *rects; |
michael@0 | 916 | |
michael@0 | 917 | if (!pixman_region32_init_rects (&fill_region, boxes, n_boxes)) |
michael@0 | 918 | return FALSE; |
michael@0 | 919 | |
michael@0 | 920 | if (dest->common.have_clip_region) |
michael@0 | 921 | { |
michael@0 | 922 | if (!pixman_region32_intersect (&fill_region, |
michael@0 | 923 | &fill_region, |
michael@0 | 924 | &dest->common.clip_region)) |
michael@0 | 925 | return FALSE; |
michael@0 | 926 | } |
michael@0 | 927 | |
michael@0 | 928 | rects = pixman_region32_rectangles (&fill_region, &n_rects); |
michael@0 | 929 | for (j = 0; j < n_rects; ++j) |
michael@0 | 930 | { |
michael@0 | 931 | const pixman_box32_t *rect = &(rects[j]); |
michael@0 | 932 | pixman_fill (dest->bits.bits, dest->bits.rowstride, PIXMAN_FORMAT_BPP (dest->bits.format), |
michael@0 | 933 | rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1, |
michael@0 | 934 | pixel); |
michael@0 | 935 | } |
michael@0 | 936 | |
michael@0 | 937 | pixman_region32_fini (&fill_region); |
michael@0 | 938 | return TRUE; |
michael@0 | 939 | } |
michael@0 | 940 | } |
michael@0 | 941 | |
michael@0 | 942 | solid = pixman_image_create_solid_fill (color); |
michael@0 | 943 | if (!solid) |
michael@0 | 944 | return FALSE; |
michael@0 | 945 | |
michael@0 | 946 | for (i = 0; i < n_boxes; ++i) |
michael@0 | 947 | { |
michael@0 | 948 | const pixman_box32_t *box = &(boxes[i]); |
michael@0 | 949 | |
michael@0 | 950 | pixman_image_composite32 (op, solid, NULL, dest, |
michael@0 | 951 | 0, 0, 0, 0, |
michael@0 | 952 | box->x1, box->y1, |
michael@0 | 953 | box->x2 - box->x1, box->y2 - box->y1); |
michael@0 | 954 | } |
michael@0 | 955 | |
michael@0 | 956 | pixman_image_unref (solid); |
michael@0 | 957 | |
michael@0 | 958 | return TRUE; |
michael@0 | 959 | } |
michael@0 | 960 | |
michael@0 | 961 | /** |
michael@0 | 962 | * pixman_version: |
michael@0 | 963 | * |
michael@0 | 964 | * Returns the version of the pixman library encoded in a single |
michael@0 | 965 | * integer as per %PIXMAN_VERSION_ENCODE. The encoding ensures that |
michael@0 | 966 | * later versions compare greater than earlier versions. |
michael@0 | 967 | * |
michael@0 | 968 | * A run-time comparison to check that pixman's version is greater than |
michael@0 | 969 | * or equal to version X.Y.Z could be performed as follows: |
michael@0 | 970 | * |
michael@0 | 971 | * <informalexample><programlisting> |
michael@0 | 972 | * if (pixman_version() >= PIXMAN_VERSION_ENCODE(X,Y,Z)) {...} |
michael@0 | 973 | * </programlisting></informalexample> |
michael@0 | 974 | * |
michael@0 | 975 | * See also pixman_version_string() as well as the compile-time |
michael@0 | 976 | * equivalents %PIXMAN_VERSION and %PIXMAN_VERSION_STRING. |
michael@0 | 977 | * |
michael@0 | 978 | * Return value: the encoded version. |
michael@0 | 979 | **/ |
michael@0 | 980 | PIXMAN_EXPORT int |
michael@0 | 981 | pixman_version (void) |
michael@0 | 982 | { |
michael@0 | 983 | return PIXMAN_VERSION; |
michael@0 | 984 | } |
michael@0 | 985 | |
michael@0 | 986 | /** |
michael@0 | 987 | * pixman_version_string: |
michael@0 | 988 | * |
michael@0 | 989 | * Returns the version of the pixman library as a human-readable string |
michael@0 | 990 | * of the form "X.Y.Z". |
michael@0 | 991 | * |
michael@0 | 992 | * See also pixman_version() as well as the compile-time equivalents |
michael@0 | 993 | * %PIXMAN_VERSION_STRING and %PIXMAN_VERSION. |
michael@0 | 994 | * |
michael@0 | 995 | * Return value: a string containing the version. |
michael@0 | 996 | **/ |
michael@0 | 997 | PIXMAN_EXPORT const char* |
michael@0 | 998 | pixman_version_string (void) |
michael@0 | 999 | { |
michael@0 | 1000 | return PIXMAN_VERSION_STRING; |
michael@0 | 1001 | } |
michael@0 | 1002 | |
michael@0 | 1003 | /** |
michael@0 | 1004 | * pixman_format_supported_source: |
michael@0 | 1005 | * @format: A pixman_format_code_t format |
michael@0 | 1006 | * |
michael@0 | 1007 | * Return value: whether the provided format code is a supported |
michael@0 | 1008 | * format for a pixman surface used as a source in |
michael@0 | 1009 | * rendering. |
michael@0 | 1010 | * |
michael@0 | 1011 | * Currently, all pixman_format_code_t values are supported. |
michael@0 | 1012 | **/ |
michael@0 | 1013 | PIXMAN_EXPORT pixman_bool_t |
michael@0 | 1014 | pixman_format_supported_source (pixman_format_code_t format) |
michael@0 | 1015 | { |
michael@0 | 1016 | switch (format) |
michael@0 | 1017 | { |
michael@0 | 1018 | /* 32 bpp formats */ |
michael@0 | 1019 | case PIXMAN_a2b10g10r10: |
michael@0 | 1020 | case PIXMAN_x2b10g10r10: |
michael@0 | 1021 | case PIXMAN_a2r10g10b10: |
michael@0 | 1022 | case PIXMAN_x2r10g10b10: |
michael@0 | 1023 | case PIXMAN_a8r8g8b8: |
michael@0 | 1024 | case PIXMAN_a8r8g8b8_sRGB: |
michael@0 | 1025 | case PIXMAN_x8r8g8b8: |
michael@0 | 1026 | case PIXMAN_a8b8g8r8: |
michael@0 | 1027 | case PIXMAN_x8b8g8r8: |
michael@0 | 1028 | case PIXMAN_b8g8r8a8: |
michael@0 | 1029 | case PIXMAN_b8g8r8x8: |
michael@0 | 1030 | case PIXMAN_r8g8b8a8: |
michael@0 | 1031 | case PIXMAN_r8g8b8x8: |
michael@0 | 1032 | case PIXMAN_r8g8b8: |
michael@0 | 1033 | case PIXMAN_b8g8r8: |
michael@0 | 1034 | case PIXMAN_r5g6b5: |
michael@0 | 1035 | case PIXMAN_b5g6r5: |
michael@0 | 1036 | case PIXMAN_x14r6g6b6: |
michael@0 | 1037 | /* 16 bpp formats */ |
michael@0 | 1038 | case PIXMAN_a1r5g5b5: |
michael@0 | 1039 | case PIXMAN_x1r5g5b5: |
michael@0 | 1040 | case PIXMAN_a1b5g5r5: |
michael@0 | 1041 | case PIXMAN_x1b5g5r5: |
michael@0 | 1042 | case PIXMAN_a4r4g4b4: |
michael@0 | 1043 | case PIXMAN_x4r4g4b4: |
michael@0 | 1044 | case PIXMAN_a4b4g4r4: |
michael@0 | 1045 | case PIXMAN_x4b4g4r4: |
michael@0 | 1046 | /* 8bpp formats */ |
michael@0 | 1047 | case PIXMAN_a8: |
michael@0 | 1048 | case PIXMAN_r3g3b2: |
michael@0 | 1049 | case PIXMAN_b2g3r3: |
michael@0 | 1050 | case PIXMAN_a2r2g2b2: |
michael@0 | 1051 | case PIXMAN_a2b2g2r2: |
michael@0 | 1052 | case PIXMAN_c8: |
michael@0 | 1053 | case PIXMAN_g8: |
michael@0 | 1054 | case PIXMAN_x4a4: |
michael@0 | 1055 | /* Collides with PIXMAN_c8 |
michael@0 | 1056 | case PIXMAN_x4c4: |
michael@0 | 1057 | */ |
michael@0 | 1058 | /* Collides with PIXMAN_g8 |
michael@0 | 1059 | case PIXMAN_x4g4: |
michael@0 | 1060 | */ |
michael@0 | 1061 | /* 4bpp formats */ |
michael@0 | 1062 | case PIXMAN_a4: |
michael@0 | 1063 | case PIXMAN_r1g2b1: |
michael@0 | 1064 | case PIXMAN_b1g2r1: |
michael@0 | 1065 | case PIXMAN_a1r1g1b1: |
michael@0 | 1066 | case PIXMAN_a1b1g1r1: |
michael@0 | 1067 | case PIXMAN_c4: |
michael@0 | 1068 | case PIXMAN_g4: |
michael@0 | 1069 | /* 1bpp formats */ |
michael@0 | 1070 | case PIXMAN_a1: |
michael@0 | 1071 | case PIXMAN_g1: |
michael@0 | 1072 | /* YUV formats */ |
michael@0 | 1073 | case PIXMAN_yuy2: |
michael@0 | 1074 | case PIXMAN_yv12: |
michael@0 | 1075 | return TRUE; |
michael@0 | 1076 | |
michael@0 | 1077 | default: |
michael@0 | 1078 | return FALSE; |
michael@0 | 1079 | } |
michael@0 | 1080 | } |
michael@0 | 1081 | |
michael@0 | 1082 | /** |
michael@0 | 1083 | * pixman_format_supported_destination: |
michael@0 | 1084 | * @format: A pixman_format_code_t format |
michael@0 | 1085 | * |
michael@0 | 1086 | * Return value: whether the provided format code is a supported |
michael@0 | 1087 | * format for a pixman surface used as a destination in |
michael@0 | 1088 | * rendering. |
michael@0 | 1089 | * |
michael@0 | 1090 | * Currently, all pixman_format_code_t values are supported |
michael@0 | 1091 | * except for the YUV formats. |
michael@0 | 1092 | **/ |
michael@0 | 1093 | PIXMAN_EXPORT pixman_bool_t |
michael@0 | 1094 | pixman_format_supported_destination (pixman_format_code_t format) |
michael@0 | 1095 | { |
michael@0 | 1096 | /* YUV formats cannot be written to at the moment */ |
michael@0 | 1097 | if (format == PIXMAN_yuy2 || format == PIXMAN_yv12) |
michael@0 | 1098 | return FALSE; |
michael@0 | 1099 | |
michael@0 | 1100 | return pixman_format_supported_source (format); |
michael@0 | 1101 | } |
michael@0 | 1102 | |
michael@0 | 1103 | PIXMAN_EXPORT pixman_bool_t |
michael@0 | 1104 | pixman_compute_composite_region (pixman_region16_t * region, |
michael@0 | 1105 | pixman_image_t * src_image, |
michael@0 | 1106 | pixman_image_t * mask_image, |
michael@0 | 1107 | pixman_image_t * dest_image, |
michael@0 | 1108 | int16_t src_x, |
michael@0 | 1109 | int16_t src_y, |
michael@0 | 1110 | int16_t mask_x, |
michael@0 | 1111 | int16_t mask_y, |
michael@0 | 1112 | int16_t dest_x, |
michael@0 | 1113 | int16_t dest_y, |
michael@0 | 1114 | uint16_t width, |
michael@0 | 1115 | uint16_t height) |
michael@0 | 1116 | { |
michael@0 | 1117 | pixman_region32_t r32; |
michael@0 | 1118 | pixman_bool_t retval; |
michael@0 | 1119 | |
michael@0 | 1120 | pixman_region32_init (&r32); |
michael@0 | 1121 | |
michael@0 | 1122 | retval = _pixman_compute_composite_region32 ( |
michael@0 | 1123 | &r32, src_image, mask_image, dest_image, |
michael@0 | 1124 | src_x, src_y, mask_x, mask_y, dest_x, dest_y, |
michael@0 | 1125 | width, height); |
michael@0 | 1126 | |
michael@0 | 1127 | if (retval) |
michael@0 | 1128 | { |
michael@0 | 1129 | if (!pixman_region16_copy_from_region32 (region, &r32)) |
michael@0 | 1130 | retval = FALSE; |
michael@0 | 1131 | } |
michael@0 | 1132 | |
michael@0 | 1133 | pixman_region32_fini (&r32); |
michael@0 | 1134 | return retval; |
michael@0 | 1135 | } |