pixman-utils.c revision 953d7d37
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 33b4b94579Smrgpixman_bool_t 34b4b94579Smrgpixman_multiply_overflows_int (unsigned int a, 35d0321353Smrg unsigned int b) 36b4b94579Smrg{ 37b4b94579Smrg return a >= INT32_MAX / b; 38b4b94579Smrg} 39b4b94579Smrg 40b4b94579Smrgpixman_bool_t 41b4b94579Smrgpixman_addition_overflows_int (unsigned int a, 42d0321353Smrg unsigned int b) 43b4b94579Smrg{ 44b4b94579Smrg return a > INT32_MAX - b; 45b4b94579Smrg} 46b4b94579Smrg 47b4b94579Smrgvoid * 48d0321353Smrgpixman_malloc_ab (unsigned int a, 49d0321353Smrg unsigned int b) 50b4b94579Smrg{ 51b4b94579Smrg if (a >= INT32_MAX / b) 52b4b94579Smrg return NULL; 53b4b94579Smrg 54b4b94579Smrg return malloc (a * b); 55b4b94579Smrg} 56b4b94579Smrg 57b4b94579Smrgvoid * 58b4b94579Smrgpixman_malloc_abc (unsigned int a, 59d0321353Smrg unsigned int b, 60d0321353Smrg unsigned int c) 61b4b94579Smrg{ 62b4b94579Smrg if (a >= INT32_MAX / b) 63b4b94579Smrg return NULL; 64b4b94579Smrg else if (a * b >= INT32_MAX / c) 65b4b94579Smrg return NULL; 66b4b94579Smrg else 67b4b94579Smrg return malloc (a * b * c); 68b4b94579Smrg} 69b4b94579Smrg 70317c648bSmrg/* 71d0321353Smrg * Helper routine to expand a color component from 0 < n <= 8 bits to 16 72d0321353Smrg * bits by replication. 73317c648bSmrg */ 74317c648bSmrgstatic inline uint64_t 75d0321353Smrgexpand16 (const uint8_t val, int nbits) 76317c648bSmrg{ 77d0321353Smrg /* Start out with the high bit of val in the high bit of result. */ 78317c648bSmrg uint16_t result = (uint16_t)val << (16 - nbits); 79317c648bSmrg 80317c648bSmrg if (nbits == 0) 81d0321353Smrg return 0; 82317c648bSmrg 83d0321353Smrg /* Copy the bits in result, doubling the number of bits each time, until 84d0321353Smrg * we fill all 16 bits. 85d0321353Smrg */ 86d0321353Smrg while (nbits < 16) 87d0321353Smrg { 88d0321353Smrg result |= result >> nbits; 89d0321353Smrg nbits *= 2; 90317c648bSmrg } 91317c648bSmrg 92317c648bSmrg return result; 93317c648bSmrg} 94317c648bSmrg 95317c648bSmrg/* 96317c648bSmrg * This function expands images from ARGB8 format to ARGB16. To preserve 97317c648bSmrg * precision, it needs to know the original source format. For example, if the 98317c648bSmrg * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then 99317c648bSmrg * the expanded value is 12345123. To correctly expand this to 16 bits, it 100317c648bSmrg * should be 1234512345123451 and not 1234512312345123. 101317c648bSmrg */ 102317c648bSmrgvoid 103d0321353Smrgpixman_expand (uint64_t * dst, 104d0321353Smrg const uint32_t * src, 105d0321353Smrg pixman_format_code_t format, 106d0321353Smrg int width) 107317c648bSmrg{ 108317c648bSmrg /* 109d0321353Smrg * Determine the sizes of each component and the masks and shifts 110d0321353Smrg * required to extract them from the source pixel. 111317c648bSmrg */ 112d0321353Smrg const int a_size = PIXMAN_FORMAT_A (format), 113d0321353Smrg r_size = PIXMAN_FORMAT_R (format), 114d0321353Smrg g_size = PIXMAN_FORMAT_G (format), 115d0321353Smrg b_size = PIXMAN_FORMAT_B (format); 116317c648bSmrg const int a_shift = 32 - a_size, 117317c648bSmrg r_shift = 24 - r_size, 118317c648bSmrg g_shift = 16 - g_size, 119317c648bSmrg b_shift = 8 - b_size; 120317c648bSmrg const uint8_t a_mask = ~(~0 << a_size), 121317c648bSmrg r_mask = ~(~0 << r_size), 122317c648bSmrg g_mask = ~(~0 << g_size), 123317c648bSmrg b_mask = ~(~0 << b_size); 124317c648bSmrg int i; 125317c648bSmrg 126d0321353Smrg /* Start at the end so that we can do the expansion in place 127d0321353Smrg * when src == dst 128d0321353Smrg */ 129317c648bSmrg for (i = width - 1; i >= 0; i--) 130317c648bSmrg { 131d0321353Smrg const uint32_t pixel = src[i]; 132d0321353Smrg const uint8_t a = (pixel >> a_shift) & a_mask, 133d0321353Smrg r = (pixel >> r_shift) & r_mask, 134d0321353Smrg g = (pixel >> g_shift) & g_mask, 135d0321353Smrg b = (pixel >> b_shift) & b_mask; 136d0321353Smrg const uint64_t a16 = a_size ? expand16 (a, a_size) : 0xffff, 137d0321353Smrg r16 = expand16 (r, r_size), 138d0321353Smrg g16 = expand16 (g, g_size), 139d0321353Smrg b16 = expand16 (b, b_size); 140d0321353Smrg 141d0321353Smrg dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16; 142317c648bSmrg } 143317c648bSmrg} 144317c648bSmrg 145317c648bSmrg/* 146317c648bSmrg * Contracting is easier than expanding. We just need to truncate the 147317c648bSmrg * components. 148317c648bSmrg */ 149317c648bSmrgvoid 150d0321353Smrgpixman_contract (uint32_t * dst, 151d0321353Smrg const uint64_t *src, 152d0321353Smrg int width) 153317c648bSmrg{ 154317c648bSmrg int i; 155317c648bSmrg 156d0321353Smrg /* Start at the beginning so that we can do the contraction in 157d0321353Smrg * place when src == dst 158d0321353Smrg */ 159317c648bSmrg for (i = 0; i < width; i++) 160317c648bSmrg { 161d0321353Smrg const uint8_t a = src[i] >> 56, 162d0321353Smrg r = src[i] >> 40, 163d0321353Smrg g = src[i] >> 24, 164d0321353Smrg b = src[i] >> 8; 165d0321353Smrg 166d0321353Smrg dst[i] = a << 24 | r << 16 | g << 8 | b; 167317c648bSmrg } 168317c648bSmrg} 169317c648bSmrg 170953d7d37Smrguint32_t * 171953d7d37Smrg_pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask) 172953d7d37Smrg{ 173953d7d37Smrg return iter->buffer; 174953d7d37Smrg} 175953d7d37Smrg 176dc259aabSmrg#define N_TMP_BOXES (16) 177dc259aabSmrg 178dc259aabSmrgpixman_bool_t 179dc259aabSmrgpixman_region16_copy_from_region32 (pixman_region16_t *dst, 180d0321353Smrg pixman_region32_t *src) 181dc259aabSmrg{ 182dc259aabSmrg int n_boxes, i; 183dc259aabSmrg pixman_box32_t *boxes32; 184dc259aabSmrg pixman_box16_t *boxes16; 185dc259aabSmrg pixman_bool_t retval; 186d0321353Smrg 187dc259aabSmrg boxes32 = pixman_region32_rectangles (src, &n_boxes); 188dc259aabSmrg 189dc259aabSmrg boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t)); 190dc259aabSmrg 191dc259aabSmrg if (!boxes16) 192dc259aabSmrg return FALSE; 193d0321353Smrg 194dc259aabSmrg for (i = 0; i < n_boxes; ++i) 195dc259aabSmrg { 196dc259aabSmrg boxes16[i].x1 = boxes32[i].x1; 197dc259aabSmrg boxes16[i].y1 = boxes32[i].y1; 198dc259aabSmrg boxes16[i].x2 = boxes32[i].x2; 199dc259aabSmrg boxes16[i].y2 = boxes32[i].y2; 200dc259aabSmrg } 201dc259aabSmrg 202dc259aabSmrg pixman_region_fini (dst); 203dc259aabSmrg retval = pixman_region_init_rects (dst, boxes16, n_boxes); 204dc259aabSmrg free (boxes16); 205dc259aabSmrg return retval; 206317c648bSmrg} 207dc259aabSmrg 208dc259aabSmrgpixman_bool_t 209dc259aabSmrgpixman_region32_copy_from_region16 (pixman_region32_t *dst, 210d0321353Smrg pixman_region16_t *src) 211dc259aabSmrg{ 212dc259aabSmrg int n_boxes, i; 213dc259aabSmrg pixman_box16_t *boxes16; 214dc259aabSmrg pixman_box32_t *boxes32; 215dc259aabSmrg pixman_box32_t tmp_boxes[N_TMP_BOXES]; 216dc259aabSmrg pixman_bool_t retval; 217d0321353Smrg 218dc259aabSmrg boxes16 = pixman_region_rectangles (src, &n_boxes); 219dc259aabSmrg 220dc259aabSmrg if (n_boxes > N_TMP_BOXES) 221dc259aabSmrg boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t)); 222dc259aabSmrg else 223dc259aabSmrg boxes32 = tmp_boxes; 224d0321353Smrg 225dc259aabSmrg if (!boxes32) 226dc259aabSmrg return FALSE; 227d0321353Smrg 228dc259aabSmrg for (i = 0; i < n_boxes; ++i) 229dc259aabSmrg { 230dc259aabSmrg boxes32[i].x1 = boxes16[i].x1; 231dc259aabSmrg boxes32[i].y1 = boxes16[i].y1; 232dc259aabSmrg boxes32[i].x2 = boxes16[i].x2; 233dc259aabSmrg boxes32[i].y2 = boxes16[i].y2; 234dc259aabSmrg } 235dc259aabSmrg 236dc259aabSmrg pixman_region32_fini (dst); 237dc259aabSmrg retval = pixman_region32_init_rects (dst, boxes32, n_boxes); 238dc259aabSmrg 239dc259aabSmrg if (boxes32 != tmp_boxes) 240dc259aabSmrg free (boxes32); 241dc259aabSmrg 242dc259aabSmrg return retval; 243dc259aabSmrg} 244952204abSmrg 245952204abSmrg#ifdef DEBUG 246952204abSmrg 247952204abSmrgvoid 248952204abSmrg_pixman_log_error (const char *function, const char *message) 249952204abSmrg{ 250952204abSmrg static int n_messages = 0; 251952204abSmrg 252952204abSmrg if (n_messages < 10) 253952204abSmrg { 254952204abSmrg fprintf (stderr, 255952204abSmrg "*** BUG ***\n" 256952204abSmrg "In %s: %s\n" 257952204abSmrg "Set a breakpoint on '_pixman_log_error' to debug\n\n", 258952204abSmrg function, message); 259952204abSmrg 260952204abSmrg n_messages++; 261952204abSmrg } 262952204abSmrg} 263952204abSmrg 264952204abSmrg#endif 265