blob: 1e566a92b85a29b1ac24ab5f9e723878475416b5 [file] [log] [blame]
/*
*
* Copyright © 1999 Keith Packard
*
* 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 Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD 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.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include "pixman-private.h"
#define BOUND(v) (int16_t) ((v) < INT16_MIN ? INT16_MIN : (v) > INT16_MAX ? INT16_MAX : (v))
static inline pixman_bool_t
miClipPictureReg (pixman_region16_t * pRegion,
pixman_region16_t * pClip,
int dx,
int dy)
{
if (pixman_region_n_rects(pRegion) == 1 &&
pixman_region_n_rects(pClip) == 1)
{
pixman_box16_t * pRbox = pixman_region_rectangles(pRegion, NULL);
pixman_box16_t * pCbox = pixman_region_rectangles(pClip, NULL);
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_init (pRegion);
}
}
else if (!pixman_region_not_empty (pClip))
return FALSE;
else
{
if (dx || dy)
pixman_region_translate (pRegion, -dx, -dy);
if (!pixman_region_intersect (pRegion, pRegion, pClip))
return FALSE;
if (dx || dy)
pixman_region_translate(pRegion, dx, dy);
}
return pixman_region_not_empty(pRegion);
}
static inline pixman_bool_t
miClipPictureSrc (pixman_region16_t * pRegion,
pixman_image_t * pPicture,
int dx,
int dy)
{
/* XXX what to do with clipping from transformed pictures? */
if (pPicture->common.transform || pPicture->type != BITS)
return TRUE;
if (pPicture->common.repeat)
{
/* If the clip region was set by a client, then it should be intersected
* with the composite region since it's interpreted as happening
* after the repeat algorithm.
*
* If the clip region was not set by a client, then it was imposed by
* boundaries of the pixmap, or by sibling or child windows, which means
* it should in theory be repeated along. FIXME: we ignore that case.
* It is only relevant for windows that are (a) clipped by siblings/children
* and (b) used as source. However this case is not useful anyway due
* to lack of GraphicsExpose events.
*/
if (pPicture->common.has_client_clip)
{
pixman_region_translate ( pRegion, dx, dy);
if (!pixman_region_intersect (pRegion, pRegion,
(pixman_region16_t *) pPicture->common.src_clip))
return FALSE;
pixman_region_translate ( pRegion, -dx, -dy);
}
return TRUE;
}
else
{
return miClipPictureReg (pRegion,
pPicture->common.src_clip,
dx,
dy);
}
}
/*
* returns FALSE if the final region is empty. Indistinguishable from
* an allocation failure, but rendering ignores those anyways.
*/
pixman_bool_t
pixman_compute_composite_region (pixman_region16_t * pRegion,
pixman_image_t * pSrc,
pixman_image_t * pMask,
pixman_image_t * pDst,
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;
pRegion->extents.x1 = xDst;
v = xDst + width;
pRegion->extents.x2 = BOUND(v);
pRegion->extents.y1 = yDst;
v = yDst + height;
pRegion->extents.y2 = BOUND(v);
pRegion->data = 0;
/* Check for empty operation */
if (pRegion->extents.x1 >= pRegion->extents.x2 ||
pRegion->extents.y1 >= pRegion->extents.y2)
{
pixman_region_init (pRegion);
return FALSE;
}
/* clip against dst */
if (!miClipPictureReg (pRegion, &pDst->common.clip_region, 0, 0))
{
pixman_region_fini (pRegion);
return FALSE;
}
if (pDst->common.alpha_map)
{
if (!miClipPictureReg (pRegion, &pDst->common.alpha_map->common.clip_region,
-pDst->common.alpha_origin.x,
-pDst->common.alpha_origin.y))
{
pixman_region_fini (pRegion);
return FALSE;
}
}
/* clip against src */
if (!miClipPictureSrc (pRegion, pSrc, xDst - xSrc, yDst - ySrc))
{
pixman_region_fini (pRegion);
return FALSE;
}
if (pSrc->common.alpha_map)
{
if (!miClipPictureSrc (pRegion, (pixman_image_t *)pSrc->common.alpha_map,
xDst - (xSrc + pSrc->common.alpha_origin.x),
yDst - (ySrc + pSrc->common.alpha_origin.y)))
{
pixman_region_fini (pRegion);
return FALSE;
}
}
/* clip against mask */
if (pMask)
{
if (!miClipPictureSrc (pRegion, pMask, xDst - xMask, yDst - yMask))
{
pixman_region_fini (pRegion);
return FALSE;
}
if (pMask->common.alpha_map)
{
if (!miClipPictureSrc (pRegion, (pixman_image_t *)pMask->common.alpha_map,
xDst - (xMask + pMask->common.alpha_origin.x),
yDst - (yMask + pMask->common.alpha_origin.y)))
{
pixman_region_fini (pRegion);
return FALSE;
}
}
}
return TRUE;
}