diff options
author | Søren Sandmann Pedersen <sandmann@redhat.com> | 2009-06-13 10:28:21 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <sandmann@redhat.com> | 2009-06-18 12:36:11 -0400 |
commit | e9aa61e9f0d663d5b34a397b943b4d1df44e873d (patch) | |
tree | 6e9db60321ec4f624b78655e07b948e3de87a8eb /fb/fbpict.c | |
parent | d9b5e77a0e48a16c53653b56bc61a0b8dc4122a1 (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.c | 118 |
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) { |