#include "pixman-xserver-compat.h"
pixman_image_t *
pixman_image_create (pixman_format_t *format,
int width,
int height)
{
pixman_image_t *image;
FbPixels *pixels;
pixels = FbPixelsCreate (width, height, format->depth);
if (pixels == NULL)
return NULL;
image = pixman_image_createForPixels (pixels, format);
if (image == NULL) {
FbPixelsDestroy (pixels);
return NULL;
}
image->owns_pixels = 1;
return image;
}
slim_hidden_def(pixman_image_create);
pixman_image_t *
pixman_image_create_for_data (FbBits *data, pixman_format_t *format, int width, int height, int bpp, int stride)
{
pixman_image_t *image;
FbPixels *pixels;
pixels = FbPixelsCreateForData (data, width, height, format->depth, bpp, stride);
if (pixels == NULL)
return NULL;
image = pixman_image_createForPixels (pixels, format);
if (image == NULL) {
FbPixelsDestroy (pixels);
return NULL;
}
image->owns_pixels = 1;
return image;
}
pixman_image_t *
pixman_image_createForPixels (FbPixels *pixels,
pixman_format_t *format)
{
pixman_image_t *image;
image = malloc (sizeof (pixman_image_t));
if (!image)
{
return NULL;
}
image->pixels = pixels;
image->image_format = *format;
image->format_code = format->format_code;
pixman_image_init (image);
return image;
}
static CARD32 xRenderColorToCard32(pixman_color_t c)
{
return
(c.alpha >> 8 << 24) |
(c.red >> 8 << 16) |
(c.green & 0xff00) |
(c.blue >> 8);
}
static uint32_t premultiply(uint32_t x)
{
uint32_t a = x >> 24;
uint32_t t = (x & 0xff00ff) * a + 0x800080;
t = (t + ((t >> 8) & 0xff00ff)) >> 8;
t &= 0xff00ff;
x = ((x >> 8) & 0xff) * a + 0x80;
x = (x + ((x >> 8) & 0xff));
x &= 0xff00;
x |= t | (a << 24);
return x;
}
static uint32_t INTERPOLATE_PIXEL_256(uint32_t x, uint32_t a, uint32_t y, uint32_t b)
{
CARD32 t = (x & 0xff00ff) * a + (y & 0xff00ff) * b;
t >>= 8;
t &= 0xff00ff;
x = ((x >> 8) & 0xff00ff) * a + ((y >> 8) & 0xff00ff) * b;
x &= 0xff00ff00;
x |= t;
return x;
}
uint32_t
pixman_gradient_color (pixman_gradient_stop_t *stop1,
pixman_gradient_stop_t *stop2,
uint32_t x)
{
uint32_t current_color, next_color;
int dist, idist;
current_color = xRenderColorToCard32 (stop1->color);
next_color = xRenderColorToCard32 (stop2->color);
dist = (int) (256 * (x - stop1->x) / (stop2->x - stop1->x));
idist = 256 - dist;
return premultiply (INTERPOLATE_PIXEL_256 (current_color, idist,
next_color, dist));
}
static int
pixman_init_gradient_color_table (pixman_gradient_image_t *gradient,
int tableSize)
{
int begin_pos, end_pos;
xFixed incr, dpos;
int pos, current_stop;
pixman_gradient_stop_t *stops = gradient->stops;
int nstops = gradient->nstops;
if (gradient->colorTableSize < tableSize)
{
uint32_t *newColorTable;
newColorTable = realloc (gradient->colorTable,
tableSize * sizeof (uint32_t));
if (!newColorTable)
return 1;
gradient->colorTable = newColorTable;
gradient->colorTableSize = tableSize;
}
gradient->stopRange = tableSize;
begin_pos = (stops[0].x * gradient->colorTableSize) >> 16;
end_pos = (stops[nstops - 1].x * gradient->colorTableSize) >> 16;
pos = 0;
while (pos <= begin_pos) {
gradient->colorTable[pos] = xRenderColorToCard32(stops[0].color);
++pos;
}
incr = (1<<16)/ gradient->colorTableSize;
dpos = incr * pos;
current_stop = 0;
while (pos < end_pos) {
gradient->colorTable[pos] =
pixman_gradient_color (&stops[current_stop],
&stops[current_stop + 1],
dpos);
++pos;
dpos += incr;
if (dpos > stops[current_stop + 1].x)
++current_stop;
}
while (pos < gradient->colorTableSize) {
gradient->colorTable[pos] =
xRenderColorToCard32 (stops[nstops - 1].color);
++pos;
}
return 0;
}
static int
_pixman_init_gradient (pixman_gradient_image_t *gradient,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_fixed16_16_t dpos;
int i;
if (n_stops <= 0)
return 1;
dpos = -1;
for (i = 0; i < n_stops; i++)
{
if (stops[i].x < dpos || stops[i].x > (1 << 16))
return 1;
dpos = stops[i].x;
}
gradient->class = SourcePictClassUnknown;
gradient->stopRange = 0xffff;
gradient->colorTable = NULL;
gradient->colorTableSize = 0;
return 0;
}
static pixman_image_t *
_pixman_create_source_image (void)
{
pixman_image_t *image;
image = (pixman_image_t *) malloc (sizeof (pixman_image_t));
image->pDrawable = 0;
image->pixels = 0;
image->format_code = PICT_a8r8g8b8;
pixman_image_init (image);
return image;
}
pixman_image_t *
pixman_image_create_linear_gradient (const pixman_linear_gradient_t *gradient,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_linear_gradient_image_t *linear;
pixman_image_t *image;
if (n_stops < 2)
return 0;
image = _pixman_create_source_image ();
if (!image)
return 0;
linear = malloc (sizeof (pixman_linear_gradient_image_t) +
sizeof (pixman_gradient_stop_t) * n_stops);
if (!linear)
{
free (image);
return 0;
}
linear->stops = (pixman_gradient_stop_t *) (linear + 1);
linear->nstops = n_stops;
memcpy (linear->stops, stops, sizeof (pixman_gradient_stop_t) * n_stops);
linear->type = SourcePictTypeLinear;
linear->p1 = gradient->p1;
linear->p2 = gradient->p2;
image->pSourcePict = (pixman_source_image_t *) linear;
if (_pixman_init_gradient (&image->pSourcePict->gradient, stops, n_stops))
{
free (image);
return 0;
}
return image;
}
pixman_image_t *
pixman_image_create_radial_gradient (const pixman_radial_gradient_t *gradient,
const pixman_gradient_stop_t *stops,
int n_stops)
{
pixman_radial_gradient_image_t *radial;
pixman_image_t *image;
double x;
if (n_stops < 2)
return 0;
image = _pixman_create_source_image ();
if (!image)
return 0;
radial = malloc (sizeof (pixman_radial_gradient_image_t) +
sizeof (pixman_gradient_stop_t) * n_stops);
if (!radial)
{
free (image);
return 0;
}
radial->stops = (pixman_gradient_stop_t *) (radial + 1);
radial->nstops = n_stops;
memcpy (radial->stops, stops, sizeof (pixman_gradient_stop_t) * n_stops);
radial->type = SourcePictTypeRadial;
x = (double) gradient->inner.radius / (double) gradient->outer.radius;
radial->dx = (gradient->outer.x - gradient->inner.x);
radial->dy = (gradient->outer.y - gradient->inner.y);
radial->fx = (gradient->inner.x) - x * radial->dx;
radial->fy = (gradient->inner.y) - x * radial->dy;
radial->m = 1. / (1 + x);
radial->b = -x * radial->m;
radial->dx /= 65536.;
radial->dy /= 65536.;
radial->fx /= 65536.;
radial->fy /= 65536.;
x = gradient->outer.radius / 65536.;
radial->a = x * x - radial->dx * radial->dx - radial->dy * radial->dy;
image->pSourcePict = (pixman_source_image_t *) radial;
if (_pixman_init_gradient (&image->pSourcePict->gradient, stops, n_stops))
{
free (image);
return 0;
}
return image;
}
void
pixman_image_init (pixman_image_t *image)
{
image->refcnt = 1;
image->repeat = PIXMAN_REPEAT_NONE;
image->graphicsExposures = 0;
image->subWindowMode = ClipByChildren;
image->polyEdge = PolyEdgeSharp;
image->polyMode = PolyModePrecise;
image->freeCompClip = 0;
image->freeSourceClip = 0;
image->clientClipType = CT_NONE;
image->componentAlpha = 0;
image->compositeClipSource = 0;
image->alphaMap = NULL;
image->alphaOrigin.x = 0;
image->alphaOrigin.y = 0;
image->clipOrigin.x = 0;
image->clipOrigin.y = 0;
image->clientClip = NULL;
image->dither = 0L;
image->stateChanges = (1 << (CPLastBit+1)) - 1;
if (image->pixels)
{
image->pCompositeClip = pixman_region_create();
pixman_region_union_rect (image->pCompositeClip, image->pCompositeClip,
0, 0, image->pixels->width,
image->pixels->height);
image->freeCompClip = 1;
image->pSourceClip = pixman_region_create ();
pixman_region_union_rect (image->pSourceClip, image->pSourceClip,
0, 0, image->pixels->width,
image->pixels->height);
image->freeSourceClip = 1;
}
else
{
image->pCompositeClip = NULL;
image->pSourceClip = NULL;
}
image->transform = NULL;
image->filter = PIXMAN_FILTER_NEAREST;
image->filter_params = NULL;
image->filter_nparams = 0;
image->owns_pixels = 0;
image->pSourcePict = NULL;
}
void
pixman_image_set_component_alpha (pixman_image_t *image,
int component_alpha)
{
if (image)
image->componentAlpha = component_alpha;
}
slim_hidden_def(pixman_image_set_component_alpha);
int
pixman_image_set_transform (pixman_image_t *image,
pixman_transform_t *transform)
{
static const pixman_transform_t identity = { {
{ xFixed1, 0x00000, 0x00000 },
{ 0x00000, xFixed1, 0x00000 },
{ 0x00000, 0x00000, xFixed1 },
} };
if (transform && memcmp (transform, &identity, sizeof (pixman_transform_t)) == 0)
transform = NULL;
if (transform)
{
if (!image->transform)
{
image->transform = malloc (sizeof (pixman_transform_t));
if (!image->transform)
return 1;
}
*image->transform = *transform;
}
else
{
if (image->transform)
{
free (image->transform);
image->transform = NULL;
}
}
return 0;
}
void
pixman_image_set_repeat (pixman_image_t *image,
pixman_repeat_t repeat)
{
if (image)
image->repeat = repeat;
}
slim_hidden_def(pixman_image_set_repeat);
void
pixman_image_set_filter (pixman_image_t *image,
pixman_filter_t filter)
{
if (image)
image->filter = filter;
}
int
pixman_image_get_width (pixman_image_t *image)
{
if (image->pixels)
return image->pixels->width;
return 0;
}
int
pixman_image_get_height (pixman_image_t *image)
{
if (image->pixels)
return image->pixels->height;
return 0;
}
int
pixman_image_get_depth (pixman_image_t *image)
{
if (image->pixels)
return image->pixels->depth;
return 0;
}
int
pixman_image_get_stride (pixman_image_t *image)
{
if (image->pixels)
return image->pixels->stride;
return 0;
}
pixman_format_t *
pixman_image_get_format (pixman_image_t *image)
{
return &image->image_format;
}
FbBits *
pixman_image_get_data (pixman_image_t *image)
{
if (image->pixels)
return image->pixels->data;
return 0;
}
void
pixman_image_destroy (pixman_image_t *image)
{
pixman_image_destroyClip (image);
if (image->freeCompClip) {
pixman_region_destroy (image->pCompositeClip);
image->pCompositeClip = NULL;
}
if (image->freeSourceClip) {
pixman_region_destroy (image->pSourceClip);
image->pSourceClip = NULL;
}
if (image->owns_pixels) {
FbPixelsDestroy (image->pixels);
image->pixels = NULL;
}
if (image->transform) {
free (image->transform);
image->transform = NULL;
}
if (image->pSourcePict) {
free (image->pSourcePict);
image->pSourcePict = NULL;
}
free (image);
}
slim_hidden_def(pixman_image_destroy);
void
pixman_image_destroyClip (pixman_image_t *image)
{
switch (image->clientClipType) {
case CT_NONE:
return;
case CT_PIXMAP:
pixman_image_destroy (image->clientClip);
break;
default:
pixman_region_destroy (image->clientClip);
break;
}
image->clientClip = NULL;
image->clientClipType = CT_NONE;
}
int
pixman_image_set_clip_region (pixman_image_t *image,
pixman_region16_t *region)
{
pixman_image_destroyClip (image);
if (region) {
image->clientClip = pixman_region_create ();
pixman_region_copy (image->clientClip, region);
image->clientClipType = CT_REGION;
}
image->stateChanges |= CPClipMask;
if (image->pSourcePict)
return 0;
if (image->freeCompClip)
pixman_region_destroy (image->pCompositeClip);
image->pCompositeClip = pixman_region_create();
pixman_region_union_rect (image->pCompositeClip, image->pCompositeClip,
0, 0, image->pixels->width, image->pixels->height);
image->freeCompClip = 1;
if (region) {
pixman_region_translate (image->pCompositeClip,
- image->clipOrigin.x,
- image->clipOrigin.y);
pixman_region_intersect (image->pCompositeClip,
image->pCompositeClip,
region);
pixman_region_translate (image->pCompositeClip,
image->clipOrigin.x,
image->clipOrigin.y);
}
return 0;
}
#define BOUND(v) (int16_t) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v))
static __inline int
FbClipImageReg (pixman_region16_t *region,
pixman_region16_t *clip,
int dx,
int dy)
{
if (pixman_region_num_rects (region) == 1 &&
pixman_region_num_rects (clip) == 1)
{
pixman_box16_t *pRbox = pixman_region_rects (region);
pixman_box16_t *pCbox = pixman_region_rects (clip);
int v;
if (pRbox->x1 < (v = pCbox->x1 + dx))
pRbox->x1 = BOUND(v);
if (pRbox->x2 > (v = pCbox->x2 + dx))
pRbox->x2 = BOUND(v);
if (pRbox->y1 < (v = pCbox->y1 + dy))
pRbox->y1 = BOUND(v);
if (pRbox->y2 > (v = pCbox->y2 + dy))
pRbox->y2 = BOUND(v);
if (pRbox->x1 >= pRbox->x2 ||
pRbox->y1 >= pRbox->y2)
{
pixman_region_empty (region);
}
}
else
{
pixman_region_translate (region, dx, dy);
pixman_region_intersect (region, clip, region);
pixman_region_translate (region, -dx, -dy);
}
return 1;
}
static __inline int
FbClipImageSrc (pixman_region16_t *region,
pixman_image_t *image,
int dx,
int dy)
{
if (image->transform)
return 1;
if (image->repeat != PIXMAN_REPEAT_NONE || image->pSourcePict)
{
if (image->compositeClipSource &&
image->clientClipType != CT_NONE)
{
pixman_region_translate (region,
dx - image->clipOrigin.x,
dy - image->clipOrigin.y);
pixman_region_intersect (region, image->clientClip, region);
pixman_region_translate (region,
- (dx - image->clipOrigin.x),
- (dy - image->clipOrigin.y));
}
return 1;
}
else
{
pixman_region16_t *clip;
if (image->compositeClipSource)
clip = image->pCompositeClip;
else
clip = image->pSourceClip;
return FbClipImageReg (region,
clip,
dx,
dy);
}
return 1;
}
int
FbComputeCompositeRegion (pixman_region16_t *region,
pixman_image_t *iSrc,
pixman_image_t *iMask,
pixman_image_t *iDst,
int16_t xSrc,
int16_t ySrc,
int16_t xMask,
int16_t yMask,
int16_t xDst,
int16_t yDst,
uint16_t width,
uint16_t height)
{
int v;
int x1, y1, x2, y2;
x1 = xDst;
v = xDst + width;
x2 = BOUND(v);
y1 = yDst;
v = yDst + height;
y2 = BOUND(v);
if (x1 >= x2 ||
y1 >= y2)
{
pixman_region_empty (region);
return 1;
}
if (!FbClipImageSrc (region, iSrc, xDst - xSrc, yDst - ySrc))
{
pixman_region_destroy (region);
return 0;
}
if (iSrc->alphaMap)
{
if (!FbClipImageSrc (region, iSrc->alphaMap,
xDst - (xSrc + iSrc->alphaOrigin.x),
yDst - (ySrc + iSrc->alphaOrigin.y)))
{
pixman_region_destroy (region);
return 0;
}
}
if (iMask)
{
if (!FbClipImageSrc (region, iMask, xDst - xMask, yDst - yMask))
{
pixman_region_destroy (region);
return 0;
}
if (iMask->alphaMap)
{
if (!FbClipImageSrc (region, iMask->alphaMap,
xDst - (xMask + iMask->alphaOrigin.x),
yDst - (yMask + iMask->alphaOrigin.y)))
{
pixman_region_destroy (region);
return 0;
}
}
}
if (!FbClipImageReg (region, iDst->pCompositeClip, 0, 0))
{
pixman_region_destroy (region);
return 0;
}
if (iDst->alphaMap)
{
if (!FbClipImageReg (region, iDst->alphaMap->pCompositeClip,
-iDst->alphaOrigin.x,
-iDst->alphaOrigin.y))
{
pixman_region_destroy (region);
return 0;
}
}
return 1;
}
int
miIsSolidAlpha (pixman_image_t *src)
{
char line[1];
if (PICT_FORMAT_TYPE (src->format_code) != PICT_TYPE_A)
return 0;
if (!src->repeat)
return 0;
if (src->pixels->width != 1 || src->pixels->height != 1)
return 0;
line[0] = 1;
line[0] = src->pixels->data[0];
switch (src->pixels->bpp) {
case 1:
return (uint8_t) line[0] == 1 || (uint8_t) line[0] == 0x80;
case 4:
return (uint8_t) line[0] == 0xf || (uint8_t) line[0] == 0xf0;
case 8:
return (uint8_t) line[0] == 0xff;
default:
return 0;
}
}