pixman-utils.c revision dc259aab
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 */ 36dc259aabSmrg#define BOUND(v) (int16_t) ((v) < INT16_MIN ? INT16_MIN : (v) > INT16_MAX ? INT16_MAX : (v)) 37b4b94579Smrg 38dc259aabSmrgstatic inline pixman_bool_t 39dc259aabSmrgmiClipPictureReg (pixman_region32_t * pRegion, 40dc259aabSmrg pixman_region32_t * pClip, 41dc259aabSmrg int dx, 42dc259aabSmrg int dy) 43b4b94579Smrg{ 44dc259aabSmrg if (pixman_region32_n_rects(pRegion) == 1 && 45dc259aabSmrg pixman_region32_n_rects(pClip) == 1) 46b4b94579Smrg { 47dc259aabSmrg pixman_box32_t * pRbox = pixman_region32_rectangles(pRegion, NULL); 48dc259aabSmrg pixman_box32_t * pCbox = pixman_region32_rectangles(pClip, NULL); 49dc259aabSmrg int v; 50dc259aabSmrg 51dc259aabSmrg if (pRbox->x1 < (v = pCbox->x1 + dx)) 52dc259aabSmrg pRbox->x1 = BOUND(v); 53dc259aabSmrg if (pRbox->x2 > (v = pCbox->x2 + dx)) 54dc259aabSmrg pRbox->x2 = BOUND(v); 55dc259aabSmrg if (pRbox->y1 < (v = pCbox->y1 + dy)) 56dc259aabSmrg pRbox->y1 = BOUND(v); 57dc259aabSmrg if (pRbox->y2 > (v = pCbox->y2 + dy)) 58dc259aabSmrg pRbox->y2 = BOUND(v); 59dc259aabSmrg if (pRbox->x1 >= pRbox->x2 || 60dc259aabSmrg pRbox->y1 >= pRbox->y2) 61317c648bSmrg { 62dc259aabSmrg pixman_region32_init (pRegion); 63317c648bSmrg } 64b4b94579Smrg } 65dc259aabSmrg else if (!pixman_region32_not_empty (pClip)) 66dc259aabSmrg { 67dc259aabSmrg return FALSE; 68dc259aabSmrg } 69dc259aabSmrg else 70dc259aabSmrg { 71dc259aabSmrg if (dx || dy) 72dc259aabSmrg pixman_region32_translate (pRegion, -dx, -dy); 73dc259aabSmrg if (!pixman_region32_intersect (pRegion, pRegion, pClip)) 74dc259aabSmrg return FALSE; 75dc259aabSmrg if (dx || dy) 76dc259aabSmrg pixman_region32_translate(pRegion, dx, dy); 77dc259aabSmrg } 78dc259aabSmrg return pixman_region32_not_empty(pRegion); 79b4b94579Smrg} 80b4b94579Smrg 81b4b94579Smrg 82dc259aabSmrgstatic inline pixman_bool_t 83dc259aabSmrgmiClipPictureSrc (pixman_region32_t * pRegion, 84dc259aabSmrg pixman_image_t * pPicture, 85dc259aabSmrg int dx, 86dc259aabSmrg int dy) 87b4b94579Smrg{ 88dc259aabSmrg /* Source clips are ignored, unless they are explicitly turned on 89dc259aabSmrg * and the clip in question was set by an X client 90dc259aabSmrg */ 91dc259aabSmrg if (!pPicture->common.clip_sources || !pPicture->common.client_clip) 92dc259aabSmrg return TRUE; 93b4b94579Smrg 94dc259aabSmrg return miClipPictureReg (pRegion, 95dc259aabSmrg &pPicture->common.clip_region, 96dc259aabSmrg dx, dy); 97b4b94579Smrg} 98b4b94579Smrg 99b4b94579Smrg/* 100dc259aabSmrg * returns FALSE if the final region is empty. Indistinguishable from 101dc259aabSmrg * an allocation failure, but rendering ignores those anyways. 102b4b94579Smrg */ 103dc259aabSmrgstatic pixman_bool_t 104dc259aabSmrgpixman_compute_composite_region32 (pixman_region32_t * pRegion, 105dc259aabSmrg pixman_image_t * pSrc, 106dc259aabSmrg pixman_image_t * pMask, 107dc259aabSmrg pixman_image_t * pDst, 108dc259aabSmrg int16_t xSrc, 109dc259aabSmrg int16_t ySrc, 110dc259aabSmrg int16_t xMask, 111dc259aabSmrg int16_t yMask, 112dc259aabSmrg int16_t xDst, 113dc259aabSmrg int16_t yDst, 114dc259aabSmrg uint16_t width, 115dc259aabSmrg uint16_t height) 116b4b94579Smrg{ 117dc259aabSmrg int v; 118dc259aabSmrg 119dc259aabSmrg pRegion->extents.x1 = xDst; 120dc259aabSmrg v = xDst + width; 121dc259aabSmrg pRegion->extents.x2 = BOUND(v); 122dc259aabSmrg pRegion->extents.y1 = yDst; 123dc259aabSmrg v = yDst + height; 124dc259aabSmrg pRegion->extents.y2 = BOUND(v); 125dc259aabSmrg 126dc259aabSmrg pRegion->extents.x1 = MAX (pRegion->extents.x1, 0); 127dc259aabSmrg pRegion->extents.y1 = MAX (pRegion->extents.y1, 0); 128dc259aabSmrg 129dc259aabSmrg /* Some X servers rely on an old bug, where pixman would just believe the 130dc259aabSmrg * set clip_region and not clip against the destination geometry. So, 131dc259aabSmrg * since only X servers set "source clip", we don't clip against 132dc259aabSmrg * destination geometry when that is set. 133dc259aabSmrg */ 134dc259aabSmrg if (!pDst->common.clip_sources) 135dc259aabSmrg { 136dc259aabSmrg pRegion->extents.x2 = MIN (pRegion->extents.x2, pDst->bits.width); 137dc259aabSmrg pRegion->extents.y2 = MIN (pRegion->extents.y2, pDst->bits.height); 138dc259aabSmrg } 139dc259aabSmrg 140dc259aabSmrg pRegion->data = 0; 141dc259aabSmrg 142dc259aabSmrg /* Check for empty operation */ 143dc259aabSmrg if (pRegion->extents.x1 >= pRegion->extents.x2 || 144dc259aabSmrg pRegion->extents.y1 >= pRegion->extents.y2) 145b4b94579Smrg { 146dc259aabSmrg pixman_region32_init (pRegion); 147dc259aabSmrg return FALSE; 148dc259aabSmrg } 149dc259aabSmrg 150dc259aabSmrg if (pDst->common.have_clip_region) 151dc259aabSmrg { 152dc259aabSmrg if (!miClipPictureReg (pRegion, &pDst->common.clip_region, 0, 0)) 153b4b94579Smrg { 154dc259aabSmrg pixman_region32_fini (pRegion); 155dc259aabSmrg return FALSE; 156b4b94579Smrg } 157b4b94579Smrg } 158dc259aabSmrg 159dc259aabSmrg if (pDst->common.alpha_map && pDst->common.alpha_map->common.have_clip_region) 160b4b94579Smrg { 161dc259aabSmrg if (!miClipPictureReg (pRegion, &pDst->common.alpha_map->common.clip_region, 162dc259aabSmrg -pDst->common.alpha_origin_x, 163dc259aabSmrg -pDst->common.alpha_origin_y)) 164b4b94579Smrg { 165dc259aabSmrg pixman_region32_fini (pRegion); 166dc259aabSmrg return FALSE; 167b4b94579Smrg } 168b4b94579Smrg } 169dc259aabSmrg 170dc259aabSmrg /* clip against src */ 171dc259aabSmrg if (pSrc->common.have_clip_region) 172b4b94579Smrg { 173dc259aabSmrg if (!miClipPictureSrc (pRegion, pSrc, xDst - xSrc, yDst - ySrc)) 174dc259aabSmrg { 175dc259aabSmrg pixman_region32_fini (pRegion); 176dc259aabSmrg return FALSE; 177dc259aabSmrg } 178b4b94579Smrg } 179dc259aabSmrg if (pSrc->common.alpha_map && pSrc->common.alpha_map->common.have_clip_region) 180b4b94579Smrg { 181dc259aabSmrg if (!miClipPictureSrc (pRegion, (pixman_image_t *)pSrc->common.alpha_map, 182dc259aabSmrg xDst - (xSrc - pSrc->common.alpha_origin_x), 183dc259aabSmrg yDst - (ySrc - pSrc->common.alpha_origin_y))) 184b4b94579Smrg { 185dc259aabSmrg pixman_region32_fini (pRegion); 186dc259aabSmrg return FALSE; 187b4b94579Smrg } 188dc259aabSmrg } 189dc259aabSmrg /* clip against mask */ 190dc259aabSmrg if (pMask && pMask->common.have_clip_region) 191dc259aabSmrg { 192dc259aabSmrg if (!miClipPictureSrc (pRegion, pMask, xDst - xMask, yDst - yMask)) 193dc259aabSmrg { 194dc259aabSmrg pixman_region32_fini (pRegion); 195dc259aabSmrg return FALSE; 196dc259aabSmrg } 197dc259aabSmrg if (pMask->common.alpha_map && pMask->common.alpha_map->common.have_clip_region) 198b4b94579Smrg { 199dc259aabSmrg if (!miClipPictureSrc (pRegion, (pixman_image_t *)pMask->common.alpha_map, 200dc259aabSmrg xDst - (xMask - pMask->common.alpha_origin_x), 201dc259aabSmrg yDst - (yMask - pMask->common.alpha_origin_y))) 202dc259aabSmrg { 203dc259aabSmrg pixman_region32_fini (pRegion); 204dc259aabSmrg return FALSE; 205dc259aabSmrg } 206b4b94579Smrg } 207b4b94579Smrg } 208dc259aabSmrg 209dc259aabSmrg return TRUE; 210b4b94579Smrg} 211b4b94579Smrg 212dc259aabSmrgPIXMAN_EXPORT pixman_bool_t 213dc259aabSmrgpixman_compute_composite_region (pixman_region16_t * pRegion, 214dc259aabSmrg pixman_image_t * pSrc, 215dc259aabSmrg pixman_image_t * pMask, 216dc259aabSmrg pixman_image_t * pDst, 217dc259aabSmrg int16_t xSrc, 218dc259aabSmrg int16_t ySrc, 219dc259aabSmrg int16_t xMask, 220dc259aabSmrg int16_t yMask, 221dc259aabSmrg int16_t xDst, 222dc259aabSmrg int16_t yDst, 223dc259aabSmrg uint16_t width, 224dc259aabSmrg uint16_t height) 225b4b94579Smrg{ 226dc259aabSmrg pixman_region32_t r32; 227dc259aabSmrg pixman_bool_t retval; 228b4b94579Smrg 229dc259aabSmrg pixman_region32_init (&r32); 230dc259aabSmrg 231dc259aabSmrg retval = pixman_compute_composite_region32 (&r32, pSrc, pMask, pDst, 232dc259aabSmrg xSrc, ySrc, xMask, yMask, xDst, yDst, 233dc259aabSmrg width, height); 234dc259aabSmrg 235dc259aabSmrg if (retval) 236b4b94579Smrg { 237dc259aabSmrg if (!pixman_region16_copy_from_region32 (pRegion, &r32)) 238dc259aabSmrg retval = FALSE; 239b4b94579Smrg } 240dc259aabSmrg 241dc259aabSmrg pixman_region32_fini (&r32); 242dc259aabSmrg return retval; 243b4b94579Smrg} 244b4b94579Smrg 245b4b94579Smrgpixman_bool_t 246b4b94579Smrgpixman_multiply_overflows_int (unsigned int a, 247b4b94579Smrg unsigned int b) 248b4b94579Smrg{ 249b4b94579Smrg return a >= INT32_MAX / b; 250b4b94579Smrg} 251b4b94579Smrg 252b4b94579Smrgpixman_bool_t 253b4b94579Smrgpixman_addition_overflows_int (unsigned int a, 254b4b94579Smrg unsigned int b) 255b4b94579Smrg{ 256b4b94579Smrg return a > INT32_MAX - b; 257b4b94579Smrg} 258b4b94579Smrg 259b4b94579Smrgvoid * 260b4b94579Smrgpixman_malloc_ab(unsigned int a, 261b4b94579Smrg unsigned int b) 262b4b94579Smrg{ 263b4b94579Smrg if (a >= INT32_MAX / b) 264b4b94579Smrg return NULL; 265b4b94579Smrg 266b4b94579Smrg return malloc (a * b); 267b4b94579Smrg} 268b4b94579Smrg 269b4b94579Smrgvoid * 270b4b94579Smrgpixman_malloc_abc (unsigned int a, 271b4b94579Smrg unsigned int b, 272b4b94579Smrg unsigned int c) 273b4b94579Smrg{ 274b4b94579Smrg if (a >= INT32_MAX / b) 275b4b94579Smrg return NULL; 276b4b94579Smrg else if (a * b >= INT32_MAX / c) 277b4b94579Smrg return NULL; 278b4b94579Smrg else 279b4b94579Smrg return malloc (a * b * c); 280b4b94579Smrg} 281b4b94579Smrg 282317c648bSmrg/* 283317c648bSmrg * Helper routine to expand a color component from 0 < n <= 8 bits to 16 bits by 284317c648bSmrg * replication. 285317c648bSmrg */ 286317c648bSmrgstatic inline uint64_t 287317c648bSmrgexpand16(const uint8_t val, int nbits) 288317c648bSmrg{ 289317c648bSmrg // Start out with the high bit of val in the high bit of result. 290317c648bSmrg uint16_t result = (uint16_t)val << (16 - nbits); 291317c648bSmrg 292317c648bSmrg if (nbits == 0) 293317c648bSmrg return 0; 294317c648bSmrg 295317c648bSmrg // Copy the bits in result, doubling the number of bits each time, until we 296317c648bSmrg // fill all 16 bits. 297317c648bSmrg while (nbits < 16) { 298317c648bSmrg result |= result >> nbits; 299317c648bSmrg nbits *= 2; 300317c648bSmrg } 301317c648bSmrg 302317c648bSmrg return result; 303317c648bSmrg} 304317c648bSmrg 305317c648bSmrg/* 306317c648bSmrg * This function expands images from ARGB8 format to ARGB16. To preserve 307317c648bSmrg * precision, it needs to know the original source format. For example, if the 308317c648bSmrg * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then 309317c648bSmrg * the expanded value is 12345123. To correctly expand this to 16 bits, it 310317c648bSmrg * should be 1234512345123451 and not 1234512312345123. 311317c648bSmrg */ 312317c648bSmrgvoid 313317c648bSmrgpixman_expand(uint64_t *dst, const uint32_t *src, 314317c648bSmrg pixman_format_code_t format, int width) 315317c648bSmrg{ 316317c648bSmrg /* 317317c648bSmrg * Determine the sizes of each component and the masks and shifts required 318317c648bSmrg * to extract them from the source pixel. 319317c648bSmrg */ 320317c648bSmrg const int a_size = PIXMAN_FORMAT_A(format), 321317c648bSmrg r_size = PIXMAN_FORMAT_R(format), 322317c648bSmrg g_size = PIXMAN_FORMAT_G(format), 323317c648bSmrg b_size = PIXMAN_FORMAT_B(format); 324317c648bSmrg const int a_shift = 32 - a_size, 325317c648bSmrg r_shift = 24 - r_size, 326317c648bSmrg g_shift = 16 - g_size, 327317c648bSmrg b_shift = 8 - b_size; 328317c648bSmrg const uint8_t a_mask = ~(~0 << a_size), 329317c648bSmrg r_mask = ~(~0 << r_size), 330317c648bSmrg g_mask = ~(~0 << g_size), 331317c648bSmrg b_mask = ~(~0 << b_size); 332317c648bSmrg int i; 333317c648bSmrg 334317c648bSmrg /* Start at the end so that we can do the expansion in place when src == dst */ 335317c648bSmrg for (i = width - 1; i >= 0; i--) 336317c648bSmrg { 337317c648bSmrg const uint32_t pixel = src[i]; 338317c648bSmrg // Extract the components. 339317c648bSmrg const uint8_t a = (pixel >> a_shift) & a_mask, 340317c648bSmrg r = (pixel >> r_shift) & r_mask, 341317c648bSmrg g = (pixel >> g_shift) & g_mask, 342317c648bSmrg b = (pixel >> b_shift) & b_mask; 343317c648bSmrg const uint64_t a16 = a_size ? expand16(a, a_size) : 0xffff, 344317c648bSmrg r16 = expand16(r, r_size), 345317c648bSmrg g16 = expand16(g, g_size), 346317c648bSmrg b16 = expand16(b, b_size); 347317c648bSmrg 348317c648bSmrg dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16; 349317c648bSmrg } 350317c648bSmrg} 351317c648bSmrg 352317c648bSmrg/* 353317c648bSmrg * Contracting is easier than expanding. We just need to truncate the 354317c648bSmrg * components. 355317c648bSmrg */ 356317c648bSmrgvoid 357317c648bSmrgpixman_contract(uint32_t *dst, const uint64_t *src, int width) 358317c648bSmrg{ 359317c648bSmrg int i; 360317c648bSmrg 361317c648bSmrg /* Start at the beginning so that we can do the contraction in place when 362317c648bSmrg * src == dst */ 363317c648bSmrg for (i = 0; i < width; i++) 364317c648bSmrg { 365317c648bSmrg const uint8_t a = src[i] >> 56, 366317c648bSmrg r = src[i] >> 40, 367317c648bSmrg g = src[i] >> 24, 368317c648bSmrg b = src[i] >> 8; 369317c648bSmrg dst[i] = a << 24 | r << 16 | g << 8 | b; 370317c648bSmrg } 371317c648bSmrg} 372317c648bSmrg 373dc259aabSmrgstatic void 374dc259aabSmrgwalk_region_internal (pixman_implementation_t *imp, 375dc259aabSmrg pixman_op_t op, 376dc259aabSmrg pixman_image_t * pSrc, 377dc259aabSmrg pixman_image_t * pMask, 378dc259aabSmrg pixman_image_t * pDst, 379dc259aabSmrg int16_t xSrc, 380dc259aabSmrg int16_t ySrc, 381dc259aabSmrg int16_t xMask, 382dc259aabSmrg int16_t yMask, 383dc259aabSmrg int16_t xDst, 384dc259aabSmrg int16_t yDst, 385dc259aabSmrg uint16_t width, 386dc259aabSmrg uint16_t height, 387dc259aabSmrg pixman_bool_t srcRepeat, 388dc259aabSmrg pixman_bool_t maskRepeat, 389dc259aabSmrg pixman_region32_t *region, 390dc259aabSmrg pixman_composite_func_t compositeRect) 391317c648bSmrg{ 392dc259aabSmrg int n; 393317c648bSmrg const pixman_box32_t *pbox; 394dc259aabSmrg int w, h, w_this, h_this; 395dc259aabSmrg int x_msk, y_msk, x_src, y_src, x_dst, y_dst; 396317c648bSmrg 397317c648bSmrg pbox = pixman_region32_rectangles (region, &n); 398317c648bSmrg while (n--) 399317c648bSmrg { 400317c648bSmrg h = pbox->y2 - pbox->y1; 401317c648bSmrg y_src = pbox->y1 - yDst + ySrc; 402317c648bSmrg y_msk = pbox->y1 - yDst + yMask; 403317c648bSmrg y_dst = pbox->y1; 404317c648bSmrg while (h) 405317c648bSmrg { 406317c648bSmrg h_this = h; 407317c648bSmrg w = pbox->x2 - pbox->x1; 408317c648bSmrg x_src = pbox->x1 - xDst + xSrc; 409317c648bSmrg x_msk = pbox->x1 - xDst + xMask; 410317c648bSmrg x_dst = pbox->x1; 411dc259aabSmrg 412317c648bSmrg if (maskRepeat) 413317c648bSmrg { 414317c648bSmrg y_msk = MOD (y_msk, pMask->bits.height); 415317c648bSmrg if (h_this > pMask->bits.height - y_msk) 416317c648bSmrg h_this = pMask->bits.height - y_msk; 417317c648bSmrg } 418317c648bSmrg if (srcRepeat) 419317c648bSmrg { 420317c648bSmrg y_src = MOD (y_src, pSrc->bits.height); 421317c648bSmrg if (h_this > pSrc->bits.height - y_src) 422317c648bSmrg h_this = pSrc->bits.height - y_src; 423317c648bSmrg } 424317c648bSmrg while (w) 425317c648bSmrg { 426317c648bSmrg w_this = w; 427317c648bSmrg if (maskRepeat) 428317c648bSmrg { 429317c648bSmrg x_msk = MOD (x_msk, pMask->bits.width); 430317c648bSmrg if (w_this > pMask->bits.width - x_msk) 431317c648bSmrg w_this = pMask->bits.width - x_msk; 432317c648bSmrg } 433317c648bSmrg if (srcRepeat) 434317c648bSmrg { 435317c648bSmrg x_src = MOD (x_src, pSrc->bits.width); 436317c648bSmrg if (w_this > pSrc->bits.width - x_src) 437317c648bSmrg w_this = pSrc->bits.width - x_src; 438317c648bSmrg } 439317c648bSmrg (*compositeRect) (imp, 440317c648bSmrg op, pSrc, pMask, pDst, 441317c648bSmrg x_src, y_src, x_msk, y_msk, x_dst, y_dst, 442317c648bSmrg w_this, h_this); 443317c648bSmrg w -= w_this; 444317c648bSmrg x_src += w_this; 445317c648bSmrg x_msk += w_this; 446317c648bSmrg x_dst += w_this; 447317c648bSmrg } 448317c648bSmrg h -= h_this; 449317c648bSmrg y_src += h_this; 450317c648bSmrg y_msk += h_this; 451317c648bSmrg y_dst += h_this; 452317c648bSmrg } 453317c648bSmrg pbox++; 454317c648bSmrg } 455317c648bSmrg} 456317c648bSmrg 457dc259aabSmrgvoid 458dc259aabSmrg_pixman_walk_composite_region (pixman_implementation_t *imp, 459dc259aabSmrg pixman_op_t op, 460dc259aabSmrg pixman_image_t * pSrc, 461dc259aabSmrg pixman_image_t * pMask, 462dc259aabSmrg pixman_image_t * pDst, 463dc259aabSmrg int16_t xSrc, 464dc259aabSmrg int16_t ySrc, 465dc259aabSmrg int16_t xMask, 466dc259aabSmrg int16_t yMask, 467dc259aabSmrg int16_t xDst, 468dc259aabSmrg int16_t yDst, 469dc259aabSmrg uint16_t width, 470dc259aabSmrg uint16_t height, 471dc259aabSmrg pixman_composite_func_t compositeRect) 472dc259aabSmrg{ 473dc259aabSmrg pixman_region32_t region; 474dc259aabSmrg 475dc259aabSmrg pixman_region32_init (®ion); 476dc259aabSmrg 477dc259aabSmrg if (pixman_compute_composite_region32 ( 478dc259aabSmrg ®ion, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height)) 479dc259aabSmrg { 480dc259aabSmrg walk_region_internal (imp, op, 481dc259aabSmrg pSrc, pMask, pDst, 482dc259aabSmrg xSrc, ySrc, xMask, yMask, xDst, yDst, 483dc259aabSmrg width, height, FALSE, FALSE, 484dc259aabSmrg ®ion, 485dc259aabSmrg compositeRect); 486dc259aabSmrg } 487dc259aabSmrg 488dc259aabSmrg pixman_region32_fini (®ion); 489dc259aabSmrg} 490dc259aabSmrg 491dc259aabSmrg 492317c648bSmrgstatic pixman_bool_t 493317c648bSmrgmask_is_solid (pixman_image_t *mask) 494317c648bSmrg{ 495317c648bSmrg if (mask->type == SOLID) 496317c648bSmrg return TRUE; 497317c648bSmrg 498317c648bSmrg if (mask->type == BITS && 499317c648bSmrg mask->common.repeat == PIXMAN_REPEAT_NORMAL && 500317c648bSmrg mask->bits.width == 1 && 501317c648bSmrg mask->bits.height == 1) 502317c648bSmrg { 503317c648bSmrg return TRUE; 504317c648bSmrg } 505317c648bSmrg 506317c648bSmrg return FALSE; 507317c648bSmrg} 508317c648bSmrg 509dc259aabSmrgstatic const pixman_fast_path_t * 510dc259aabSmrgget_fast_path (const pixman_fast_path_t *fast_paths, 511317c648bSmrg pixman_op_t op, 512317c648bSmrg pixman_image_t *pSrc, 513317c648bSmrg pixman_image_t *pMask, 514317c648bSmrg pixman_image_t *pDst, 515317c648bSmrg pixman_bool_t is_pixbuf) 516317c648bSmrg{ 517dc259aabSmrg const pixman_fast_path_t *info; 518317c648bSmrg 519317c648bSmrg for (info = fast_paths; info->op != PIXMAN_OP_NONE; info++) 520317c648bSmrg { 521dc259aabSmrg pixman_bool_t valid_src = FALSE; 522dc259aabSmrg pixman_bool_t valid_mask = FALSE; 523317c648bSmrg 524317c648bSmrg if (info->op != op) 525317c648bSmrg continue; 526317c648bSmrg 527dc259aabSmrg if ((info->src_format == PIXMAN_solid && _pixman_image_is_solid (pSrc)) || 528317c648bSmrg (pSrc->type == BITS && info->src_format == pSrc->bits.format)) 529317c648bSmrg { 530317c648bSmrg valid_src = TRUE; 531317c648bSmrg } 532317c648bSmrg 533317c648bSmrg if (!valid_src) 534317c648bSmrg continue; 535317c648bSmrg 536dc259aabSmrg if ((info->mask_format == PIXMAN_null && !pMask) || 537317c648bSmrg (pMask && pMask->type == BITS && info->mask_format == pMask->bits.format)) 538317c648bSmrg { 539317c648bSmrg valid_mask = TRUE; 540317c648bSmrg 541317c648bSmrg if (info->flags & NEED_SOLID_MASK) 542317c648bSmrg { 543317c648bSmrg if (!pMask || !mask_is_solid (pMask)) 544317c648bSmrg valid_mask = FALSE; 545317c648bSmrg } 546317c648bSmrg 547317c648bSmrg if (info->flags & NEED_COMPONENT_ALPHA) 548317c648bSmrg { 549317c648bSmrg if (!pMask || !pMask->common.component_alpha) 550317c648bSmrg valid_mask = FALSE; 551317c648bSmrg } 552317c648bSmrg } 553317c648bSmrg 554317c648bSmrg if (!valid_mask) 555317c648bSmrg continue; 556317c648bSmrg 557317c648bSmrg if (info->dest_format != pDst->bits.format) 558317c648bSmrg continue; 559317c648bSmrg 560317c648bSmrg if ((info->flags & NEED_PIXBUF) && !is_pixbuf) 561317c648bSmrg continue; 562317c648bSmrg 563317c648bSmrg return info; 564317c648bSmrg } 565317c648bSmrg 566317c648bSmrg return NULL; 567317c648bSmrg} 568317c648bSmrg 569dc259aabSmrgstatic inline pixman_bool_t 570dc259aabSmrgimage_covers (pixman_image_t *image, pixman_box32_t *extents, int x, int y) 571dc259aabSmrg{ 572dc259aabSmrg if (image->common.type == BITS && image->common.repeat == PIXMAN_REPEAT_NONE) 573dc259aabSmrg { 574dc259aabSmrg if (x > extents->x1 || y > extents->y1 || 575dc259aabSmrg x + image->bits.width < extents->x2 || 576dc259aabSmrg y + image->bits.height < extents->y2) 577dc259aabSmrg { 578dc259aabSmrg return FALSE; 579dc259aabSmrg } 580dc259aabSmrg } 581dc259aabSmrg 582dc259aabSmrg return TRUE; 583dc259aabSmrg} 584dc259aabSmrg 585317c648bSmrgpixman_bool_t 586dc259aabSmrg_pixman_run_fast_path (const pixman_fast_path_t *paths, 587317c648bSmrg pixman_implementation_t *imp, 588317c648bSmrg pixman_op_t op, 589317c648bSmrg pixman_image_t *src, 590317c648bSmrg pixman_image_t *mask, 591317c648bSmrg pixman_image_t *dest, 592317c648bSmrg int32_t src_x, 593317c648bSmrg int32_t src_y, 594317c648bSmrg int32_t mask_x, 595317c648bSmrg int32_t mask_y, 596317c648bSmrg int32_t dest_x, 597317c648bSmrg int32_t dest_y, 598317c648bSmrg int32_t width, 599317c648bSmrg int32_t height) 600317c648bSmrg{ 601317c648bSmrg pixman_composite_func_t func = NULL; 602317c648bSmrg pixman_bool_t src_repeat = src->common.repeat == PIXMAN_REPEAT_NORMAL; 603317c648bSmrg pixman_bool_t mask_repeat = mask && mask->common.repeat == PIXMAN_REPEAT_NORMAL; 604dc259aabSmrg pixman_bool_t result; 605dc259aabSmrg 606dc259aabSmrg if ((src->type == BITS || _pixman_image_is_solid (src)) && 607317c648bSmrg (!mask || mask->type == BITS) 608dc259aabSmrg && !src->common.transform && !(mask && mask->common.transform) 609dc259aabSmrg && !(mask && mask->common.alpha_map) && !src->common.alpha_map && !dest->common.alpha_map 610dc259aabSmrg && (src->common.filter != PIXMAN_FILTER_CONVOLUTION) 611dc259aabSmrg && (src->common.repeat != PIXMAN_REPEAT_PAD) 612dc259aabSmrg && (src->common.repeat != PIXMAN_REPEAT_REFLECT) 613dc259aabSmrg && (!mask || (mask->common.filter != PIXMAN_FILTER_CONVOLUTION && 614317c648bSmrg mask->common.repeat != PIXMAN_REPEAT_PAD && 615317c648bSmrg mask->common.repeat != PIXMAN_REPEAT_REFLECT)) 616317c648bSmrg && !src->common.read_func && !src->common.write_func 617317c648bSmrg && !(mask && mask->common.read_func) 618317c648bSmrg && !(mask && mask->common.write_func) 619317c648bSmrg && !dest->common.read_func 620317c648bSmrg && !dest->common.write_func) 621317c648bSmrg { 622dc259aabSmrg const pixman_fast_path_t *info; 623317c648bSmrg pixman_bool_t pixbuf; 624317c648bSmrg 625317c648bSmrg pixbuf = 626317c648bSmrg src && src->type == BITS && 627317c648bSmrg mask && mask->type == BITS && 628317c648bSmrg src->bits.bits == mask->bits.bits && 629317c648bSmrg src_x == mask_x && 630317c648bSmrg src_y == mask_y && 631317c648bSmrg !mask->common.component_alpha && 632317c648bSmrg !mask_repeat; 633317c648bSmrg 634317c648bSmrg info = get_fast_path (paths, op, src, mask, dest, pixbuf); 635dc259aabSmrg 636317c648bSmrg if (info) 637317c648bSmrg { 638317c648bSmrg func = info->func; 639dc259aabSmrg 640317c648bSmrg if (info->src_format == PIXMAN_solid) 641317c648bSmrg src_repeat = FALSE; 642dc259aabSmrg 643317c648bSmrg if (info->mask_format == PIXMAN_solid || info->flags & NEED_SOLID_MASK) 644317c648bSmrg mask_repeat = FALSE; 645dc259aabSmrg 646317c648bSmrg if ((src_repeat && 647317c648bSmrg src->bits.width == 1 && 648317c648bSmrg src->bits.height == 1) || 649317c648bSmrg (mask_repeat && 650317c648bSmrg mask->bits.width == 1 && 651317c648bSmrg mask->bits.height == 1)) 652317c648bSmrg { 653317c648bSmrg /* If src or mask are repeating 1x1 images and src_repeat or 654317c648bSmrg * mask_repeat are still TRUE, it means the fast path we 655317c648bSmrg * selected does not actually handle repeating images. 656317c648bSmrg * 657317c648bSmrg * So rather than call the "fast path" with a zillion 658317c648bSmrg * 1x1 requests, we just fall back to the general code (which 659317c648bSmrg * does do something sensible with 1x1 repeating images). 660317c648bSmrg */ 661317c648bSmrg func = NULL; 662317c648bSmrg } 663317c648bSmrg } 664317c648bSmrg } 665dc259aabSmrg 666dc259aabSmrg result = FALSE; 667dc259aabSmrg 668317c648bSmrg if (func) 669317c648bSmrg { 670dc259aabSmrg pixman_region32_t region; 671dc259aabSmrg pixman_region32_init (®ion); 672dc259aabSmrg 673dc259aabSmrg if (pixman_compute_composite_region32 ( 674dc259aabSmrg ®ion, src, mask, dest, src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height)) 675dc259aabSmrg { 676dc259aabSmrg pixman_box32_t *extents = pixman_region32_extents (®ion); 677dc259aabSmrg 678dc259aabSmrg if (image_covers (src, extents, dest_x - src_x, dest_y - src_y) && 679dc259aabSmrg (!mask || image_covers (mask, extents, dest_x - mask_x, dest_y - mask_y))) 680dc259aabSmrg { 681dc259aabSmrg walk_region_internal (imp, op, 682dc259aabSmrg src, mask, dest, 683dc259aabSmrg src_x, src_y, mask_x, mask_y, 684dc259aabSmrg dest_x, dest_y, 685dc259aabSmrg width, height, 686dc259aabSmrg src_repeat, mask_repeat, 687dc259aabSmrg ®ion, 688dc259aabSmrg func); 689dc259aabSmrg 690dc259aabSmrg result = TRUE; 691dc259aabSmrg } 692dc259aabSmrg } 693dc259aabSmrg 694dc259aabSmrg pixman_region32_fini (®ion); 695317c648bSmrg } 696317c648bSmrg 697dc259aabSmrg return result; 698dc259aabSmrg} 699dc259aabSmrg 700dc259aabSmrg#define N_TMP_BOXES (16) 701dc259aabSmrg 702dc259aabSmrgpixman_bool_t 703dc259aabSmrgpixman_region16_copy_from_region32 (pixman_region16_t *dst, 704dc259aabSmrg pixman_region32_t *src) 705dc259aabSmrg{ 706dc259aabSmrg int n_boxes, i; 707dc259aabSmrg pixman_box32_t *boxes32; 708dc259aabSmrg pixman_box16_t *boxes16; 709dc259aabSmrg pixman_bool_t retval; 710dc259aabSmrg 711dc259aabSmrg boxes32 = pixman_region32_rectangles (src, &n_boxes); 712dc259aabSmrg 713dc259aabSmrg boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t)); 714dc259aabSmrg 715dc259aabSmrg if (!boxes16) 716dc259aabSmrg return FALSE; 717dc259aabSmrg 718dc259aabSmrg for (i = 0; i < n_boxes; ++i) 719dc259aabSmrg { 720dc259aabSmrg boxes16[i].x1 = boxes32[i].x1; 721dc259aabSmrg boxes16[i].y1 = boxes32[i].y1; 722dc259aabSmrg boxes16[i].x2 = boxes32[i].x2; 723dc259aabSmrg boxes16[i].y2 = boxes32[i].y2; 724dc259aabSmrg } 725dc259aabSmrg 726dc259aabSmrg pixman_region_fini (dst); 727dc259aabSmrg retval = pixman_region_init_rects (dst, boxes16, n_boxes); 728dc259aabSmrg free (boxes16); 729dc259aabSmrg return retval; 730317c648bSmrg} 731dc259aabSmrg 732dc259aabSmrgpixman_bool_t 733dc259aabSmrgpixman_region32_copy_from_region16 (pixman_region32_t *dst, 734dc259aabSmrg pixman_region16_t *src) 735dc259aabSmrg{ 736dc259aabSmrg int n_boxes, i; 737dc259aabSmrg pixman_box16_t *boxes16; 738dc259aabSmrg pixman_box32_t *boxes32; 739dc259aabSmrg pixman_box32_t tmp_boxes[N_TMP_BOXES]; 740dc259aabSmrg pixman_bool_t retval; 741dc259aabSmrg 742dc259aabSmrg boxes16 = pixman_region_rectangles (src, &n_boxes); 743dc259aabSmrg 744dc259aabSmrg if (n_boxes > N_TMP_BOXES) 745dc259aabSmrg boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t)); 746dc259aabSmrg else 747dc259aabSmrg boxes32 = tmp_boxes; 748dc259aabSmrg 749dc259aabSmrg if (!boxes32) 750dc259aabSmrg return FALSE; 751dc259aabSmrg 752dc259aabSmrg for (i = 0; i < n_boxes; ++i) 753dc259aabSmrg { 754dc259aabSmrg boxes32[i].x1 = boxes16[i].x1; 755dc259aabSmrg boxes32[i].y1 = boxes16[i].y1; 756dc259aabSmrg boxes32[i].x2 = boxes16[i].x2; 757dc259aabSmrg boxes32[i].y2 = boxes16[i].y2; 758dc259aabSmrg } 759dc259aabSmrg 760dc259aabSmrg pixman_region32_fini (dst); 761dc259aabSmrg retval = pixman_region32_init_rects (dst, boxes32, n_boxes); 762dc259aabSmrg 763dc259aabSmrg if (boxes32 != tmp_boxes) 764dc259aabSmrg free (boxes32); 765dc259aabSmrg 766dc259aabSmrg return retval; 767dc259aabSmrg} 768dc259aabSmrg 769