pixman-utils.c revision d0321353
1b4b94579Smrg/* 2b4b94579Smrg * Copyright © 2000 SuSE, Inc. 3dc259aabSmrg * Copyright © 1999 Keith Packard 4b4b94579Smrg * 5b4b94579Smrg * Permission to use, copy, modify, distribute, and sell this software and its 6b4b94579Smrg * documentation for any purpose is hereby granted without fee, provided that 7b4b94579Smrg * the above copyright notice appear in all copies and that both that 8b4b94579Smrg * copyright notice and this permission notice appear in supporting 9b4b94579Smrg * documentation, and that the name of SuSE not be used in advertising or 10b4b94579Smrg * publicity pertaining to distribution of the software without specific, 11b4b94579Smrg * written prior permission. SuSE makes no representations about the 12b4b94579Smrg * suitability of this software for any purpose. It is provided "as is" 13b4b94579Smrg * without express or implied warranty. 14b4b94579Smrg * 15b4b94579Smrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 16b4b94579Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 17b4b94579Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18b4b94579Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 19b4b94579Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 20b4b94579Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21b4b94579Smrg * 22b4b94579Smrg * Author: Keith Packard, SuSE, Inc. 23b4b94579Smrg */ 24b4b94579Smrg 25b4b94579Smrg#ifdef HAVE_CONFIG_H 26b4b94579Smrg#include <config.h> 27b4b94579Smrg#endif 28dc259aabSmrg#include <stdio.h> 29b4b94579Smrg#include <stdlib.h> 30b4b94579Smrg 31b4b94579Smrg#include "pixman-private.h" 32b4b94579Smrg 33b4b94579Smrg/* 34dc259aabSmrg * Computing composite region 35b4b94579Smrg */ 36d0321353Smrg#define BOUND(v) (int16_t) ((v) < INT16_MIN ? INT16_MIN : (v) > INT16_MAX ? INT16_MAX : (v)) 37b4b94579Smrg 38dc259aabSmrgstatic inline pixman_bool_t 39d0321353Smrgclip_general_image (pixman_region32_t * region, 40d0321353Smrg pixman_region32_t * clip, 41d0321353Smrg int dx, 42d0321353Smrg int dy) 43b4b94579Smrg{ 44d0321353Smrg if (pixman_region32_n_rects (region) == 1 && 45d0321353Smrg pixman_region32_n_rects (clip) == 1) 46b4b94579Smrg { 47d0321353Smrg pixman_box32_t * rbox = pixman_region32_rectangles (region, NULL); 48d0321353Smrg pixman_box32_t * cbox = pixman_region32_rectangles (clip, NULL); 49d0321353Smrg int v; 50d0321353Smrg 51d0321353Smrg if (rbox->x1 < (v = cbox->x1 + dx)) 52d0321353Smrg rbox->x1 = BOUND (v); 53d0321353Smrg if (rbox->x2 > (v = cbox->x2 + dx)) 54d0321353Smrg rbox->x2 = BOUND (v); 55d0321353Smrg if (rbox->y1 < (v = cbox->y1 + dy)) 56d0321353Smrg rbox->y1 = BOUND (v); 57d0321353Smrg if (rbox->y2 > (v = cbox->y2 + dy)) 58d0321353Smrg rbox->y2 = BOUND (v); 59d0321353Smrg if (rbox->x1 >= rbox->x2 || 60d0321353Smrg rbox->y1 >= rbox->y2) 61317c648bSmrg { 62d0321353Smrg pixman_region32_init (region); 63317c648bSmrg } 64b4b94579Smrg } 65d0321353Smrg else if (!pixman_region32_not_empty (clip)) 66dc259aabSmrg { 67dc259aabSmrg return FALSE; 68dc259aabSmrg } 69dc259aabSmrg else 70dc259aabSmrg { 71dc259aabSmrg if (dx || dy) 72d0321353Smrg pixman_region32_translate (region, -dx, -dy); 73d0321353Smrg if (!pixman_region32_intersect (region, region, clip)) 74dc259aabSmrg return FALSE; 75dc259aabSmrg if (dx || dy) 76d0321353Smrg pixman_region32_translate (region, dx, dy); 77dc259aabSmrg } 78d0321353Smrg return pixman_region32_not_empty (region); 79b4b94579Smrg} 80b4b94579Smrg 81dc259aabSmrgstatic inline pixman_bool_t 82d0321353Smrgclip_source_image (pixman_region32_t * region, 83d0321353Smrg pixman_image_t * picture, 84d0321353Smrg int dx, 85d0321353Smrg int dy) 86b4b94579Smrg{ 87d0321353Smrg /* The workaround lets certain fast paths run even when they 88d0321353Smrg * would normally be rejected because of out-of-bounds access. 89d0321353Smrg * We need to clip against the source geometry in that case 90dc259aabSmrg */ 91d0321353Smrg if (!picture->common.need_workaround) 92d0321353Smrg { 93d0321353Smrg /* Source clips are ignored, unless they are explicitly turned on 94d0321353Smrg * and the clip in question was set by an X client. (Because if 95d0321353Smrg * the clip was not set by a client, then it is a hierarchy 96d0321353Smrg * clip and those should always be ignored for sources). 97d0321353Smrg */ 98d0321353Smrg if (!picture->common.clip_sources || !picture->common.client_clip) 99d0321353Smrg return TRUE; 100d0321353Smrg } 101b4b94579Smrg 102d0321353Smrg return clip_general_image (region, 103d0321353Smrg &picture->common.clip_region, 104d0321353Smrg dx, dy); 105b4b94579Smrg} 106b4b94579Smrg 107b4b94579Smrg/* 108dc259aabSmrg * returns FALSE if the final region is empty. Indistinguishable from 109dc259aabSmrg * an allocation failure, but rendering ignores those anyways. 110b4b94579Smrg */ 111dc259aabSmrgstatic pixman_bool_t 112d0321353Smrgpixman_compute_composite_region32 (pixman_region32_t * region, 113d0321353Smrg pixman_image_t * src_image, 114d0321353Smrg pixman_image_t * mask_image, 115d0321353Smrg pixman_image_t * dst_image, 116d0321353Smrg int16_t src_x, 117d0321353Smrg int16_t src_y, 118d0321353Smrg int16_t mask_x, 119d0321353Smrg int16_t mask_y, 120d0321353Smrg int16_t dest_x, 121d0321353Smrg int16_t dest_y, 122d0321353Smrg uint16_t width, 123d0321353Smrg uint16_t height) 124b4b94579Smrg{ 125d0321353Smrg int v; 126d0321353Smrg 127d0321353Smrg region->extents.x1 = dest_x; 128d0321353Smrg v = dest_x + width; 129d0321353Smrg region->extents.x2 = BOUND (v); 130d0321353Smrg region->extents.y1 = dest_y; 131d0321353Smrg v = dest_y + height; 132d0321353Smrg region->extents.y2 = BOUND (v); 133d0321353Smrg 134d0321353Smrg region->extents.x1 = MAX (region->extents.x1, 0); 135d0321353Smrg region->extents.y1 = MAX (region->extents.y1, 0); 136d0321353Smrg 137dc259aabSmrg /* Some X servers rely on an old bug, where pixman would just believe the 138d0321353Smrg * set clip_region and not clip against the destination geometry. So, 139dc259aabSmrg * since only X servers set "source clip", we don't clip against 140d0321353Smrg * destination geometry when that is set and when the workaround has 141d0321353Smrg * not been explicitly disabled by 142d0321353Smrg * 143d0321353Smrg * pixman_disable_out_of_bounds_workaround(); 144d0321353Smrg * 145dc259aabSmrg */ 146d0321353Smrg if (!(dst_image->common.need_workaround)) 147dc259aabSmrg { 148d0321353Smrg region->extents.x2 = MIN (region->extents.x2, dst_image->bits.width); 149d0321353Smrg region->extents.y2 = MIN (region->extents.y2, dst_image->bits.height); 150dc259aabSmrg } 151d0321353Smrg 152d0321353Smrg region->data = 0; 153d0321353Smrg 154dc259aabSmrg /* Check for empty operation */ 155d0321353Smrg if (region->extents.x1 >= region->extents.x2 || 156d0321353Smrg region->extents.y1 >= region->extents.y2) 157b4b94579Smrg { 158d0321353Smrg pixman_region32_init (region); 159dc259aabSmrg return FALSE; 160dc259aabSmrg } 161d0321353Smrg 162d0321353Smrg if (dst_image->common.have_clip_region) 163dc259aabSmrg { 164d0321353Smrg if (!clip_general_image (region, &dst_image->common.clip_region, 0, 0)) 165b4b94579Smrg { 166d0321353Smrg pixman_region32_fini (region); 167dc259aabSmrg return FALSE; 168b4b94579Smrg } 169b4b94579Smrg } 170d0321353Smrg 171d0321353Smrg if (dst_image->common.alpha_map && dst_image->common.alpha_map->common.have_clip_region) 172b4b94579Smrg { 173d0321353Smrg if (!clip_general_image (region, &dst_image->common.alpha_map->common.clip_region, 174d0321353Smrg -dst_image->common.alpha_origin_x, 175d0321353Smrg -dst_image->common.alpha_origin_y)) 176b4b94579Smrg { 177d0321353Smrg pixman_region32_fini (region); 178dc259aabSmrg return FALSE; 179b4b94579Smrg } 180b4b94579Smrg } 181d0321353Smrg 182dc259aabSmrg /* clip against src */ 183d0321353Smrg if (src_image->common.have_clip_region) 184b4b94579Smrg { 185d0321353Smrg if (!clip_source_image (region, src_image, dest_x - src_x, dest_y - src_y)) 186dc259aabSmrg { 187d0321353Smrg pixman_region32_fini (region); 188dc259aabSmrg return FALSE; 189dc259aabSmrg } 190b4b94579Smrg } 191d0321353Smrg if (src_image->common.alpha_map && src_image->common.alpha_map->common.have_clip_region) 192b4b94579Smrg { 193d0321353Smrg if (!clip_source_image (region, (pixman_image_t *)src_image->common.alpha_map, 194d0321353Smrg dest_x - (src_x - src_image->common.alpha_origin_x), 195d0321353Smrg dest_y - (src_y - src_image->common.alpha_origin_y))) 196b4b94579Smrg { 197d0321353Smrg pixman_region32_fini (region); 198dc259aabSmrg return FALSE; 199b4b94579Smrg } 200dc259aabSmrg } 201dc259aabSmrg /* clip against mask */ 202d0321353Smrg if (mask_image && mask_image->common.have_clip_region) 203dc259aabSmrg { 204d0321353Smrg if (!clip_source_image (region, mask_image, dest_x - mask_x, dest_y - mask_y)) 205dc259aabSmrg { 206d0321353Smrg pixman_region32_fini (region); 207dc259aabSmrg return FALSE; 208d0321353Smrg } 209d0321353Smrg if (mask_image->common.alpha_map && mask_image->common.alpha_map->common.have_clip_region) 210b4b94579Smrg { 211d0321353Smrg if (!clip_source_image (region, (pixman_image_t *)mask_image->common.alpha_map, 212d0321353Smrg dest_x - (mask_x - mask_image->common.alpha_origin_x), 213d0321353Smrg dest_y - (mask_y - mask_image->common.alpha_origin_y))) 214dc259aabSmrg { 215d0321353Smrg pixman_region32_fini (region); 216dc259aabSmrg return FALSE; 217dc259aabSmrg } 218b4b94579Smrg } 219b4b94579Smrg } 220dc259aabSmrg 221dc259aabSmrg return TRUE; 222b4b94579Smrg} 223b4b94579Smrg 224dc259aabSmrgPIXMAN_EXPORT pixman_bool_t 225d0321353Smrgpixman_compute_composite_region (pixman_region16_t * region, 226d0321353Smrg pixman_image_t * src_image, 227d0321353Smrg pixman_image_t * mask_image, 228d0321353Smrg pixman_image_t * dst_image, 229d0321353Smrg int16_t src_x, 230d0321353Smrg int16_t src_y, 231d0321353Smrg int16_t mask_x, 232d0321353Smrg int16_t mask_y, 233d0321353Smrg int16_t dest_x, 234d0321353Smrg int16_t dest_y, 235d0321353Smrg uint16_t width, 236d0321353Smrg uint16_t height) 237b4b94579Smrg{ 238dc259aabSmrg pixman_region32_t r32; 239dc259aabSmrg pixman_bool_t retval; 240b4b94579Smrg 241dc259aabSmrg pixman_region32_init (&r32); 242d0321353Smrg 243d0321353Smrg retval = pixman_compute_composite_region32 ( 244d0321353Smrg &r32, src_image, mask_image, dst_image, 245d0321353Smrg src_x, src_y, mask_x, mask_y, dest_x, dest_y, 246d0321353Smrg width, height); 247dc259aabSmrg 248dc259aabSmrg if (retval) 249b4b94579Smrg { 250d0321353Smrg if (!pixman_region16_copy_from_region32 (region, &r32)) 251dc259aabSmrg retval = FALSE; 252b4b94579Smrg } 253d0321353Smrg 254dc259aabSmrg pixman_region32_fini (&r32); 255dc259aabSmrg return retval; 256b4b94579Smrg} 257b4b94579Smrg 258b4b94579Smrgpixman_bool_t 259b4b94579Smrgpixman_multiply_overflows_int (unsigned int a, 260d0321353Smrg unsigned int b) 261b4b94579Smrg{ 262b4b94579Smrg return a >= INT32_MAX / b; 263b4b94579Smrg} 264b4b94579Smrg 265b4b94579Smrgpixman_bool_t 266b4b94579Smrgpixman_addition_overflows_int (unsigned int a, 267d0321353Smrg unsigned int b) 268b4b94579Smrg{ 269b4b94579Smrg return a > INT32_MAX - b; 270b4b94579Smrg} 271b4b94579Smrg 272b4b94579Smrgvoid * 273d0321353Smrgpixman_malloc_ab (unsigned int a, 274d0321353Smrg unsigned int b) 275b4b94579Smrg{ 276b4b94579Smrg if (a >= INT32_MAX / b) 277b4b94579Smrg return NULL; 278b4b94579Smrg 279b4b94579Smrg return malloc (a * b); 280b4b94579Smrg} 281b4b94579Smrg 282b4b94579Smrgvoid * 283b4b94579Smrgpixman_malloc_abc (unsigned int a, 284d0321353Smrg unsigned int b, 285d0321353Smrg unsigned int c) 286b4b94579Smrg{ 287b4b94579Smrg if (a >= INT32_MAX / b) 288b4b94579Smrg return NULL; 289b4b94579Smrg else if (a * b >= INT32_MAX / c) 290b4b94579Smrg return NULL; 291b4b94579Smrg else 292b4b94579Smrg return malloc (a * b * c); 293b4b94579Smrg} 294b4b94579Smrg 295317c648bSmrg/* 296d0321353Smrg * Helper routine to expand a color component from 0 < n <= 8 bits to 16 297d0321353Smrg * bits by replication. 298317c648bSmrg */ 299317c648bSmrgstatic inline uint64_t 300d0321353Smrgexpand16 (const uint8_t val, int nbits) 301317c648bSmrg{ 302d0321353Smrg /* Start out with the high bit of val in the high bit of result. */ 303317c648bSmrg uint16_t result = (uint16_t)val << (16 - nbits); 304317c648bSmrg 305317c648bSmrg if (nbits == 0) 306d0321353Smrg return 0; 307317c648bSmrg 308d0321353Smrg /* Copy the bits in result, doubling the number of bits each time, until 309d0321353Smrg * we fill all 16 bits. 310d0321353Smrg */ 311d0321353Smrg while (nbits < 16) 312d0321353Smrg { 313d0321353Smrg result |= result >> nbits; 314d0321353Smrg nbits *= 2; 315317c648bSmrg } 316317c648bSmrg 317317c648bSmrg return result; 318317c648bSmrg} 319317c648bSmrg 320317c648bSmrg/* 321317c648bSmrg * This function expands images from ARGB8 format to ARGB16. To preserve 322317c648bSmrg * precision, it needs to know the original source format. For example, if the 323317c648bSmrg * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then 324317c648bSmrg * the expanded value is 12345123. To correctly expand this to 16 bits, it 325317c648bSmrg * should be 1234512345123451 and not 1234512312345123. 326317c648bSmrg */ 327317c648bSmrgvoid 328d0321353Smrgpixman_expand (uint64_t * dst, 329d0321353Smrg const uint32_t * src, 330d0321353Smrg pixman_format_code_t format, 331d0321353Smrg int width) 332317c648bSmrg{ 333317c648bSmrg /* 334d0321353Smrg * Determine the sizes of each component and the masks and shifts 335d0321353Smrg * required to extract them from the source pixel. 336317c648bSmrg */ 337d0321353Smrg const int a_size = PIXMAN_FORMAT_A (format), 338d0321353Smrg r_size = PIXMAN_FORMAT_R (format), 339d0321353Smrg g_size = PIXMAN_FORMAT_G (format), 340d0321353Smrg b_size = PIXMAN_FORMAT_B (format); 341317c648bSmrg const int a_shift = 32 - a_size, 342317c648bSmrg r_shift = 24 - r_size, 343317c648bSmrg g_shift = 16 - g_size, 344317c648bSmrg b_shift = 8 - b_size; 345317c648bSmrg const uint8_t a_mask = ~(~0 << a_size), 346317c648bSmrg r_mask = ~(~0 << r_size), 347317c648bSmrg g_mask = ~(~0 << g_size), 348317c648bSmrg b_mask = ~(~0 << b_size); 349317c648bSmrg int i; 350317c648bSmrg 351d0321353Smrg /* Start at the end so that we can do the expansion in place 352d0321353Smrg * when src == dst 353d0321353Smrg */ 354317c648bSmrg for (i = width - 1; i >= 0; i--) 355317c648bSmrg { 356d0321353Smrg const uint32_t pixel = src[i]; 357d0321353Smrg const uint8_t a = (pixel >> a_shift) & a_mask, 358d0321353Smrg r = (pixel >> r_shift) & r_mask, 359d0321353Smrg g = (pixel >> g_shift) & g_mask, 360d0321353Smrg b = (pixel >> b_shift) & b_mask; 361d0321353Smrg const uint64_t a16 = a_size ? expand16 (a, a_size) : 0xffff, 362d0321353Smrg r16 = expand16 (r, r_size), 363d0321353Smrg g16 = expand16 (g, g_size), 364d0321353Smrg b16 = expand16 (b, b_size); 365d0321353Smrg 366d0321353Smrg dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16; 367317c648bSmrg } 368317c648bSmrg} 369317c648bSmrg 370317c648bSmrg/* 371317c648bSmrg * Contracting is easier than expanding. We just need to truncate the 372317c648bSmrg * components. 373317c648bSmrg */ 374317c648bSmrgvoid 375d0321353Smrgpixman_contract (uint32_t * dst, 376d0321353Smrg const uint64_t *src, 377d0321353Smrg int width) 378317c648bSmrg{ 379317c648bSmrg int i; 380317c648bSmrg 381d0321353Smrg /* Start at the beginning so that we can do the contraction in 382d0321353Smrg * place when src == dst 383d0321353Smrg */ 384317c648bSmrg for (i = 0; i < width; i++) 385317c648bSmrg { 386d0321353Smrg const uint8_t a = src[i] >> 56, 387d0321353Smrg r = src[i] >> 40, 388d0321353Smrg g = src[i] >> 24, 389d0321353Smrg b = src[i] >> 8; 390d0321353Smrg 391d0321353Smrg dst[i] = a << 24 | r << 16 | g << 8 | b; 392317c648bSmrg } 393317c648bSmrg} 394317c648bSmrg 395dc259aabSmrgstatic void 396dc259aabSmrgwalk_region_internal (pixman_implementation_t *imp, 397d0321353Smrg pixman_op_t op, 398d0321353Smrg pixman_image_t * src_image, 399d0321353Smrg pixman_image_t * mask_image, 400d0321353Smrg pixman_image_t * dst_image, 401d0321353Smrg int16_t src_x, 402d0321353Smrg int16_t src_y, 403d0321353Smrg int16_t mask_x, 404d0321353Smrg int16_t mask_y, 405d0321353Smrg int16_t dest_x, 406d0321353Smrg int16_t dest_y, 407d0321353Smrg uint16_t width, 408d0321353Smrg uint16_t height, 409d0321353Smrg pixman_bool_t src_repeat, 410d0321353Smrg pixman_bool_t mask_repeat, 411d0321353Smrg pixman_region32_t * region, 412d0321353Smrg pixman_composite_func_t composite_rect) 413317c648bSmrg{ 414dc259aabSmrg int n; 415317c648bSmrg const pixman_box32_t *pbox; 416dc259aabSmrg int w, h, w_this, h_this; 417dc259aabSmrg int x_msk, y_msk, x_src, y_src, x_dst, y_dst; 418317c648bSmrg 419317c648bSmrg pbox = pixman_region32_rectangles (region, &n); 420317c648bSmrg while (n--) 421317c648bSmrg { 422317c648bSmrg h = pbox->y2 - pbox->y1; 423d0321353Smrg y_src = pbox->y1 - dest_y + src_y; 424d0321353Smrg y_msk = pbox->y1 - dest_y + mask_y; 425317c648bSmrg y_dst = pbox->y1; 426d0321353Smrg 427317c648bSmrg while (h) 428317c648bSmrg { 429317c648bSmrg h_this = h; 430317c648bSmrg w = pbox->x2 - pbox->x1; 431d0321353Smrg x_src = pbox->x1 - dest_x + src_x; 432d0321353Smrg x_msk = pbox->x1 - dest_x + mask_x; 433317c648bSmrg x_dst = pbox->x1; 434d0321353Smrg 435d0321353Smrg if (mask_repeat) 436317c648bSmrg { 437d0321353Smrg y_msk = MOD (y_msk, mask_image->bits.height); 438d0321353Smrg if (h_this > mask_image->bits.height - y_msk) 439d0321353Smrg h_this = mask_image->bits.height - y_msk; 440317c648bSmrg } 441d0321353Smrg 442d0321353Smrg if (src_repeat) 443317c648bSmrg { 444d0321353Smrg y_src = MOD (y_src, src_image->bits.height); 445d0321353Smrg if (h_this > src_image->bits.height - y_src) 446d0321353Smrg h_this = src_image->bits.height - y_src; 447317c648bSmrg } 448d0321353Smrg 449317c648bSmrg while (w) 450317c648bSmrg { 451317c648bSmrg w_this = w; 452d0321353Smrg 453d0321353Smrg if (mask_repeat) 454317c648bSmrg { 455d0321353Smrg x_msk = MOD (x_msk, mask_image->bits.width); 456d0321353Smrg if (w_this > mask_image->bits.width - x_msk) 457d0321353Smrg w_this = mask_image->bits.width - x_msk; 458317c648bSmrg } 459d0321353Smrg 460d0321353Smrg if (src_repeat) 461317c648bSmrg { 462d0321353Smrg x_src = MOD (x_src, src_image->bits.width); 463d0321353Smrg if (w_this > src_image->bits.width - x_src) 464d0321353Smrg w_this = src_image->bits.width - x_src; 465317c648bSmrg } 466d0321353Smrg 467d0321353Smrg (*composite_rect) (imp, op, 468d0321353Smrg src_image, mask_image, dst_image, 469d0321353Smrg x_src, y_src, x_msk, y_msk, x_dst, y_dst, 470d0321353Smrg w_this, h_this); 471317c648bSmrg w -= w_this; 472d0321353Smrg 473317c648bSmrg x_src += w_this; 474317c648bSmrg x_msk += w_this; 475317c648bSmrg x_dst += w_this; 476317c648bSmrg } 477d0321353Smrg 478317c648bSmrg h -= h_this; 479317c648bSmrg y_src += h_this; 480317c648bSmrg y_msk += h_this; 481317c648bSmrg y_dst += h_this; 482317c648bSmrg } 483d0321353Smrg 484317c648bSmrg pbox++; 485317c648bSmrg } 486317c648bSmrg} 487317c648bSmrg 488dc259aabSmrgvoid 489dc259aabSmrg_pixman_walk_composite_region (pixman_implementation_t *imp, 490d0321353Smrg pixman_op_t op, 491d0321353Smrg pixman_image_t * src_image, 492d0321353Smrg pixman_image_t * mask_image, 493d0321353Smrg pixman_image_t * dst_image, 494d0321353Smrg int16_t src_x, 495d0321353Smrg int16_t src_y, 496d0321353Smrg int16_t mask_x, 497d0321353Smrg int16_t mask_y, 498d0321353Smrg int16_t dest_x, 499d0321353Smrg int16_t dest_y, 500d0321353Smrg uint16_t width, 501d0321353Smrg uint16_t height, 502d0321353Smrg pixman_composite_func_t composite_rect) 503dc259aabSmrg{ 504dc259aabSmrg pixman_region32_t region; 505d0321353Smrg 506dc259aabSmrg pixman_region32_init (®ion); 507dc259aabSmrg 508dc259aabSmrg if (pixman_compute_composite_region32 ( 509d0321353Smrg ®ion, src_image, mask_image, dst_image, 510d0321353Smrg src_x, src_y, mask_x, mask_y, dest_x, dest_y, 511d0321353Smrg width, height)) 512dc259aabSmrg { 513dc259aabSmrg walk_region_internal (imp, op, 514d0321353Smrg src_image, mask_image, dst_image, 515d0321353Smrg src_x, src_y, mask_x, mask_y, dest_x, dest_y, 516d0321353Smrg width, height, FALSE, FALSE, 517d0321353Smrg ®ion, 518d0321353Smrg composite_rect); 519dc259aabSmrg 520d0321353Smrg pixman_region32_fini (®ion); 521d0321353Smrg } 522dc259aabSmrg} 523dc259aabSmrg 524317c648bSmrgstatic pixman_bool_t 525317c648bSmrgmask_is_solid (pixman_image_t *mask) 526317c648bSmrg{ 527317c648bSmrg if (mask->type == SOLID) 528317c648bSmrg return TRUE; 529317c648bSmrg 530317c648bSmrg if (mask->type == BITS && 531d0321353Smrg mask->common.repeat == PIXMAN_REPEAT_NORMAL && 532d0321353Smrg mask->bits.width == 1 && 533d0321353Smrg mask->bits.height == 1) 534317c648bSmrg { 535317c648bSmrg return TRUE; 536317c648bSmrg } 537317c648bSmrg 538317c648bSmrg return FALSE; 539317c648bSmrg} 540317c648bSmrg 541dc259aabSmrgstatic const pixman_fast_path_t * 542dc259aabSmrgget_fast_path (const pixman_fast_path_t *fast_paths, 543d0321353Smrg pixman_op_t op, 544d0321353Smrg pixman_image_t * src_image, 545d0321353Smrg pixman_image_t * mask_image, 546d0321353Smrg pixman_image_t * dst_image, 547d0321353Smrg pixman_bool_t is_pixbuf) 548317c648bSmrg{ 549dc259aabSmrg const pixman_fast_path_t *info; 550317c648bSmrg 551317c648bSmrg for (info = fast_paths; info->op != PIXMAN_OP_NONE; info++) 552317c648bSmrg { 553dc259aabSmrg pixman_bool_t valid_src = FALSE; 554dc259aabSmrg pixman_bool_t valid_mask = FALSE; 555317c648bSmrg 556317c648bSmrg if (info->op != op) 557317c648bSmrg continue; 558317c648bSmrg 559d0321353Smrg if ((info->src_format == PIXMAN_solid && 560d0321353Smrg _pixman_image_is_solid (src_image)) || 561d0321353Smrg (src_image->type == BITS && 562d0321353Smrg info->src_format == src_image->bits.format)) 563317c648bSmrg { 564317c648bSmrg valid_src = TRUE; 565317c648bSmrg } 566317c648bSmrg 567317c648bSmrg if (!valid_src) 568317c648bSmrg continue; 569317c648bSmrg 570d0321353Smrg if ((info->mask_format == PIXMAN_null && !mask_image) || 571d0321353Smrg (mask_image && mask_image->type == BITS && 572d0321353Smrg info->mask_format == mask_image->bits.format)) 573317c648bSmrg { 574317c648bSmrg valid_mask = TRUE; 575317c648bSmrg 576317c648bSmrg if (info->flags & NEED_SOLID_MASK) 577317c648bSmrg { 578d0321353Smrg if (!mask_image || !mask_is_solid (mask_image)) 579317c648bSmrg valid_mask = FALSE; 580317c648bSmrg } 581317c648bSmrg 582317c648bSmrg if (info->flags & NEED_COMPONENT_ALPHA) 583317c648bSmrg { 584d0321353Smrg if (!mask_image || !mask_image->common.component_alpha) 585317c648bSmrg valid_mask = FALSE; 586317c648bSmrg } 587317c648bSmrg } 588317c648bSmrg 589317c648bSmrg if (!valid_mask) 590317c648bSmrg continue; 591d0321353Smrg 592d0321353Smrg if (info->dest_format != dst_image->bits.format) 593317c648bSmrg continue; 594317c648bSmrg 595317c648bSmrg if ((info->flags & NEED_PIXBUF) && !is_pixbuf) 596317c648bSmrg continue; 597317c648bSmrg 598317c648bSmrg return info; 599317c648bSmrg } 600317c648bSmrg 601317c648bSmrg return NULL; 602317c648bSmrg} 603317c648bSmrg 604d0321353Smrgstatic force_inline pixman_bool_t 605d0321353Smrgimage_covers (pixman_image_t *image, 606d0321353Smrg pixman_box32_t *extents, 607d0321353Smrg int x, 608d0321353Smrg int y) 609dc259aabSmrg{ 610d0321353Smrg if (image->common.type == BITS && 611d0321353Smrg image->common.repeat == PIXMAN_REPEAT_NONE) 612dc259aabSmrg { 613dc259aabSmrg if (x > extents->x1 || y > extents->y1 || 614dc259aabSmrg x + image->bits.width < extents->x2 || 615dc259aabSmrg y + image->bits.height < extents->y2) 616dc259aabSmrg { 617dc259aabSmrg return FALSE; 618dc259aabSmrg } 619dc259aabSmrg } 620dc259aabSmrg 621dc259aabSmrg return TRUE; 622dc259aabSmrg} 623dc259aabSmrg 624d0321353Smrgstatic force_inline pixman_bool_t 625d0321353Smrgsources_cover (pixman_image_t *src, 626d0321353Smrg pixman_image_t *mask, 627d0321353Smrg pixman_box32_t *extents, 628d0321353Smrg int src_x, 629d0321353Smrg int src_y, 630d0321353Smrg int mask_x, 631d0321353Smrg int mask_y, 632d0321353Smrg int dest_x, 633d0321353Smrg int dest_y) 634d0321353Smrg{ 635d0321353Smrg if (!image_covers (src, extents, dest_x - src_x, dest_y - src_y)) 636d0321353Smrg return FALSE; 637d0321353Smrg 638d0321353Smrg if (!mask) 639d0321353Smrg return TRUE; 640d0321353Smrg 641d0321353Smrg if (!image_covers (mask, extents, dest_x - mask_x, dest_y - mask_y)) 642d0321353Smrg return FALSE; 643d0321353Smrg 644d0321353Smrg return TRUE; 645d0321353Smrg} 646d0321353Smrg 647317c648bSmrgpixman_bool_t 648dc259aabSmrg_pixman_run_fast_path (const pixman_fast_path_t *paths, 649d0321353Smrg pixman_implementation_t * imp, 650d0321353Smrg pixman_op_t op, 651d0321353Smrg pixman_image_t * src, 652d0321353Smrg pixman_image_t * mask, 653d0321353Smrg pixman_image_t * dest, 654d0321353Smrg int32_t src_x, 655d0321353Smrg int32_t src_y, 656d0321353Smrg int32_t mask_x, 657d0321353Smrg int32_t mask_y, 658d0321353Smrg int32_t dest_x, 659d0321353Smrg int32_t dest_y, 660d0321353Smrg int32_t width, 661d0321353Smrg int32_t height) 662317c648bSmrg{ 663317c648bSmrg pixman_composite_func_t func = NULL; 664d0321353Smrg pixman_bool_t src_repeat = 665d0321353Smrg src->common.repeat == PIXMAN_REPEAT_NORMAL; 666d0321353Smrg pixman_bool_t mask_repeat = 667d0321353Smrg mask && mask->common.repeat == PIXMAN_REPEAT_NORMAL; 668dc259aabSmrg pixman_bool_t result; 669dc259aabSmrg 670dc259aabSmrg if ((src->type == BITS || _pixman_image_is_solid (src)) && 671d0321353Smrg (!mask || mask->type == BITS) 672d0321353Smrg && !src->common.transform && !(mask && mask->common.transform) 673d0321353Smrg && !src->common.alpha_map && !dest->common.alpha_map 674d0321353Smrg && !(mask && mask->common.alpha_map) 675d0321353Smrg && (src->common.filter != PIXMAN_FILTER_CONVOLUTION) 676d0321353Smrg && (src->common.repeat != PIXMAN_REPEAT_PAD) 677d0321353Smrg && (src->common.repeat != PIXMAN_REPEAT_REFLECT) 678d0321353Smrg && (!mask || (mask->common.filter != PIXMAN_FILTER_CONVOLUTION && 679d0321353Smrg mask->common.repeat != PIXMAN_REPEAT_PAD && 680d0321353Smrg mask->common.repeat != PIXMAN_REPEAT_REFLECT)) 681d0321353Smrg && !src->common.read_func && !src->common.write_func 682d0321353Smrg && !(mask && mask->common.read_func) 683d0321353Smrg && !(mask && mask->common.write_func) 684d0321353Smrg && !dest->common.read_func 685d0321353Smrg && !dest->common.write_func) 686317c648bSmrg { 687d0321353Smrg const pixman_fast_path_t *info; 688317c648bSmrg pixman_bool_t pixbuf; 689317c648bSmrg 690317c648bSmrg pixbuf = 691d0321353Smrg src && src->type == BITS && 692d0321353Smrg mask && mask->type == BITS && 693d0321353Smrg src->bits.bits == mask->bits.bits && 694d0321353Smrg src_x == mask_x && 695d0321353Smrg src_y == mask_y && 696d0321353Smrg !mask->common.component_alpha && 697317c648bSmrg !mask_repeat; 698d0321353Smrg 699317c648bSmrg info = get_fast_path (paths, op, src, mask, dest, pixbuf); 700d0321353Smrg 701317c648bSmrg if (info) 702317c648bSmrg { 703317c648bSmrg func = info->func; 704d0321353Smrg 705317c648bSmrg if (info->src_format == PIXMAN_solid) 706317c648bSmrg src_repeat = FALSE; 707d0321353Smrg 708d0321353Smrg if (info->mask_format == PIXMAN_solid || 709d0321353Smrg info->flags & NEED_SOLID_MASK) 710d0321353Smrg { 711317c648bSmrg mask_repeat = FALSE; 712d0321353Smrg } 713d0321353Smrg 714d0321353Smrg if ((src_repeat && 715d0321353Smrg src->bits.width == 1 && 716d0321353Smrg src->bits.height == 1) || 717d0321353Smrg (mask_repeat && 718d0321353Smrg mask->bits.width == 1 && 719d0321353Smrg mask->bits.height == 1)) 720317c648bSmrg { 721317c648bSmrg /* If src or mask are repeating 1x1 images and src_repeat or 722317c648bSmrg * mask_repeat are still TRUE, it means the fast path we 723317c648bSmrg * selected does not actually handle repeating images. 724317c648bSmrg * 725317c648bSmrg * So rather than call the "fast path" with a zillion 726317c648bSmrg * 1x1 requests, we just fall back to the general code (which 727317c648bSmrg * does do something sensible with 1x1 repeating images). 728317c648bSmrg */ 729317c648bSmrg func = NULL; 730317c648bSmrg } 731317c648bSmrg } 732317c648bSmrg } 733d0321353Smrg 734dc259aabSmrg result = FALSE; 735d0321353Smrg 736317c648bSmrg if (func) 737317c648bSmrg { 738dc259aabSmrg pixman_region32_t region; 739dc259aabSmrg pixman_region32_init (®ion); 740dc259aabSmrg 741dc259aabSmrg if (pixman_compute_composite_region32 ( 742d0321353Smrg ®ion, src, mask, dest, 743d0321353Smrg src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height)) 744dc259aabSmrg { 745dc259aabSmrg pixman_box32_t *extents = pixman_region32_extents (®ion); 746dc259aabSmrg 747d0321353Smrg if (sources_cover ( 748d0321353Smrg src, mask, extents, 749d0321353Smrg src_x, src_y, mask_x, mask_y, dest_x, dest_y)) 750dc259aabSmrg { 751dc259aabSmrg walk_region_internal (imp, op, 752d0321353Smrg src, mask, dest, 753d0321353Smrg src_x, src_y, mask_x, mask_y, 754d0321353Smrg dest_x, dest_y, 755d0321353Smrg width, height, 756d0321353Smrg src_repeat, mask_repeat, 757d0321353Smrg ®ion, 758d0321353Smrg func); 759d0321353Smrg 760dc259aabSmrg result = TRUE; 761dc259aabSmrg } 762d0321353Smrg 763d0321353Smrg pixman_region32_fini (®ion); 764dc259aabSmrg } 765317c648bSmrg } 766d0321353Smrg 767dc259aabSmrg return result; 768dc259aabSmrg} 769dc259aabSmrg 770dc259aabSmrg#define N_TMP_BOXES (16) 771dc259aabSmrg 772dc259aabSmrgpixman_bool_t 773dc259aabSmrgpixman_region16_copy_from_region32 (pixman_region16_t *dst, 774d0321353Smrg pixman_region32_t *src) 775dc259aabSmrg{ 776dc259aabSmrg int n_boxes, i; 777dc259aabSmrg pixman_box32_t *boxes32; 778dc259aabSmrg pixman_box16_t *boxes16; 779dc259aabSmrg pixman_bool_t retval; 780d0321353Smrg 781dc259aabSmrg boxes32 = pixman_region32_rectangles (src, &n_boxes); 782dc259aabSmrg 783dc259aabSmrg boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t)); 784dc259aabSmrg 785dc259aabSmrg if (!boxes16) 786dc259aabSmrg return FALSE; 787d0321353Smrg 788dc259aabSmrg for (i = 0; i < n_boxes; ++i) 789dc259aabSmrg { 790dc259aabSmrg boxes16[i].x1 = boxes32[i].x1; 791dc259aabSmrg boxes16[i].y1 = boxes32[i].y1; 792dc259aabSmrg boxes16[i].x2 = boxes32[i].x2; 793dc259aabSmrg boxes16[i].y2 = boxes32[i].y2; 794dc259aabSmrg } 795dc259aabSmrg 796dc259aabSmrg pixman_region_fini (dst); 797dc259aabSmrg retval = pixman_region_init_rects (dst, boxes16, n_boxes); 798dc259aabSmrg free (boxes16); 799dc259aabSmrg return retval; 800317c648bSmrg} 801dc259aabSmrg 802dc259aabSmrgpixman_bool_t 803dc259aabSmrgpixman_region32_copy_from_region16 (pixman_region32_t *dst, 804d0321353Smrg pixman_region16_t *src) 805dc259aabSmrg{ 806dc259aabSmrg int n_boxes, i; 807dc259aabSmrg pixman_box16_t *boxes16; 808dc259aabSmrg pixman_box32_t *boxes32; 809dc259aabSmrg pixman_box32_t tmp_boxes[N_TMP_BOXES]; 810dc259aabSmrg pixman_bool_t retval; 811d0321353Smrg 812dc259aabSmrg boxes16 = pixman_region_rectangles (src, &n_boxes); 813dc259aabSmrg 814dc259aabSmrg if (n_boxes > N_TMP_BOXES) 815dc259aabSmrg boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t)); 816dc259aabSmrg else 817dc259aabSmrg boxes32 = tmp_boxes; 818d0321353Smrg 819dc259aabSmrg if (!boxes32) 820dc259aabSmrg return FALSE; 821d0321353Smrg 822dc259aabSmrg for (i = 0; i < n_boxes; ++i) 823dc259aabSmrg { 824dc259aabSmrg boxes32[i].x1 = boxes16[i].x1; 825dc259aabSmrg boxes32[i].y1 = boxes16[i].y1; 826dc259aabSmrg boxes32[i].x2 = boxes16[i].x2; 827dc259aabSmrg boxes32[i].y2 = boxes16[i].y2; 828dc259aabSmrg } 829dc259aabSmrg 830dc259aabSmrg pixman_region32_fini (dst); 831dc259aabSmrg retval = pixman_region32_init_rects (dst, boxes32, n_boxes); 832dc259aabSmrg 833dc259aabSmrg if (boxes32 != tmp_boxes) 834dc259aabSmrg free (boxes32); 835dc259aabSmrg 836dc259aabSmrg return retval; 837dc259aabSmrg} 838