blob: 888e487e9f8be3a527aa90ea87500bb48ab6bbc5 [file] [log] [blame]
/*
* Copyright © 2000 SuSE, Inc.
* Copyright © 2007 Red Hat, 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.
*/
#include <config.h>
#include <stdlib.h>
#include "pixman-private.h"
#define READ_ACCESS(f) ((image->common.read_func)? f##_accessors : f)
#define WRITE_ACCESS(f) ((image->common.write_func)? f##_accessors : f)
static void
fbFetchSolid(bits_image_t * image,
int x, int y, int width,
uint32_t *buffer,
uint32_t *mask, uint32_t maskBits)
{
uint32_t color;
uint32_t *end;
fetchPixelProc32 fetch =
READ_ACCESS(pixman_fetchPixelProcForPicture32)(image);
color = fetch(image, 0, 0);
end = buffer + width;
while (buffer < end)
*(buffer++) = color;
}
static void
fbFetchSolid64(bits_image_t * image,
int x, int y, int width,
uint64_t *buffer, void *unused, uint32_t unused2)
{
uint64_t color;
uint64_t *end;
fetchPixelProc64 fetch =
READ_ACCESS(pixman_fetchPixelProcForPicture64)(image);
color = fetch(image, 0, 0);
end = buffer + width;
while (buffer < end)
*(buffer++) = color;
}
static void
fbFetch(bits_image_t * image,
int x, int y, int width,
uint32_t *buffer, uint32_t *mask, uint32_t maskBits)
{
fetchProc32 fetch = READ_ACCESS(pixman_fetchProcForPicture32)(image);
fetch(image, x, y, width, buffer);
}
static void
fbFetch64(bits_image_t * image,
int x, int y, int width,
uint64_t *buffer, void *unused, uint32_t unused2)
{
fetchProc64 fetch = READ_ACCESS(pixman_fetchProcForPicture64)(image);
fetch(image, x, y, width, buffer);
}
static void
fbStore(bits_image_t * image, int x, int y, int width, uint32_t *buffer)
{
uint32_t *bits;
int32_t stride;
storeProc32 store = WRITE_ACCESS(pixman_storeProcForPicture32)(image);
const pixman_indexed_t * indexed = image->indexed;
bits = image->bits;
stride = image->rowstride;
bits += y*stride;
store((pixman_image_t *)image, bits, buffer, x, width, indexed);
}
static void
fbStore64 (bits_image_t * image, int x, int y, int width, uint64_t *buffer)
{
uint32_t *bits;
int32_t stride;
storeProc64 store = WRITE_ACCESS(pixman_storeProcForPicture64)(image);
const pixman_indexed_t * indexed = image->indexed;
bits = image->bits;
stride = image->rowstride;
bits += y*stride;
store((pixman_image_t *)image, bits, buffer, x, width, indexed);
}
static void
fbStoreExternalAlpha (bits_image_t * image, int x, int y, int width,
uint32_t *buffer)
{
uint32_t *bits, *alpha_bits;
int32_t stride, astride;
int ax, ay;
storeProc32 store;
storeProc32 astore;
const pixman_indexed_t * indexed = image->indexed;
const pixman_indexed_t * aindexed;
if (!image->common.alpha_map) {
// XXX[AGP]: This should never happen!
// fbStore(image, x, y, width, buffer);
abort();
return;
}
store = WRITE_ACCESS(pixman_storeProcForPicture32)(image);
astore = WRITE_ACCESS(pixman_storeProcForPicture32)(image->common.alpha_map);
aindexed = image->common.alpha_map->indexed;
ax = x;
ay = y;
bits = image->bits;
stride = image->rowstride;
alpha_bits = image->common.alpha_map->bits;
astride = image->common.alpha_map->rowstride;
bits += y*stride;
alpha_bits += (ay - image->common.alpha_origin.y)*astride;
store((pixman_image_t *)image, bits, buffer, x, width, indexed);
astore((pixman_image_t *)image->common.alpha_map,
alpha_bits, buffer, ax - image->common.alpha_origin.x, width, aindexed);
}
static void
fbStoreExternalAlpha64 (bits_image_t * image, int x, int y, int width,
uint64_t *buffer)
{
uint32_t *bits, *alpha_bits;
int32_t stride, astride;
int ax, ay;
storeProc64 store;
storeProc64 astore;
const pixman_indexed_t * indexed = image->indexed;
const pixman_indexed_t * aindexed;
store = ACCESS(pixman_storeProcForPicture64)(image);
astore = ACCESS(pixman_storeProcForPicture64)(image->common.alpha_map);
aindexed = image->common.alpha_map->indexed;
ax = x;
ay = y;
bits = image->bits;
stride = image->rowstride;
alpha_bits = image->common.alpha_map->bits;
astride = image->common.alpha_map->rowstride;
bits += y*stride;
alpha_bits += (ay - image->common.alpha_origin.y)*astride;
store((pixman_image_t *)image, bits, buffer, x, width, indexed);
astore((pixman_image_t *)image->common.alpha_map,
alpha_bits, buffer, ax - image->common.alpha_origin.x, width, aindexed);
}
static void
bits_image_property_changed (pixman_image_t *image)
{
bits_image_t *bits = (bits_image_t *)image;
if (bits->common.alpha_map)
{
image->common.get_scanline_64 =
(scanFetchProc)_pixman_image_get_scanline_64_generic;
image->common.get_scanline_32 =
(scanFetchProc)READ_ACCESS(fbFetchExternalAlpha);
}
else if ((bits->common.repeat != PIXMAN_REPEAT_NONE) &&
bits->width == 1 &&
bits->height == 1)
{
image->common.get_scanline_64 = (scanFetchProc)fbFetchSolid64;
image->common.get_scanline_32 = (scanFetchProc)fbFetchSolid;
}
else if (!bits->common.transform &&
bits->common.filter != PIXMAN_FILTER_CONVOLUTION &&
bits->common.repeat != PIXMAN_REPEAT_PAD &&
bits->common.repeat != PIXMAN_REPEAT_REFLECT)
{
image->common.get_scanline_64 = (scanFetchProc)fbFetch64;
image->common.get_scanline_32 = (scanFetchProc)fbFetch;
}
else
{
image->common.get_scanline_64 =
(scanFetchProc)_pixman_image_get_scanline_64_generic;
image->common.get_scanline_32 =
(scanFetchProc)READ_ACCESS(fbFetchTransformed);
}
if (bits->common.alpha_map)
{
bits->store_scanline_64 = (scanStoreProc)fbStoreExternalAlpha64;
bits->store_scanline_32 = fbStoreExternalAlpha;
}
else
{
bits->store_scanline_64 = (scanStoreProc)fbStore64;
bits->store_scanline_32 = fbStore;
}
}
void
_pixman_image_store_scanline_32 (bits_image_t *image, int x, int y, int width,
uint32_t *buffer)
{
image->store_scanline_32 (image, x, y, width, buffer);
}
void
_pixman_image_store_scanline_64 (bits_image_t *image, int x, int y, int width,
uint32_t *buffer)
{
image->store_scanline_64 (image, x, y, width, buffer);
}
static uint32_t *
create_bits (pixman_format_code_t format,
int width,
int height,
int *rowstride_bytes)
{
int stride;
int buf_size;
int bpp;
/* what follows is a long-winded way, avoiding any possibility of integer
* overflows, of saying:
* stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (uint32_t);
*/
bpp = PIXMAN_FORMAT_BPP (format);
if (pixman_multiply_overflows_int (width, bpp))
return NULL;
stride = width * bpp;
if (pixman_addition_overflows_int (stride, FB_MASK))
return NULL;
stride += FB_MASK;
stride >>= FB_SHIFT;
#if FB_SHIFT < 2
if (pixman_multiply_overflows_int (stride, sizeof (uint32_t)))
return NULL;
#endif
stride *= sizeof (uint32_t);
if (pixman_multiply_overflows_int (height, stride))
return NULL;
buf_size = height * stride;
if (rowstride_bytes)
*rowstride_bytes = stride;
return calloc (buf_size, 1);
}
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_bits (pixman_format_code_t format,
int width,
int height,
uint32_t *bits,
int rowstride_bytes)
{
pixman_image_t *image;
uint32_t *free_me = NULL;
/* must be a whole number of uint32_t's
*/
return_val_if_fail (bits == NULL ||
(rowstride_bytes % sizeof (uint32_t)) == 0, NULL);
if (!bits && width && height)
{
free_me = bits = create_bits (format, width, height, &rowstride_bytes);
if (!bits)
return NULL;
}
image = _pixman_image_allocate();
if (!image) {
if (free_me)
free (free_me);
return NULL;
}
image->type = BITS;
image->bits.format = format;
image->bits.width = width;
image->bits.height = height;
image->bits.bits = bits;
image->bits.free_me = free_me;
image->bits.rowstride = rowstride_bytes / (int) sizeof (uint32_t); /* we store it in number
* of uint32_t's
*/
image->bits.indexed = NULL;
pixman_region32_fini (&image->common.full_region);
pixman_region32_init_rect (&image->common.full_region, 0, 0,
image->bits.width, image->bits.height);
image->common.property_changed = bits_image_property_changed;
bits_image_property_changed (image);
_pixman_image_reset_clip_region (image);
return image;
}