mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-17 06:06:00 -06:00
581 lines
13 KiB
C
581 lines
13 KiB
C
/*
|
|
* 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 <config.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "pixman-private.h"
|
|
#include "pixman-mmx.h"
|
|
#include "pixman-sse2.h"
|
|
|
|
#if defined(USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
|
|
__attribute__((__force_align_arg_pointer__))
|
|
#endif
|
|
PIXMAN_EXPORT 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_SSE2
|
|
if (pixman_have_sse2())
|
|
{
|
|
return pixmanBltsse2 (src_bits, dst_bits, src_stride, dst_stride, src_bpp, dst_bpp,
|
|
src_x, src_y, dst_x, dst_y, width, height);
|
|
}
|
|
else
|
|
#endif
|
|
#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;
|
|
}
|
|
}
|
|
|
|
#if defined(USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
|
|
__attribute__((__force_align_arg_pointer__))
|
|
#endif
|
|
PIXMAN_EXPORT 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_SSE2
|
|
if (pixman_have_sse2() && pixmanFillsse2 (bits, stride, bpp, x, y, width, height, xor))
|
|
return TRUE;
|
|
#endif
|
|
|
|
#ifdef USE_MMX
|
|
if (pixman_have_mmx() && pixman_fill_mmx (bits, stride, bpp, x, y, width, height, xor))
|
|
return TRUE;
|
|
#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_EXPORT 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_EXPORT 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)
|
|
*/
|
|
PIXMAN_EXPORT 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
|
|
*/
|
|
PIXMAN_EXPORT 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
|
|
*/
|
|
PIXMAN_EXPORT 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);
|
|
}
|
|
|
|
|
|
/**
|
|
* pixman_version:
|
|
*
|
|
* Returns the version of the pixman library encoded in a single
|
|
* integer as per %PIXMAN_VERSION_ENCODE. The encoding ensures that
|
|
* later versions compare greater than earlier versions.
|
|
*
|
|
* A run-time comparison to check that pixman's version is greater than
|
|
* or equal to version X.Y.Z could be performed as follows:
|
|
*
|
|
* <informalexample><programlisting>
|
|
* if (pixman_version() >= PIXMAN_VERSION_ENCODE(X,Y,Z)) {...}
|
|
* </programlisting></informalexample>
|
|
*
|
|
* See also pixman_version_string() as well as the compile-time
|
|
* equivalents %PIXMAN_VERSION and %PIXMAN_VERSION_STRING.
|
|
*
|
|
* Return value: the encoded version.
|
|
**/
|
|
PIXMAN_EXPORT int
|
|
pixman_version (void)
|
|
{
|
|
return PIXMAN_VERSION;
|
|
}
|
|
|
|
/**
|
|
* pixman_version_string:
|
|
*
|
|
* Returns the version of the pixman library as a human-readable string
|
|
* of the form "X.Y.Z".
|
|
*
|
|
* See also pixman_version() as well as the compile-time equivalents
|
|
* %PIXMAN_VERSION_STRING and %PIXMAN_VERSION.
|
|
*
|
|
* Return value: a string containing the version.
|
|
**/
|
|
PIXMAN_EXPORT const char*
|
|
pixman_version_string (void)
|
|
{
|
|
return PIXMAN_VERSION_STRING;
|
|
}
|
|
|
|
/**
|
|
* pixman_format_supported_destination:
|
|
* @format: A pixman_format_code_t format
|
|
*
|
|
* Return value: whether the provided format code is a supported
|
|
* format for a pixman surface used as a destination in
|
|
* rendering.
|
|
*
|
|
* Currently, all pixman_format_code_t values are supported
|
|
* except for the YUV formats.
|
|
**/
|
|
PIXMAN_EXPORT pixman_bool_t
|
|
pixman_format_supported_destination (pixman_format_code_t format)
|
|
{
|
|
switch (format) {
|
|
/* 32 bpp formats */
|
|
case PIXMAN_a2b10g10r10:
|
|
case PIXMAN_x2b10g10r10:
|
|
case PIXMAN_a8r8g8b8:
|
|
case PIXMAN_x8r8g8b8:
|
|
case PIXMAN_a8b8g8r8:
|
|
case PIXMAN_x8b8g8r8:
|
|
case PIXMAN_r8g8b8:
|
|
case PIXMAN_b8g8r8:
|
|
case PIXMAN_r5g6b5:
|
|
case PIXMAN_b5g6r5:
|
|
/* 16 bpp formats */
|
|
case PIXMAN_a1r5g5b5:
|
|
case PIXMAN_x1r5g5b5:
|
|
case PIXMAN_a1b5g5r5:
|
|
case PIXMAN_x1b5g5r5:
|
|
case PIXMAN_a4r4g4b4:
|
|
case PIXMAN_x4r4g4b4:
|
|
case PIXMAN_a4b4g4r4:
|
|
case PIXMAN_x4b4g4r4:
|
|
/* 8bpp formats */
|
|
case PIXMAN_a8:
|
|
case PIXMAN_r3g3b2:
|
|
case PIXMAN_b2g3r3:
|
|
case PIXMAN_a2r2g2b2:
|
|
case PIXMAN_a2b2g2r2:
|
|
case PIXMAN_c8:
|
|
case PIXMAN_g8:
|
|
case PIXMAN_x4a4:
|
|
/* Collides with PIXMAN_c8
|
|
case PIXMAN_x4c4:
|
|
*/
|
|
/* Collides with PIXMAN_g8
|
|
case PIXMAN_x4g4:
|
|
*/
|
|
/* 4bpp formats */
|
|
case PIXMAN_a4:
|
|
case PIXMAN_r1g2b1:
|
|
case PIXMAN_b1g2r1:
|
|
case PIXMAN_a1r1g1b1:
|
|
case PIXMAN_a1b1g1r1:
|
|
case PIXMAN_c4:
|
|
case PIXMAN_g4:
|
|
/* 1bpp formats */
|
|
case PIXMAN_a1:
|
|
case PIXMAN_g1:
|
|
return TRUE;
|
|
|
|
/* YUV formats */
|
|
case PIXMAN_yuy2:
|
|
case PIXMAN_yv12:
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* pixman_format_supported_source:
|
|
* @format: A pixman_format_code_t format
|
|
*
|
|
* Return value: whether the provided format code is a supported
|
|
* format for a pixman surface used as a source in
|
|
* rendering.
|
|
*
|
|
* Currently, all pixman_format_code_t values are supported.
|
|
**/
|
|
PIXMAN_EXPORT pixman_bool_t
|
|
pixman_format_supported_source (pixman_format_code_t format)
|
|
{
|
|
switch (format) {
|
|
/* 32 bpp formats */
|
|
case PIXMAN_a2b10g10r10:
|
|
case PIXMAN_x2b10g10r10:
|
|
case PIXMAN_a8r8g8b8:
|
|
case PIXMAN_x8r8g8b8:
|
|
case PIXMAN_a8b8g8r8:
|
|
case PIXMAN_x8b8g8r8:
|
|
case PIXMAN_r8g8b8:
|
|
case PIXMAN_b8g8r8:
|
|
case PIXMAN_r5g6b5:
|
|
case PIXMAN_b5g6r5:
|
|
/* 16 bpp formats */
|
|
case PIXMAN_a1r5g5b5:
|
|
case PIXMAN_x1r5g5b5:
|
|
case PIXMAN_a1b5g5r5:
|
|
case PIXMAN_x1b5g5r5:
|
|
case PIXMAN_a4r4g4b4:
|
|
case PIXMAN_x4r4g4b4:
|
|
case PIXMAN_a4b4g4r4:
|
|
case PIXMAN_x4b4g4r4:
|
|
/* 8bpp formats */
|
|
case PIXMAN_a8:
|
|
case PIXMAN_r3g3b2:
|
|
case PIXMAN_b2g3r3:
|
|
case PIXMAN_a2r2g2b2:
|
|
case PIXMAN_a2b2g2r2:
|
|
case PIXMAN_c8:
|
|
case PIXMAN_g8:
|
|
case PIXMAN_x4a4:
|
|
/* Collides with PIXMAN_c8
|
|
case PIXMAN_x4c4:
|
|
*/
|
|
/* Collides with PIXMAN_g8
|
|
case PIXMAN_x4g4:
|
|
*/
|
|
/* 4bpp formats */
|
|
case PIXMAN_a4:
|
|
case PIXMAN_r1g2b1:
|
|
case PIXMAN_b1g2r1:
|
|
case PIXMAN_a1r1g1b1:
|
|
case PIXMAN_a1b1g1r1:
|
|
case PIXMAN_c4:
|
|
case PIXMAN_g4:
|
|
/* 1bpp formats */
|
|
case PIXMAN_a1:
|
|
case PIXMAN_g1:
|
|
/* YUV formats */
|
|
case PIXMAN_yuy2:
|
|
case PIXMAN_yv12:
|
|
return TRUE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|