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