cairo/pixman/src/icimage.c

616 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.
*/
#include "icint.h"
pixman_image_t *
pixman_image_create (pixman_format_t *format,
int width,
int height)
{
pixman_image_t *image;
IcPixels *pixels;
pixels = IcPixelsCreate (width, height, format->depth);
if (pixels == NULL)
return NULL;
image = pixman_image_createForPixels (pixels, format);
if (image == NULL) {
IcPixelsDestroy (pixels);
return NULL;
}
image->owns_pixels = 1;
return image;
}
slim_hidden_def(pixman_image_create);
pixman_image_t *
pixman_image_createForData (pixman_bits_t *data, pixman_format_t *format, int width, int height, int bpp, int stride)
{
pixman_image_t *image;
IcPixels *pixels;
pixels = IcPixelsCreateForData (data, width, height, format->depth, bpp, stride);
if (pixels == NULL)
return NULL;
image = pixman_image_createForPixels (pixels, format);
if (image == NULL) {
IcPixelsDestroy (pixels);
return NULL;
}
image->owns_pixels = 1;
return image;
}
pixman_image_t *
pixman_image_createForPixels (IcPixels *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;
/* XXX: What's all this about?
if (pDrawable->type == DRAWABLE_PIXMAP)
{
++((PixmapPtr)pDrawable)->refcnt;
image->pNext = 0;
}
else
{
image->pNext = GetPictureWindow(((WindowPtr) pDrawable));
SetPictureWindow(((WindowPtr) pDrawable), image);
}
*/
pixman_image_init (image);
return image;
}
void
pixman_image_init (pixman_image_t *image)
{
image->refcnt = 1;
image->repeat = 0;
image->graphicsExposures = 0;
image->subWindowMode = ClipByChildren;
image->polyEdge = PolyEdgeSharp;
image->polyMode = PolyModePrecise;
/* XXX: In the server this was 0. Why? */
image->freeCompClip = 1;
image->clientClipType = CT_NONE;
image->componentAlpha = 0;
image->alphaMap = 0;
image->alphaOrigin.x = 0;
image->alphaOrigin.y = 0;
image->clipOrigin.x = 0;
image->clipOrigin.y = 0;
image->clientClip = 0;
image->dither = 0L;
image->stateChanges = (1 << (CPLastBit+1)) - 1;
/* XXX: What to lodge here?
image->serialNumber = GC_CHANGE_SERIAL_BIT;
*/
image->pCompositeClip = pixman_region_create();
pixman_region_unionRect (image->pCompositeClip, image->pCompositeClip,
0, 0, image->pixels->width, image->pixels->height);
image->transform = NULL;
image->filter = PIXMAN_FILTER_NEAREST;
image->filter_params = 0;
image->filter_nparams = 0;
image->owns_pixels = 0;
}
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 = 0;
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 = 0;
}
}
return 0;
}
void
pixman_image_set_repeat (pixman_image_t *image,
int 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)
{
return image->pixels->width;
}
int
pixman_image_get_height (pixman_image_t *image)
{
return image->pixels->height;
}
int
pixman_image_get_depth (pixman_image_t *image)
{
return image->pixels->depth;
}
int
pixman_image_get_stride (pixman_image_t *image)
{
return image->pixels->stride;
}
pixman_bits_t *
pixman_image_get_data (pixman_image_t *image)
{
return image->pixels->data;
}
void
pixman_image_destroy (pixman_image_t *image)
{
if (image->freeCompClip)
pixman_region_destroy (image->pCompositeClip);
if (image->owns_pixels)
IcPixelsDestroy (image->pixels);
if (image->transform)
free (image->transform);
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);
image->clientClip = region;
image->clientClipType = CT_REGION;
image->stateChanges |= CPClipMask;
return 0;
}
#define BOUND(v) (int16_t) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v))
static __inline int
IcClipImageReg (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
IcClipImageSrc (pixman_region16_t *region,
pixman_image_t *image,
int dx,
int dy)
{
/* XXX what to do with clipping from transformed pictures? */
if (image->transform)
return 1;
if (image->repeat)
{
if (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
{
return IcClipImageReg (region,
image->pCompositeClip,
dx,
dy);
}
return 1;
}
/* XXX: Need to decide what to do with this
#define NEXT_VAL(_type) (vlist ? (_type) *vlist++ : (_type) ulist++->val)
#define NEXT_PTR(_type) ((_type) ulist++->ptr)
int
pixman_image_tChange (pixman_image_t *image,
Mask vmask,
unsigned int *vlist,
DevUnion *ulist,
int *error_value)
{
BITS32 index2;
int error = 0;
BITS32 maskQ;
maskQ = vmask;
while (vmask && !error)
{
index2 = (BITS32) lowbit (vmask);
vmask &= ~index2;
image->stateChanges |= index2;
switch (index2)
{
case CPRepeat:
{
unsigned int newr;
newr = NEXT_VAL(unsigned int);
if (newr <= xTrue)
image->repeat = newr;
else
{
*error_value = newr;
error = BadValue;
}
}
break;
case CPAlphaMap:
{
pixman_image_t *iAlpha;
iAlpha = NEXT_PTR(pixman_image_t *);
if (iAlpha)
iAlpha->refcnt++;
if (image->alphaMap)
pixman_image_destroy ((void *) image->alphaMap);
image->alphaMap = iAlpha;
}
break;
case CPAlphaXOrigin:
image->alphaOrigin.x = NEXT_VAL(int16_t);
break;
case CPAlphaYOrigin:
image->alphaOrigin.y = NEXT_VAL(int16_t);
break;
case CPClipXOrigin:
image->clipOrigin.x = NEXT_VAL(int16_t);
break;
case CPClipYOrigin:
image->clipOrigin.y = NEXT_VAL(int16_t);
break;
case CPClipMask:
{
pixman_image_t *mask;
int clipType;
mask = NEXT_PTR(pixman_image_t *);
if (mask) {
clipType = CT_PIXMAP;
mask->refcnt++;
} else {
clipType = CT_NONE;
}
error = pixman_image_tChangeClip (image, clipType,
(void *)mask, 0);
break;
}
case CPGraphicsExposure:
{
unsigned int newe;
newe = NEXT_VAL(unsigned int);
if (newe <= xTrue)
image->graphicsExposures = newe;
else
{
*error_value = newe;
error = BadValue;
}
}
break;
case CPSubwindowMode:
{
unsigned int news;
news = NEXT_VAL(unsigned int);
if (news == ClipByChildren || news == IncludeInferiors)
image->subWindowMode = news;
else
{
*error_value = news;
error = BadValue;
}
}
break;
case CPPolyEdge:
{
unsigned int newe;
newe = NEXT_VAL(unsigned int);
if (newe == PolyEdgeSharp || newe == PolyEdgeSmooth)
image->polyEdge = newe;
else
{
*error_value = newe;
error = BadValue;
}
}
break;
case CPPolyMode:
{
unsigned int newm;
newm = NEXT_VAL(unsigned int);
if (newm == PolyModePrecise || newm == PolyModeImprecise)
image->polyMode = newm;
else
{
*error_value = newm;
error = BadValue;
}
}
break;
case CPDither:
image->dither = NEXT_VAL(unsigned long);
break;
case CPComponentAlpha:
{
unsigned int newca;
newca = NEXT_VAL (unsigned int);
if (newca <= xTrue)
image->componentAlpha = newca;
else
{
*error_value = newca;
error = BadValue;
}
}
break;
default:
*error_value = maskQ;
error = BadValue;
break;
}
}
return error;
}
*/
/* XXX: Do we need this?
int
SetPictureClipRects (PicturePtr pPicture,
int xOrigin,
int yOrigin,
int nRect,
xRectangle *rects)
{
ScreenPtr pScreen = pPicture->pDrawable->pScreen;
PictureScreenPtr ps = GetPictureScreen(pScreen);
pixman_region16_t *clientClip;
int result;
clientClip = RECTS_TO_REGION(pScreen,
nRect, rects, CT_UNSORTED);
if (!clientClip)
return 1;
result =(*ps->ChangePictureClip) (pPicture, CT_REGION,
(void *) clientClip, 0);
if (result == 0)
{
pPicture->clipOrigin.x = xOrigin;
pPicture->clipOrigin.y = yOrigin;
pPicture->stateChanges |= CPClipXOrigin|CPClipYOrigin|CPClipMask;
pPicture->serialNumber |= GC_CHANGE_SERIAL_BIT;
}
return result;
}
*/
int
IcComputeCompositeRegion (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;
/* XXX: This code previously directly set the extents of the
region here. I need to decide whether removing that has broken
this. Also, it might be necessary to just make the pixman_region16_t
data structure transparent anyway in which case I can just put
the code back. */
x1 = xDst;
v = xDst + width;
x2 = BOUND(v);
y1 = yDst;
v = yDst + height;
y2 = BOUND(v);
/* Check for empty operation */
if (x1 >= x2 ||
y1 >= y2)
{
pixman_region_empty (region);
return 1;
}
/* clip against src */
if (!IcClipImageSrc (region, iSrc, xDst - xSrc, yDst - ySrc))
{
pixman_region_destroy (region);
return 0;
}
if (iSrc->alphaMap)
{
if (!IcClipImageSrc (region, iSrc->alphaMap,
xDst - (xSrc + iSrc->alphaOrigin.x),
yDst - (ySrc + iSrc->alphaOrigin.y)))
{
pixman_region_destroy (region);
return 0;
}
}
/* clip against mask */
if (iMask)
{
if (!IcClipImageSrc (region, iMask, xDst - xMask, yDst - yMask))
{
pixman_region_destroy (region);
return 0;
}
if (iMask->alphaMap)
{
if (!IcClipImageSrc (region, iMask->alphaMap,
xDst - (xMask + iMask->alphaOrigin.x),
yDst - (yMask + iMask->alphaOrigin.y)))
{
pixman_region_destroy (region);
return 0;
}
}
}
if (!IcClipImageReg (region, iDst->pCompositeClip, 0, 0))
{
pixman_region_destroy (region);
return 0;
}
if (iDst->alphaMap)
{
if (!IcClipImageReg (region, iDst->alphaMap->pCompositeClip,
-iDst->alphaOrigin.x,
-iDst->alphaOrigin.y))
{
pixman_region_destroy (region);
return 0;
}
}
return 1;
}