/* * * 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 #endif #include #include #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; }