Fixed bug introduced in WIN_FindWindow.
[wine/multimedia.git] / objects / region.c
blob3e32b81d779ddaf933ebb17ae2fb2b9b3c7d5322
1 /*
2 * GDI region objects. Shamelessly ripped out from the X11 distribution
3 * Thanks for the nice licence.
5 * Copyright 1993, 1994, 1995 Alexandre Julliard
6 * Modifications and additions: Copyright 1998 Huw Davies
8 */
10 /************************************************************************
12 Copyright (c) 1987, 1988 X Consortium
14 Permission is hereby granted, free of charge, to any person obtaining a copy
15 of this software and associated documentation files (the "Software"), to deal
16 in the Software without restriction, including without limitation the rights
17 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 copies of the Software, and to permit persons to whom the Software is
19 furnished to do so, subject to the following conditions:
21 The above copyright notice and this permission notice shall be included in
22 all copies or substantial portions of the Software.
24 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
28 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 Except as contained in this notice, the name of the X Consortium shall not be
32 used in advertising or otherwise to promote the sale, use or other dealings
33 in this Software without prior written authorization from the X Consortium.
36 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
38 All Rights Reserved
40 Permission to use, copy, modify, and distribute this software and its
41 documentation for any purpose and without fee is hereby granted,
42 provided that the above copyright notice appear in all copies and that
43 both that copyright notice and this permission notice appear in
44 supporting documentation, and that the name of Digital not be
45 used in advertising or publicity pertaining to distribution of the
46 software without specific, written prior permission.
48 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
49 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
50 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
51 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
52 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
53 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
54 SOFTWARE.
56 ************************************************************************/
58 * The functions in this file implement the Region abstraction, similar to one
59 * used in the X11 sample server. A Region is simply an area, as the name
60 * implies, and is implemented as a "y-x-banded" array of rectangles. To
61 * explain: Each Region is made up of a certain number of rectangles sorted
62 * by y coordinate first, and then by x coordinate.
64 * Furthermore, the rectangles are banded such that every rectangle with a
65 * given upper-left y coordinate (y1) will have the same lower-right y
66 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
67 * will span the entire vertical distance of the band. This means that some
68 * areas that could be merged into a taller rectangle will be represented as
69 * several shorter rectangles to account for shorter rectangles to its left
70 * or right but within its "vertical scope".
72 * An added constraint on the rectangles is that they must cover as much
73 * horizontal area as possible. E.g. no two rectangles in a band are allowed
74 * to touch.
76 * Whenever possible, bands will be merged together to cover a greater vertical
77 * distance (and thus reduce the number of rectangles). Two bands can be merged
78 * only if the bottom of one touches the top of the other and they have
79 * rectangles in the same places (of the same width, of course). This maintains
80 * the y-x-banding that's so nice to have...
83 #include <stdlib.h>
84 #include <string.h>
85 #include "region.h"
86 #include "winuser.h"
87 #include "debug.h"
88 #include "heap.h"
89 #include "dc.h"
91 typedef void (*voidProcp)();
93 /* Note the parameter order is different from the X11 equivalents */
95 static void REGION_CopyRegion(WINEREGION *d, WINEREGION *s);
96 static void REGION_IntersectRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
97 static void REGION_UnionRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
98 static void REGION_SubtractRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
99 static void REGION_XorRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
100 static void REGION_UnionRectWithRegion(const RECT *rect, WINEREGION *rgn);
103 /***********************************************************************
104 * REGION_DumpRegion
105 * Outputs the contents of a WINEREGION
107 static void REGION_DumpRegion(WINEREGION *pReg)
109 RECT *pRect, *pRectEnd = pReg->rects + pReg->numRects;
111 TRACE(region, "Region %p: %d,%d - %d,%d %d rects\n", pReg,
112 pReg->extents.left, pReg->extents.top,
113 pReg->extents.right, pReg->extents.bottom, pReg->numRects);
114 for(pRect = pReg->rects; pRect < pRectEnd; pRect++)
115 TRACE(region, "\t%d,%d - %d,%d\n", pRect->left, pRect->top,
116 pRect->right, pRect->bottom);
117 return;
120 /***********************************************************************
121 * REGION_AllocWineRegion
122 * Create a new empty WINEREGION.
124 static WINEREGION *REGION_AllocWineRegion( void )
126 WINEREGION *pReg;
128 if ((pReg = HeapAlloc(SystemHeap, 0, sizeof( WINEREGION ))))
130 if ((pReg->rects = HeapAlloc(SystemHeap, 0, sizeof( RECT ))))
132 pReg->size = 1;
133 EMPTY_REGION(pReg);
134 return pReg;
136 HeapFree(SystemHeap, 0, pReg);
138 return NULL;
141 /***********************************************************************
142 * REGION_CreateRegion
143 * Create a new empty region.
145 static HRGN REGION_CreateRegion(void)
147 HRGN hrgn;
148 RGNOBJ *obj;
150 if(!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
151 return 0;
152 obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
153 if(!(obj->rgn = REGION_AllocWineRegion())) {
154 GDI_FreeObject( hrgn );
155 return 0;
157 GDI_HEAP_UNLOCK( hrgn );
158 return hrgn;
161 /***********************************************************************
162 * REGION_DestroyWineRegion
164 static void REGION_DestroyWineRegion( WINEREGION* pReg )
166 HeapFree( SystemHeap, 0, pReg->rects );
167 HeapFree( SystemHeap, 0, pReg );
168 return;
171 /***********************************************************************
172 * REGION_DeleteObject
174 BOOL REGION_DeleteObject( HRGN hrgn, RGNOBJ * obj )
176 TRACE(region, " %04x\n", hrgn );
178 REGION_DestroyWineRegion( obj->rgn );
179 return GDI_FreeObject( hrgn );
182 /***********************************************************************
183 * OffsetRgn16 (GDI.101)
185 INT16 WINAPI OffsetRgn16( HRGN16 hrgn, INT16 x, INT16 y )
187 return OffsetRgn( hrgn, x, y );
190 /***********************************************************************
191 * OffsetRgn32 (GDI32.256)
193 INT WINAPI OffsetRgn( HRGN hrgn, INT x, INT y )
195 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
197 if (obj)
199 INT ret;
200 int nbox = obj->rgn->numRects;
201 RECT *pbox = obj->rgn->rects;
203 TRACE(region, " %04x %d,%d\n", hrgn, x, y );
204 if(nbox && (x || y)) {
205 while(nbox--) {
206 pbox->left += x;
207 pbox->right += x;
208 pbox->top += y;
209 pbox->bottom += y;
210 pbox++;
212 obj->rgn->extents.left += x;
213 obj->rgn->extents.right += x;
214 obj->rgn->extents.top += y;
215 obj->rgn->extents.bottom += y;
217 ret = obj->rgn->type;
218 GDI_HEAP_UNLOCK( hrgn );
219 return ret;
221 return ERROR;
225 /***********************************************************************
226 * GetRgnBox16 (GDI.134)
228 INT16 WINAPI GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
230 RECT r;
231 INT16 ret = (INT16)GetRgnBox( hrgn, &r );
232 CONV_RECT32TO16( &r, rect );
233 return ret;
236 /***********************************************************************
237 * GetRgnBox32 (GDI32.219)
239 INT WINAPI GetRgnBox( HRGN hrgn, LPRECT rect )
241 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
242 if (obj)
244 INT ret;
245 TRACE(region, " %04x\n", hrgn );
246 rect->left = obj->rgn->extents.left;
247 rect->top = obj->rgn->extents.top;
248 rect->right = obj->rgn->extents.right;
249 rect->bottom = obj->rgn->extents.bottom;
250 ret = obj->rgn->type;
251 GDI_HEAP_UNLOCK(hrgn);
252 return ret;
254 return ERROR;
258 /***********************************************************************
259 * CreateRectRgn16 (GDI.64)
261 * NOTE: Doesn't call CreateRectRgn32 because of differences in SetRectRgn16/32
263 HRGN16 WINAPI CreateRectRgn16(INT16 left, INT16 top, INT16 right, INT16 bottom)
265 HRGN16 hrgn;
267 if (!(hrgn = (HRGN16)REGION_CreateRegion()))
268 return 0;
269 TRACE(region, "\n");
270 SetRectRgn16(hrgn, left, top, right, bottom);
271 return hrgn;
275 /***********************************************************************
276 * CreateRectRgn32 (GDI32.59)
278 HRGN WINAPI CreateRectRgn(INT left, INT top, INT right, INT bottom)
280 HRGN hrgn;
282 if (!(hrgn = REGION_CreateRegion()))
283 return 0;
284 TRACE(region, "\n");
285 SetRectRgn(hrgn, left, top, right, bottom);
286 return hrgn;
289 /***********************************************************************
290 * CreateRectRgnIndirect16 (GDI.65)
292 HRGN16 WINAPI CreateRectRgnIndirect16( const RECT16* rect )
294 return CreateRectRgn16( rect->left, rect->top, rect->right, rect->bottom );
298 /***********************************************************************
299 * CreateRectRgnIndirect32 (GDI32.60)
301 HRGN WINAPI CreateRectRgnIndirect( const RECT* rect )
303 return CreateRectRgn( rect->left, rect->top, rect->right, rect->bottom );
307 /***********************************************************************
308 * SetRectRgn16 (GDI.172)
310 * NOTE: Win 3.1 sets region to empty if left > right
312 VOID WINAPI SetRectRgn16( HRGN16 hrgn, INT16 left, INT16 top,
313 INT16 right, INT16 bottom )
315 if(left < right)
316 SetRectRgn( hrgn, left, top, right, bottom );
317 else
318 SetRectRgn( hrgn, 0, 0, 0, 0 );
322 /***********************************************************************
323 * SetRectRgn32 (GDI32.332)
325 * Allows either or both left and top to be greater than right or bottom.
327 VOID WINAPI SetRectRgn( HRGN hrgn, INT left, INT top,
328 INT right, INT bottom )
330 RGNOBJ * obj;
332 TRACE(region, " %04x %d,%d-%d,%d\n",
333 hrgn, left, top, right, bottom );
335 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
337 if (left > right) { INT tmp = left; left = right; right = tmp; }
338 if (top > bottom) { INT tmp = top; top = bottom; bottom = tmp; }
340 if((left != right) && (top != bottom))
342 obj->rgn->rects->left = obj->rgn->extents.left = left;
343 obj->rgn->rects->top = obj->rgn->extents.top = top;
344 obj->rgn->rects->right = obj->rgn->extents.right = right;
345 obj->rgn->rects->bottom = obj->rgn->extents.bottom = bottom;
346 obj->rgn->numRects = 1;
347 obj->rgn->type = SIMPLEREGION;
349 else
350 EMPTY_REGION(obj->rgn);
352 GDI_HEAP_UNLOCK( hrgn );
356 /***********************************************************************
357 * CreateRoundRectRgn16 (GDI.444)
359 * If either ellipse dimension is zero we call CreateRectRgn16 for its
360 * `special' behaviour. -ve ellipse dimensions can result in GPFs under win3.1
361 * we just let CreateRoundRectRgn32 convert them to +ve values.
364 HRGN16 WINAPI CreateRoundRectRgn16( INT16 left, INT16 top,
365 INT16 right, INT16 bottom,
366 INT16 ellipse_width, INT16 ellipse_height )
368 if( ellipse_width == 0 || ellipse_height == 0 )
369 return CreateRectRgn16( left, top, right, bottom );
370 else
371 return (HRGN16)CreateRoundRectRgn( left, top, right, bottom,
372 ellipse_width, ellipse_height );
375 /***********************************************************************
376 * CreateRoundRectRgn32 (GDI32.61)
378 HRGN WINAPI CreateRoundRectRgn( INT left, INT top,
379 INT right, INT bottom,
380 INT ellipse_width, INT ellipse_height )
382 RGNOBJ * obj;
383 HRGN hrgn;
384 int asq, bsq, d, xd, yd;
385 RECT rect;
387 /* Check if we can do a normal rectangle instead */
389 if ((ellipse_width == 0) || (ellipse_height == 0))
390 return CreateRectRgn( left, top, right, bottom );
392 /* Make the dimensions sensible */
394 if (left > right) { INT tmp = left; left = right; right = tmp; }
395 if (top > bottom) { INT tmp = top; top = bottom; bottom = tmp; }
397 ellipse_width = abs(ellipse_width);
398 ellipse_height = abs(ellipse_height);
400 /* Create region */
402 if (!(hrgn = REGION_CreateRegion())) return 0;
403 obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
404 TRACE(region,"(%d,%d-%d,%d %dx%d): ret=%04x\n",
405 left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
407 /* Check parameters */
409 if (ellipse_width > right-left) ellipse_width = right-left;
410 if (ellipse_height > bottom-top) ellipse_height = bottom-top;
412 /* Ellipse algorithm, based on an article by K. Porter */
413 /* in DDJ Graphics Programming Column, 8/89 */
415 asq = ellipse_width * ellipse_width / 4; /* a^2 */
416 bsq = ellipse_height * ellipse_height / 4; /* b^2 */
417 d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
418 xd = 0;
419 yd = asq * ellipse_height; /* 2a^2b */
421 rect.left = left + ellipse_width / 2;
422 rect.right = right - ellipse_width / 2;
424 /* Loop to draw first half of quadrant */
426 while (xd < yd)
428 if (d > 0) /* if nearest pixel is toward the center */
430 /* move toward center */
431 rect.top = top++;
432 rect.bottom = rect.top + 1;
433 REGION_UnionRectWithRegion( &rect, obj->rgn );
434 rect.top = --bottom;
435 rect.bottom = rect.top + 1;
436 REGION_UnionRectWithRegion( &rect, obj->rgn );
437 yd -= 2*asq;
438 d -= yd;
440 rect.left--; /* next horiz point */
441 rect.right++;
442 xd += 2*bsq;
443 d += bsq + xd;
446 /* Loop to draw second half of quadrant */
448 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
449 while (yd >= 0)
451 /* next vertical point */
452 rect.top = top++;
453 rect.bottom = rect.top + 1;
454 REGION_UnionRectWithRegion( &rect, obj->rgn );
455 rect.top = --bottom;
456 rect.bottom = rect.top + 1;
457 REGION_UnionRectWithRegion( &rect, obj->rgn );
458 if (d < 0) /* if nearest pixel is outside ellipse */
460 rect.left--; /* move away from center */
461 rect.right++;
462 xd += 2*bsq;
463 d += xd;
465 yd -= 2*asq;
466 d += asq - yd;
469 /* Add the inside rectangle */
471 if (top <= bottom)
473 rect.top = top;
474 rect.bottom = bottom;
475 REGION_UnionRectWithRegion( &rect, obj->rgn );
477 obj->rgn->type = SIMPLEREGION; /* FIXME? */
478 GDI_HEAP_UNLOCK( hrgn );
479 return hrgn;
483 /***********************************************************************
484 * CreateEllipticRgn16 (GDI.54)
486 HRGN16 WINAPI CreateEllipticRgn16( INT16 left, INT16 top,
487 INT16 right, INT16 bottom )
489 return (HRGN16)CreateRoundRectRgn( left, top, right, bottom,
490 right-left, bottom-top );
494 /***********************************************************************
495 * CreateEllipticRgn32 (GDI32.39)
497 HRGN WINAPI CreateEllipticRgn( INT left, INT top,
498 INT right, INT bottom )
500 return CreateRoundRectRgn( left, top, right, bottom,
501 right-left, bottom-top );
505 /***********************************************************************
506 * CreateEllipticRgnIndirect16 (GDI.55)
508 HRGN16 WINAPI CreateEllipticRgnIndirect16( const RECT16 *rect )
510 return CreateRoundRectRgn( rect->left, rect->top, rect->right,
511 rect->bottom, rect->right - rect->left,
512 rect->bottom - rect->top );
516 /***********************************************************************
517 * CreateEllipticRgnIndirect32 (GDI32.40)
519 HRGN WINAPI CreateEllipticRgnIndirect( const RECT *rect )
521 return CreateRoundRectRgn( rect->left, rect->top, rect->right,
522 rect->bottom, rect->right - rect->left,
523 rect->bottom - rect->top );
526 /***********************************************************************
527 * GetRegionData32 (GDI32.217)
530 DWORD WINAPI GetRegionData(HRGN hrgn, DWORD count, LPRGNDATA rgndata)
532 DWORD size;
533 RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
535 TRACE(region, " %04x count = %ld, rgndata = %p\n",
536 hrgn, count, rgndata);
538 if(!obj) return 0;
540 size = obj->rgn->numRects * sizeof(RECT);
541 if(count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
543 GDI_HEAP_UNLOCK( hrgn );
544 return size + sizeof(RGNDATAHEADER);
547 rgndata->rdh.dwSize = sizeof(RGNDATAHEADER);
548 rgndata->rdh.iType = RDH_RECTANGLES;
549 rgndata->rdh.nCount = obj->rgn->numRects;
550 rgndata->rdh.nRgnSize = size;
551 rgndata->rdh.rcBound.left = obj->rgn->extents.left;
552 rgndata->rdh.rcBound.top = obj->rgn->extents.top;
553 rgndata->rdh.rcBound.right = obj->rgn->extents.right;
554 rgndata->rdh.rcBound.bottom = obj->rgn->extents.bottom;
556 memcpy( rgndata->Buffer, obj->rgn->rects, size );
558 GDI_HEAP_UNLOCK( hrgn );
559 return 1;
562 /***********************************************************************
563 * GetRegionData16 (GDI.607)
564 * FIXME: is LPRGNDATA the same in Win16 and Win32 ?
566 DWORD WINAPI GetRegionData16(HRGN16 hrgn, DWORD count, LPRGNDATA rgndata)
568 return GetRegionData((HRGN)hrgn, count, rgndata);
571 /***********************************************************************
572 * ExtCreateRegion (GDI32.94)
575 HRGN WINAPI ExtCreateRegion( const XFORM* lpXform, DWORD dwCount, const RGNDATA* rgndata)
577 HRGN hrgn = CreateRectRgn(0, 0, 0, 0);
578 RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
579 RECT *pCurRect, *pEndRect;
581 TRACE(region, " %p %ld %p. Returning %04x\n",
582 lpXform, dwCount, rgndata, hrgn);
583 if(!hrgn)
585 WARN(region, "Can't create a region!\n");
586 return 0;
588 if(lpXform)
589 WARN(region, "Xform not implemented - ignoring\n");
591 if(rgndata->rdh.iType != RDH_RECTANGLES)
593 WARN(region, "Type not RDH_RECTANGLES\n");
594 GDI_HEAP_UNLOCK( hrgn );
595 DeleteObject( hrgn );
596 return 0;
599 pEndRect = (RECT *)rgndata->Buffer + rgndata->rdh.nCount;
600 for(pCurRect = (RECT *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
601 REGION_UnionRectWithRegion( pCurRect, obj->rgn );
603 GDI_HEAP_UNLOCK( hrgn );
604 return hrgn;
607 /***********************************************************************
608 * PtInRegion16 (GDI.161)
610 BOOL16 WINAPI PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
612 return PtInRegion( hrgn, x, y );
616 /***********************************************************************
617 * PtInRegion32 (GDI32.278)
619 BOOL WINAPI PtInRegion( HRGN hrgn, INT x, INT y )
621 RGNOBJ * obj;
623 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
625 BOOL ret = FALSE;
626 int i;
628 if (obj->rgn->numRects > 0 && INRECT(obj->rgn->extents, x, y))
629 for (i = 0; i < obj->rgn->numRects; i++)
630 if (INRECT (obj->rgn->rects[i], x, y))
631 ret = TRUE;
632 GDI_HEAP_UNLOCK( hrgn );
633 return ret;
635 return FALSE;
639 /***********************************************************************
640 * RectInRegion16 (GDI.181)
642 BOOL16 WINAPI RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
644 RECT r32;
646 CONV_RECT16TO32(rect, &r32);
647 return (BOOL16)RectInRegion(hrgn, &r32);
651 /***********************************************************************
652 * RectInRegion32 (GDI32.281)
654 * Returns TRUE if rect is at least partly inside hrgn
656 BOOL WINAPI RectInRegion( HRGN hrgn, const RECT *rect )
658 RGNOBJ * obj;
660 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
662 RECT *pCurRect, *pRectEnd;
663 BOOL ret = FALSE;
665 /* this is (just) a useful optimization */
666 if ((obj->rgn->numRects > 0) && EXTENTCHECK(&obj->rgn->extents,
667 rect))
669 for (pCurRect = obj->rgn->rects, pRectEnd = pCurRect +
670 obj->rgn->numRects; pCurRect < pRectEnd; pCurRect++)
672 if (pCurRect->bottom <= rect->top)
673 continue; /* not far enough down yet */
675 if (pCurRect->top >= rect->bottom) {
676 ret = FALSE; /* too far down */
677 break;
680 if (pCurRect->right <= rect->left)
681 continue; /* not far enough over yet */
683 if (pCurRect->left >= rect->right) {
684 continue;
687 ret = TRUE;
688 break;
691 GDI_HEAP_UNLOCK(hrgn);
692 return ret;
694 return FALSE;
697 /***********************************************************************
698 * EqualRgn16 (GDI.72)
700 BOOL16 WINAPI EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
702 return EqualRgn( rgn1, rgn2 );
706 /***********************************************************************
707 * EqualRgn32 (GDI32.90)
709 BOOL WINAPI EqualRgn( HRGN hrgn1, HRGN hrgn2 )
711 RGNOBJ *obj1, *obj2;
712 BOOL ret = FALSE;
714 if ((obj1 = (RGNOBJ *) GDI_GetObjPtr( hrgn1, REGION_MAGIC )))
716 if ((obj2 = (RGNOBJ *) GDI_GetObjPtr( hrgn2, REGION_MAGIC )))
718 int i;
720 ret = TRUE;
721 if ( obj1->rgn->numRects != obj2->rgn->numRects ) ret = FALSE;
722 else if ( obj1->rgn->numRects == 0 ) ret = TRUE;
723 else if ( !EqualRect(&obj1->rgn->extents, &obj2->rgn->extents) )
724 ret = FALSE;
725 else for( i = 0; i < obj1->rgn->numRects; i++ ) {
726 if (!EqualRect(obj1->rgn->rects + i, obj2->rgn->rects + i)) {
727 ret = FALSE;
728 break;
731 GDI_HEAP_UNLOCK(hrgn2);
733 GDI_HEAP_UNLOCK(hrgn1);
735 return ret;
737 /***********************************************************************
738 * REGION_UnionRectWithRegion
739 * Adds a rectangle to a WINEREGION
740 * See below for REGION_UnionRectWithRgn
742 static void REGION_UnionRectWithRegion(const RECT *rect, WINEREGION *rgn)
744 WINEREGION region;
746 region.rects = &region.extents;
747 region.numRects = 1;
748 region.size = 1;
749 region.type = SIMPLEREGION;
750 CopyRect(&(region.extents), rect);
751 REGION_UnionRegion(rgn, rgn, &region);
752 return;
755 /***********************************************************************
756 * REGION_UnionRectWithRgn
757 * Adds a rectangle to a HRGN32
758 * A helper used by scroll.c
760 BOOL REGION_UnionRectWithRgn( HRGN hrgn, const RECT *lpRect )
762 RGNOBJ *obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
764 if(!obj) return FALSE;
765 REGION_UnionRectWithRegion( lpRect, obj->rgn );
766 GDI_HEAP_UNLOCK(hrgn);
767 return TRUE;
770 /***********************************************************************
771 * REGION_CreateFrameRgn
773 * Create a region that is a frame around another region.
774 * Expand all rectangles by +/- x and y, then subtract original region.
776 BOOL REGION_FrameRgn( HRGN hDest, HRGN hSrc, INT x, INT y )
778 BOOL bRet;
779 RGNOBJ *srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
781 if (srcObj->rgn->numRects != 0)
783 RGNOBJ* destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
784 RECT *pRect, *pEndRect;
785 RECT tempRect;
787 EMPTY_REGION( destObj->rgn );
789 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
790 for(pRect = srcObj->rgn->rects; pRect < pEndRect; pRect++)
792 tempRect.left = pRect->left - x;
793 tempRect.top = pRect->top - y;
794 tempRect.right = pRect->right + x;
795 tempRect.bottom = pRect->bottom + y;
796 REGION_UnionRectWithRegion( &tempRect, destObj->rgn );
798 REGION_SubtractRegion( destObj->rgn, destObj->rgn, srcObj->rgn );
799 GDI_HEAP_UNLOCK ( hDest );
800 bRet = TRUE;
802 else
803 bRet = FALSE;
804 GDI_HEAP_UNLOCK( hSrc );
805 return bRet;
808 /***********************************************************************
809 * REGION_LPTODP
811 * Convert region to device co-ords for the supplied dc.
812 * Used by X11DRV_PaintRgn.
814 BOOL REGION_LPTODP( HDC hdc, HRGN hDest, HRGN hSrc )
816 RECT *pCurRect, *pEndRect;
817 RGNOBJ *srcObj, *destObj;
818 DC * dc = DC_GetDCPtr( hdc );
819 RECT tmpRect;
821 TRACE(region, " hdc=%04x dest=%04x src=%04x\n",
822 hdc, hDest, hSrc) ;
824 if (dc->w.MapMode == MM_TEXT) /* Requires only a translation */
826 if( CombineRgn( hDest, hSrc, 0, RGN_COPY ) == ERROR ) return FALSE;
827 OffsetRgn( hDest, dc->vportOrgX - dc->wndOrgX,
828 dc->vportOrgY - dc->wndOrgY );
829 return TRUE;
832 if(!( srcObj = (RGNOBJ *) GDI_GetObjPtr( hSrc, REGION_MAGIC) ))
833 return FALSE;
834 if(!( destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC) ))
836 GDI_HEAP_UNLOCK( hSrc );
837 return FALSE;
839 EMPTY_REGION( destObj->rgn );
841 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
842 for(pCurRect = srcObj->rgn->rects; pCurRect < pEndRect; pCurRect++)
844 tmpRect = *pCurRect;
845 tmpRect.left = XLPTODP( dc, tmpRect.left );
846 tmpRect.top = YLPTODP( dc, tmpRect.top );
847 tmpRect.right = XLPTODP( dc, tmpRect.right );
848 tmpRect.bottom = YLPTODP( dc, tmpRect.bottom );
849 REGION_UnionRectWithRegion( &tmpRect, destObj->rgn );
852 GDI_HEAP_UNLOCK( hDest );
853 GDI_HEAP_UNLOCK( hSrc );
854 return TRUE;
857 /***********************************************************************
858 * CombineRgn16 (GDI.451)
860 INT16 WINAPI CombineRgn16(HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode)
862 return (INT16)CombineRgn( hDest, hSrc1, hSrc2, mode );
866 /***********************************************************************
867 * CombineRgn32 (GDI32.19)
869 * Note: The behavior is correct even if src and dest regions are the same.
871 INT WINAPI CombineRgn(HRGN hDest, HRGN hSrc1, HRGN hSrc2, INT mode)
873 RGNOBJ *destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC);
874 INT result = ERROR;
876 TRACE(region, " %04x,%04x -> %04x mode=%x\n",
877 hSrc1, hSrc2, hDest, mode );
878 if (destObj)
880 RGNOBJ *src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC);
882 if (src1Obj)
884 TRACE(region, "dump:\n");
885 if(TRACE_ON(region))
886 REGION_DumpRegion(src1Obj->rgn);
887 if (mode == RGN_COPY)
889 REGION_CopyRegion( destObj->rgn, src1Obj->rgn );
890 result = destObj->rgn->type;
892 else
894 RGNOBJ *src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC);
896 if (src2Obj)
898 TRACE(region, "dump:\n");
899 if(TRACE_ON(region))
900 REGION_DumpRegion(src2Obj->rgn);
901 switch (mode)
903 case RGN_AND:
904 REGION_IntersectRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn);
905 break;
906 case RGN_OR:
907 REGION_UnionRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
908 break;
909 case RGN_XOR:
910 REGION_XorRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
911 break;
912 case RGN_DIFF:
913 REGION_SubtractRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
914 break;
916 result = destObj->rgn->type;
917 GDI_HEAP_UNLOCK( hSrc2 );
920 GDI_HEAP_UNLOCK( hSrc1 );
922 TRACE(region, "dump:\n");
923 if(TRACE_ON(region))
924 REGION_DumpRegion(destObj->rgn);
926 GDI_HEAP_UNLOCK( hDest );
928 return result;
931 /***********************************************************************
932 * REGION_SetExtents
933 * Re-calculate the extents of a region
935 static void REGION_SetExtents (WINEREGION *pReg)
937 RECT *pRect, *pRectEnd, *pExtents;
939 if (pReg->numRects == 0)
941 pReg->extents.left = 0;
942 pReg->extents.top = 0;
943 pReg->extents.right = 0;
944 pReg->extents.bottom = 0;
945 return;
948 pExtents = &pReg->extents;
949 pRect = pReg->rects;
950 pRectEnd = &pRect[pReg->numRects - 1];
953 * Since pRect is the first rectangle in the region, it must have the
954 * smallest top and since pRectEnd is the last rectangle in the region,
955 * it must have the largest bottom, because of banding. Initialize left and
956 * right from pRect and pRectEnd, resp., as good things to initialize them
957 * to...
959 pExtents->left = pRect->left;
960 pExtents->top = pRect->top;
961 pExtents->right = pRectEnd->right;
962 pExtents->bottom = pRectEnd->bottom;
964 while (pRect <= pRectEnd)
966 if (pRect->left < pExtents->left)
967 pExtents->left = pRect->left;
968 if (pRect->right > pExtents->right)
969 pExtents->right = pRect->right;
970 pRect++;
974 /***********************************************************************
975 * REGION_CopyRegion
977 static void REGION_CopyRegion(WINEREGION *dst, WINEREGION *src)
979 if (dst != src) /* don't want to copy to itself */
981 if (dst->size < src->numRects)
983 if (! (dst->rects = HeapReAlloc( SystemHeap, 0, dst->rects,
984 src->numRects * sizeof(RECT) )))
985 return;
986 dst->size = src->numRects;
988 dst->numRects = src->numRects;
989 dst->extents.left = src->extents.left;
990 dst->extents.top = src->extents.top;
991 dst->extents.right = src->extents.right;
992 dst->extents.bottom = src->extents.bottom;
993 dst->type = src->type;
995 memcpy((char *) dst->rects, (char *) src->rects,
996 (int) (src->numRects * sizeof(RECT)));
998 return;
1001 /***********************************************************************
1002 * REGION_Coalesce
1004 * Attempt to merge the rects in the current band with those in the
1005 * previous one. Used only by REGION_RegionOp.
1007 * Results:
1008 * The new index for the previous band.
1010 * Side Effects:
1011 * If coalescing takes place:
1012 * - rectangles in the previous band will have their bottom fields
1013 * altered.
1014 * - pReg->numRects will be decreased.
1017 static INT REGION_Coalesce (
1018 WINEREGION *pReg, /* Region to coalesce */
1019 INT prevStart, /* Index of start of previous band */
1020 INT curStart /* Index of start of current band */
1022 RECT *pPrevRect; /* Current rect in previous band */
1023 RECT *pCurRect; /* Current rect in current band */
1024 RECT *pRegEnd; /* End of region */
1025 INT curNumRects; /* Number of rectangles in current band */
1026 INT prevNumRects; /* Number of rectangles in previous band */
1027 INT bandtop; /* top coordinate for current band */
1029 pRegEnd = &pReg->rects[pReg->numRects];
1031 pPrevRect = &pReg->rects[prevStart];
1032 prevNumRects = curStart - prevStart;
1035 * Figure out how many rectangles are in the current band. Have to do
1036 * this because multiple bands could have been added in REGION_RegionOp
1037 * at the end when one region has been exhausted.
1039 pCurRect = &pReg->rects[curStart];
1040 bandtop = pCurRect->top;
1041 for (curNumRects = 0;
1042 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
1043 curNumRects++)
1045 pCurRect++;
1048 if (pCurRect != pRegEnd)
1051 * If more than one band was added, we have to find the start
1052 * of the last band added so the next coalescing job can start
1053 * at the right place... (given when multiple bands are added,
1054 * this may be pointless -- see above).
1056 pRegEnd--;
1057 while (pRegEnd[-1].top == pRegEnd->top)
1059 pRegEnd--;
1061 curStart = pRegEnd - pReg->rects;
1062 pRegEnd = pReg->rects + pReg->numRects;
1065 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
1066 pCurRect -= curNumRects;
1068 * The bands may only be coalesced if the bottom of the previous
1069 * matches the top scanline of the current.
1071 if (pPrevRect->bottom == pCurRect->top)
1074 * Make sure the bands have rects in the same places. This
1075 * assumes that rects have been added in such a way that they
1076 * cover the most area possible. I.e. two rects in a band must
1077 * have some horizontal space between them.
1081 if ((pPrevRect->left != pCurRect->left) ||
1082 (pPrevRect->right != pCurRect->right))
1085 * The bands don't line up so they can't be coalesced.
1087 return (curStart);
1089 pPrevRect++;
1090 pCurRect++;
1091 prevNumRects -= 1;
1092 } while (prevNumRects != 0);
1094 pReg->numRects -= curNumRects;
1095 pCurRect -= curNumRects;
1096 pPrevRect -= curNumRects;
1099 * The bands may be merged, so set the bottom of each rect
1100 * in the previous band to that of the corresponding rect in
1101 * the current band.
1105 pPrevRect->bottom = pCurRect->bottom;
1106 pPrevRect++;
1107 pCurRect++;
1108 curNumRects -= 1;
1109 } while (curNumRects != 0);
1112 * If only one band was added to the region, we have to backup
1113 * curStart to the start of the previous band.
1115 * If more than one band was added to the region, copy the
1116 * other bands down. The assumption here is that the other bands
1117 * came from the same region as the current one and no further
1118 * coalescing can be done on them since it's all been done
1119 * already... curStart is already in the right place.
1121 if (pCurRect == pRegEnd)
1123 curStart = prevStart;
1125 else
1129 *pPrevRect++ = *pCurRect++;
1130 } while (pCurRect != pRegEnd);
1135 return (curStart);
1138 /***********************************************************************
1139 * REGION_RegionOp
1141 * Apply an operation to two regions. Called by REGION_Union,
1142 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
1144 * Results:
1145 * None.
1147 * Side Effects:
1148 * The new region is overwritten.
1150 * Notes:
1151 * The idea behind this function is to view the two regions as sets.
1152 * Together they cover a rectangle of area that this function divides
1153 * into horizontal bands where points are covered only by one region
1154 * or by both. For the first case, the nonOverlapFunc is called with
1155 * each the band and the band's upper and lower extents. For the
1156 * second, the overlapFunc is called to process the entire band. It
1157 * is responsible for clipping the rectangles in the band, though
1158 * this function provides the boundaries.
1159 * At the end of each band, the new region is coalesced, if possible,
1160 * to reduce the number of rectangles in the region.
1163 static void REGION_RegionOp(
1164 WINEREGION *newReg, /* Place to store result */
1165 WINEREGION *reg1, /* First region in operation */
1166 WINEREGION *reg2, /* 2nd region in operation */
1167 void (*overlapFunc)(), /* Function to call for over-lapping bands */
1168 void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
1169 void (*nonOverlap2Func)() /* Function to call for non-overlapping bands in region 2 */
1171 RECT *r1; /* Pointer into first region */
1172 RECT *r2; /* Pointer into 2d region */
1173 RECT *r1End; /* End of 1st region */
1174 RECT *r2End; /* End of 2d region */
1175 INT ybot; /* Bottom of intersection */
1176 INT ytop; /* Top of intersection */
1177 RECT *oldRects; /* Old rects for newReg */
1178 INT prevBand; /* Index of start of
1179 * previous band in newReg */
1180 INT curBand; /* Index of start of current
1181 * band in newReg */
1182 RECT *r1BandEnd; /* End of current band in r1 */
1183 RECT *r2BandEnd; /* End of current band in r2 */
1184 INT top; /* Top of non-overlapping band */
1185 INT bot; /* Bottom of non-overlapping band */
1188 * Initialization:
1189 * set r1, r2, r1End and r2End appropriately, preserve the important
1190 * parts of the destination region until the end in case it's one of
1191 * the two source regions, then mark the "new" region empty, allocating
1192 * another array of rectangles for it to use.
1194 r1 = reg1->rects;
1195 r2 = reg2->rects;
1196 r1End = r1 + reg1->numRects;
1197 r2End = r2 + reg2->numRects;
1201 * newReg may be one of the src regions so we can't empty it. We keep a
1202 * note of its rects pointer (so that we can free them later), preserve its
1203 * extents and simply set numRects to zero.
1206 oldRects = newReg->rects;
1207 newReg->numRects = 0;
1210 * Allocate a reasonable number of rectangles for the new region. The idea
1211 * is to allocate enough so the individual functions don't need to
1212 * reallocate and copy the array, which is time consuming, yet we don't
1213 * have to worry about using too much memory. I hope to be able to
1214 * nuke the Xrealloc() at the end of this function eventually.
1216 newReg->size = MAX(reg1->numRects,reg2->numRects) * 2;
1218 if (! (newReg->rects = HeapAlloc( SystemHeap, 0,
1219 sizeof(RECT) * newReg->size )))
1221 newReg->size = 0;
1222 return;
1226 * Initialize ybot and ytop.
1227 * In the upcoming loop, ybot and ytop serve different functions depending
1228 * on whether the band being handled is an overlapping or non-overlapping
1229 * band.
1230 * In the case of a non-overlapping band (only one of the regions
1231 * has points in the band), ybot is the bottom of the most recent
1232 * intersection and thus clips the top of the rectangles in that band.
1233 * ytop is the top of the next intersection between the two regions and
1234 * serves to clip the bottom of the rectangles in the current band.
1235 * For an overlapping band (where the two regions intersect), ytop clips
1236 * the top of the rectangles of both regions and ybot clips the bottoms.
1238 if (reg1->extents.top < reg2->extents.top)
1239 ybot = reg1->extents.top;
1240 else
1241 ybot = reg2->extents.top;
1244 * prevBand serves to mark the start of the previous band so rectangles
1245 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1246 * In the beginning, there is no previous band, so prevBand == curBand
1247 * (curBand is set later on, of course, but the first band will always
1248 * start at index 0). prevBand and curBand must be indices because of
1249 * the possible expansion, and resultant moving, of the new region's
1250 * array of rectangles.
1252 prevBand = 0;
1256 curBand = newReg->numRects;
1259 * This algorithm proceeds one source-band (as opposed to a
1260 * destination band, which is determined by where the two regions
1261 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1262 * rectangle after the last one in the current band for their
1263 * respective regions.
1265 r1BandEnd = r1;
1266 while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
1268 r1BandEnd++;
1271 r2BandEnd = r2;
1272 while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
1274 r2BandEnd++;
1278 * First handle the band that doesn't intersect, if any.
1280 * Note that attention is restricted to one band in the
1281 * non-intersecting region at once, so if a region has n
1282 * bands between the current position and the next place it overlaps
1283 * the other, this entire loop will be passed through n times.
1285 if (r1->top < r2->top)
1287 top = MAX(r1->top,ybot);
1288 bot = MIN(r1->bottom,r2->top);
1290 if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
1292 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
1295 ytop = r2->top;
1297 else if (r2->top < r1->top)
1299 top = MAX(r2->top,ybot);
1300 bot = MIN(r2->bottom,r1->top);
1302 if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
1304 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
1307 ytop = r1->top;
1309 else
1311 ytop = r1->top;
1315 * If any rectangles got added to the region, try and coalesce them
1316 * with rectangles from the previous band. Note we could just do
1317 * this test in miCoalesce, but some machines incur a not
1318 * inconsiderable cost for function calls, so...
1320 if (newReg->numRects != curBand)
1322 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1326 * Now see if we've hit an intersecting band. The two bands only
1327 * intersect if ybot > ytop
1329 ybot = MIN(r1->bottom, r2->bottom);
1330 curBand = newReg->numRects;
1331 if (ybot > ytop)
1333 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1337 if (newReg->numRects != curBand)
1339 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1343 * If we've finished with a band (bottom == ybot) we skip forward
1344 * in the region to the next band.
1346 if (r1->bottom == ybot)
1348 r1 = r1BandEnd;
1350 if (r2->bottom == ybot)
1352 r2 = r2BandEnd;
1354 } while ((r1 != r1End) && (r2 != r2End));
1357 * Deal with whichever region still has rectangles left.
1359 curBand = newReg->numRects;
1360 if (r1 != r1End)
1362 if (nonOverlap1Func != (void (*)())NULL)
1366 r1BandEnd = r1;
1367 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
1369 r1BandEnd++;
1371 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
1372 MAX(r1->top,ybot), r1->bottom);
1373 r1 = r1BandEnd;
1374 } while (r1 != r1End);
1377 else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
1381 r2BandEnd = r2;
1382 while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
1384 r2BandEnd++;
1386 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
1387 MAX(r2->top,ybot), r2->bottom);
1388 r2 = r2BandEnd;
1389 } while (r2 != r2End);
1392 if (newReg->numRects != curBand)
1394 (void) REGION_Coalesce (newReg, prevBand, curBand);
1398 * A bit of cleanup. To keep regions from growing without bound,
1399 * we shrink the array of rectangles to match the new number of
1400 * rectangles in the region. This never goes to 0, however...
1402 * Only do this stuff if the number of rectangles allocated is more than
1403 * twice the number of rectangles in the region (a simple optimization...).
1405 if (newReg->numRects < (newReg->size >> 1))
1407 if (REGION_NOT_EMPTY(newReg))
1409 RECT *prev_rects = newReg->rects;
1410 newReg->size = newReg->numRects;
1411 newReg->rects = HeapReAlloc( SystemHeap, 0, newReg->rects,
1412 sizeof(RECT) * newReg->size );
1413 if (! newReg->rects)
1414 newReg->rects = prev_rects;
1416 else
1419 * No point in doing the extra work involved in an Xrealloc if
1420 * the region is empty
1422 newReg->size = 1;
1423 HeapFree( SystemHeap, 0, newReg->rects );
1424 newReg->rects = HeapAlloc( SystemHeap, 0, sizeof(RECT) );
1427 HeapFree( SystemHeap, 0, oldRects );
1428 return;
1431 /***********************************************************************
1432 * Region Intersection
1433 ***********************************************************************/
1436 /***********************************************************************
1437 * REGION_IntersectO
1439 * Handle an overlapping band for REGION_Intersect.
1441 * Results:
1442 * None.
1444 * Side Effects:
1445 * Rectangles may be added to the region.
1448 static void REGION_IntersectO(WINEREGION *pReg, RECT *r1, RECT *r1End,
1449 RECT *r2, RECT *r2End, INT top, INT bottom)
1452 INT left, right;
1453 RECT *pNextRect;
1455 pNextRect = &pReg->rects[pReg->numRects];
1457 while ((r1 != r1End) && (r2 != r2End))
1459 left = MAX(r1->left, r2->left);
1460 right = MIN(r1->right, r2->right);
1463 * If there's any overlap between the two rectangles, add that
1464 * overlap to the new region.
1465 * There's no need to check for subsumption because the only way
1466 * such a need could arise is if some region has two rectangles
1467 * right next to each other. Since that should never happen...
1469 if (left < right)
1471 MEMCHECK(pReg, pNextRect, pReg->rects);
1472 pNextRect->left = left;
1473 pNextRect->top = top;
1474 pNextRect->right = right;
1475 pNextRect->bottom = bottom;
1476 pReg->numRects += 1;
1477 pNextRect++;
1481 * Need to advance the pointers. Shift the one that extends
1482 * to the right the least, since the other still has a chance to
1483 * overlap with that region's next rectangle, if you see what I mean.
1485 if (r1->right < r2->right)
1487 r1++;
1489 else if (r2->right < r1->right)
1491 r2++;
1493 else
1495 r1++;
1496 r2++;
1499 return;
1502 /***********************************************************************
1503 * REGION_IntersectRegion
1505 static void REGION_IntersectRegion(WINEREGION *newReg, WINEREGION *reg1,
1506 WINEREGION *reg2)
1508 /* check for trivial reject */
1509 if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
1510 (!EXTENTCHECK(&reg1->extents, &reg2->extents)))
1511 newReg->numRects = 0;
1512 else
1513 REGION_RegionOp (newReg, reg1, reg2,
1514 (voidProcp) REGION_IntersectO, (voidProcp) NULL, (voidProcp) NULL);
1517 * Can't alter newReg's extents before we call miRegionOp because
1518 * it might be one of the source regions and miRegionOp depends
1519 * on the extents of those regions being the same. Besides, this
1520 * way there's no checking against rectangles that will be nuked
1521 * due to coalescing, so we have to examine fewer rectangles.
1523 REGION_SetExtents(newReg);
1524 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1525 return;
1528 /***********************************************************************
1529 * Region Union
1530 ***********************************************************************/
1532 /***********************************************************************
1533 * REGION_UnionNonO
1535 * Handle a non-overlapping band for the union operation. Just
1536 * Adds the rectangles into the region. Doesn't have to check for
1537 * subsumption or anything.
1539 * Results:
1540 * None.
1542 * Side Effects:
1543 * pReg->numRects is incremented and the final rectangles overwritten
1544 * with the rectangles we're passed.
1547 static void REGION_UnionNonO (WINEREGION *pReg, RECT *r, RECT *rEnd,
1548 INT top, INT bottom)
1550 RECT *pNextRect;
1552 pNextRect = &pReg->rects[pReg->numRects];
1554 while (r != rEnd)
1556 MEMCHECK(pReg, pNextRect, pReg->rects);
1557 pNextRect->left = r->left;
1558 pNextRect->top = top;
1559 pNextRect->right = r->right;
1560 pNextRect->bottom = bottom;
1561 pReg->numRects += 1;
1562 pNextRect++;
1563 r++;
1565 return;
1568 /***********************************************************************
1569 * REGION_UnionO
1571 * Handle an overlapping band for the union operation. Picks the
1572 * left-most rectangle each time and merges it into the region.
1574 * Results:
1575 * None.
1577 * Side Effects:
1578 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1579 * be changed.
1582 static void REGION_UnionO (WINEREGION *pReg, RECT *r1, RECT *r1End,
1583 RECT *r2, RECT *r2End, INT top, INT bottom)
1585 RECT *pNextRect;
1587 pNextRect = &pReg->rects[pReg->numRects];
1589 #define MERGERECT(r) \
1590 if ((pReg->numRects != 0) && \
1591 (pNextRect[-1].top == top) && \
1592 (pNextRect[-1].bottom == bottom) && \
1593 (pNextRect[-1].right >= r->left)) \
1595 if (pNextRect[-1].right < r->right) \
1597 pNextRect[-1].right = r->right; \
1600 else \
1602 MEMCHECK(pReg, pNextRect, pReg->rects); \
1603 pNextRect->top = top; \
1604 pNextRect->bottom = bottom; \
1605 pNextRect->left = r->left; \
1606 pNextRect->right = r->right; \
1607 pReg->numRects += 1; \
1608 pNextRect += 1; \
1610 r++;
1612 while ((r1 != r1End) && (r2 != r2End))
1614 if (r1->left < r2->left)
1616 MERGERECT(r1);
1618 else
1620 MERGERECT(r2);
1624 if (r1 != r1End)
1628 MERGERECT(r1);
1629 } while (r1 != r1End);
1631 else while (r2 != r2End)
1633 MERGERECT(r2);
1635 return;
1638 /***********************************************************************
1639 * REGION_UnionRegion
1641 static void REGION_UnionRegion(WINEREGION *newReg, WINEREGION *reg1,
1642 WINEREGION *reg2)
1644 /* checks all the simple cases */
1647 * Region 1 and 2 are the same or region 1 is empty
1649 if ( (reg1 == reg2) || (!(reg1->numRects)) )
1651 if (newReg != reg2)
1652 REGION_CopyRegion(newReg, reg2);
1653 return;
1657 * if nothing to union (region 2 empty)
1659 if (!(reg2->numRects))
1661 if (newReg != reg1)
1662 REGION_CopyRegion(newReg, reg1);
1663 return;
1667 * Region 1 completely subsumes region 2
1669 if ((reg1->numRects == 1) &&
1670 (reg1->extents.left <= reg2->extents.left) &&
1671 (reg1->extents.top <= reg2->extents.top) &&
1672 (reg1->extents.right >= reg2->extents.right) &&
1673 (reg1->extents.bottom >= reg2->extents.bottom))
1675 if (newReg != reg1)
1676 REGION_CopyRegion(newReg, reg1);
1677 return;
1681 * Region 2 completely subsumes region 1
1683 if ((reg2->numRects == 1) &&
1684 (reg2->extents.left <= reg1->extents.left) &&
1685 (reg2->extents.top <= reg1->extents.top) &&
1686 (reg2->extents.right >= reg1->extents.right) &&
1687 (reg2->extents.bottom >= reg1->extents.bottom))
1689 if (newReg != reg2)
1690 REGION_CopyRegion(newReg, reg2);
1691 return;
1694 REGION_RegionOp (newReg, reg1, reg2, (voidProcp) REGION_UnionO,
1695 (voidProcp) REGION_UnionNonO, (voidProcp) REGION_UnionNonO);
1697 newReg->extents.left = MIN(reg1->extents.left, reg2->extents.left);
1698 newReg->extents.top = MIN(reg1->extents.top, reg2->extents.top);
1699 newReg->extents.right = MAX(reg1->extents.right, reg2->extents.right);
1700 newReg->extents.bottom = MAX(reg1->extents.bottom, reg2->extents.bottom);
1701 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1702 return;
1705 /***********************************************************************
1706 * Region Subtraction
1707 ***********************************************************************/
1709 /***********************************************************************
1710 * REGION_SubtractNonO1
1712 * Deal with non-overlapping band for subtraction. Any parts from
1713 * region 2 we discard. Anything from region 1 we add to the region.
1715 * Results:
1716 * None.
1718 * Side Effects:
1719 * pReg may be affected.
1722 static void REGION_SubtractNonO1 (WINEREGION *pReg, RECT *r, RECT *rEnd,
1723 INT top, INT bottom)
1725 RECT *pNextRect;
1727 pNextRect = &pReg->rects[pReg->numRects];
1729 while (r != rEnd)
1731 MEMCHECK(pReg, pNextRect, pReg->rects);
1732 pNextRect->left = r->left;
1733 pNextRect->top = top;
1734 pNextRect->right = r->right;
1735 pNextRect->bottom = bottom;
1736 pReg->numRects += 1;
1737 pNextRect++;
1738 r++;
1740 return;
1744 /***********************************************************************
1745 * REGION_SubtractO
1747 * Overlapping band subtraction. x1 is the left-most point not yet
1748 * checked.
1750 * Results:
1751 * None.
1753 * Side Effects:
1754 * pReg may have rectangles added to it.
1757 static void REGION_SubtractO (WINEREGION *pReg, RECT *r1, RECT *r1End,
1758 RECT *r2, RECT *r2End, INT top, INT bottom)
1760 RECT *pNextRect;
1761 INT left;
1763 left = r1->left;
1764 pNextRect = &pReg->rects[pReg->numRects];
1766 while ((r1 != r1End) && (r2 != r2End))
1768 if (r2->right <= left)
1771 * Subtrahend missed the boat: go to next subtrahend.
1773 r2++;
1775 else if (r2->left <= left)
1778 * Subtrahend preceeds minuend: nuke left edge of minuend.
1780 left = r2->right;
1781 if (left >= r1->right)
1784 * Minuend completely covered: advance to next minuend and
1785 * reset left fence to edge of new minuend.
1787 r1++;
1788 if (r1 != r1End)
1789 left = r1->left;
1791 else
1794 * Subtrahend now used up since it doesn't extend beyond
1795 * minuend
1797 r2++;
1800 else if (r2->left < r1->right)
1803 * Left part of subtrahend covers part of minuend: add uncovered
1804 * part of minuend to region and skip to next subtrahend.
1806 MEMCHECK(pReg, pNextRect, pReg->rects);
1807 pNextRect->left = left;
1808 pNextRect->top = top;
1809 pNextRect->right = r2->left;
1810 pNextRect->bottom = bottom;
1811 pReg->numRects += 1;
1812 pNextRect++;
1813 left = r2->right;
1814 if (left >= r1->right)
1817 * Minuend used up: advance to new...
1819 r1++;
1820 if (r1 != r1End)
1821 left = r1->left;
1823 else
1826 * Subtrahend used up
1828 r2++;
1831 else
1834 * Minuend used up: add any remaining piece before advancing.
1836 if (r1->right > left)
1838 MEMCHECK(pReg, pNextRect, pReg->rects);
1839 pNextRect->left = left;
1840 pNextRect->top = top;
1841 pNextRect->right = r1->right;
1842 pNextRect->bottom = bottom;
1843 pReg->numRects += 1;
1844 pNextRect++;
1846 r1++;
1847 left = r1->left;
1852 * Add remaining minuend rectangles to region.
1854 while (r1 != r1End)
1856 MEMCHECK(pReg, pNextRect, pReg->rects);
1857 pNextRect->left = left;
1858 pNextRect->top = top;
1859 pNextRect->right = r1->right;
1860 pNextRect->bottom = bottom;
1861 pReg->numRects += 1;
1862 pNextRect++;
1863 r1++;
1864 if (r1 != r1End)
1866 left = r1->left;
1869 return;
1872 /***********************************************************************
1873 * REGION_SubtractRegion
1875 * Subtract regS from regM and leave the result in regD.
1876 * S stands for subtrahend, M for minuend and D for difference.
1878 * Results:
1879 * TRUE.
1881 * Side Effects:
1882 * regD is overwritten.
1885 static void REGION_SubtractRegion(WINEREGION *regD, WINEREGION *regM,
1886 WINEREGION *regS )
1888 /* check for trivial reject */
1889 if ( (!(regM->numRects)) || (!(regS->numRects)) ||
1890 (!EXTENTCHECK(&regM->extents, &regS->extents)) )
1892 REGION_CopyRegion(regD, regM);
1893 return;
1896 REGION_RegionOp (regD, regM, regS, (voidProcp) REGION_SubtractO,
1897 (voidProcp) REGION_SubtractNonO1, (voidProcp) NULL);
1900 * Can't alter newReg's extents before we call miRegionOp because
1901 * it might be one of the source regions and miRegionOp depends
1902 * on the extents of those regions being the unaltered. Besides, this
1903 * way there's no checking against rectangles that will be nuked
1904 * due to coalescing, so we have to examine fewer rectangles.
1906 REGION_SetExtents (regD);
1907 regD->type = (regD->numRects) ? COMPLEXREGION : NULLREGION ;
1908 return;
1911 /***********************************************************************
1912 * REGION_XorRegion
1914 static void REGION_XorRegion(WINEREGION *dr, WINEREGION *sra,
1915 WINEREGION *srb)
1917 WINEREGION *tra, *trb;
1919 if ((! (tra = REGION_AllocWineRegion())) ||
1920 (! (trb = REGION_AllocWineRegion())))
1921 return;
1922 REGION_SubtractRegion(tra,sra,srb);
1923 REGION_SubtractRegion(trb,srb,sra);
1924 REGION_UnionRegion(dr,tra,trb);
1925 REGION_DestroyWineRegion(tra);
1926 REGION_DestroyWineRegion(trb);
1927 return;
1930 /**************************************************************************
1932 * Poly Regions
1934 *************************************************************************/
1936 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
1937 #define SMALL_COORDINATE 0x80000000
1939 /***********************************************************************
1940 * REGION_InsertEdgeInET
1942 * Insert the given edge into the edge table.
1943 * First we must find the correct bucket in the
1944 * Edge table, then find the right slot in the
1945 * bucket. Finally, we can insert it.
1948 static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
1949 INT scanline, ScanLineListBlock **SLLBlock, INT *iSLLBlock)
1952 EdgeTableEntry *start, *prev;
1953 ScanLineList *pSLL, *pPrevSLL;
1954 ScanLineListBlock *tmpSLLBlock;
1957 * find the right bucket to put the edge into
1959 pPrevSLL = &ET->scanlines;
1960 pSLL = pPrevSLL->next;
1961 while (pSLL && (pSLL->scanline < scanline))
1963 pPrevSLL = pSLL;
1964 pSLL = pSLL->next;
1968 * reassign pSLL (pointer to ScanLineList) if necessary
1970 if ((!pSLL) || (pSLL->scanline > scanline))
1972 if (*iSLLBlock > SLLSPERBLOCK-1)
1974 tmpSLLBlock = HeapAlloc( SystemHeap, 0, sizeof(ScanLineListBlock));
1975 if(!tmpSLLBlock)
1977 WARN(region, "Can't alloc SLLB\n");
1978 return;
1980 (*SLLBlock)->next = tmpSLLBlock;
1981 tmpSLLBlock->next = (ScanLineListBlock *)NULL;
1982 *SLLBlock = tmpSLLBlock;
1983 *iSLLBlock = 0;
1985 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
1987 pSLL->next = pPrevSLL->next;
1988 pSLL->edgelist = (EdgeTableEntry *)NULL;
1989 pPrevSLL->next = pSLL;
1991 pSLL->scanline = scanline;
1994 * now insert the edge in the right bucket
1996 prev = (EdgeTableEntry *)NULL;
1997 start = pSLL->edgelist;
1998 while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
2000 prev = start;
2001 start = start->next;
2003 ETE->next = start;
2005 if (prev)
2006 prev->next = ETE;
2007 else
2008 pSLL->edgelist = ETE;
2011 /***********************************************************************
2012 * REGION_CreateEdgeTable
2014 * This routine creates the edge table for
2015 * scan converting polygons.
2016 * The Edge Table (ET) looks like:
2018 * EdgeTable
2019 * --------
2020 * | ymax | ScanLineLists
2021 * |scanline|-->------------>-------------->...
2022 * -------- |scanline| |scanline|
2023 * |edgelist| |edgelist|
2024 * --------- ---------
2025 * | |
2026 * | |
2027 * V V
2028 * list of ETEs list of ETEs
2030 * where ETE is an EdgeTableEntry data structure,
2031 * and there is one ScanLineList per scanline at
2032 * which an edge is initially entered.
2035 static void REGION_CreateETandAET(const INT *Count, INT nbpolygons,
2036 const POINT *pts, EdgeTable *ET, EdgeTableEntry *AET,
2037 EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
2039 const POINT *top, *bottom;
2040 const POINT *PrevPt, *CurrPt, *EndPt;
2041 INT poly, count;
2042 int iSLLBlock = 0;
2043 int dy;
2047 * initialize the Active Edge Table
2049 AET->next = (EdgeTableEntry *)NULL;
2050 AET->back = (EdgeTableEntry *)NULL;
2051 AET->nextWETE = (EdgeTableEntry *)NULL;
2052 AET->bres.minor_axis = SMALL_COORDINATE;
2055 * initialize the Edge Table.
2057 ET->scanlines.next = (ScanLineList *)NULL;
2058 ET->ymax = SMALL_COORDINATE;
2059 ET->ymin = LARGE_COORDINATE;
2060 pSLLBlock->next = (ScanLineListBlock *)NULL;
2062 EndPt = pts - 1;
2063 for(poly = 0; poly < nbpolygons; poly++)
2065 count = Count[poly];
2066 EndPt += count;
2067 if(count < 2)
2068 continue;
2070 PrevPt = EndPt;
2073 * for each vertex in the array of points.
2074 * In this loop we are dealing with two vertices at
2075 * a time -- these make up one edge of the polygon.
2077 while (count--)
2079 CurrPt = pts++;
2082 * find out which point is above and which is below.
2084 if (PrevPt->y > CurrPt->y)
2086 bottom = PrevPt, top = CurrPt;
2087 pETEs->ClockWise = 0;
2089 else
2091 bottom = CurrPt, top = PrevPt;
2092 pETEs->ClockWise = 1;
2096 * don't add horizontal edges to the Edge table.
2098 if (bottom->y != top->y)
2100 pETEs->ymax = bottom->y-1;
2101 /* -1 so we don't get last scanline */
2104 * initialize integer edge algorithm
2106 dy = bottom->y - top->y;
2107 BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
2109 REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
2110 &iSLLBlock);
2112 if (PrevPt->y > ET->ymax)
2113 ET->ymax = PrevPt->y;
2114 if (PrevPt->y < ET->ymin)
2115 ET->ymin = PrevPt->y;
2116 pETEs++;
2119 PrevPt = CurrPt;
2124 /***********************************************************************
2125 * REGION_loadAET
2127 * This routine moves EdgeTableEntries from the
2128 * EdgeTable into the Active Edge Table,
2129 * leaving them sorted by smaller x coordinate.
2132 static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
2134 EdgeTableEntry *pPrevAET;
2135 EdgeTableEntry *tmp;
2137 pPrevAET = AET;
2138 AET = AET->next;
2139 while (ETEs)
2141 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
2143 pPrevAET = AET;
2144 AET = AET->next;
2146 tmp = ETEs->next;
2147 ETEs->next = AET;
2148 if (AET)
2149 AET->back = ETEs;
2150 ETEs->back = pPrevAET;
2151 pPrevAET->next = ETEs;
2152 pPrevAET = ETEs;
2154 ETEs = tmp;
2158 /***********************************************************************
2159 * REGION_computeWAET
2161 * This routine links the AET by the
2162 * nextWETE (winding EdgeTableEntry) link for
2163 * use by the winding number rule. The final
2164 * Active Edge Table (AET) might look something
2165 * like:
2167 * AET
2168 * ---------- --------- ---------
2169 * |ymax | |ymax | |ymax |
2170 * | ... | |... | |... |
2171 * |next |->|next |->|next |->...
2172 * |nextWETE| |nextWETE| |nextWETE|
2173 * --------- --------- ^--------
2174 * | | |
2175 * V-------------------> V---> ...
2178 static void REGION_computeWAET(EdgeTableEntry *AET)
2180 register EdgeTableEntry *pWETE;
2181 register int inside = 1;
2182 register int isInside = 0;
2184 AET->nextWETE = (EdgeTableEntry *)NULL;
2185 pWETE = AET;
2186 AET = AET->next;
2187 while (AET)
2189 if (AET->ClockWise)
2190 isInside++;
2191 else
2192 isInside--;
2194 if ((!inside && !isInside) ||
2195 ( inside && isInside))
2197 pWETE->nextWETE = AET;
2198 pWETE = AET;
2199 inside = !inside;
2201 AET = AET->next;
2203 pWETE->nextWETE = (EdgeTableEntry *)NULL;
2206 /***********************************************************************
2207 * REGION_InsertionSort
2209 * Just a simple insertion sort using
2210 * pointers and back pointers to sort the Active
2211 * Edge Table.
2214 static BOOL REGION_InsertionSort(EdgeTableEntry *AET)
2216 EdgeTableEntry *pETEchase;
2217 EdgeTableEntry *pETEinsert;
2218 EdgeTableEntry *pETEchaseBackTMP;
2219 BOOL changed = FALSE;
2221 AET = AET->next;
2222 while (AET)
2224 pETEinsert = AET;
2225 pETEchase = AET;
2226 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
2227 pETEchase = pETEchase->back;
2229 AET = AET->next;
2230 if (pETEchase != pETEinsert)
2232 pETEchaseBackTMP = pETEchase->back;
2233 pETEinsert->back->next = AET;
2234 if (AET)
2235 AET->back = pETEinsert->back;
2236 pETEinsert->next = pETEchase;
2237 pETEchase->back->next = pETEinsert;
2238 pETEchase->back = pETEinsert;
2239 pETEinsert->back = pETEchaseBackTMP;
2240 changed = TRUE;
2243 return changed;
2246 /***********************************************************************
2247 * REGION_FreeStorage
2249 * Clean up our act.
2251 static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
2253 ScanLineListBlock *tmpSLLBlock;
2255 while (pSLLBlock)
2257 tmpSLLBlock = pSLLBlock->next;
2258 HeapFree( SystemHeap, 0, pSLLBlock );
2259 pSLLBlock = tmpSLLBlock;
2264 /***********************************************************************
2265 * REGION_PtsToRegion
2267 * Create an array of rectangles from a list of points.
2269 static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
2270 POINTBLOCK *FirstPtBlock, WINEREGION *reg)
2272 RECT *rects;
2273 POINT *pts;
2274 POINTBLOCK *CurPtBlock;
2275 int i;
2276 RECT *extents;
2277 INT numRects;
2279 extents = &reg->extents;
2281 numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
2283 if (!(reg->rects = HeapReAlloc( SystemHeap, 0, reg->rects,
2284 sizeof(RECT) * numRects )))
2285 return(0);
2287 reg->size = numRects;
2288 CurPtBlock = FirstPtBlock;
2289 rects = reg->rects - 1;
2290 numRects = 0;
2291 extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
2293 for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
2294 /* the loop uses 2 points per iteration */
2295 i = NUMPTSTOBUFFER >> 1;
2296 if (!numFullPtBlocks)
2297 i = iCurPtBlock >> 1;
2298 for (pts = CurPtBlock->pts; i--; pts += 2) {
2299 if (pts->x == pts[1].x)
2300 continue;
2301 if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
2302 pts[1].x == rects->right &&
2303 (numRects == 1 || rects[-1].top != rects->top) &&
2304 (i && pts[2].y > pts[1].y)) {
2305 rects->bottom = pts[1].y + 1;
2306 continue;
2308 numRects++;
2309 rects++;
2310 rects->left = pts->x; rects->top = pts->y;
2311 rects->right = pts[1].x; rects->bottom = pts[1].y + 1;
2312 if (rects->left < extents->left)
2313 extents->left = rects->left;
2314 if (rects->right > extents->right)
2315 extents->right = rects->right;
2317 CurPtBlock = CurPtBlock->next;
2320 if (numRects) {
2321 extents->top = reg->rects->top;
2322 extents->bottom = rects->bottom;
2323 } else {
2324 extents->left = 0;
2325 extents->top = 0;
2326 extents->right = 0;
2327 extents->bottom = 0;
2329 reg->numRects = numRects;
2331 return(TRUE);
2334 /***********************************************************************
2335 * CreatePolyPolygonRgn32 (GDI32.57)
2337 HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count,
2338 INT nbpolygons, INT mode)
2340 HRGN hrgn;
2341 RGNOBJ *obj;
2342 WINEREGION *region;
2343 register EdgeTableEntry *pAET; /* Active Edge Table */
2344 register INT y; /* current scanline */
2345 register int iPts = 0; /* number of pts in buffer */
2346 register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
2347 register ScanLineList *pSLL; /* current scanLineList */
2348 register POINT *pts; /* output buffer */
2349 EdgeTableEntry *pPrevAET; /* ptr to previous AET */
2350 EdgeTable ET; /* header node for ET */
2351 EdgeTableEntry AET; /* header node for AET */
2352 EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
2353 ScanLineListBlock SLLBlock; /* header for scanlinelist */
2354 int fixWAET = FALSE;
2355 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
2356 POINTBLOCK *tmpPtBlock;
2357 int numFullPtBlocks = 0;
2358 INT poly, total;
2360 if(!(hrgn = REGION_CreateRegion()))
2361 return 0;
2362 obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
2363 region = obj->rgn;
2365 /* special case a rectangle */
2367 if (((nbpolygons == 1) && ((*Count == 4) ||
2368 ((*Count == 5) && (Pts[4].x == Pts[0].x) && (Pts[4].y == Pts[0].y)))) &&
2369 (((Pts[0].y == Pts[1].y) &&
2370 (Pts[1].x == Pts[2].x) &&
2371 (Pts[2].y == Pts[3].y) &&
2372 (Pts[3].x == Pts[0].x)) ||
2373 ((Pts[0].x == Pts[1].x) &&
2374 (Pts[1].y == Pts[2].y) &&
2375 (Pts[2].x == Pts[3].x) &&
2376 (Pts[3].y == Pts[0].y))))
2378 SetRectRgn( hrgn, MIN(Pts[0].x, Pts[2].x), MIN(Pts[0].y, Pts[2].y),
2379 MAX(Pts[0].x, Pts[2].x), MAX(Pts[0].y, Pts[2].y) );
2380 GDI_HEAP_UNLOCK( hrgn );
2381 return hrgn;
2384 for(poly = total = 0; poly < nbpolygons; poly++)
2385 total += Count[poly];
2386 if (! (pETEs = HeapAlloc( SystemHeap, 0, sizeof(EdgeTableEntry) * total )))
2388 REGION_DeleteObject( hrgn, obj );
2389 return 0;
2391 pts = FirstPtBlock.pts;
2392 REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
2393 pSLL = ET.scanlines.next;
2394 curPtBlock = &FirstPtBlock;
2396 if (mode != WINDING) {
2398 * for each scanline
2400 for (y = ET.ymin; y < ET.ymax; y++) {
2402 * Add a new edge to the active edge table when we
2403 * get to the next edge.
2405 if (pSLL != NULL && y == pSLL->scanline) {
2406 REGION_loadAET(&AET, pSLL->edgelist);
2407 pSLL = pSLL->next;
2409 pPrevAET = &AET;
2410 pAET = AET.next;
2413 * for each active edge
2415 while (pAET) {
2416 pts->x = pAET->bres.minor_axis, pts->y = y;
2417 pts++, iPts++;
2420 * send out the buffer
2422 if (iPts == NUMPTSTOBUFFER) {
2423 tmpPtBlock = HeapAlloc( SystemHeap, 0, sizeof(POINTBLOCK));
2424 if(!tmpPtBlock) {
2425 WARN(region, "Can't alloc tPB\n");
2426 return 0;
2428 curPtBlock->next = tmpPtBlock;
2429 curPtBlock = tmpPtBlock;
2430 pts = curPtBlock->pts;
2431 numFullPtBlocks++;
2432 iPts = 0;
2434 EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
2436 REGION_InsertionSort(&AET);
2439 else {
2441 * for each scanline
2443 for (y = ET.ymin; y < ET.ymax; y++) {
2445 * Add a new edge to the active edge table when we
2446 * get to the next edge.
2448 if (pSLL != NULL && y == pSLL->scanline) {
2449 REGION_loadAET(&AET, pSLL->edgelist);
2450 REGION_computeWAET(&AET);
2451 pSLL = pSLL->next;
2453 pPrevAET = &AET;
2454 pAET = AET.next;
2455 pWETE = pAET;
2458 * for each active edge
2460 while (pAET) {
2462 * add to the buffer only those edges that
2463 * are in the Winding active edge table.
2465 if (pWETE == pAET) {
2466 pts->x = pAET->bres.minor_axis, pts->y = y;
2467 pts++, iPts++;
2470 * send out the buffer
2472 if (iPts == NUMPTSTOBUFFER) {
2473 tmpPtBlock = HeapAlloc( SystemHeap, 0,
2474 sizeof(POINTBLOCK) );
2475 if(!tmpPtBlock) {
2476 WARN(region, "Can't alloc tPB\n");
2477 return 0;
2479 curPtBlock->next = tmpPtBlock;
2480 curPtBlock = tmpPtBlock;
2481 pts = curPtBlock->pts;
2482 numFullPtBlocks++; iPts = 0;
2484 pWETE = pWETE->nextWETE;
2486 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
2490 * recompute the winding active edge table if
2491 * we just resorted or have exited an edge.
2493 if (REGION_InsertionSort(&AET) || fixWAET) {
2494 REGION_computeWAET(&AET);
2495 fixWAET = FALSE;
2499 REGION_FreeStorage(SLLBlock.next);
2500 REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
2501 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
2502 tmpPtBlock = curPtBlock->next;
2503 HeapFree( SystemHeap, 0, curPtBlock );
2504 curPtBlock = tmpPtBlock;
2506 HeapFree( SystemHeap, 0, pETEs );
2507 GDI_HEAP_UNLOCK( hrgn );
2508 return hrgn;
2512 /***********************************************************************
2513 * CreatePolygonRgn16 (GDI.63)
2515 HRGN16 WINAPI CreatePolygonRgn16( const POINT16 * points, INT16 count,
2516 INT16 mode )
2518 return CreatePolyPolygonRgn16( points, &count, 1, mode );
2521 /***********************************************************************
2522 * CreatePolyPolygonRgn16 (GDI.451)
2524 HRGN16 WINAPI CreatePolyPolygonRgn16( const POINT16 *points,
2525 const INT16 *count, INT16 nbpolygons, INT16 mode )
2527 HRGN hrgn;
2528 int i, npts = 0;
2529 INT *count32;
2530 POINT *points32;
2532 for (i = 0; i < nbpolygons; i++)
2533 npts += count[i];
2534 points32 = HeapAlloc( SystemHeap, 0, npts * sizeof(POINT) );
2535 for (i = 0; i < npts; i++)
2536 CONV_POINT16TO32( &(points[i]), &(points32[i]) );
2538 count32 = HeapAlloc( SystemHeap, 0, nbpolygons * sizeof(INT) );
2539 for (i = 0; i < nbpolygons; i++)
2540 count32[i] = count[i];
2541 hrgn = CreatePolyPolygonRgn( points32, count32, nbpolygons, mode );
2542 HeapFree( SystemHeap, 0, count32 );
2543 HeapFree( SystemHeap, 0, points32 );
2544 return hrgn;
2547 /***********************************************************************
2548 * CreatePolygonRgn32 (GDI32.58)
2550 HRGN WINAPI CreatePolygonRgn( const POINT *points, INT count,
2551 INT mode )
2553 return CreatePolyPolygonRgn( points, &count, 1, mode );
2557 /***********************************************************************
2558 * GetRandomRgn [GDI32.215]
2560 * NOTES
2561 * This function is UNDOCUMENTED, it isn't even in the header file.
2562 * I assume that it will return a HRGN32!??
2564 HRGN WINAPI GetRandomRgn(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3)
2566 FIXME (region, "(0x%08lx 0x%08lx 0x%08lx): empty stub!\n",
2567 dwArg1, dwArg2, dwArg3);
2569 return 0;