Don't map data beyond the virtual size of a section.
[wine.git] / server / region.c
blob9a3891aef25ce39630fddd4b3015fc473cdceb1b
1 /*
2 * Server-side region objects. Based on the X11 implementation.
4 * Copyright 1993, 1994, 1995, 2004 Alexandre Julliard
5 * Modifications and additions: Copyright 1998 Huw Davies
6 * 1999 Alex Korobka
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Note:
23 * This is a simplified version of the code, without all the explanations.
24 * Check the equivalent GDI code to make sense of it.
27 /************************************************************************
29 Copyright (c) 1987, 1988 X Consortium
31 Permission is hereby granted, free of charge, to any person obtaining a copy
32 of this software and associated documentation files (the "Software"), to deal
33 in the Software without restriction, including without limitation the rights
34 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35 copies of the Software, and to permit persons to whom the Software is
36 furnished to do so, subject to the following conditions:
38 The above copyright notice and this permission notice shall be included in
39 all copies or substantial portions of the Software.
41 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
45 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
46 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48 Except as contained in this notice, the name of the X Consortium shall not be
49 used in advertising or otherwise to promote the sale, use or other dealings
50 in this Software without prior written authorization from the X Consortium.
53 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
55 All Rights Reserved
57 Permission to use, copy, modify, and distribute this software and its
58 documentation for any purpose and without fee is hereby granted,
59 provided that the above copyright notice appear in all copies and that
60 both that copyright notice and this permission notice appear in
61 supporting documentation, and that the name of Digital not be
62 used in advertising or publicity pertaining to distribution of the
63 software without specific, written prior permission.
65 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
66 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
67 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
68 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
69 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
70 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
71 SOFTWARE.
73 ************************************************************************/
75 #include <stdarg.h>
76 #include <stdlib.h>
77 #include <string.h>
78 #include "request.h"
79 #include "user.h"
81 struct region
83 int size;
84 int num_rects;
85 rectangle_t *rects;
86 rectangle_t extents;
90 #define RGN_DEFAULT_RECTS 2
92 #define EXTENTCHECK(r1, r2) \
93 ((r1)->right > (r2)->left && \
94 (r1)->left < (r2)->right && \
95 (r1)->bottom > (r2)->top && \
96 (r1)->top < (r2)->bottom)
98 typedef int (*overlap_func_t)( struct region *reg, const rectangle_t *r1, const rectangle_t *r1End,
99 const rectangle_t *r2, const rectangle_t *r2End, int top, int bottom );
100 typedef int (*non_overlap_func_t)( struct region *reg, const rectangle_t *r,
101 const rectangle_t *rEnd, int top, int bottom );
103 static const rectangle_t empty_rect; /* all-zero rectangle for empty regions */
105 /* add a rectangle to a region */
106 static inline rectangle_t *add_rect( struct region *reg )
108 if (reg->num_rects >= reg->size - 1)
110 rectangle_t *new_rect = realloc( reg->rects, 2 * sizeof(rectangle_t) * reg->size );
111 if (!new_rect)
113 set_error( STATUS_NO_MEMORY );
114 return NULL;
116 reg->rects = new_rect;
117 reg->size *= 2;
119 return reg->rects + reg->num_rects++;
122 /* make sure all the rectangles are valid and that the region is properly y-x-banded */
123 static inline int validate_rectangles( const rectangle_t *rects, unsigned int nb_rects )
125 const rectangle_t *ptr, *end;
127 for (ptr = rects, end = rects + nb_rects; ptr < end; ptr++)
129 if (ptr->left >= ptr->right || ptr->top >= ptr->bottom) return 0; /* empty rectangle */
130 if (ptr == end - 1) break;
131 if (ptr[0].top == ptr[1].top) /* same band */
133 if (ptr[0].bottom != ptr[1].bottom) return 0; /* not same y extent */
134 if (ptr[0].right >= ptr[1].left) return 0; /* not properly x ordered */
136 else /* new band */
138 if (ptr[0].bottom > ptr[1].top) return 0; /* not properly y ordered */
141 return 1;
144 /* attempt to merge the rects in the current band with those in the */
145 /* previous one. Used only by region_op. */
146 static int coalesce_region( struct region *pReg, int prevStart, int curStart )
148 int curNumRects;
149 rectangle_t *pRegEnd = &pReg->rects[pReg->num_rects];
150 rectangle_t *pPrevRect = &pReg->rects[prevStart];
151 rectangle_t *pCurRect = &pReg->rects[curStart];
152 int prevNumRects = curStart - prevStart;
153 int bandtop = pCurRect->top;
155 for (curNumRects = 0;
156 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
157 curNumRects++)
159 pCurRect++;
162 if (pCurRect != pRegEnd)
164 pRegEnd--;
165 while (pRegEnd[-1].top == pRegEnd->top) pRegEnd--;
166 curStart = pRegEnd - pReg->rects;
167 pRegEnd = pReg->rects + pReg->num_rects;
170 if ((curNumRects == prevNumRects) && (curNumRects != 0))
172 pCurRect -= curNumRects;
173 if (pPrevRect->bottom == pCurRect->top)
177 if ((pPrevRect->left != pCurRect->left) ||
178 (pPrevRect->right != pCurRect->right)) return curStart;
179 pPrevRect++;
180 pCurRect++;
181 prevNumRects -= 1;
182 } while (prevNumRects != 0);
184 pReg->num_rects -= curNumRects;
185 pCurRect -= curNumRects;
186 pPrevRect -= curNumRects;
190 pPrevRect->bottom = pCurRect->bottom;
191 pPrevRect++;
192 pCurRect++;
193 curNumRects -= 1;
194 } while (curNumRects != 0);
196 if (pCurRect == pRegEnd) curStart = prevStart;
197 else do { *pPrevRect++ = *pCurRect++; } while (pCurRect != pRegEnd);
201 return curStart;
204 /* apply an operation to two regions */
205 /* check the GDI version of the code for explanations */
206 static int region_op( struct region *newReg, const struct region *reg1, const struct region *reg2,
207 overlap_func_t overlap_func,
208 non_overlap_func_t non_overlap1_func,
209 non_overlap_func_t non_overlap2_func )
211 int ybot, ytop, top, bot, prevBand, curBand;
212 const rectangle_t *r1BandEnd, *r2BandEnd;
214 const rectangle_t *r1 = reg1->rects;
215 const rectangle_t *r2 = reg2->rects;
216 const rectangle_t *r1End = r1 + reg1->num_rects;
217 const rectangle_t *r2End = r2 + reg2->num_rects;
219 rectangle_t *new_rects, *old_rects = newReg->rects;
220 int new_size, ret = 0;
222 new_size = max( reg1->num_rects, reg2->num_rects ) * 2;
223 if (!(new_rects = mem_alloc( new_size * sizeof(*newReg->rects) ))) return 0;
225 newReg->size = new_size;
226 newReg->rects = new_rects;
227 newReg->num_rects = 0;
229 if (reg1->extents.top < reg2->extents.top)
230 ybot = reg1->extents.top;
231 else
232 ybot = reg2->extents.top;
234 prevBand = 0;
238 curBand = newReg->num_rects;
240 r1BandEnd = r1;
241 while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top)) r1BandEnd++;
243 r2BandEnd = r2;
244 while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top)) r2BandEnd++;
246 if (r1->top < r2->top)
248 top = max(r1->top,ybot);
249 bot = min(r1->bottom,r2->top);
251 if ((top != bot) && non_overlap1_func)
253 if (!non_overlap1_func( newReg, r1, r1BandEnd, top, bot )) goto done;
256 ytop = r2->top;
258 else if (r2->top < r1->top)
260 top = max(r2->top,ybot);
261 bot = min(r2->bottom,r1->top);
263 if ((top != bot) && non_overlap2_func)
265 if (!non_overlap2_func( newReg, r2, r2BandEnd, top, bot )) goto done;
268 ytop = r1->top;
270 else
272 ytop = r1->top;
275 if (newReg->num_rects != curBand)
276 prevBand = coalesce_region(newReg, prevBand, curBand);
278 ybot = min(r1->bottom, r2->bottom);
279 curBand = newReg->num_rects;
280 if (ybot > ytop)
282 if (!overlap_func( newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot )) goto done;
285 if (newReg->num_rects != curBand)
286 prevBand = coalesce_region(newReg, prevBand, curBand);
288 if (r1->bottom == ybot) r1 = r1BandEnd;
289 if (r2->bottom == ybot) r2 = r2BandEnd;
290 } while ((r1 != r1End) && (r2 != r2End));
292 curBand = newReg->num_rects;
293 if (r1 != r1End)
295 if (non_overlap1_func)
299 r1BandEnd = r1;
300 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top)) r1BandEnd++;
301 if (!non_overlap1_func( newReg, r1, r1BandEnd, max(r1->top,ybot), r1->bottom ))
302 goto done;
303 r1 = r1BandEnd;
304 } while (r1 != r1End);
307 else if ((r2 != r2End) && non_overlap2_func)
311 r2BandEnd = r2;
312 while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top)) r2BandEnd++;
313 if (!non_overlap2_func( newReg, r2, r2BandEnd, max(r2->top,ybot), r2->bottom ))
314 goto done;
315 r2 = r2BandEnd;
316 } while (r2 != r2End);
319 if (newReg->num_rects != curBand) coalesce_region(newReg, prevBand, curBand);
321 if ((newReg->num_rects < (newReg->size / 2)) && (newReg->size > 2))
323 new_size = max( newReg->num_rects, RGN_DEFAULT_RECTS );
324 if ((new_rects = realloc( newReg->rects, sizeof(*newReg->rects) * new_size )))
326 newReg->rects = new_rects;
327 newReg->size = new_size;
330 ret = 1;
331 done:
332 free( old_rects );
333 return ret;
336 /* recalculate the extents of a region */
337 static void set_region_extents( struct region *region )
339 rectangle_t *pRect, *pRectEnd;
341 if (region->num_rects == 0)
343 region->extents.left = 0;
344 region->extents.top = 0;
345 region->extents.right = 0;
346 region->extents.bottom = 0;
347 return;
350 pRect = region->rects;
351 pRectEnd = &pRect[region->num_rects - 1];
353 region->extents.left = pRect->left;
354 region->extents.top = pRect->top;
355 region->extents.right = pRectEnd->right;
356 region->extents.bottom = pRectEnd->bottom;
358 while (pRect <= pRectEnd)
360 if (pRect->left < region->extents.left) region->extents.left = pRect->left;
361 if (pRect->right > region->extents.right) region->extents.right = pRect->right;
362 pRect++;
366 /* handle an overlapping band for intersect_region */
367 static int intersect_overlapping( struct region *pReg,
368 const rectangle_t *r1, const rectangle_t *r1End,
369 const rectangle_t *r2, const rectangle_t *r2End,
370 int top, int bottom )
373 int left, right;
375 while ((r1 != r1End) && (r2 != r2End))
377 left = max(r1->left, r2->left);
378 right = min(r1->right, r2->right);
380 if (left < right)
382 rectangle_t *rect = add_rect( pReg );
383 if (!rect) return 0;
384 rect->left = left;
385 rect->top = top;
386 rect->right = right;
387 rect->bottom = bottom;
390 if (r1->right < r2->right) r1++;
391 else if (r2->right < r1->right) r2++;
392 else
394 r1++;
395 r2++;
398 return 1;
401 /* handle a non-overlapping band for subtract_region */
402 static int subtract_non_overlapping( struct region *pReg, const rectangle_t *r,
403 const rectangle_t *rEnd, int top, int bottom )
405 while (r != rEnd)
407 rectangle_t *rect = add_rect( pReg );
408 if (!rect) return 0;
409 rect->left = r->left;
410 rect->top = top;
411 rect->right = r->right;
412 rect->bottom = bottom;
413 r++;
415 return 1;
418 /* handle an overlapping band for subtract_region */
419 static int subtract_overlapping( struct region *pReg,
420 const rectangle_t *r1, const rectangle_t *r1End,
421 const rectangle_t *r2, const rectangle_t *r2End,
422 int top, int bottom )
424 int left = r1->left;
426 while ((r1 != r1End) && (r2 != r2End))
428 if (r2->right <= left) r2++;
429 else if (r2->left <= left)
431 left = r2->right;
432 if (left >= r1->right)
434 r1++;
435 if (r1 != r1End)
436 left = r1->left;
438 else r2++;
440 else if (r2->left < r1->right)
442 rectangle_t *rect = add_rect( pReg );
443 if (!rect) return 0;
444 rect->left = left;
445 rect->top = top;
446 rect->right = r2->left;
447 rect->bottom = bottom;
448 left = r2->right;
449 if (left >= r1->right)
451 r1++;
452 if (r1 != r1End)
453 left = r1->left;
455 else r2++;
457 else
459 if (r1->right > left)
461 rectangle_t *rect = add_rect( pReg );
462 if (!rect) return 0;
463 rect->left = left;
464 rect->top = top;
465 rect->right = r1->right;
466 rect->bottom = bottom;
468 r1++;
469 left = r1->left;
473 while (r1 != r1End)
475 rectangle_t *rect = add_rect( pReg );
476 if (!rect) return 0;
477 rect->left = left;
478 rect->top = top;
479 rect->right = r1->right;
480 rect->bottom = bottom;
481 r1++;
482 if (r1 != r1End) left = r1->left;
484 return 1;
487 /* handle a non-overlapping band for union_region */
488 static int union_non_overlapping( struct region *pReg, const rectangle_t *r,
489 const rectangle_t *rEnd, int top, int bottom )
491 while (r != rEnd)
493 rectangle_t *rect = add_rect( pReg );
494 if (!rect) return 0;
495 rect->left = r->left;
496 rect->top = top;
497 rect->right = r->right;
498 rect->bottom = bottom;
499 r++;
501 return 1;
504 /* handle an overlapping band for union_region */
505 static int union_overlapping( struct region *pReg,
506 const rectangle_t *r1, const rectangle_t *r1End,
507 const rectangle_t *r2, const rectangle_t *r2End,
508 int top, int bottom )
510 #define MERGERECT(r) \
511 if ((pReg->num_rects != 0) && \
512 (pReg->rects[pReg->num_rects-1].top == top) && \
513 (pReg->rects[pReg->num_rects-1].bottom == bottom) && \
514 (pReg->rects[pReg->num_rects-1].right >= r->left)) \
516 if (pReg->rects[pReg->num_rects-1].right < r->right) \
518 pReg->rects[pReg->num_rects-1].right = r->right; \
521 else \
523 rectangle_t *rect = add_rect( pReg ); \
524 if (!rect) return 0; \
525 rect->top = top; \
526 rect->bottom = bottom; \
527 rect->left = r->left; \
528 rect->right = r->right; \
530 r++;
532 while ((r1 != r1End) && (r2 != r2End))
534 if (r1->left < r2->left)
536 MERGERECT(r1);
538 else
540 MERGERECT(r2);
544 if (r1 != r1End)
548 MERGERECT(r1);
549 } while (r1 != r1End);
551 else while (r2 != r2End)
553 MERGERECT(r2);
555 return 1;
556 #undef MERGERECT
560 /* create an empty region */
561 struct region *create_empty_region(void)
563 struct region *region;
565 if (!(region = mem_alloc( sizeof(*region) ))) return NULL;
566 if (!(region->rects = mem_alloc( RGN_DEFAULT_RECTS * sizeof(*region->rects) )))
568 free( region );
569 return NULL;
571 region->size = RGN_DEFAULT_RECTS;
572 region->num_rects = 0;
573 region->extents.left = 0;
574 region->extents.top = 0;
575 region->extents.right = 0;
576 region->extents.bottom = 0;
577 return region;
580 /* create a region from request data */
581 struct region *create_region_from_req_data( const void *data, size_t size )
583 unsigned int alloc_rects;
584 struct region *region;
585 const rectangle_t *rects = data;
586 int nb_rects = size / sizeof(rectangle_t);
588 /* special case: empty region can be specified by a single all-zero rectangle */
589 if (nb_rects == 1 && !memcmp( rects, &empty_rect, sizeof(empty_rect) )) nb_rects = 0;
591 if (!validate_rectangles( rects, nb_rects ))
593 set_error( STATUS_INVALID_PARAMETER );
594 return NULL;
597 if (!(region = mem_alloc( sizeof(*region) ))) return NULL;
599 alloc_rects = max( nb_rects, RGN_DEFAULT_RECTS );
600 if (!(region->rects = mem_alloc( alloc_rects * sizeof(*region->rects) )))
602 free( region );
603 return NULL;
605 region->size = alloc_rects;
606 region->num_rects = nb_rects;
607 memcpy( region->rects, rects, nb_rects * sizeof(*rects) );
608 set_region_extents( region );
609 return region;
612 /* free a region */
613 void free_region( struct region *region )
615 free( region->rects );
616 free( region );
619 /* set region to a simple rectangle */
620 void set_region_rect( struct region *region, const rectangle_t *rect )
622 if (rect->left < rect->right && rect->top < rect->bottom)
624 region->num_rects = 1;
625 region->rects[0] = region->extents = *rect;
627 else
629 region->num_rects = 0;
630 region->extents.left = 0;
631 region->extents.top = 0;
632 region->extents.right = 0;
633 region->extents.bottom = 0;
637 /* retrieve the region data for sending to the client */
638 rectangle_t *get_region_data( const struct region *region, size_t max_size, size_t *total_size )
640 const rectangle_t *data = region->rects;
642 if (!(*total_size = region->num_rects * sizeof(rectangle_t)))
644 /* return a single empty rect for empty regions */
645 *total_size = sizeof(empty_rect);
646 data = &empty_rect;
648 if (max_size >= *total_size) return memdup( data, *total_size );
649 set_error( STATUS_BUFFER_OVERFLOW );
650 return NULL;
653 /* retrieve the region data for sending to the client and free the region at the same time */
654 rectangle_t *get_region_data_and_free( struct region *region, size_t max_size, size_t *total_size )
656 rectangle_t *ret = region->rects;
658 if (!(*total_size = region->num_rects * sizeof(rectangle_t)))
660 /* return a single empty rect for empty regions */
661 *total_size = sizeof(empty_rect);
662 if (max_size >= sizeof(empty_rect))
664 ret = memdup( &empty_rect, sizeof(empty_rect) );
665 free( region->rects );
669 if (max_size < *total_size)
671 free( region->rects );
672 set_error( STATUS_BUFFER_OVERFLOW );
673 ret = NULL;
675 free( region );
676 return ret;
679 /* check if a given region is empty */
680 int is_region_empty( const struct region *region )
682 return region->num_rects == 0;
686 /* get the extents rect of a region */
687 void get_region_extents( const struct region *region, rectangle_t *rect )
689 *rect = region->extents;
692 /* add an offset to a region */
693 void offset_region( struct region *region, int x, int y )
695 rectangle_t *rect, *end;
697 if (!region->num_rects) return;
698 for (rect = region->rects, end = rect + region->num_rects; rect < end; rect++)
700 rect->left += x;
701 rect->right += x;
702 rect->top += y;
703 rect->bottom += y;
705 region->extents.left += x;
706 region->extents.right += x;
707 region->extents.top += y;
708 region->extents.bottom += y;
711 /* make a copy of a region; returns dst or NULL on error */
712 struct region *copy_region( struct region *dst, const struct region *src )
714 if (dst == src) return dst;
716 if (dst->size < src->num_rects)
718 rectangle_t *rect = realloc( dst->rects, src->num_rects * sizeof(*rect) );
719 if (!rect)
721 set_error( STATUS_NO_MEMORY );
722 return NULL;
724 dst->rects = rect;
725 dst->size = src->num_rects;
727 dst->num_rects = src->num_rects;
728 dst->extents = src->extents;
729 memcpy( dst->rects, src->rects, src->num_rects * sizeof(*dst->rects) );
730 return dst;
733 /* compute the intersection of two regions into dst, which can be one of the source regions */
734 struct region *intersect_region( struct region *dst, const struct region *src1,
735 const struct region *src2 )
737 if (!src1->num_rects || !src2->num_rects || !EXTENTCHECK(&src1->extents, &src2->extents))
739 dst->num_rects = 0;
740 dst->extents.left = 0;
741 dst->extents.top = 0;
742 dst->extents.right = 0;
743 dst->extents.bottom = 0;
744 return dst;
746 if (!region_op( dst, src1, src2, intersect_overlapping, NULL, NULL )) return NULL;
747 set_region_extents( dst );
748 return dst;
751 /* compute the subtraction of two regions into dst, which can be one of the source regions */
752 struct region *subtract_region( struct region *dst, const struct region *src1,
753 const struct region *src2 )
755 if (!src1->num_rects || !src2->num_rects || !EXTENTCHECK(&src1->extents, &src2->extents))
756 return copy_region( dst, src1 );
758 if (!region_op( dst, src1, src2, subtract_overlapping,
759 subtract_non_overlapping, NULL )) return NULL;
760 set_region_extents( dst );
761 return dst;
764 /* compute the union of two regions into dst, which can be one of the source regions */
765 struct region *union_region( struct region *dst, const struct region *src1,
766 const struct region *src2 )
768 if (src1 == src2) return copy_region( dst, src1 );
769 if (!src1->num_rects) return copy_region( dst, src2 );
770 if (!src2->num_rects) return copy_region( dst, src1 );
772 if ((src1->num_rects == 1) &&
773 (src1->extents.left <= src2->extents.left) &&
774 (src1->extents.top <= src2->extents.top) &&
775 (src1->extents.right >= src2->extents.right) &&
776 (src1->extents.bottom >= src2->extents.bottom))
777 return copy_region( dst, src1 );
779 if ((src2->num_rects == 1) &&
780 (src2->extents.left <= src1->extents.left) &&
781 (src2->extents.top <= src1->extents.top) &&
782 (src2->extents.right >= src1->extents.right) &&
783 (src2->extents.bottom >= src1->extents.bottom))
784 return copy_region( dst, src2 );
786 if (!region_op( dst, src1, src2, union_overlapping,
787 union_non_overlapping, union_non_overlapping )) return NULL;
789 dst->extents.left = min(src1->extents.left, src2->extents.left);
790 dst->extents.top = min(src1->extents.top, src2->extents.top);
791 dst->extents.right = max(src1->extents.right, src2->extents.right);
792 dst->extents.bottom = max(src1->extents.bottom, src2->extents.bottom);
793 return dst;
796 /* compute the exclusive or of two regions into dst, which can be one of the source regions */
797 struct region *xor_region( struct region *dst, const struct region *src1,
798 const struct region *src2 )
800 struct region *tmp = create_empty_region();
802 if (!tmp) return NULL;
804 if (!subtract_region( tmp, src1, src2 ) ||
805 !subtract_region( dst, src2, src1 ) ||
806 !union_region( dst, dst, tmp ))
807 dst = NULL;
809 free_region( tmp );
810 return dst;
813 /* check if the given point is inside the region */
814 int point_in_region( struct region *region, int x, int y )
816 const rectangle_t *ptr, *end;
818 for (ptr = region->rects, end = region->rects + region->num_rects; ptr < end; ptr++)
820 if (ptr->top > y) return 0;
821 if (ptr->bottom <= y) continue;
822 /* now we are in the correct band */
823 if (ptr->left > x) return 0;
824 if (ptr->right <= x) continue;
825 return 1;
827 return 0;
830 /* check if the given rectangle is (at least partially) inside the region */
831 int rect_in_region( struct region *region, const rectangle_t *rect )
833 const rectangle_t *ptr, *end;
835 for (ptr = region->rects, end = region->rects + region->num_rects; ptr < end; ptr++)
837 if (ptr->top >= rect->bottom) return 0;
838 if (ptr->bottom <= rect->top) continue;
839 if (ptr->left >= rect->right) continue;
840 if (ptr->right <= rect->left) continue;
841 return 1;
843 return 0;