michael@0: /* michael@0: * Copyright © 2000 SuSE, Inc. michael@0: * Copyright © 1999 Keith Packard michael@0: * michael@0: * Permission to use, copy, modify, distribute, and sell this software and its michael@0: * documentation for any purpose is hereby granted without fee, provided that michael@0: * the above copyright notice appear in all copies and that both that michael@0: * copyright notice and this permission notice appear in supporting michael@0: * documentation, and that the name of SuSE not be used in advertising or michael@0: * publicity pertaining to distribution of the software without specific, michael@0: * written prior permission. SuSE makes no representations about the michael@0: * suitability of this software for any purpose. It is provided "as is" michael@0: * without express or implied warranty. michael@0: * michael@0: * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL michael@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE michael@0: * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES michael@0: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION michael@0: * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN michael@0: * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. michael@0: * michael@0: * Author: Keith Packard, SuSE, Inc. michael@0: */ michael@0: michael@0: #ifdef HAVE_CONFIG_H michael@0: #include michael@0: #endif michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "pixman-private.h" michael@0: michael@0: pixman_bool_t michael@0: _pixman_multiply_overflows_size (size_t a, size_t b) michael@0: { michael@0: return a >= SIZE_MAX / b; michael@0: } michael@0: michael@0: pixman_bool_t michael@0: _pixman_multiply_overflows_int (unsigned int a, unsigned int b) michael@0: { michael@0: return a >= INT32_MAX / b; michael@0: } michael@0: michael@0: pixman_bool_t michael@0: _pixman_addition_overflows_int (unsigned int a, unsigned int b) michael@0: { michael@0: return a > INT32_MAX - b; michael@0: } michael@0: michael@0: void * michael@0: pixman_malloc_ab (unsigned int a, michael@0: unsigned int b) michael@0: { michael@0: if (a >= INT32_MAX / b) michael@0: return NULL; michael@0: michael@0: return malloc (a * b); michael@0: } michael@0: michael@0: void * michael@0: pixman_malloc_abc (unsigned int a, michael@0: unsigned int b, michael@0: unsigned int c) michael@0: { michael@0: if (a >= INT32_MAX / b) michael@0: return NULL; michael@0: else if (a * b >= INT32_MAX / c) michael@0: return NULL; michael@0: else michael@0: return malloc (a * b * c); michael@0: } michael@0: michael@0: static force_inline uint16_t michael@0: float_to_unorm (float f, int n_bits) michael@0: { michael@0: uint32_t u; michael@0: michael@0: if (f > 1.0) michael@0: f = 1.0; michael@0: if (f < 0.0) michael@0: f = 0.0; michael@0: michael@0: u = f * (1 << n_bits); michael@0: u -= (u >> n_bits); michael@0: michael@0: return u; michael@0: } michael@0: michael@0: static force_inline float michael@0: unorm_to_float (uint16_t u, int n_bits) michael@0: { michael@0: uint32_t m = ((1 << n_bits) - 1); michael@0: michael@0: return (u & m) * (1.f / (float)m); michael@0: } michael@0: michael@0: /* michael@0: * This function expands images from a8r8g8b8 to argb_t. To preserve michael@0: * precision, it needs to know from which source format the a8r8g8b8 pixels michael@0: * originally came. michael@0: * michael@0: * For example, if the source was PIXMAN_x1r5g5b5 and the red component michael@0: * contained bits 12345, then the 8-bit value is 12345123. To correctly michael@0: * expand this to floating point, it should be 12345 / 31.0 and not michael@0: * 12345123 / 255.0. michael@0: */ michael@0: void michael@0: pixman_expand_to_float (argb_t *dst, michael@0: const uint32_t *src, michael@0: pixman_format_code_t format, michael@0: int width) michael@0: { michael@0: static const float multipliers[16] = { michael@0: 0.0f, michael@0: 1.0f / ((1 << 1) - 1), michael@0: 1.0f / ((1 << 2) - 1), michael@0: 1.0f / ((1 << 3) - 1), michael@0: 1.0f / ((1 << 4) - 1), michael@0: 1.0f / ((1 << 5) - 1), michael@0: 1.0f / ((1 << 6) - 1), michael@0: 1.0f / ((1 << 7) - 1), michael@0: 1.0f / ((1 << 8) - 1), michael@0: 1.0f / ((1 << 9) - 1), michael@0: 1.0f / ((1 << 10) - 1), michael@0: 1.0f / ((1 << 11) - 1), michael@0: 1.0f / ((1 << 12) - 1), michael@0: 1.0f / ((1 << 13) - 1), michael@0: 1.0f / ((1 << 14) - 1), michael@0: 1.0f / ((1 << 15) - 1), michael@0: }; michael@0: int a_size, r_size, g_size, b_size; michael@0: int a_shift, r_shift, g_shift, b_shift; michael@0: float a_mul, r_mul, g_mul, b_mul; michael@0: uint32_t a_mask, r_mask, g_mask, b_mask; michael@0: int i; michael@0: michael@0: if (!PIXMAN_FORMAT_VIS (format)) michael@0: format = PIXMAN_a8r8g8b8; michael@0: michael@0: /* michael@0: * Determine the sizes of each component and the masks and shifts michael@0: * required to extract them from the source pixel. michael@0: */ michael@0: a_size = PIXMAN_FORMAT_A (format); michael@0: r_size = PIXMAN_FORMAT_R (format); michael@0: g_size = PIXMAN_FORMAT_G (format); michael@0: b_size = PIXMAN_FORMAT_B (format); michael@0: michael@0: a_shift = 32 - a_size; michael@0: r_shift = 24 - r_size; michael@0: g_shift = 16 - g_size; michael@0: b_shift = 8 - b_size; michael@0: michael@0: a_mask = ((1 << a_size) - 1); michael@0: r_mask = ((1 << r_size) - 1); michael@0: g_mask = ((1 << g_size) - 1); michael@0: b_mask = ((1 << b_size) - 1); michael@0: michael@0: a_mul = multipliers[a_size]; michael@0: r_mul = multipliers[r_size]; michael@0: g_mul = multipliers[g_size]; michael@0: b_mul = multipliers[b_size]; michael@0: michael@0: /* Start at the end so that we can do the expansion in place michael@0: * when src == dst michael@0: */ michael@0: for (i = width - 1; i >= 0; i--) michael@0: { michael@0: const uint32_t pixel = src[i]; michael@0: michael@0: dst[i].a = a_mask? ((pixel >> a_shift) & a_mask) * a_mul : 1.0f; michael@0: dst[i].r = ((pixel >> r_shift) & r_mask) * r_mul; michael@0: dst[i].g = ((pixel >> g_shift) & g_mask) * g_mul; michael@0: dst[i].b = ((pixel >> b_shift) & b_mask) * b_mul; michael@0: } michael@0: } michael@0: michael@0: uint16_t michael@0: pixman_float_to_unorm (float f, int n_bits) michael@0: { michael@0: return float_to_unorm (f, n_bits); michael@0: } michael@0: michael@0: float michael@0: pixman_unorm_to_float (uint16_t u, int n_bits) michael@0: { michael@0: return unorm_to_float (u, n_bits); michael@0: } michael@0: michael@0: void michael@0: pixman_contract_from_float (uint32_t *dst, michael@0: const argb_t *src, michael@0: int width) michael@0: { michael@0: int i; michael@0: michael@0: for (i = 0; i < width; ++i) michael@0: { michael@0: uint8_t a, r, g, b; michael@0: michael@0: a = float_to_unorm (src[i].a, 8); michael@0: r = float_to_unorm (src[i].r, 8); michael@0: g = float_to_unorm (src[i].g, 8); michael@0: b = float_to_unorm (src[i].b, 8); michael@0: michael@0: dst[i] = (a << 24) | (r << 16) | (g << 8) | (b << 0); michael@0: } michael@0: } michael@0: michael@0: uint32_t * michael@0: _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask) michael@0: { michael@0: return iter->buffer; michael@0: } michael@0: michael@0: #define N_TMP_BOXES (16) michael@0: michael@0: pixman_bool_t michael@0: pixman_region16_copy_from_region32 (pixman_region16_t *dst, michael@0: pixman_region32_t *src) michael@0: { michael@0: int n_boxes, i; michael@0: pixman_box32_t *boxes32; michael@0: pixman_box16_t *boxes16; michael@0: pixman_bool_t retval; michael@0: michael@0: boxes32 = pixman_region32_rectangles (src, &n_boxes); michael@0: michael@0: boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t)); michael@0: michael@0: if (!boxes16) michael@0: return FALSE; michael@0: michael@0: for (i = 0; i < n_boxes; ++i) michael@0: { michael@0: boxes16[i].x1 = boxes32[i].x1; michael@0: boxes16[i].y1 = boxes32[i].y1; michael@0: boxes16[i].x2 = boxes32[i].x2; michael@0: boxes16[i].y2 = boxes32[i].y2; michael@0: } michael@0: michael@0: pixman_region_fini (dst); michael@0: retval = pixman_region_init_rects (dst, boxes16, n_boxes); michael@0: free (boxes16); michael@0: return retval; michael@0: } michael@0: michael@0: pixman_bool_t michael@0: pixman_region32_copy_from_region16 (pixman_region32_t *dst, michael@0: pixman_region16_t *src) michael@0: { michael@0: int n_boxes, i; michael@0: pixman_box16_t *boxes16; michael@0: pixman_box32_t *boxes32; michael@0: pixman_box32_t tmp_boxes[N_TMP_BOXES]; michael@0: pixman_bool_t retval; michael@0: michael@0: boxes16 = pixman_region_rectangles (src, &n_boxes); michael@0: michael@0: if (n_boxes > N_TMP_BOXES) michael@0: boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t)); michael@0: else michael@0: boxes32 = tmp_boxes; michael@0: michael@0: if (!boxes32) michael@0: return FALSE; michael@0: michael@0: for (i = 0; i < n_boxes; ++i) michael@0: { michael@0: boxes32[i].x1 = boxes16[i].x1; michael@0: boxes32[i].y1 = boxes16[i].y1; michael@0: boxes32[i].x2 = boxes16[i].x2; michael@0: boxes32[i].y2 = boxes16[i].y2; michael@0: } michael@0: michael@0: pixman_region32_fini (dst); michael@0: retval = pixman_region32_init_rects (dst, boxes32, n_boxes); michael@0: michael@0: if (boxes32 != tmp_boxes) michael@0: free (boxes32); michael@0: michael@0: return retval; michael@0: } michael@0: michael@0: /* This function is exported for the sake of the test suite and not part michael@0: * of the ABI. michael@0: */ michael@0: PIXMAN_EXPORT pixman_implementation_t * michael@0: _pixman_internal_only_get_implementation (void) michael@0: { michael@0: return get_implementation (); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: michael@0: void michael@0: _pixman_log_error (const char *function, const char *message) michael@0: { michael@0: static int n_messages = 0; michael@0: michael@0: if (n_messages < 10) michael@0: { michael@0: fprintf (stderr, michael@0: "*** BUG ***\n" michael@0: "In %s: %s\n" michael@0: "Set a breakpoint on '_pixman_log_error' to debug\n\n", michael@0: function, message); michael@0: michael@0: n_messages++; michael@0: } michael@0: } michael@0: michael@0: #endif