summaryrefslogtreecommitdiff
path: root/fb/fbpict.c
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <sandmann@redhat.com>2009-06-13 10:28:21 -0400
committerSøren Sandmann Pedersen <sandmann@redhat.com>2009-06-18 12:36:11 -0400
commite9aa61e9f0d663d5b34a397b943b4d1df44e873d (patch)
tree6e9db60321ec4f624b78655e07b948e3de87a8eb /fb/fbpict.c
parentd9b5e77a0e48a16c53653b56bc61a0b8dc4122a1 (diff)
Fix clipping when windows are used as sources
The new clipping rules: - client clips happen after transformation - pixels unavailable due to the hierarchy are undefined The first one is implemented in pixman; the second one is realized by making a copy of window sources (to prevent out-of-bounds access).
Diffstat (limited to 'fb/fbpict.c')
-rw-r--r--fb/fbpict.c118
1 files changed, 97 insertions, 21 deletions
diff --git a/fb/fbpict.c b/fb/fbpict.c
index c89691d1b..32052e9e2 100644
--- a/fb/fbpict.c
+++ b/fb/fbpict.c
@@ -163,9 +163,9 @@ fbComposite (CARD8 op,
if (pMask)
miCompositeSourceValidate (pMask, xMask - xDst, yMask - yDst, width, height);
- src = image_from_pict (pSrc, TRUE);
- mask = image_from_pict (pMask, TRUE);
- dest = image_from_pict (pDst, TRUE);
+ src = image_from_pict (pSrc, TRUE, TRUE);
+ mask = image_from_pict (pMask, TRUE, TRUE);
+ dest = image_from_pict (pDst, TRUE, FALSE);
if (src && dest && !(pMask && !mask))
{
@@ -268,23 +268,77 @@ create_conical_gradient_image (PictGradient *gradient)
gradient->nstops);
}
+static DrawablePtr
+copy_drawable (DrawablePtr pDraw)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ PixmapPtr pPixmap;
+ GCPtr pGC;
+ int width, height;
+ ChangeGCVal gcv[1];
+
+ width = pDraw->width;
+ height = pDraw->height;
+
+ pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, pDraw->depth, 0);
+
+ if (!pPixmap)
+ return NULL;
+
+ pGC = GetScratchGC (pDraw->depth, pScreen);
+
+ if (!pGC)
+ {
+ (*pScreen->DestroyPixmap) (pPixmap);
+ return NULL;
+ }
+
+ /* First fill the pixmap with zeros */
+ gcv[0].val = 0x00000000;
+ dixChangeGC (NullClient, pGC, GCBackground, NULL, gcv);
+ ValidateGC ((DrawablePtr)pPixmap, pGC);
+ miClearDrawable ((DrawablePtr)pPixmap, pGC);
+
+ /* Then copy the window there */
+ ValidateGC(&pPixmap->drawable, pGC);
+ (* pGC->ops->CopyArea) (pDraw, &pPixmap->drawable, pGC, 0, 0, width, height, 0, 0);
+
+ FreeScratchGC (pGC);
+
+ return &pPixmap->drawable;
+}
+
+static void
+destroy_drawable (pixman_image_t *image, void *data)
+{
+ DrawablePtr pDrawable = data;
+ ScreenPtr pScreen = pDrawable->pScreen;
+
+ pScreen->DestroyPixmap ((PixmapPtr)pDrawable);
+}
+
static pixman_image_t *
create_bits_picture (PicturePtr pict,
- Bool has_clip)
+ Bool has_clip,
+ Bool is_src)
{
FbBits *bits;
FbStride stride;
int bpp, xoff, yoff;
pixman_image_t *image;
+ DrawablePtr drawable;
+
+ if (is_src && pict->pDrawable->type == DRAWABLE_WINDOW)
+ drawable = copy_drawable (pict->pDrawable);
+ else
+ drawable = pict->pDrawable;
- fbGetDrawable (pict->pDrawable, bits, stride, bpp, xoff, yoff);
+ fbGetDrawable (drawable, bits, stride, bpp, xoff, yoff);
- bits = (FbBits*)((CARD8*)bits +
- pict->pDrawable->y * stride * sizeof(FbBits) + pict->pDrawable->x * (bpp / 8));
+ bits = (FbBits*)((CARD8*)bits + drawable->y * stride * sizeof(FbBits) + drawable->x * (bpp / 8));
image = pixman_image_create_bits (
- pict->format,
- pict->pDrawable->width, pict->pDrawable->height,
+ pict->format, drawable->width, drawable->height,
(uint32_t *)bits, stride * sizeof (FbStride));
@@ -302,25 +356,46 @@ create_bits_picture (PicturePtr pict,
#endif
#endif
- /* pCompositeClip is undefined for source pictures, so
- * only set the clip region for pictures with drawables
- */
if (has_clip)
{
- if (pict->clientClipType != CT_NONE)
- pixman_image_set_has_client_clip (image, TRUE);
+ if (is_src)
+ {
+ if (pict->clientClipType != CT_NONE)
+ {
+ pixman_image_set_has_client_clip (image, TRUE);
- pixman_region_translate (pict->pCompositeClip, - pict->pDrawable->x, - pict->pDrawable->y);
-
- pixman_image_set_clip_region (image, pict->pCompositeClip);
+ pixman_region_translate (pict->clientClip,
+ pict->clipOrigin.x,
+ pict->clipOrigin.y);
+
+ pixman_image_set_clip_region (image, pict->clientClip);
- pixman_region_translate (pict->pCompositeClip, pict->pDrawable->x, pict->pDrawable->y);
+ pixman_region_translate (pict->clientClip,
+ - pict->clipOrigin.x,
+ - pict->clipOrigin.y);
+ }
+ }
+ else
+ {
+ pixman_region_translate (pict->pCompositeClip,
+ - pict->pDrawable->x,
+ - pict->pDrawable->y);
+
+ pixman_image_set_clip_region (image, pict->pCompositeClip);
+
+ pixman_region_translate (pict->pCompositeClip,
+ pict->pDrawable->x,
+ pict->pDrawable->y);
+ }
}
/* Indexed table */
if (pict->pFormat->index.devPrivate)
pixman_image_set_indexed (image, pict->pFormat->index.devPrivate);
+ if (drawable != pict->pDrawable)
+ pixman_image_set_destroy_function (image, destroy_drawable, drawable);
+
return image;
}
@@ -360,7 +435,7 @@ set_image_properties (pixman_image_t *image, PicturePtr pict)
if (pict->alphaMap)
{
- pixman_image_t *alpha_map = image_from_pict (pict->alphaMap, TRUE);
+ pixman_image_t *alpha_map = image_from_pict (pict->alphaMap, TRUE, TRUE);
pixman_image_set_alpha_map (
image, alpha_map, pict->alphaOrigin.x, pict->alphaOrigin.y);
@@ -394,7 +469,8 @@ set_image_properties (pixman_image_t *image, PicturePtr pict)
pixman_image_t *
image_from_pict (PicturePtr pict,
- Bool has_clip)
+ Bool has_clip,
+ Bool is_src)
{
pixman_image_t *image = NULL;
@@ -403,7 +479,7 @@ image_from_pict (PicturePtr pict,
if (pict->pDrawable)
{
- image = create_bits_picture (pict, has_clip);
+ image = create_bits_picture (pict, has_clip, is_src);
}
else if (pict->pSourcePict)
{