/* * Copyright © 2000 SuSE, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of SuSE not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. SuSE makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Keith Packard, SuSE, Inc. */ #ifdef HAVE_CONFIG_H #include #endif #include #include "pixman.h" #include "pixman-private.h" #include "pixman-mmx.h" pixman_bool_t pixman_transform_point_3d (pixman_transform_t *transform, pixman_vector_t *vector) { pixman_vector_t result; int i, j; pixman_fixed_32_32_t partial; pixman_fixed_48_16_t v; for (j = 0; j < 3; j++) { v = 0; for (i = 0; i < 3; i++) { partial = ((pixman_fixed_48_16_t) transform->matrix[j][i] * (pixman_fixed_48_16_t) vector->vector[i]); v += partial >> 16; } if (v > pixman_max_fixed_48_16 || v < pixman_min_fixed_48_16) return FALSE; result.vector[j] = (pixman_fixed_48_16_t) v; } if (!result.vector[2]) return FALSE; *vector = result; return TRUE; } pixman_bool_t pixman_blt (uint32_t *src_bits, uint32_t *dst_bits, int src_stride, int dst_stride, int src_bpp, int dst_bpp, int src_x, int src_y, int dst_x, int dst_y, int width, int height) { #ifdef USE_MMX if (pixman_have_mmx()) { return pixman_blt_mmx (src_bits, dst_bits, src_stride, dst_stride, src_bpp, dst_bpp, src_x, src_y, dst_x, dst_y, width, height); } else #endif return FALSE; } static void pixman_fill8 (uint32_t *bits, int stride, int x, int y, int width, int height, uint32_t xor) { int byte_stride = stride * (int) sizeof (uint32_t); uint8_t *dst = (uint8_t *) bits; uint8_t v = xor & 0xff; int i; dst = dst + y * byte_stride + x; while (height--) { for (i = 0; i < width; ++i) dst[i] = v; dst += byte_stride; } } static void pixman_fill16 (uint32_t *bits, int stride, int x, int y, int width, int height, uint32_t xor) { int short_stride = (stride * (int) sizeof (uint32_t)) / (int) sizeof (uint16_t); uint16_t *dst = (uint16_t *)bits; uint16_t v = xor & 0xffff; int i; dst = dst + y * short_stride + x; while (height--) { for (i = 0; i < width; ++i) dst[i] = v; dst += short_stride; } } static void pixman_fill32 (uint32_t *bits, int stride, int x, int y, int width, int height, uint32_t xor) { int i; bits = bits + y * stride + x; while (height--) { for (i = 0; i < width; ++i) bits[i] = xor; bits += stride; } } pixman_bool_t pixman_fill (uint32_t *bits, int stride, int bpp, int x, int y, int width, int height, uint32_t xor) { #if 0 printf ("filling: %d %d %d %d (stride: %d, bpp: %d) pixel: %x\n", x, y, width, height, stride, bpp, xor); #endif #ifdef USE_MMX if (!pixman_have_mmx() || !pixman_fill_mmx (bits, stride, bpp, x, y, width, height, xor)) #endif { switch (bpp) { case 8: pixman_fill8 (bits, stride, x, y, width, height, xor); break; case 16: pixman_fill16 (bits, stride, x, y, width, height, xor); break; case 32: pixman_fill32 (bits, stride, x, y, width, height, xor); break; default: return FALSE; break; } } return TRUE; } /* * Compute the smallest value no less than y which is on a * grid row */ pixman_fixed_t pixman_sample_ceil_y (pixman_fixed_t y, int n) { pixman_fixed_t f = pixman_fixed_frac(y); pixman_fixed_t i = pixman_fixed_floor(y); f = ((f + Y_FRAC_FIRST(n)) / STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n); if (f > Y_FRAC_LAST(n)) { f = Y_FRAC_FIRST(n); i += pixman_fixed_1; } return (i | f); } #define _div(a,b) ((a) >= 0 ? (a) / (b) : -((-(a) + (b) - 1) / (b))) /* * Compute the largest value no greater than y which is on a * grid row */ pixman_fixed_t pixman_sample_floor_y (pixman_fixed_t y, int n) { pixman_fixed_t f = pixman_fixed_frac(y); pixman_fixed_t i = pixman_fixed_floor (y); f = _div(f - Y_FRAC_FIRST(n), STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n); if (f < Y_FRAC_FIRST(n)) { f = Y_FRAC_LAST(n); i -= pixman_fixed_1; } return (i | f); } /* * Step an edge by any amount (including negative values) */ void pixman_edge_step (pixman_edge_t *e, int n) { pixman_fixed_48_16_t ne; e->x += n * e->stepx; ne = e->e + n * (pixman_fixed_48_16_t) e->dx; if (n >= 0) { if (ne > 0) { int nx = (ne + e->dy - 1) / e->dy; e->e = ne - nx * (pixman_fixed_48_16_t) e->dy; e->x += nx * e->signdx; } } else { if (ne <= -e->dy) { int nx = (-ne) / e->dy; e->e = ne + nx * (pixman_fixed_48_16_t) e->dy; e->x -= nx * e->signdx; } } } /* * A private routine to initialize the multi-step * elements of an edge structure */ static void _pixman_edge_tMultiInit (pixman_edge_t *e, int n, pixman_fixed_t *stepx_p, pixman_fixed_t *dx_p) { pixman_fixed_t stepx; pixman_fixed_48_16_t ne; ne = n * (pixman_fixed_48_16_t) e->dx; stepx = n * e->stepx; if (ne > 0) { int nx = ne / e->dy; ne -= nx * e->dy; stepx += nx * e->signdx; } *dx_p = ne; *stepx_p = stepx; } /* * Initialize one edge structure given the line endpoints and a * starting y value */ void pixman_edge_init (pixman_edge_t *e, int n, pixman_fixed_t y_start, pixman_fixed_t x_top, pixman_fixed_t y_top, pixman_fixed_t x_bot, pixman_fixed_t y_bot) { pixman_fixed_t dx, dy; e->x = x_top; e->e = 0; dx = x_bot - x_top; dy = y_bot - y_top; e->dy = dy; e->dx = 0; if (dy) { if (dx >= 0) { e->signdx = 1; e->stepx = dx / dy; e->dx = dx % dy; e->e = -dy; } else { e->signdx = -1; e->stepx = -(-dx / dy); e->dx = -dx % dy; e->e = 0; } _pixman_edge_tMultiInit (e, STEP_Y_SMALL(n), &e->stepx_small, &e->dx_small); _pixman_edge_tMultiInit (e, STEP_Y_BIG(n), &e->stepx_big, &e->dx_big); } pixman_edge_step (e, y_start - y_top); } /* * Initialize one edge structure given a line, starting y value * and a pixel offset for the line */ void pixman_line_fixed_edge_init (pixman_edge_t *e, int n, pixman_fixed_t y, const pixman_line_fixed_t *line, int x_off, int y_off) { pixman_fixed_t x_off_fixed = pixman_int_to_fixed(x_off); pixman_fixed_t y_off_fixed = pixman_int_to_fixed(y_off); const pixman_point_fixed_t *top, *bot; if (line->p1.y <= line->p2.y) { top = &line->p1; bot = &line->p2; } else { top = &line->p2; bot = &line->p1; } pixman_edge_init (e, n, y, top->x + x_off_fixed, top->y + y_off_fixed, bot->x + x_off_fixed, bot->y + y_off_fixed); } pixman_bool_t pixman_multiply_overflows_int (unsigned int a, unsigned int b) { return a >= INT32_MAX / b; } pixman_bool_t pixman_addition_overflows_int (unsigned int a, unsigned int b) { return a > INT32_MAX - b; } void * pixman_malloc_ab(unsigned int a, unsigned int b) { if (a >= INT32_MAX / b) return NULL; return malloc (a * b); } void * pixman_malloc_abc (unsigned int a, unsigned int b, unsigned int c) { if (a >= INT32_MAX / b) return NULL; else if (a * b >= INT32_MAX / c) return NULL; else return malloc (a * b * c); }