123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872 |
- /*
- * Server-side region objects. Based on the X11 implementation.
- *
- * Copyright 1993, 1994, 1995, 2004 Alexandre Julliard
- * Modifications and additions: Copyright 1998 Huw Davies
- * 1999 Alex Korobka
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * Note:
- * This is a simplified version of the code, without all the explanations.
- * Check the equivalent GDI code to make sense of it.
- */
- /************************************************************************
- Copyright (c) 1987, 1988 X Consortium
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Except as contained in this notice, the name of the X Consortium shall not be
- used in advertising or otherwise to promote the sale, use or other dealings
- in this Software without prior written authorization from the X Consortium.
- Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
- All Rights Reserved
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- 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 Digital not be
- used in advertising or publicity pertaining to distribution of the
- software without specific, written prior permission.
- DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- DIGITAL 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.
- ************************************************************************/
- #include <stdarg.h>
- #include <stdlib.h>
- #include <string.h>
- #include "ntstatus.h"
- #define WIN32_NO_STATUS
- #include "winternl.h"
- #include "request.h"
- #include "user.h"
- struct region
- {
- int size;
- int num_rects;
- rectangle_t *rects;
- rectangle_t extents;
- };
- #define RGN_DEFAULT_RECTS 2
- #define EXTENTCHECK(r1, r2) \
- ((r1)->right > (r2)->left && \
- (r1)->left < (r2)->right && \
- (r1)->bottom > (r2)->top && \
- (r1)->top < (r2)->bottom)
- typedef int (*overlap_func_t)( struct region *reg, const rectangle_t *r1, const rectangle_t *r1End,
- const rectangle_t *r2, const rectangle_t *r2End, int top, int bottom );
- typedef int (*non_overlap_func_t)( struct region *reg, const rectangle_t *r,
- const rectangle_t *rEnd, int top, int bottom );
- static const rectangle_t empty_rect; /* all-zero rectangle for empty regions */
- /* add a rectangle to a region */
- static inline rectangle_t *add_rect( struct region *reg )
- {
- if (reg->num_rects >= reg->size)
- {
- rectangle_t *new_rect = realloc( reg->rects, 2 * sizeof(rectangle_t) * reg->size );
- if (!new_rect)
- {
- set_error( STATUS_NO_MEMORY );
- return NULL;
- }
- reg->rects = new_rect;
- reg->size *= 2;
- }
- return reg->rects + reg->num_rects++;
- }
- /* make sure all the rectangles are valid and that the region is properly y-x-banded */
- static inline int validate_rectangles( const rectangle_t *rects, unsigned int nb_rects )
- {
- const rectangle_t *ptr, *end;
- for (ptr = rects, end = rects + nb_rects; ptr < end; ptr++)
- {
- if (is_rect_empty( ptr )) return 0; /* empty rectangle */
- if (ptr == end - 1) break;
- if (ptr[0].top == ptr[1].top) /* same band */
- {
- if (ptr[0].bottom != ptr[1].bottom) return 0; /* not same y extent */
- if (ptr[0].right >= ptr[1].left) return 0; /* not properly x ordered */
- }
- else /* new band */
- {
- if (ptr[0].bottom > ptr[1].top) return 0; /* not properly y ordered */
- }
- }
- return 1;
- }
- /* attempt to merge the rects in the current band with those in the */
- /* previous one. Used only by region_op. */
- static int coalesce_region( struct region *pReg, int prevStart, int curStart )
- {
- int curNumRects;
- rectangle_t *pRegEnd = &pReg->rects[pReg->num_rects];
- rectangle_t *pPrevRect = &pReg->rects[prevStart];
- rectangle_t *pCurRect = &pReg->rects[curStart];
- int prevNumRects = curStart - prevStart;
- int bandtop = pCurRect->top;
- for (curNumRects = 0;
- (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
- curNumRects++)
- {
- pCurRect++;
- }
- if (pCurRect != pRegEnd)
- {
- pRegEnd--;
- while (pRegEnd[-1].top == pRegEnd->top) pRegEnd--;
- curStart = pRegEnd - pReg->rects;
- pRegEnd = pReg->rects + pReg->num_rects;
- }
- if ((curNumRects == prevNumRects) && (curNumRects != 0))
- {
- pCurRect -= curNumRects;
- if (pPrevRect->bottom == pCurRect->top)
- {
- do
- {
- if ((pPrevRect->left != pCurRect->left) ||
- (pPrevRect->right != pCurRect->right)) return curStart;
- pPrevRect++;
- pCurRect++;
- prevNumRects -= 1;
- } while (prevNumRects != 0);
- pReg->num_rects -= curNumRects;
- pCurRect -= curNumRects;
- pPrevRect -= curNumRects;
- do
- {
- pPrevRect->bottom = pCurRect->bottom;
- pPrevRect++;
- pCurRect++;
- curNumRects -= 1;
- } while (curNumRects != 0);
- if (pCurRect == pRegEnd) curStart = prevStart;
- else do { *pPrevRect++ = *pCurRect++; } while (pCurRect != pRegEnd);
- }
- }
- return curStart;
- }
- /* apply an operation to two regions */
- /* check the GDI version of the code for explanations */
- static int region_op( struct region *newReg, const struct region *reg1, const struct region *reg2,
- overlap_func_t overlap_func,
- non_overlap_func_t non_overlap1_func,
- non_overlap_func_t non_overlap2_func )
- {
- int ybot, ytop, top, bot, prevBand, curBand;
- const rectangle_t *r1BandEnd, *r2BandEnd;
- const rectangle_t *r1 = reg1->rects;
- const rectangle_t *r2 = reg2->rects;
- const rectangle_t *r1End = r1 + reg1->num_rects;
- const rectangle_t *r2End = r2 + reg2->num_rects;
- rectangle_t *new_rects, *old_rects = newReg->rects;
- int new_size, ret = 0;
- new_size = max( reg1->num_rects, reg2->num_rects ) * 2;
- if (!(new_rects = mem_alloc( new_size * sizeof(*newReg->rects) ))) return 0;
- newReg->size = new_size;
- newReg->rects = new_rects;
- newReg->num_rects = 0;
- if (reg1->extents.top < reg2->extents.top)
- ybot = reg1->extents.top;
- else
- ybot = reg2->extents.top;
- prevBand = 0;
- do
- {
- curBand = newReg->num_rects;
- r1BandEnd = r1;
- while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top)) r1BandEnd++;
- r2BandEnd = r2;
- while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top)) r2BandEnd++;
- if (r1->top < r2->top)
- {
- top = max(r1->top,ybot);
- bot = min(r1->bottom,r2->top);
- if ((top != bot) && non_overlap1_func)
- {
- if (!non_overlap1_func( newReg, r1, r1BandEnd, top, bot )) goto done;
- }
- ytop = r2->top;
- }
- else if (r2->top < r1->top)
- {
- top = max(r2->top,ybot);
- bot = min(r2->bottom,r1->top);
- if ((top != bot) && non_overlap2_func)
- {
- if (!non_overlap2_func( newReg, r2, r2BandEnd, top, bot )) goto done;
- }
- ytop = r1->top;
- }
- else
- {
- ytop = r1->top;
- }
- if (newReg->num_rects != curBand)
- prevBand = coalesce_region(newReg, prevBand, curBand);
- ybot = min(r1->bottom, r2->bottom);
- curBand = newReg->num_rects;
- if (ybot > ytop)
- {
- if (!overlap_func( newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot )) goto done;
- }
- if (newReg->num_rects != curBand)
- prevBand = coalesce_region(newReg, prevBand, curBand);
- if (r1->bottom == ybot) r1 = r1BandEnd;
- if (r2->bottom == ybot) r2 = r2BandEnd;
- } while ((r1 != r1End) && (r2 != r2End));
- curBand = newReg->num_rects;
- if (r1 != r1End)
- {
- if (non_overlap1_func)
- {
- do
- {
- r1BandEnd = r1;
- while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top)) r1BandEnd++;
- if (!non_overlap1_func( newReg, r1, r1BandEnd, max(r1->top,ybot), r1->bottom ))
- goto done;
- r1 = r1BandEnd;
- } while (r1 != r1End);
- }
- }
- else if ((r2 != r2End) && non_overlap2_func)
- {
- do
- {
- r2BandEnd = r2;
- while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top)) r2BandEnd++;
- if (!non_overlap2_func( newReg, r2, r2BandEnd, max(r2->top,ybot), r2->bottom ))
- goto done;
- r2 = r2BandEnd;
- } while (r2 != r2End);
- }
- if (newReg->num_rects != curBand) coalesce_region(newReg, prevBand, curBand);
- if ((newReg->num_rects < (newReg->size / 2)) && (newReg->size > 2))
- {
- new_size = max( newReg->num_rects, RGN_DEFAULT_RECTS );
- if ((new_rects = realloc( newReg->rects, sizeof(*newReg->rects) * new_size )))
- {
- newReg->rects = new_rects;
- newReg->size = new_size;
- }
- }
- ret = 1;
- done:
- free( old_rects );
- return ret;
- }
- /* recalculate the extents of a region */
- static void set_region_extents( struct region *region )
- {
- rectangle_t *pRect, *pRectEnd;
- if (region->num_rects == 0)
- {
- region->extents.left = 0;
- region->extents.top = 0;
- region->extents.right = 0;
- region->extents.bottom = 0;
- return;
- }
- pRect = region->rects;
- pRectEnd = &pRect[region->num_rects - 1];
- region->extents.left = pRect->left;
- region->extents.top = pRect->top;
- region->extents.right = pRectEnd->right;
- region->extents.bottom = pRectEnd->bottom;
- while (pRect <= pRectEnd)
- {
- if (pRect->left < region->extents.left) region->extents.left = pRect->left;
- if (pRect->right > region->extents.right) region->extents.right = pRect->right;
- pRect++;
- }
- }
- /* handle an overlapping band for intersect_region */
- static int intersect_overlapping( struct region *pReg,
- const rectangle_t *r1, const rectangle_t *r1End,
- const rectangle_t *r2, const rectangle_t *r2End,
- int top, int bottom )
- {
- int left, right;
- while ((r1 != r1End) && (r2 != r2End))
- {
- left = max(r1->left, r2->left);
- right = min(r1->right, r2->right);
- if (left < right)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = left;
- rect->top = top;
- rect->right = right;
- rect->bottom = bottom;
- }
- if (r1->right < r2->right) r1++;
- else if (r2->right < r1->right) r2++;
- else
- {
- r1++;
- r2++;
- }
- }
- return 1;
- }
- /* handle a non-overlapping band for subtract_region */
- static int subtract_non_overlapping( struct region *pReg, const rectangle_t *r,
- const rectangle_t *rEnd, int top, int bottom )
- {
- while (r != rEnd)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = r->left;
- rect->top = top;
- rect->right = r->right;
- rect->bottom = bottom;
- r++;
- }
- return 1;
- }
- /* handle an overlapping band for subtract_region */
- static int subtract_overlapping( struct region *pReg,
- const rectangle_t *r1, const rectangle_t *r1End,
- const rectangle_t *r2, const rectangle_t *r2End,
- int top, int bottom )
- {
- int left = r1->left;
- while ((r1 != r1End) && (r2 != r2End))
- {
- if (r2->right <= left) r2++;
- else if (r2->left <= left)
- {
- left = r2->right;
- if (left >= r1->right)
- {
- r1++;
- if (r1 != r1End)
- left = r1->left;
- }
- else r2++;
- }
- else if (r2->left < r1->right)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = left;
- rect->top = top;
- rect->right = r2->left;
- rect->bottom = bottom;
- left = r2->right;
- if (left >= r1->right)
- {
- r1++;
- if (r1 != r1End)
- left = r1->left;
- }
- else r2++;
- }
- else
- {
- if (r1->right > left)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = left;
- rect->top = top;
- rect->right = r1->right;
- rect->bottom = bottom;
- }
- r1++;
- if (r1 != r1End)
- left = r1->left;
- }
- }
- while (r1 != r1End)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = left;
- rect->top = top;
- rect->right = r1->right;
- rect->bottom = bottom;
- r1++;
- if (r1 != r1End) left = r1->left;
- }
- return 1;
- }
- /* handle a non-overlapping band for union_region */
- static int union_non_overlapping( struct region *pReg, const rectangle_t *r,
- const rectangle_t *rEnd, int top, int bottom )
- {
- while (r != rEnd)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = r->left;
- rect->top = top;
- rect->right = r->right;
- rect->bottom = bottom;
- r++;
- }
- return 1;
- }
- /* handle an overlapping band for union_region */
- static int union_overlapping( struct region *pReg,
- const rectangle_t *r1, const rectangle_t *r1End,
- const rectangle_t *r2, const rectangle_t *r2End,
- int top, int bottom )
- {
- #define MERGERECT(r) \
- if ((pReg->num_rects != 0) && \
- (pReg->rects[pReg->num_rects-1].top == top) && \
- (pReg->rects[pReg->num_rects-1].bottom == bottom) && \
- (pReg->rects[pReg->num_rects-1].right >= r->left)) \
- { \
- if (pReg->rects[pReg->num_rects-1].right < r->right) \
- { \
- pReg->rects[pReg->num_rects-1].right = r->right; \
- } \
- } \
- else \
- { \
- rectangle_t *rect = add_rect( pReg ); \
- if (!rect) return 0; \
- rect->top = top; \
- rect->bottom = bottom; \
- rect->left = r->left; \
- rect->right = r->right; \
- } \
- r++;
- while ((r1 != r1End) && (r2 != r2End))
- {
- if (r1->left < r2->left)
- {
- MERGERECT(r1);
- }
- else
- {
- MERGERECT(r2);
- }
- }
- if (r1 != r1End)
- {
- do
- {
- MERGERECT(r1);
- } while (r1 != r1End);
- }
- else while (r2 != r2End)
- {
- MERGERECT(r2);
- }
- return 1;
- #undef MERGERECT
- }
- /* create an empty region */
- struct region *create_empty_region(void)
- {
- struct region *region;
- if (!(region = mem_alloc( sizeof(*region) ))) return NULL;
- if (!(region->rects = mem_alloc( RGN_DEFAULT_RECTS * sizeof(*region->rects) )))
- {
- free( region );
- return NULL;
- }
- region->size = RGN_DEFAULT_RECTS;
- region->num_rects = 0;
- region->extents.left = 0;
- region->extents.top = 0;
- region->extents.right = 0;
- region->extents.bottom = 0;
- return region;
- }
- /* create a region from request data */
- struct region *create_region_from_req_data( const void *data, data_size_t size )
- {
- unsigned int alloc_rects;
- struct region *region;
- const rectangle_t *rects = data;
- int nb_rects = size / sizeof(rectangle_t);
- /* special case: empty region can be specified by a single all-zero rectangle */
- if (nb_rects == 1 && !memcmp( rects, &empty_rect, sizeof(empty_rect) )) nb_rects = 0;
- if (!validate_rectangles( rects, nb_rects ))
- {
- set_error( STATUS_INVALID_PARAMETER );
- return NULL;
- }
- if (!(region = mem_alloc( sizeof(*region) ))) return NULL;
- alloc_rects = max( nb_rects, RGN_DEFAULT_RECTS );
- if (!(region->rects = mem_alloc( alloc_rects * sizeof(*region->rects) )))
- {
- free( region );
- return NULL;
- }
- region->size = alloc_rects;
- region->num_rects = nb_rects;
- memcpy( region->rects, rects, nb_rects * sizeof(*rects) );
- set_region_extents( region );
- return region;
- }
- /* free a region */
- void free_region( struct region *region )
- {
- free( region->rects );
- free( region );
- }
- /* set region to a simple rectangle */
- void set_region_rect( struct region *region, const rectangle_t *rect )
- {
- if (!is_rect_empty( rect ))
- {
- region->num_rects = 1;
- region->rects[0] = region->extents = *rect;
- }
- else
- {
- region->num_rects = 0;
- region->extents = empty_rect;
- }
- }
- /* retrieve the region data for sending to the client */
- rectangle_t *get_region_data( const struct region *region, data_size_t max_size, data_size_t *total_size )
- {
- const rectangle_t *data = region->rects;
- if (!(*total_size = region->num_rects * sizeof(rectangle_t)))
- {
- /* return a single empty rect for empty regions */
- *total_size = sizeof(empty_rect);
- data = &empty_rect;
- }
- if (max_size >= *total_size) return memdup( data, *total_size );
- set_error( STATUS_BUFFER_OVERFLOW );
- return NULL;
- }
- /* retrieve the region data for sending to the client and free the region at the same time */
- rectangle_t *get_region_data_and_free( struct region *region, data_size_t max_size, data_size_t *total_size )
- {
- rectangle_t *ret = region->rects;
- if (!(*total_size = region->num_rects * sizeof(rectangle_t)))
- {
- /* return a single empty rect for empty regions */
- *total_size = sizeof(empty_rect);
- if (max_size >= sizeof(empty_rect))
- {
- ret = memdup( &empty_rect, sizeof(empty_rect) );
- free( region->rects );
- }
- }
- if (max_size < *total_size)
- {
- free( region->rects );
- set_error( STATUS_BUFFER_OVERFLOW );
- ret = NULL;
- }
- free( region );
- return ret;
- }
- /* check if a given region is empty */
- int is_region_empty( const struct region *region )
- {
- return region->num_rects == 0;
- }
- /* get the extents rect of a region */
- void get_region_extents( const struct region *region, rectangle_t *rect )
- {
- *rect = region->extents;
- }
- /* add an offset to a region */
- void offset_region( struct region *region, int x, int y )
- {
- rectangle_t *rect, *end;
- if (!region->num_rects) return;
- for (rect = region->rects, end = rect + region->num_rects; rect < end; rect++)
- offset_rect( rect, x, y );
- offset_rect( ®ion->extents, x, y );
- }
- /* mirror a region relative to a window client rect */
- void mirror_region( const rectangle_t *client_rect, struct region *region )
- {
- int start, end, i, j;
- for (start = 0; start < region->num_rects; start = end + 1)
- {
- for (end = start; end < region->num_rects - 1; end++)
- if (region->rects[end + 1].top != region->rects[end].top) break;
- for (i = start, j = end; i < j; i++, j--)
- {
- rectangle_t rect = region->rects[j];
- region->rects[i] = region->rects[j];
- region->rects[j] = rect;
- mirror_rect( client_rect, ®ion->rects[j] );
- mirror_rect( client_rect, ®ion->rects[i] );
- }
- if (i == j) mirror_rect( client_rect, ®ion->rects[i] );
- }
- mirror_rect( client_rect, ®ion->extents );
- }
- /* scale a region for a given dpi factor */
- void scale_region( struct region *region, unsigned int dpi_from, unsigned int dpi_to )
- {
- rectangle_t *rect, *end;
- if (!region->num_rects) return;
- for (rect = region->rects, end = rect + region->num_rects; rect < end; rect++)
- scale_dpi_rect( rect, dpi_from, dpi_to );
- scale_dpi_rect( ®ion->extents, dpi_from, dpi_to );
- }
- /* make a copy of a region; returns dst or NULL on error */
- struct region *copy_region( struct region *dst, const struct region *src )
- {
- if (dst == src) return dst;
- if (dst->size < src->num_rects)
- {
- rectangle_t *rect = realloc( dst->rects, src->num_rects * sizeof(*rect) );
- if (!rect)
- {
- set_error( STATUS_NO_MEMORY );
- return NULL;
- }
- dst->rects = rect;
- dst->size = src->num_rects;
- }
- dst->num_rects = src->num_rects;
- dst->extents = src->extents;
- memcpy( dst->rects, src->rects, src->num_rects * sizeof(*dst->rects) );
- return dst;
- }
- /* compute the intersection of two regions into dst, which can be one of the source regions */
- struct region *intersect_region( struct region *dst, const struct region *src1,
- const struct region *src2 )
- {
- if (!src1->num_rects || !src2->num_rects || !EXTENTCHECK(&src1->extents, &src2->extents))
- {
- dst->num_rects = 0;
- dst->extents.left = 0;
- dst->extents.top = 0;
- dst->extents.right = 0;
- dst->extents.bottom = 0;
- return dst;
- }
- if (!region_op( dst, src1, src2, intersect_overlapping, NULL, NULL )) return NULL;
- set_region_extents( dst );
- return dst;
- }
- /* compute the subtraction of two regions into dst, which can be one of the source regions */
- struct region *subtract_region( struct region *dst, const struct region *src1,
- const struct region *src2 )
- {
- if (!src1->num_rects || !src2->num_rects || !EXTENTCHECK(&src1->extents, &src2->extents))
- return copy_region( dst, src1 );
- if (!region_op( dst, src1, src2, subtract_overlapping,
- subtract_non_overlapping, NULL )) return NULL;
- set_region_extents( dst );
- return dst;
- }
- /* compute the union of two regions into dst, which can be one of the source regions */
- struct region *union_region( struct region *dst, const struct region *src1,
- const struct region *src2 )
- {
- if (src1 == src2) return copy_region( dst, src1 );
- if (!src1->num_rects) return copy_region( dst, src2 );
- if (!src2->num_rects) return copy_region( dst, src1 );
- if ((src1->num_rects == 1) &&
- (src1->extents.left <= src2->extents.left) &&
- (src1->extents.top <= src2->extents.top) &&
- (src1->extents.right >= src2->extents.right) &&
- (src1->extents.bottom >= src2->extents.bottom))
- return copy_region( dst, src1 );
- if ((src2->num_rects == 1) &&
- (src2->extents.left <= src1->extents.left) &&
- (src2->extents.top <= src1->extents.top) &&
- (src2->extents.right >= src1->extents.right) &&
- (src2->extents.bottom >= src1->extents.bottom))
- return copy_region( dst, src2 );
- if (!region_op( dst, src1, src2, union_overlapping,
- union_non_overlapping, union_non_overlapping )) return NULL;
- dst->extents.left = min(src1->extents.left, src2->extents.left);
- dst->extents.top = min(src1->extents.top, src2->extents.top);
- dst->extents.right = max(src1->extents.right, src2->extents.right);
- dst->extents.bottom = max(src1->extents.bottom, src2->extents.bottom);
- return dst;
- }
- /* compute the exclusive or of two regions into dst, which can be one of the source regions */
- struct region *xor_region( struct region *dst, const struct region *src1,
- const struct region *src2 )
- {
- struct region *tmp = create_empty_region();
- if (!tmp) return NULL;
- if (!subtract_region( tmp, src1, src2 ) ||
- !subtract_region( dst, src2, src1 ) ||
- !union_region( dst, dst, tmp ))
- dst = NULL;
- free_region( tmp );
- return dst;
- }
- /* check if the given point is inside the region */
- int point_in_region( struct region *region, int x, int y )
- {
- const rectangle_t *ptr, *end;
- for (ptr = region->rects, end = region->rects + region->num_rects; ptr < end; ptr++)
- {
- if (ptr->top > y) return 0;
- if (ptr->bottom <= y) continue;
- /* now we are in the correct band */
- if (ptr->left > x) return 0;
- if (ptr->right <= x) continue;
- return 1;
- }
- return 0;
- }
- /* check if the given rectangle is (at least partially) inside the region */
- int rect_in_region( struct region *region, const rectangle_t *rect )
- {
- const rectangle_t *ptr, *end;
- for (ptr = region->rects, end = region->rects + region->num_rects; ptr < end; ptr++)
- {
- if (ptr->top >= rect->bottom) return 0;
- if (ptr->bottom <= rect->top) continue;
- if (ptr->left >= rect->right) continue;
- if (ptr->right <= rect->left) continue;
- return 1;
- }
- return 0;
- }
|