pixman-utils.c revision 952204ab
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 170dc259aabSmrg#define N_TMP_BOXES (16) 171dc259aabSmrg 172dc259aabSmrgpixman_bool_t 173dc259aabSmrgpixman_region16_copy_from_region32 (pixman_region16_t *dst, 174d0321353Smrg pixman_region32_t *src) 175dc259aabSmrg{ 176dc259aabSmrg int n_boxes, i; 177dc259aabSmrg pixman_box32_t *boxes32; 178dc259aabSmrg pixman_box16_t *boxes16; 179dc259aabSmrg pixman_bool_t retval; 180d0321353Smrg 181dc259aabSmrg boxes32 = pixman_region32_rectangles (src, &n_boxes); 182dc259aabSmrg 183dc259aabSmrg boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t)); 184dc259aabSmrg 185dc259aabSmrg if (!boxes16) 186dc259aabSmrg return FALSE; 187d0321353Smrg 188dc259aabSmrg for (i = 0; i < n_boxes; ++i) 189dc259aabSmrg { 190dc259aabSmrg boxes16[i].x1 = boxes32[i].x1; 191dc259aabSmrg boxes16[i].y1 = boxes32[i].y1; 192dc259aabSmrg boxes16[i].x2 = boxes32[i].x2; 193dc259aabSmrg boxes16[i].y2 = boxes32[i].y2; 194dc259aabSmrg } 195dc259aabSmrg 196dc259aabSmrg pixman_region_fini (dst); 197dc259aabSmrg retval = pixman_region_init_rects (dst, boxes16, n_boxes); 198dc259aabSmrg free (boxes16); 199dc259aabSmrg return retval; 200317c648bSmrg} 201dc259aabSmrg 202dc259aabSmrgpixman_bool_t 203dc259aabSmrgpixman_region32_copy_from_region16 (pixman_region32_t *dst, 204d0321353Smrg pixman_region16_t *src) 205dc259aabSmrg{ 206dc259aabSmrg int n_boxes, i; 207dc259aabSmrg pixman_box16_t *boxes16; 208dc259aabSmrg pixman_box32_t *boxes32; 209dc259aabSmrg pixman_box32_t tmp_boxes[N_TMP_BOXES]; 210dc259aabSmrg pixman_bool_t retval; 211d0321353Smrg 212dc259aabSmrg boxes16 = pixman_region_rectangles (src, &n_boxes); 213dc259aabSmrg 214dc259aabSmrg if (n_boxes > N_TMP_BOXES) 215dc259aabSmrg boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t)); 216dc259aabSmrg else 217dc259aabSmrg boxes32 = tmp_boxes; 218d0321353Smrg 219dc259aabSmrg if (!boxes32) 220dc259aabSmrg return FALSE; 221d0321353Smrg 222dc259aabSmrg for (i = 0; i < n_boxes; ++i) 223dc259aabSmrg { 224dc259aabSmrg boxes32[i].x1 = boxes16[i].x1; 225dc259aabSmrg boxes32[i].y1 = boxes16[i].y1; 226dc259aabSmrg boxes32[i].x2 = boxes16[i].x2; 227dc259aabSmrg boxes32[i].y2 = boxes16[i].y2; 228dc259aabSmrg } 229dc259aabSmrg 230dc259aabSmrg pixman_region32_fini (dst); 231dc259aabSmrg retval = pixman_region32_init_rects (dst, boxes32, n_boxes); 232dc259aabSmrg 233dc259aabSmrg if (boxes32 != tmp_boxes) 234dc259aabSmrg free (boxes32); 235dc259aabSmrg 236dc259aabSmrg return retval; 237dc259aabSmrg} 238952204abSmrg 239952204abSmrg#ifdef DEBUG 240952204abSmrg 241952204abSmrgvoid 242952204abSmrg_pixman_log_error (const char *function, const char *message) 243952204abSmrg{ 244952204abSmrg static int n_messages = 0; 245952204abSmrg 246952204abSmrg if (n_messages < 10) 247952204abSmrg { 248952204abSmrg fprintf (stderr, 249952204abSmrg "*** BUG ***\n" 250952204abSmrg "In %s: %s\n" 251952204abSmrg "Set a breakpoint on '_pixman_log_error' to debug\n\n", 252952204abSmrg function, message); 253952204abSmrg 254952204abSmrg n_messages++; 255952204abSmrg } 256952204abSmrg} 257952204abSmrg 258952204abSmrg#endif 259