Release 980601
[wine.git] / objects / region.c
blob6c79e1ef3b15282a8f67b04de1349e946e71779b
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 "region.h"
84 #include "debug.h"
85 #include "heap.h"
86 #include "dc.h"
88 typedef void (*voidProcp)();
90 /* Note the parameter order is different from the X11 equivalents */
92 static void REGION_CopyRegion(WINEREGION *d, WINEREGION *s);
93 static void REGION_IntersectRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
94 static void REGION_UnionRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
95 static void REGION_SubtractRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
96 static void REGION_XorRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
97 static void REGION_UnionRectWithRegion(const RECT32 *rect, WINEREGION *rgn);
100 /***********************************************************************
101 * REGION_DumpRegion
102 * Outputs the contents of a WINEREGION
104 static void REGION_DumpRegion(WINEREGION *pReg)
106 RECT32 *pRect, *pRectEnd = pReg->rects + pReg->numRects;
108 TRACE(region, "Region %p: %d,%d - %d,%d %d rects\n", pReg,
109 pReg->extents.left, pReg->extents.top,
110 pReg->extents.right, pReg->extents.bottom, pReg->numRects);
111 for(pRect = pReg->rects; pRect < pRectEnd; pRect++)
112 TRACE(region, "\t%d,%d - %d,%d\n", pRect->left, pRect->top,
113 pRect->right, pRect->bottom);
114 return;
117 /***********************************************************************
118 * REGION_AllocWineRegion
119 * Create a new empty WINEREGION.
121 static WINEREGION *REGION_AllocWineRegion( void )
123 WINEREGION *pReg;
125 if (!(pReg = HeapAlloc(SystemHeap, 0, sizeof( WINEREGION ))))
126 return NULL;
127 if (!(pReg->rects = HeapAlloc(SystemHeap, 0, sizeof( RECT32 ))))
129 HeapFree(SystemHeap, 0, pReg);
130 return NULL;
132 pReg->size = 1;
133 EMPTY_REGION(pReg);
134 return pReg;
137 /***********************************************************************
138 * REGION_CreateRegion
139 * Create a new empty region.
141 static HRGN32 REGION_CreateRegion(void)
143 HRGN32 hrgn;
144 RGNOBJ *obj;
146 if(!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
147 return 0;
148 obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
149 if(!(obj->rgn = REGION_AllocWineRegion())) {
150 GDI_FreeObject( hrgn );
151 return 0;
153 GDI_HEAP_UNLOCK( hrgn );
154 return hrgn;
157 /***********************************************************************
158 * REGION_DestroyWineRegion
160 static void REGION_DestroyWineRegion( WINEREGION* pReg )
162 HeapFree( SystemHeap, 0, pReg->rects );
163 HeapFree( SystemHeap, 0, pReg );
164 return;
167 /***********************************************************************
168 * REGION_DeleteObject
170 BOOL32 REGION_DeleteObject( HRGN32 hrgn, RGNOBJ * obj )
172 TRACE(region, " %04x\n", hrgn );
174 REGION_DestroyWineRegion( obj->rgn );
175 return GDI_FreeObject( hrgn );
178 /***********************************************************************
179 * OffsetRgn16 (GDI.101)
181 INT16 WINAPI OffsetRgn16( HRGN16 hrgn, INT16 x, INT16 y )
183 return OffsetRgn32( hrgn, x, y );
186 /***********************************************************************
187 * OffsetRgn32 (GDI32.256)
189 INT32 WINAPI OffsetRgn32( HRGN32 hrgn, INT32 x, INT32 y )
191 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
193 if (obj)
195 INT32 ret;
196 int nbox = obj->rgn->numRects;
197 RECT32 *pbox = obj->rgn->rects;
199 TRACE(region, " %04x %d,%d\n", hrgn, x, y );
200 if(nbox && (x || y)) {
201 while(nbox--) {
202 pbox->left += x;
203 pbox->right += x;
204 pbox->top += y;
205 pbox->bottom += y;
206 pbox++;
208 obj->rgn->extents.left += x;
209 obj->rgn->extents.right += x;
210 obj->rgn->extents.top += y;
211 obj->rgn->extents.bottom += y;
213 ret = obj->rgn->type;
214 GDI_HEAP_UNLOCK( hrgn );
215 return ret;
217 return ERROR;
221 /***********************************************************************
222 * GetRgnBox16 (GDI.134)
224 INT16 WINAPI GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
226 RECT32 r;
227 INT16 ret = (INT16)GetRgnBox32( hrgn, &r );
228 CONV_RECT32TO16( &r, rect );
229 return ret;
232 /***********************************************************************
233 * GetRgnBox32 (GDI32.219)
235 INT32 WINAPI GetRgnBox32( HRGN32 hrgn, LPRECT32 rect )
237 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
238 if (obj)
240 INT32 ret;
241 TRACE(region, " %04x\n", hrgn );
242 rect->left = obj->rgn->extents.left;
243 rect->top = obj->rgn->extents.top;
244 rect->right = obj->rgn->extents.right;
245 rect->bottom = obj->rgn->extents.bottom;
246 ret = obj->rgn->type;
247 GDI_HEAP_UNLOCK(hrgn);
248 return ret;
250 return ERROR;
254 /***********************************************************************
255 * CreateRectRgn16 (GDI.64)
257 HRGN16 WINAPI CreateRectRgn16(INT16 left, INT16 top, INT16 right, INT16 bottom)
259 return (HRGN16)CreateRectRgn32( left, top, right, bottom );
263 /***********************************************************************
264 * CreateRectRgn32 (GDI32.59)
266 HRGN32 WINAPI CreateRectRgn32(INT32 left, INT32 top, INT32 right, INT32 bottom)
268 HRGN32 hrgn;
270 if (!(hrgn = REGION_CreateRegion()))
271 return 0;
272 TRACE(region, " \n");
273 SetRectRgn32(hrgn, left, top, right, bottom);
274 return hrgn;
277 /***********************************************************************
278 * CreateRectRgnIndirect16 (GDI.65)
280 HRGN16 WINAPI CreateRectRgnIndirect16( const RECT16* rect )
282 return CreateRectRgn32( rect->left, rect->top, rect->right, rect->bottom );
286 /***********************************************************************
287 * CreateRectRgnIndirect32 (GDI32.60)
289 HRGN32 WINAPI CreateRectRgnIndirect32( const RECT32* rect )
291 return CreateRectRgn32( rect->left, rect->top, rect->right, rect->bottom );
295 /***********************************************************************
296 * SetRectRgn16 (GDI.172)
298 VOID WINAPI SetRectRgn16( HRGN16 hrgn, INT16 left, INT16 top,
299 INT16 right, INT16 bottom )
301 SetRectRgn32( hrgn, left, top, right, bottom );
305 /***********************************************************************
306 * SetRectRgn32 (GDI32.332)
308 VOID WINAPI SetRectRgn32( HRGN32 hrgn, INT32 left, INT32 top,
309 INT32 right, INT32 bottom )
311 RGNOBJ * obj;
313 TRACE(region, " %04x %d,%d-%d,%d\n",
314 hrgn, left, top, right, bottom );
316 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
317 if ((right > left) && (bottom > top))
319 obj->rgn->rects->left = obj->rgn->extents.left = left;
320 obj->rgn->rects->top = obj->rgn->extents.top = top;
321 obj->rgn->rects->right = obj->rgn->extents.right = right;
322 obj->rgn->rects->bottom = obj->rgn->extents.bottom = bottom;
323 obj->rgn->numRects = 1;
324 obj->rgn->type = SIMPLEREGION;
326 else
327 EMPTY_REGION(obj->rgn);
329 GDI_HEAP_UNLOCK( hrgn );
333 /***********************************************************************
334 * CreateRoundRectRgn16 (GDI.444)
336 HRGN16 WINAPI CreateRoundRectRgn16( INT16 left, INT16 top,
337 INT16 right, INT16 bottom,
338 INT16 ellipse_width, INT16 ellipse_height )
340 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
341 ellipse_width, ellipse_height );
344 /***********************************************************************
345 * CreateRoundRectRgn32 (GDI32.61)
347 HRGN32 WINAPI CreateRoundRectRgn32( INT32 left, INT32 top,
348 INT32 right, INT32 bottom,
349 INT32 ellipse_width, INT32 ellipse_height )
351 RGNOBJ * obj;
352 HRGN32 hrgn;
353 int asq, bsq, d, xd, yd;
354 RECT32 rect;
356 /* Check if we can do a normal rectangle instead */
358 if ((right <= left) || (bottom <= top) ||
359 (ellipse_width <= 0) || (ellipse_height <= 0))
360 return CreateRectRgn32( left, top, right, bottom );
362 /* Create region */
364 if (!(hrgn = REGION_CreateRegion())) return 0;
365 obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
366 TRACE(region,"(%d,%d-%d,%d %dx%d): ret=%04x\n",
367 left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
369 /* Check parameters */
371 if (ellipse_width > right-left) ellipse_width = right-left;
372 if (ellipse_height > bottom-top) ellipse_height = bottom-top;
374 /* Ellipse algorithm, based on an article by K. Porter */
375 /* in DDJ Graphics Programming Column, 8/89 */
377 asq = ellipse_width * ellipse_width / 4; /* a^2 */
378 bsq = ellipse_height * ellipse_height / 4; /* b^2 */
379 d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
380 xd = 0;
381 yd = asq * ellipse_height; /* 2a^2b */
383 rect.left = left + ellipse_width / 2;
384 rect.right = right - ellipse_width;
386 /* Loop to draw first half of quadrant */
388 while (xd < yd)
390 if (d > 0) /* if nearest pixel is toward the center */
392 /* move toward center */
393 rect.top = top++;
394 rect.bottom = rect.top + 1;
395 REGION_UnionRectWithRegion( &rect, obj->rgn );
396 rect.top = --bottom;
397 rect.bottom = rect.top + 1;
398 REGION_UnionRectWithRegion( &rect, obj->rgn );
399 yd -= 2*asq;
400 d -= yd;
402 rect.left--; /* next horiz point */
403 rect.right++;
404 xd += 2*bsq;
405 d += bsq + xd;
408 /* Loop to draw second half of quadrant */
410 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
411 while (yd >= 0)
413 /* next vertical point */
414 rect.top = top++;
415 rect.bottom = rect.top + 1;
416 REGION_UnionRectWithRegion( &rect, obj->rgn );
417 rect.top = --bottom;
418 rect.bottom = rect.top + 1;
419 REGION_UnionRectWithRegion( &rect, obj->rgn );
420 if (d < 0) /* if nearest pixel is outside ellipse */
422 rect.left--; /* move away from center */
423 rect.right++;
424 xd += 2*bsq;
425 d += xd;
427 yd -= 2*asq;
428 d += asq - yd;
431 /* Add the inside rectangle */
433 if (top <= bottom)
435 rect.top = top;
436 rect.bottom = bottom;
437 REGION_UnionRectWithRegion( &rect, obj->rgn );
439 obj->rgn->type = SIMPLEREGION; /* FIXME? */
440 GDI_HEAP_UNLOCK( hrgn );
441 return hrgn;
445 /***********************************************************************
446 * CreateEllipticRgn16 (GDI.54)
448 HRGN16 WINAPI CreateEllipticRgn16( INT16 left, INT16 top,
449 INT16 right, INT16 bottom )
451 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
452 right-left, bottom-top );
456 /***********************************************************************
457 * CreateEllipticRgn32 (GDI32.39)
459 HRGN32 WINAPI CreateEllipticRgn32( INT32 left, INT32 top,
460 INT32 right, INT32 bottom )
462 return CreateRoundRectRgn32( left, top, right, bottom,
463 right-left, bottom-top );
467 /***********************************************************************
468 * CreateEllipticRgnIndirect16 (GDI.55)
470 HRGN16 WINAPI CreateEllipticRgnIndirect16( const RECT16 *rect )
472 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
473 rect->bottom, rect->right - rect->left,
474 rect->bottom - rect->top );
478 /***********************************************************************
479 * CreateEllipticRgnIndirect32 (GDI32.40)
481 HRGN32 WINAPI CreateEllipticRgnIndirect32( const RECT32 *rect )
483 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
484 rect->bottom, rect->right - rect->left,
485 rect->bottom - rect->top );
488 /***********************************************************************
489 * GetRegionData (GDI32.217)
492 DWORD WINAPI GetRegionData(HRGN32 hrgn, DWORD count, LPRGNDATA rgndata)
494 DWORD size;
495 RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
497 TRACE(region, " %04x count = %ld, rgndata = %p\n",
498 hrgn, count, rgndata);
500 if(!obj) return 0;
502 size = obj->rgn->numRects * sizeof(RECT32);
503 if(count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
505 GDI_HEAP_UNLOCK( hrgn );
506 return size + sizeof(RGNDATAHEADER);
509 rgndata->rdh.dwSize = sizeof(RGNDATAHEADER);
510 rgndata->rdh.iType = RDH_RECTANGLES;
511 rgndata->rdh.nCount = obj->rgn->numRects;
512 rgndata->rdh.nRgnSize = size;
513 rgndata->rdh.rcBound.left = obj->rgn->extents.left;
514 rgndata->rdh.rcBound.top = obj->rgn->extents.top;
515 rgndata->rdh.rcBound.right = obj->rgn->extents.right;
516 rgndata->rdh.rcBound.bottom = obj->rgn->extents.bottom;
518 memcpy( rgndata->Buffer, obj->rgn->rects, size );
520 GDI_HEAP_UNLOCK( hrgn );
521 return 1;
524 /***********************************************************************
525 * ExtCreateRegion (GDI32.94)
528 HRGN32 WINAPI ExtCreateRegion( XFORM *lpXform, DWORD dwCount, RGNDATA *rgndata)
530 HRGN32 hrgn = CreateRectRgn32(0, 0, 0, 0);
531 RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
532 RECT32 *pCurRect, *pEndRect;
534 TRACE(region, " %p %ld %p. Returning %04x\n",
535 lpXform, dwCount, rgndata, hrgn);
536 if(!hrgn)
538 WARN(region, "Can't create a region!\n");
539 return 0;
541 if(lpXform)
542 WARN(region, "Xform not implemented - ignoring\n");
544 if(rgndata->rdh.iType != RDH_RECTANGLES)
546 WARN(region, "Type not RDH_RECTANGLES\n");
547 GDI_HEAP_UNLOCK( hrgn );
548 DeleteObject32( hrgn );
549 return 0;
552 pEndRect = (RECT32 *)rgndata->Buffer + rgndata->rdh.nCount;
553 for(pCurRect = (RECT32 *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
554 REGION_UnionRectWithRegion( pCurRect, obj->rgn );
556 GDI_HEAP_UNLOCK( hrgn );
557 return hrgn;
560 /***********************************************************************
561 * PtInRegion16 (GDI.161)
563 BOOL16 WINAPI PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
565 return PtInRegion32( hrgn, x, y );
569 /***********************************************************************
570 * PtInRegion32 (GDI32.278)
572 BOOL32 WINAPI PtInRegion32( HRGN32 hrgn, INT32 x, INT32 y )
574 RGNOBJ * obj;
576 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
578 BOOL32 ret = FALSE;
579 int i;
581 if (obj->rgn->numRects > 0 && INRECT(obj->rgn->extents, x, y))
582 for (i = 0; i < obj->rgn->numRects; i++)
583 if (INRECT (obj->rgn->rects[i], x, y))
584 ret = TRUE;
585 GDI_HEAP_UNLOCK( hrgn );
586 return ret;
588 return FALSE;
592 /***********************************************************************
593 * RectInRegion16 (GDI.181)
595 BOOL16 WINAPI RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
597 RECT32 r32;
599 CONV_RECT16TO32(rect, &r32);
600 return (BOOL16)RectInRegion32(hrgn, &r32);
604 /***********************************************************************
605 * RectInRegion32 (GDI32.281)
607 * Returns TRUE if rect is at least partly inside hrgn
609 BOOL32 WINAPI RectInRegion32( HRGN32 hrgn, const RECT32 *rect )
611 RGNOBJ * obj;
613 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
615 RECT32 *pCurRect, *pRectEnd;
616 BOOL32 ret = FALSE;
618 /* this is (just) a useful optimization */
619 if ((obj->rgn->numRects > 0) && EXTENTCHECK(&obj->rgn->extents,
620 rect))
622 for (pCurRect = obj->rgn->rects, pRectEnd = pCurRect +
623 obj->rgn->numRects; pCurRect < pRectEnd; pCurRect++)
625 if (pCurRect->bottom <= rect->top)
626 continue; /* not far enough down yet */
628 if (pCurRect->top >= rect->bottom) {
629 ret = FALSE; /* too far down */
630 break;
633 if (pCurRect->right <= rect->left)
634 continue; /* not far enough over yet */
636 if (pCurRect->left >= rect->right) {
637 ret = FALSE; /* too far over */
638 break;
641 ret = TRUE;
642 break;
645 GDI_HEAP_UNLOCK(hrgn);
646 return ret;
648 return FALSE;
651 /***********************************************************************
652 * EqualRgn16 (GDI.72)
654 BOOL16 WINAPI EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
656 return EqualRgn32( rgn1, rgn2 );
660 /***********************************************************************
661 * EqualRgn32 (GDI32.90)
663 BOOL32 WINAPI EqualRgn32( HRGN32 hrgn1, HRGN32 hrgn2 )
665 RGNOBJ *obj1, *obj2;
666 BOOL32 ret = FALSE;
668 if ((obj1 = (RGNOBJ *) GDI_GetObjPtr( hrgn1, REGION_MAGIC )))
670 if ((obj2 = (RGNOBJ *) GDI_GetObjPtr( hrgn2, REGION_MAGIC )))
672 int i;
674 ret = TRUE;
675 if ( obj1->rgn->numRects != obj2->rgn->numRects ) ret = FALSE;
676 else if ( obj1->rgn->numRects == 0 ) ret = TRUE;
677 else if ( !EqualRect32(&obj1->rgn->extents, &obj2->rgn->extents) )
678 ret = FALSE;
679 else for( i = 0; i < obj1->rgn->numRects; i++ ) {
680 if (!EqualRect32(obj1->rgn->rects + i, obj2->rgn->rects + i)) {
681 ret = FALSE;
682 break;
685 GDI_HEAP_UNLOCK(hrgn2);
687 GDI_HEAP_UNLOCK(hrgn1);
689 return ret;
691 /***********************************************************************
692 * REGION_UnionRectWithRegion
693 * Adds a rectangle to a WINEREGION
694 * See below for REGION_UnionRectWithRgn
696 static void REGION_UnionRectWithRegion(const RECT32 *rect, WINEREGION *rgn)
698 WINEREGION region;
700 region.rects = &region.extents;
701 region.numRects = 1;
702 region.size = 1;
703 region.type = SIMPLEREGION;
704 CopyRect32(&(region.extents), rect);
705 REGION_UnionRegion(rgn, rgn, &region);
706 return;
709 /***********************************************************************
710 * REGION_UnionRectWithRgn
711 * Adds a rectangle to a HRGN32
712 * A helper used by scroll.c
714 BOOL32 REGION_UnionRectWithRgn( HRGN32 hrgn, const RECT32 *lpRect )
716 RGNOBJ *obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
718 if(!obj) return FALSE;
719 REGION_UnionRectWithRegion( lpRect, obj->rgn );
720 GDI_HEAP_UNLOCK(hrgn);
721 return TRUE;
724 /***********************************************************************
725 * REGION_CreateFrameRgn
727 * Create a region that is a frame around another region.
728 * Expand all rectangles by +/- x and y, then subtract original region.
730 BOOL32 REGION_FrameRgn( HRGN32 hDest, HRGN32 hSrc, INT32 x, INT32 y )
732 BOOL32 bRet;
733 RGNOBJ *srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
735 if (srcObj->rgn->numRects != 0)
737 RGNOBJ* destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
738 RECT32 *pRect, *pEndRect;
739 RECT32 tempRect;
741 EMPTY_REGION( destObj->rgn );
743 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
744 for(pRect = srcObj->rgn->rects; pRect < pEndRect; pRect++)
746 tempRect.left = pRect->left - x;
747 tempRect.top = pRect->top - y;
748 tempRect.right = pRect->right + x;
749 tempRect.bottom = pRect->bottom + y;
750 REGION_UnionRectWithRegion( &tempRect, destObj->rgn );
752 REGION_SubtractRegion( destObj->rgn, destObj->rgn, srcObj->rgn );
753 GDI_HEAP_UNLOCK ( hDest );
754 bRet = TRUE;
756 else
757 bRet = FALSE;
758 GDI_HEAP_UNLOCK( hSrc );
759 return bRet;
762 /***********************************************************************
763 * REGION_LPTODP
765 * Convert region to device co-ords for the supplied dc.
766 * Used by X11DRV_PaintRgn.
768 BOOL32 REGION_LPTODP( HDC32 hdc, HRGN32 hDest, HRGN32 hSrc )
770 RECT32 *pCurRect, *pEndRect;
771 RGNOBJ *srcObj, *destObj;
772 DC * dc = DC_GetDCPtr( hdc );
773 RECT32 tmpRect;
775 TRACE(region, " hdc=%04x dest=%04x src=%04x\n",
776 hdc, hDest, hSrc) ;
778 if (dc->w.MapMode == MM_TEXT) /* Requires only a translation */
780 if( CombineRgn32( hDest, hSrc, 0, RGN_COPY ) == ERROR ) return FALSE;
781 OffsetRgn32( hDest, dc->vportOrgX - dc->wndOrgX,
782 dc->vportOrgY - dc->wndOrgY );
783 return TRUE;
786 if(!( srcObj = (RGNOBJ *) GDI_GetObjPtr( hSrc, REGION_MAGIC) ))
787 return FALSE;
788 if(!( destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC) ))
790 GDI_HEAP_UNLOCK( hSrc );
791 return FALSE;
793 EMPTY_REGION( destObj->rgn );
795 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
796 for(pCurRect = srcObj->rgn->rects; pCurRect < pEndRect; pCurRect++)
798 tmpRect = *pCurRect;
799 tmpRect.left = XLPTODP( dc, tmpRect.left );
800 tmpRect.top = YLPTODP( dc, tmpRect.top );
801 tmpRect.right = XLPTODP( dc, tmpRect.right );
802 tmpRect.bottom = YLPTODP( dc, tmpRect.bottom );
803 REGION_UnionRectWithRegion( &tmpRect, destObj->rgn );
806 GDI_HEAP_UNLOCK( hDest );
807 GDI_HEAP_UNLOCK( hSrc );
808 return TRUE;
811 /***********************************************************************
812 * CombineRgn16 (GDI.451)
814 INT16 WINAPI CombineRgn16(HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode)
816 return (INT16)CombineRgn32( hDest, hSrc1, hSrc2, mode );
820 /***********************************************************************
821 * CombineRgn32 (GDI32.19)
823 * Note: The behavior is correct even if src and dest regions are the same.
825 INT32 WINAPI CombineRgn32(HRGN32 hDest, HRGN32 hSrc1, HRGN32 hSrc2, INT32 mode)
827 RGNOBJ *destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC);
828 INT32 result = ERROR;
830 TRACE(region, " %04x,%04x -> %04x mode=%x\n",
831 hSrc1, hSrc2, hDest, mode );
832 if (destObj)
834 RGNOBJ *src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC);
836 if (src1Obj)
838 TRACE(region, "dump:\n");
839 if(TRACE_ON(region))
840 REGION_DumpRegion(src1Obj->rgn);
841 if (mode == RGN_COPY)
843 REGION_CopyRegion( destObj->rgn, src1Obj->rgn );
844 result = destObj->rgn->type;
846 else
848 RGNOBJ *src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC);
850 if (src2Obj)
852 TRACE(region, "dump:\n");
853 if(TRACE_ON(region))
854 REGION_DumpRegion(src2Obj->rgn);
855 switch (mode)
857 case RGN_AND:
858 REGION_IntersectRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn);
859 break;
860 case RGN_OR:
861 REGION_UnionRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
862 break;
863 case RGN_XOR:
864 REGION_XorRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
865 break;
866 case RGN_DIFF:
867 REGION_SubtractRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
868 break;
870 result = destObj->rgn->type;
871 GDI_HEAP_UNLOCK( hSrc2 );
874 GDI_HEAP_UNLOCK( hSrc1 );
876 TRACE(region, "dump:\n");
877 if(TRACE_ON(region))
878 REGION_DumpRegion(destObj->rgn);
880 GDI_HEAP_UNLOCK( hDest );
882 return result;
885 /***********************************************************************
886 * REGION_SetExtents
887 * Re-calculate the extents of a region
889 static void REGION_SetExtents (WINEREGION *pReg)
891 RECT32 *pRect, *pRectEnd, *pExtents;
893 if (pReg->numRects == 0)
895 pReg->extents.left = 0;
896 pReg->extents.top = 0;
897 pReg->extents.right = 0;
898 pReg->extents.bottom = 0;
899 return;
902 pExtents = &pReg->extents;
903 pRect = pReg->rects;
904 pRectEnd = &pRect[pReg->numRects - 1];
907 * Since pRect is the first rectangle in the region, it must have the
908 * smallest top and since pRectEnd is the last rectangle in the region,
909 * it must have the largest bottom, because of banding. Initialize left and
910 * right from pRect and pRectEnd, resp., as good things to initialize them
911 * to...
913 pExtents->left = pRect->left;
914 pExtents->top = pRect->top;
915 pExtents->right = pRectEnd->right;
916 pExtents->bottom = pRectEnd->bottom;
918 while (pRect <= pRectEnd)
920 if (pRect->left < pExtents->left)
921 pExtents->left = pRect->left;
922 if (pRect->right > pExtents->right)
923 pExtents->right = pRect->right;
924 pRect++;
928 /***********************************************************************
929 * REGION_CopyRegion
931 static void REGION_CopyRegion(WINEREGION *dst, WINEREGION *src)
933 if (dst != src) /* don't want to copy to itself */
935 if (dst->size < src->numRects)
937 if (! (dst->rects = HeapReAlloc( SystemHeap, 0, dst->rects,
938 src->numRects * sizeof(RECT32) )))
939 return;
940 dst->size = src->numRects;
942 dst->numRects = src->numRects;
943 dst->extents.left = src->extents.left;
944 dst->extents.top = src->extents.top;
945 dst->extents.right = src->extents.right;
946 dst->extents.bottom = src->extents.bottom;
947 dst->type = src->type;
949 memcpy((char *) dst->rects, (char *) src->rects,
950 (int) (src->numRects * sizeof(RECT32)));
952 return;
955 /***********************************************************************
956 * REGION_Coalesce
958 * Attempt to merge the rects in the current band with those in the
959 * previous one. Used only by REGION_RegionOp.
961 * Results:
962 * The new index for the previous band.
964 * Side Effects:
965 * If coalescing takes place:
966 * - rectangles in the previous band will have their bottom fields
967 * altered.
968 * - pReg->numRects will be decreased.
971 static INT32 REGION_Coalesce (
972 WINEREGION *pReg, /* Region to coalesce */
973 INT32 prevStart, /* Index of start of previous band */
974 INT32 curStart /* Index of start of current band */
976 RECT32 *pPrevRect; /* Current rect in previous band */
977 RECT32 *pCurRect; /* Current rect in current band */
978 RECT32 *pRegEnd; /* End of region */
979 INT32 curNumRects; /* Number of rectangles in current band */
980 INT32 prevNumRects; /* Number of rectangles in previous band */
981 INT32 bandtop; /* top coordinate for current band */
983 pRegEnd = &pReg->rects[pReg->numRects];
985 pPrevRect = &pReg->rects[prevStart];
986 prevNumRects = curStart - prevStart;
989 * Figure out how many rectangles are in the current band. Have to do
990 * this because multiple bands could have been added in REGION_RegionOp
991 * at the end when one region has been exhausted.
993 pCurRect = &pReg->rects[curStart];
994 bandtop = pCurRect->top;
995 for (curNumRects = 0;
996 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
997 curNumRects++)
999 pCurRect++;
1002 if (pCurRect != pRegEnd)
1005 * If more than one band was added, we have to find the start
1006 * of the last band added so the next coalescing job can start
1007 * at the right place... (given when multiple bands are added,
1008 * this may be pointless -- see above).
1010 pRegEnd--;
1011 while (pRegEnd[-1].top == pRegEnd->top)
1013 pRegEnd--;
1015 curStart = pRegEnd - pReg->rects;
1016 pRegEnd = pReg->rects + pReg->numRects;
1019 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
1020 pCurRect -= curNumRects;
1022 * The bands may only be coalesced if the bottom of the previous
1023 * matches the top scanline of the current.
1025 if (pPrevRect->bottom == pCurRect->top)
1028 * Make sure the bands have rects in the same places. This
1029 * assumes that rects have been added in such a way that they
1030 * cover the most area possible. I.e. two rects in a band must
1031 * have some horizontal space between them.
1035 if ((pPrevRect->left != pCurRect->left) ||
1036 (pPrevRect->right != pCurRect->right))
1039 * The bands don't line up so they can't be coalesced.
1041 return (curStart);
1043 pPrevRect++;
1044 pCurRect++;
1045 prevNumRects -= 1;
1046 } while (prevNumRects != 0);
1048 pReg->numRects -= curNumRects;
1049 pCurRect -= curNumRects;
1050 pPrevRect -= curNumRects;
1053 * The bands may be merged, so set the bottom of each rect
1054 * in the previous band to that of the corresponding rect in
1055 * the current band.
1059 pPrevRect->bottom = pCurRect->bottom;
1060 pPrevRect++;
1061 pCurRect++;
1062 curNumRects -= 1;
1063 } while (curNumRects != 0);
1066 * If only one band was added to the region, we have to backup
1067 * curStart to the start of the previous band.
1069 * If more than one band was added to the region, copy the
1070 * other bands down. The assumption here is that the other bands
1071 * came from the same region as the current one and no further
1072 * coalescing can be done on them since it's all been done
1073 * already... curStart is already in the right place.
1075 if (pCurRect == pRegEnd)
1077 curStart = prevStart;
1079 else
1083 *pPrevRect++ = *pCurRect++;
1084 } while (pCurRect != pRegEnd);
1089 return (curStart);
1092 /***********************************************************************
1093 * REGION_RegionOp
1095 * Apply an operation to two regions. Called by REGION_Union,
1096 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
1098 * Results:
1099 * None.
1101 * Side Effects:
1102 * The new region is overwritten.
1104 * Notes:
1105 * The idea behind this function is to view the two regions as sets.
1106 * Together they cover a rectangle of area that this function divides
1107 * into horizontal bands where points are covered only by one region
1108 * or by both. For the first case, the nonOverlapFunc is called with
1109 * each the band and the band's upper and lower extents. For the
1110 * second, the overlapFunc is called to process the entire band. It
1111 * is responsible for clipping the rectangles in the band, though
1112 * this function provides the boundaries.
1113 * At the end of each band, the new region is coalesced, if possible,
1114 * to reduce the number of rectangles in the region.
1117 static void REGION_RegionOp(
1118 WINEREGION *newReg, /* Place to store result */
1119 WINEREGION *reg1, /* First region in operation */
1120 WINEREGION *reg2, /* 2nd region in operation */
1121 void (*overlapFunc)(), /* Function to call for over-lapping bands */
1122 void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
1123 void (*nonOverlap2Func)() /* Function to call for non-overlapping bands in region 2 */
1125 RECT32 *r1; /* Pointer into first region */
1126 RECT32 *r2; /* Pointer into 2d region */
1127 RECT32 *r1End; /* End of 1st region */
1128 RECT32 *r2End; /* End of 2d region */
1129 INT32 ybot; /* Bottom of intersection */
1130 INT32 ytop; /* Top of intersection */
1131 RECT32 *oldRects; /* Old rects for newReg */
1132 INT32 prevBand; /* Index of start of
1133 * previous band in newReg */
1134 INT32 curBand; /* Index of start of current
1135 * band in newReg */
1136 RECT32 *r1BandEnd; /* End of current band in r1 */
1137 RECT32 *r2BandEnd; /* End of current band in r2 */
1138 INT32 top; /* Top of non-overlapping band */
1139 INT32 bot; /* Bottom of non-overlapping band */
1142 * Initialization:
1143 * set r1, r2, r1End and r2End appropriately, preserve the important
1144 * parts of the destination region until the end in case it's one of
1145 * the two source regions, then mark the "new" region empty, allocating
1146 * another array of rectangles for it to use.
1148 r1 = reg1->rects;
1149 r2 = reg2->rects;
1150 r1End = r1 + reg1->numRects;
1151 r2End = r2 + reg2->numRects;
1155 * newReg may be one of the src regions so we can't empty it. We keep a
1156 * note of its rects pointer (so that we can free them later), preserve its
1157 * extents and simply set numRects to zero.
1160 oldRects = newReg->rects;
1161 newReg->numRects = 0;
1164 * Allocate a reasonable number of rectangles for the new region. The idea
1165 * is to allocate enough so the individual functions don't need to
1166 * reallocate and copy the array, which is time consuming, yet we don't
1167 * have to worry about using too much memory. I hope to be able to
1168 * nuke the Xrealloc() at the end of this function eventually.
1170 newReg->size = MAX(reg1->numRects,reg2->numRects) * 2;
1172 if (! (newReg->rects = HeapAlloc( SystemHeap, 0,
1173 sizeof(RECT32) * newReg->size )))
1175 newReg->size = 0;
1176 return;
1180 * Initialize ybot and ytop.
1181 * In the upcoming loop, ybot and ytop serve different functions depending
1182 * on whether the band being handled is an overlapping or non-overlapping
1183 * band.
1184 * In the case of a non-overlapping band (only one of the regions
1185 * has points in the band), ybot is the bottom of the most recent
1186 * intersection and thus clips the top of the rectangles in that band.
1187 * ytop is the top of the next intersection between the two regions and
1188 * serves to clip the bottom of the rectangles in the current band.
1189 * For an overlapping band (where the two regions intersect), ytop clips
1190 * the top of the rectangles of both regions and ybot clips the bottoms.
1192 if (reg1->extents.top < reg2->extents.top)
1193 ybot = reg1->extents.top;
1194 else
1195 ybot = reg2->extents.top;
1198 * prevBand serves to mark the start of the previous band so rectangles
1199 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1200 * In the beginning, there is no previous band, so prevBand == curBand
1201 * (curBand is set later on, of course, but the first band will always
1202 * start at index 0). prevBand and curBand must be indices because of
1203 * the possible expansion, and resultant moving, of the new region's
1204 * array of rectangles.
1206 prevBand = 0;
1210 curBand = newReg->numRects;
1213 * This algorithm proceeds one source-band (as opposed to a
1214 * destination band, which is determined by where the two regions
1215 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1216 * rectangle after the last one in the current band for their
1217 * respective regions.
1219 r1BandEnd = r1;
1220 while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
1222 r1BandEnd++;
1225 r2BandEnd = r2;
1226 while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
1228 r2BandEnd++;
1232 * First handle the band that doesn't intersect, if any.
1234 * Note that attention is restricted to one band in the
1235 * non-intersecting region at once, so if a region has n
1236 * bands between the current position and the next place it overlaps
1237 * the other, this entire loop will be passed through n times.
1239 if (r1->top < r2->top)
1241 top = MAX(r1->top,ybot);
1242 bot = MIN(r1->bottom,r2->top);
1244 if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
1246 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
1249 ytop = r2->top;
1251 else if (r2->top < r1->top)
1253 top = MAX(r2->top,ybot);
1254 bot = MIN(r2->bottom,r1->top);
1256 if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
1258 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
1261 ytop = r1->top;
1263 else
1265 ytop = r1->top;
1269 * If any rectangles got added to the region, try and coalesce them
1270 * with rectangles from the previous band. Note we could just do
1271 * this test in miCoalesce, but some machines incur a not
1272 * inconsiderable cost for function calls, so...
1274 if (newReg->numRects != curBand)
1276 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1280 * Now see if we've hit an intersecting band. The two bands only
1281 * intersect if ybot > ytop
1283 ybot = MIN(r1->bottom, r2->bottom);
1284 curBand = newReg->numRects;
1285 if (ybot > ytop)
1287 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1291 if (newReg->numRects != curBand)
1293 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1297 * If we've finished with a band (bottom == ybot) we skip forward
1298 * in the region to the next band.
1300 if (r1->bottom == ybot)
1302 r1 = r1BandEnd;
1304 if (r2->bottom == ybot)
1306 r2 = r2BandEnd;
1308 } while ((r1 != r1End) && (r2 != r2End));
1311 * Deal with whichever region still has rectangles left.
1313 curBand = newReg->numRects;
1314 if (r1 != r1End)
1316 if (nonOverlap1Func != (void (*)())NULL)
1320 r1BandEnd = r1;
1321 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
1323 r1BandEnd++;
1325 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
1326 MAX(r1->top,ybot), r1->bottom);
1327 r1 = r1BandEnd;
1328 } while (r1 != r1End);
1331 else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
1335 r2BandEnd = r2;
1336 while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
1338 r2BandEnd++;
1340 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
1341 MAX(r2->top,ybot), r2->bottom);
1342 r2 = r2BandEnd;
1343 } while (r2 != r2End);
1346 if (newReg->numRects != curBand)
1348 (void) REGION_Coalesce (newReg, prevBand, curBand);
1352 * A bit of cleanup. To keep regions from growing without bound,
1353 * we shrink the array of rectangles to match the new number of
1354 * rectangles in the region. This never goes to 0, however...
1356 * Only do this stuff if the number of rectangles allocated is more than
1357 * twice the number of rectangles in the region (a simple optimization...).
1359 if (newReg->numRects < (newReg->size >> 1))
1361 if (REGION_NOT_EMPTY(newReg))
1363 RECT32 *prev_rects = newReg->rects;
1364 newReg->size = newReg->numRects;
1365 newReg->rects = HeapReAlloc( SystemHeap, 0, newReg->rects,
1366 sizeof(RECT32) * newReg->size );
1367 if (! newReg->rects)
1368 newReg->rects = prev_rects;
1370 else
1373 * No point in doing the extra work involved in an Xrealloc if
1374 * the region is empty
1376 newReg->size = 1;
1377 HeapFree( SystemHeap, 0, newReg->rects );
1378 newReg->rects = HeapAlloc( SystemHeap, 0, sizeof(RECT32) );
1381 HeapFree( SystemHeap, 0, oldRects );
1382 return;
1385 /***********************************************************************
1386 * Region Intersection
1387 ***********************************************************************/
1390 /***********************************************************************
1391 * REGION_IntersectO
1393 * Handle an overlapping band for REGION_Intersect.
1395 * Results:
1396 * None.
1398 * Side Effects:
1399 * Rectangles may be added to the region.
1402 static void REGION_IntersectO(WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1403 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1406 INT32 left, right;
1407 RECT32 *pNextRect;
1409 pNextRect = &pReg->rects[pReg->numRects];
1411 while ((r1 != r1End) && (r2 != r2End))
1413 left = MAX(r1->left, r2->left);
1414 right = MIN(r1->right, r2->right);
1417 * If there's any overlap between the two rectangles, add that
1418 * overlap to the new region.
1419 * There's no need to check for subsumption because the only way
1420 * such a need could arise is if some region has two rectangles
1421 * right next to each other. Since that should never happen...
1423 if (left < right)
1425 MEMCHECK(pReg, pNextRect, pReg->rects);
1426 pNextRect->left = left;
1427 pNextRect->top = top;
1428 pNextRect->right = right;
1429 pNextRect->bottom = bottom;
1430 pReg->numRects += 1;
1431 pNextRect++;
1435 * Need to advance the pointers. Shift the one that extends
1436 * to the right the least, since the other still has a chance to
1437 * overlap with that region's next rectangle, if you see what I mean.
1439 if (r1->right < r2->right)
1441 r1++;
1443 else if (r2->right < r1->right)
1445 r2++;
1447 else
1449 r1++;
1450 r2++;
1453 return;
1456 /***********************************************************************
1457 * REGION_IntersectRegion
1459 static void REGION_IntersectRegion(WINEREGION *newReg, WINEREGION *reg1,
1460 WINEREGION *reg2)
1462 /* check for trivial reject */
1463 if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
1464 (!EXTENTCHECK(&reg1->extents, &reg2->extents)))
1465 newReg->numRects = 0;
1466 else
1467 REGION_RegionOp (newReg, reg1, reg2,
1468 (voidProcp) REGION_IntersectO, (voidProcp) NULL, (voidProcp) NULL);
1471 * Can't alter newReg's extents before we call miRegionOp because
1472 * it might be one of the source regions and miRegionOp depends
1473 * on the extents of those regions being the same. Besides, this
1474 * way there's no checking against rectangles that will be nuked
1475 * due to coalescing, so we have to examine fewer rectangles.
1477 REGION_SetExtents(newReg);
1478 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1479 return;
1482 /***********************************************************************
1483 * Region Union
1484 ***********************************************************************/
1486 /***********************************************************************
1487 * REGION_UnionNonO
1489 * Handle a non-overlapping band for the union operation. Just
1490 * Adds the rectangles into the region. Doesn't have to check for
1491 * subsumption or anything.
1493 * Results:
1494 * None.
1496 * Side Effects:
1497 * pReg->numRects is incremented and the final rectangles overwritten
1498 * with the rectangles we're passed.
1501 static void REGION_UnionNonO (WINEREGION *pReg, RECT32 *r, RECT32 *rEnd,
1502 INT32 top, INT32 bottom)
1504 RECT32 *pNextRect;
1506 pNextRect = &pReg->rects[pReg->numRects];
1508 while (r != rEnd)
1510 MEMCHECK(pReg, pNextRect, pReg->rects);
1511 pNextRect->left = r->left;
1512 pNextRect->top = top;
1513 pNextRect->right = r->right;
1514 pNextRect->bottom = bottom;
1515 pReg->numRects += 1;
1516 pNextRect++;
1517 r++;
1519 return;
1522 /***********************************************************************
1523 * REGION_UnionO
1525 * Handle an overlapping band for the union operation. Picks the
1526 * left-most rectangle each time and merges it into the region.
1528 * Results:
1529 * None.
1531 * Side Effects:
1532 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1533 * be changed.
1536 static void REGION_UnionO (WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1537 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1539 RECT32 *pNextRect;
1541 pNextRect = &pReg->rects[pReg->numRects];
1543 #define MERGERECT(r) \
1544 if ((pReg->numRects != 0) && \
1545 (pNextRect[-1].top == top) && \
1546 (pNextRect[-1].bottom == bottom) && \
1547 (pNextRect[-1].right >= r->left)) \
1549 if (pNextRect[-1].right < r->right) \
1551 pNextRect[-1].right = r->right; \
1554 else \
1556 MEMCHECK(pReg, pNextRect, pReg->rects); \
1557 pNextRect->top = top; \
1558 pNextRect->bottom = bottom; \
1559 pNextRect->left = r->left; \
1560 pNextRect->right = r->right; \
1561 pReg->numRects += 1; \
1562 pNextRect += 1; \
1564 r++;
1566 while ((r1 != r1End) && (r2 != r2End))
1568 if (r1->left < r2->left)
1570 MERGERECT(r1);
1572 else
1574 MERGERECT(r2);
1578 if (r1 != r1End)
1582 MERGERECT(r1);
1583 } while (r1 != r1End);
1585 else while (r2 != r2End)
1587 MERGERECT(r2);
1589 return;
1592 /***********************************************************************
1593 * REGION_UnionRegion
1595 static void REGION_UnionRegion(WINEREGION *newReg, WINEREGION *reg1,
1596 WINEREGION *reg2)
1598 /* checks all the simple cases */
1601 * Region 1 and 2 are the same or region 1 is empty
1603 if ( (reg1 == reg2) || (!(reg1->numRects)) )
1605 if (newReg != reg2)
1606 REGION_CopyRegion(newReg, reg2);
1607 return;
1611 * if nothing to union (region 2 empty)
1613 if (!(reg2->numRects))
1615 if (newReg != reg1)
1616 REGION_CopyRegion(newReg, reg1);
1617 return;
1621 * Region 1 completely subsumes region 2
1623 if ((reg1->numRects == 1) &&
1624 (reg1->extents.left <= reg2->extents.left) &&
1625 (reg1->extents.top <= reg2->extents.top) &&
1626 (reg1->extents.right >= reg2->extents.right) &&
1627 (reg1->extents.bottom >= reg2->extents.bottom))
1629 if (newReg != reg1)
1630 REGION_CopyRegion(newReg, reg1);
1631 return;
1635 * Region 2 completely subsumes region 1
1637 if ((reg2->numRects == 1) &&
1638 (reg2->extents.left <= reg1->extents.left) &&
1639 (reg2->extents.top <= reg1->extents.top) &&
1640 (reg2->extents.right >= reg1->extents.right) &&
1641 (reg2->extents.bottom >= reg1->extents.bottom))
1643 if (newReg != reg2)
1644 REGION_CopyRegion(newReg, reg2);
1645 return;
1648 REGION_RegionOp (newReg, reg1, reg2, (voidProcp) REGION_UnionO,
1649 (voidProcp) REGION_UnionNonO, (voidProcp) REGION_UnionNonO);
1651 newReg->extents.left = MIN(reg1->extents.left, reg2->extents.left);
1652 newReg->extents.top = MIN(reg1->extents.top, reg2->extents.top);
1653 newReg->extents.right = MAX(reg1->extents.right, reg2->extents.right);
1654 newReg->extents.bottom = MAX(reg1->extents.bottom, reg2->extents.bottom);
1655 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1656 return;
1659 /***********************************************************************
1660 * Region Subtraction
1661 ***********************************************************************/
1663 /***********************************************************************
1664 * REGION_SubtractNonO1
1666 * Deal with non-overlapping band for subtraction. Any parts from
1667 * region 2 we discard. Anything from region 1 we add to the region.
1669 * Results:
1670 * None.
1672 * Side Effects:
1673 * pReg may be affected.
1676 static void REGION_SubtractNonO1 (WINEREGION *pReg, RECT32 *r, RECT32 *rEnd,
1677 INT32 top, INT32 bottom)
1679 RECT32 *pNextRect;
1681 pNextRect = &pReg->rects[pReg->numRects];
1683 while (r != rEnd)
1685 MEMCHECK(pReg, pNextRect, pReg->rects);
1686 pNextRect->left = r->left;
1687 pNextRect->top = top;
1688 pNextRect->right = r->right;
1689 pNextRect->bottom = bottom;
1690 pReg->numRects += 1;
1691 pNextRect++;
1692 r++;
1694 return;
1698 /***********************************************************************
1699 * REGION_SubtractO
1701 * Overlapping band subtraction. x1 is the left-most point not yet
1702 * checked.
1704 * Results:
1705 * None.
1707 * Side Effects:
1708 * pReg may have rectangles added to it.
1711 static void REGION_SubtractO (WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1712 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1714 RECT32 *pNextRect;
1715 INT32 left;
1717 left = r1->left;
1718 pNextRect = &pReg->rects[pReg->numRects];
1720 while ((r1 != r1End) && (r2 != r2End))
1722 if (r2->right <= left)
1725 * Subtrahend missed the boat: go to next subtrahend.
1727 r2++;
1729 else if (r2->left <= left)
1732 * Subtrahend preceeds minuend: nuke left edge of minuend.
1734 left = r2->right;
1735 if (left >= r1->right)
1738 * Minuend completely covered: advance to next minuend and
1739 * reset left fence to edge of new minuend.
1741 r1++;
1742 if (r1 != r1End)
1743 left = r1->left;
1745 else
1748 * Subtrahend now used up since it doesn't extend beyond
1749 * minuend
1751 r2++;
1754 else if (r2->left < r1->right)
1757 * Left part of subtrahend covers part of minuend: add uncovered
1758 * part of minuend to region and skip to next subtrahend.
1760 MEMCHECK(pReg, pNextRect, pReg->rects);
1761 pNextRect->left = left;
1762 pNextRect->top = top;
1763 pNextRect->right = r2->left;
1764 pNextRect->bottom = bottom;
1765 pReg->numRects += 1;
1766 pNextRect++;
1767 left = r2->right;
1768 if (left >= r1->right)
1771 * Minuend used up: advance to new...
1773 r1++;
1774 if (r1 != r1End)
1775 left = r1->left;
1777 else
1780 * Subtrahend used up
1782 r2++;
1785 else
1788 * Minuend used up: add any remaining piece before advancing.
1790 if (r1->right > left)
1792 MEMCHECK(pReg, pNextRect, pReg->rects);
1793 pNextRect->left = left;
1794 pNextRect->top = top;
1795 pNextRect->right = r1->right;
1796 pNextRect->bottom = bottom;
1797 pReg->numRects += 1;
1798 pNextRect++;
1800 r1++;
1801 left = r1->left;
1806 * Add remaining minuend rectangles to region.
1808 while (r1 != r1End)
1810 MEMCHECK(pReg, pNextRect, pReg->rects);
1811 pNextRect->left = left;
1812 pNextRect->top = top;
1813 pNextRect->right = r1->right;
1814 pNextRect->bottom = bottom;
1815 pReg->numRects += 1;
1816 pNextRect++;
1817 r1++;
1818 if (r1 != r1End)
1820 left = r1->left;
1823 return;
1826 /***********************************************************************
1827 * REGION_SubtractRegion
1829 * Subtract regS from regM and leave the result in regD.
1830 * S stands for subtrahend, M for minuend and D for difference.
1832 * Results:
1833 * TRUE.
1835 * Side Effects:
1836 * regD is overwritten.
1839 static void REGION_SubtractRegion(WINEREGION *regD, WINEREGION *regM,
1840 WINEREGION *regS )
1842 /* check for trivial reject */
1843 if ( (!(regM->numRects)) || (!(regS->numRects)) ||
1844 (!EXTENTCHECK(&regM->extents, &regS->extents)) )
1846 REGION_CopyRegion(regD, regM);
1847 return;
1850 REGION_RegionOp (regD, regM, regS, (voidProcp) REGION_SubtractO,
1851 (voidProcp) REGION_SubtractNonO1, (voidProcp) NULL);
1854 * Can't alter newReg's extents before we call miRegionOp because
1855 * it might be one of the source regions and miRegionOp depends
1856 * on the extents of those regions being the unaltered. Besides, this
1857 * way there's no checking against rectangles that will be nuked
1858 * due to coalescing, so we have to examine fewer rectangles.
1860 REGION_SetExtents (regD);
1861 regD->type = (regD->numRects) ? COMPLEXREGION : NULLREGION ;
1862 return;
1865 /***********************************************************************
1866 * REGION_XorRegion
1868 static void REGION_XorRegion(WINEREGION *dr, WINEREGION *sra,
1869 WINEREGION *srb)
1871 WINEREGION *tra, *trb;
1873 if ((! (tra = REGION_AllocWineRegion())) ||
1874 (! (trb = REGION_AllocWineRegion())))
1875 return;
1876 REGION_SubtractRegion(tra,sra,srb);
1877 REGION_SubtractRegion(trb,srb,sra);
1878 REGION_UnionRegion(dr,tra,trb);
1879 REGION_DestroyWineRegion(tra);
1880 REGION_DestroyWineRegion(trb);
1881 return;
1884 /**************************************************************************
1886 * Poly Regions
1888 *************************************************************************/
1890 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
1891 #define SMALL_COORDINATE 0x80000000
1893 /***********************************************************************
1894 * REGION_InsertEdgeInET
1896 * Insert the given edge into the edge table.
1897 * First we must find the correct bucket in the
1898 * Edge table, then find the right slot in the
1899 * bucket. Finally, we can insert it.
1902 static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
1903 INT32 scanline, ScanLineListBlock **SLLBlock, INT32 *iSLLBlock)
1906 EdgeTableEntry *start, *prev;
1907 ScanLineList *pSLL, *pPrevSLL;
1908 ScanLineListBlock *tmpSLLBlock;
1911 * find the right bucket to put the edge into
1913 pPrevSLL = &ET->scanlines;
1914 pSLL = pPrevSLL->next;
1915 while (pSLL && (pSLL->scanline < scanline))
1917 pPrevSLL = pSLL;
1918 pSLL = pSLL->next;
1922 * reassign pSLL (pointer to ScanLineList) if necessary
1924 if ((!pSLL) || (pSLL->scanline > scanline))
1926 if (*iSLLBlock > SLLSPERBLOCK-1)
1928 tmpSLLBlock = HeapAlloc( SystemHeap, 0, sizeof(ScanLineListBlock));
1929 if(!tmpSLLBlock)
1931 WARN(region, "Can't alloc SLLB\n");
1932 return;
1934 (*SLLBlock)->next = tmpSLLBlock;
1935 tmpSLLBlock->next = (ScanLineListBlock *)NULL;
1936 *SLLBlock = tmpSLLBlock;
1937 *iSLLBlock = 0;
1939 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
1941 pSLL->next = pPrevSLL->next;
1942 pSLL->edgelist = (EdgeTableEntry *)NULL;
1943 pPrevSLL->next = pSLL;
1945 pSLL->scanline = scanline;
1948 * now insert the edge in the right bucket
1950 prev = (EdgeTableEntry *)NULL;
1951 start = pSLL->edgelist;
1952 while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
1954 prev = start;
1955 start = start->next;
1957 ETE->next = start;
1959 if (prev)
1960 prev->next = ETE;
1961 else
1962 pSLL->edgelist = ETE;
1965 /***********************************************************************
1966 * REGION_CreateEdgeTable
1968 * This routine creates the edge table for
1969 * scan converting polygons.
1970 * The Edge Table (ET) looks like:
1972 * EdgeTable
1973 * --------
1974 * | ymax | ScanLineLists
1975 * |scanline|-->------------>-------------->...
1976 * -------- |scanline| |scanline|
1977 * |edgelist| |edgelist|
1978 * --------- ---------
1979 * | |
1980 * | |
1981 * V V
1982 * list of ETEs list of ETEs
1984 * where ETE is an EdgeTableEntry data structure,
1985 * and there is one ScanLineList per scanline at
1986 * which an edge is initially entered.
1989 static void REGION_CreateETandAET(const INT32 *Count, INT32 nbpolygons,
1990 const POINT32 *pts, EdgeTable *ET, EdgeTableEntry *AET,
1991 EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
1993 const POINT32 *top, *bottom;
1994 const POINT32 *PrevPt, *CurrPt, *EndPt;
1995 INT32 poly, count;
1996 int iSLLBlock = 0;
1997 int dy;
2001 * initialize the Active Edge Table
2003 AET->next = (EdgeTableEntry *)NULL;
2004 AET->back = (EdgeTableEntry *)NULL;
2005 AET->nextWETE = (EdgeTableEntry *)NULL;
2006 AET->bres.minor_axis = SMALL_COORDINATE;
2009 * initialize the Edge Table.
2011 ET->scanlines.next = (ScanLineList *)NULL;
2012 ET->ymax = SMALL_COORDINATE;
2013 ET->ymin = LARGE_COORDINATE;
2014 pSLLBlock->next = (ScanLineListBlock *)NULL;
2016 EndPt = pts - 1;
2017 for(poly = 0; poly < nbpolygons; poly++)
2019 count = Count[poly];
2020 EndPt += count;
2021 if(count < 2)
2022 continue;
2024 PrevPt = EndPt;
2027 * for each vertex in the array of points.
2028 * In this loop we are dealing with two vertices at
2029 * a time -- these make up one edge of the polygon.
2031 while (count--)
2033 CurrPt = pts++;
2036 * find out which point is above and which is below.
2038 if (PrevPt->y > CurrPt->y)
2040 bottom = PrevPt, top = CurrPt;
2041 pETEs->ClockWise = 0;
2043 else
2045 bottom = CurrPt, top = PrevPt;
2046 pETEs->ClockWise = 1;
2050 * don't add horizontal edges to the Edge table.
2052 if (bottom->y != top->y)
2054 pETEs->ymax = bottom->y-1;
2055 /* -1 so we don't get last scanline */
2058 * initialize integer edge algorithm
2060 dy = bottom->y - top->y;
2061 BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
2063 REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
2064 &iSLLBlock);
2066 if (PrevPt->y > ET->ymax)
2067 ET->ymax = PrevPt->y;
2068 if (PrevPt->y < ET->ymin)
2069 ET->ymin = PrevPt->y;
2070 pETEs++;
2073 PrevPt = CurrPt;
2078 /***********************************************************************
2079 * REGION_loadAET
2081 * This routine moves EdgeTableEntries from the
2082 * EdgeTable into the Active Edge Table,
2083 * leaving them sorted by smaller x coordinate.
2086 static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
2088 EdgeTableEntry *pPrevAET;
2089 EdgeTableEntry *tmp;
2091 pPrevAET = AET;
2092 AET = AET->next;
2093 while (ETEs)
2095 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
2097 pPrevAET = AET;
2098 AET = AET->next;
2100 tmp = ETEs->next;
2101 ETEs->next = AET;
2102 if (AET)
2103 AET->back = ETEs;
2104 ETEs->back = pPrevAET;
2105 pPrevAET->next = ETEs;
2106 pPrevAET = ETEs;
2108 ETEs = tmp;
2112 /***********************************************************************
2113 * REGION_computeWAET
2115 * This routine links the AET by the
2116 * nextWETE (winding EdgeTableEntry) link for
2117 * use by the winding number rule. The final
2118 * Active Edge Table (AET) might look something
2119 * like:
2121 * AET
2122 * ---------- --------- ---------
2123 * |ymax | |ymax | |ymax |
2124 * | ... | |... | |... |
2125 * |next |->|next |->|next |->...
2126 * |nextWETE| |nextWETE| |nextWETE|
2127 * --------- --------- ^--------
2128 * | | |
2129 * V-------------------> V---> ...
2132 static void REGION_computeWAET(EdgeTableEntry *AET)
2134 register EdgeTableEntry *pWETE;
2135 register int inside = 1;
2136 register int isInside = 0;
2138 AET->nextWETE = (EdgeTableEntry *)NULL;
2139 pWETE = AET;
2140 AET = AET->next;
2141 while (AET)
2143 if (AET->ClockWise)
2144 isInside++;
2145 else
2146 isInside--;
2148 if ((!inside && !isInside) ||
2149 ( inside && isInside))
2151 pWETE->nextWETE = AET;
2152 pWETE = AET;
2153 inside = !inside;
2155 AET = AET->next;
2157 pWETE->nextWETE = (EdgeTableEntry *)NULL;
2160 /***********************************************************************
2161 * REGION_InsertionSort
2163 * Just a simple insertion sort using
2164 * pointers and back pointers to sort the Active
2165 * Edge Table.
2168 static BOOL32 REGION_InsertionSort(EdgeTableEntry *AET)
2170 EdgeTableEntry *pETEchase;
2171 EdgeTableEntry *pETEinsert;
2172 EdgeTableEntry *pETEchaseBackTMP;
2173 BOOL32 changed = FALSE;
2175 AET = AET->next;
2176 while (AET)
2178 pETEinsert = AET;
2179 pETEchase = AET;
2180 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
2181 pETEchase = pETEchase->back;
2183 AET = AET->next;
2184 if (pETEchase != pETEinsert)
2186 pETEchaseBackTMP = pETEchase->back;
2187 pETEinsert->back->next = AET;
2188 if (AET)
2189 AET->back = pETEinsert->back;
2190 pETEinsert->next = pETEchase;
2191 pETEchase->back->next = pETEinsert;
2192 pETEchase->back = pETEinsert;
2193 pETEinsert->back = pETEchaseBackTMP;
2194 changed = TRUE;
2197 return changed;
2200 /***********************************************************************
2201 * REGION_FreeStorage
2203 * Clean up our act.
2205 static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
2207 ScanLineListBlock *tmpSLLBlock;
2209 while (pSLLBlock)
2211 tmpSLLBlock = pSLLBlock->next;
2212 HeapFree( SystemHeap, 0, pSLLBlock );
2213 pSLLBlock = tmpSLLBlock;
2218 /***********************************************************************
2219 * REGION_PtsToRegion
2221 * Create an array of rectangles from a list of points.
2223 static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
2224 POINTBLOCK *FirstPtBlock, WINEREGION *reg)
2226 RECT32 *rects;
2227 POINT32 *pts;
2228 POINTBLOCK *CurPtBlock;
2229 int i;
2230 RECT32 *extents;
2231 INT32 numRects;
2233 extents = &reg->extents;
2235 numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
2237 if (!(reg->rects = HeapReAlloc( SystemHeap, 0, reg->rects,
2238 sizeof(RECT32) * numRects )))
2239 return(0);
2241 reg->size = numRects;
2242 CurPtBlock = FirstPtBlock;
2243 rects = reg->rects - 1;
2244 numRects = 0;
2245 extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
2247 for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
2248 /* the loop uses 2 points per iteration */
2249 i = NUMPTSTOBUFFER >> 1;
2250 if (!numFullPtBlocks)
2251 i = iCurPtBlock >> 1;
2252 for (pts = CurPtBlock->pts; i--; pts += 2) {
2253 if (pts->x == pts[1].x)
2254 continue;
2255 if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
2256 pts[1].x == rects->right &&
2257 (numRects == 1 || rects[-1].top != rects->top) &&
2258 (i && pts[2].y > pts[1].y)) {
2259 rects->bottom = pts[1].y + 1;
2260 continue;
2262 numRects++;
2263 rects++;
2264 rects->left = pts->x; rects->top = pts->y;
2265 rects->right = pts[1].x; rects->bottom = pts[1].y + 1;
2266 if (rects->left < extents->left)
2267 extents->left = rects->left;
2268 if (rects->right > extents->right)
2269 extents->right = rects->right;
2271 CurPtBlock = CurPtBlock->next;
2274 if (numRects) {
2275 extents->top = reg->rects->top;
2276 extents->bottom = rects->bottom;
2277 } else {
2278 extents->left = 0;
2279 extents->top = 0;
2280 extents->right = 0;
2281 extents->bottom = 0;
2283 reg->numRects = numRects;
2285 return(TRUE);
2288 /***********************************************************************
2289 * CreatePolyPolygonRgn32 (GDI32.57)
2291 HRGN32 WINAPI CreatePolyPolygonRgn32(const POINT32 *Pts, const INT32 *Count,
2292 INT32 nbpolygons, INT32 mode)
2294 HRGN32 hrgn;
2295 RGNOBJ *obj;
2296 WINEREGION *region;
2297 register EdgeTableEntry *pAET; /* Active Edge Table */
2298 register INT32 y; /* current scanline */
2299 register int iPts = 0; /* number of pts in buffer */
2300 register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
2301 register ScanLineList *pSLL; /* current scanLineList */
2302 register POINT32 *pts; /* output buffer */
2303 EdgeTableEntry *pPrevAET; /* ptr to previous AET */
2304 EdgeTable ET; /* header node for ET */
2305 EdgeTableEntry AET; /* header node for AET */
2306 EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
2307 ScanLineListBlock SLLBlock; /* header for scanlinelist */
2308 int fixWAET = FALSE;
2309 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
2310 POINTBLOCK *tmpPtBlock;
2311 int numFullPtBlocks = 0;
2312 INT32 poly, total;
2314 if(!(hrgn = REGION_CreateRegion()))
2315 return 0;
2316 obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
2317 region = obj->rgn;
2319 /* special case a rectangle */
2321 if (((nbpolygons == 1) && ((*Count == 4) ||
2322 ((*Count == 5) && (Pts[4].x == Pts[0].x) && (Pts[4].y == Pts[0].y)))) &&
2323 (((Pts[0].y == Pts[1].y) &&
2324 (Pts[1].x == Pts[2].x) &&
2325 (Pts[2].y == Pts[3].y) &&
2326 (Pts[3].x == Pts[0].x)) ||
2327 ((Pts[0].x == Pts[1].x) &&
2328 (Pts[1].y == Pts[2].y) &&
2329 (Pts[2].x == Pts[3].x) &&
2330 (Pts[3].y == Pts[0].y))))
2332 SetRectRgn32( hrgn, MIN(Pts[0].x, Pts[2].x), MIN(Pts[0].y, Pts[2].y),
2333 MAX(Pts[0].x, Pts[2].x), MAX(Pts[0].y, Pts[2].y) );
2334 GDI_HEAP_UNLOCK( hrgn );
2335 return hrgn;
2338 for(poly = total = 0; poly < nbpolygons; poly++)
2339 total += Count[poly];
2340 if (! (pETEs = HeapAlloc( SystemHeap, 0, sizeof(EdgeTableEntry) * total )))
2342 REGION_DeleteObject( hrgn, obj );
2343 return 0;
2345 pts = FirstPtBlock.pts;
2346 REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
2347 pSLL = ET.scanlines.next;
2348 curPtBlock = &FirstPtBlock;
2350 if (mode != WINDING) {
2352 * for each scanline
2354 for (y = ET.ymin; y < ET.ymax; y++) {
2356 * Add a new edge to the active edge table when we
2357 * get to the next edge.
2359 if (pSLL != NULL && y == pSLL->scanline) {
2360 REGION_loadAET(&AET, pSLL->edgelist);
2361 pSLL = pSLL->next;
2363 pPrevAET = &AET;
2364 pAET = AET.next;
2367 * for each active edge
2369 while (pAET) {
2370 pts->x = pAET->bres.minor_axis, pts->y = y;
2371 pts++, iPts++;
2374 * send out the buffer
2376 if (iPts == NUMPTSTOBUFFER) {
2377 tmpPtBlock = HeapAlloc( SystemHeap, 0, sizeof(POINTBLOCK));
2378 if(!tmpPtBlock) {
2379 WARN(region, "Can't alloc tPB\n");
2380 return 0;
2382 curPtBlock->next = tmpPtBlock;
2383 curPtBlock = tmpPtBlock;
2384 pts = curPtBlock->pts;
2385 numFullPtBlocks++;
2386 iPts = 0;
2388 EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
2390 REGION_InsertionSort(&AET);
2393 else {
2395 * for each scanline
2397 for (y = ET.ymin; y < ET.ymax; y++) {
2399 * Add a new edge to the active edge table when we
2400 * get to the next edge.
2402 if (pSLL != NULL && y == pSLL->scanline) {
2403 REGION_loadAET(&AET, pSLL->edgelist);
2404 REGION_computeWAET(&AET);
2405 pSLL = pSLL->next;
2407 pPrevAET = &AET;
2408 pAET = AET.next;
2409 pWETE = pAET;
2412 * for each active edge
2414 while (pAET) {
2416 * add to the buffer only those edges that
2417 * are in the Winding active edge table.
2419 if (pWETE == pAET) {
2420 pts->x = pAET->bres.minor_axis, pts->y = y;
2421 pts++, iPts++;
2424 * send out the buffer
2426 if (iPts == NUMPTSTOBUFFER) {
2427 tmpPtBlock = HeapAlloc( SystemHeap, 0,
2428 sizeof(POINTBLOCK) );
2429 if(!tmpPtBlock) {
2430 WARN(region, "Can't alloc tPB\n");
2431 return 0;
2433 curPtBlock->next = tmpPtBlock;
2434 curPtBlock = tmpPtBlock;
2435 pts = curPtBlock->pts;
2436 numFullPtBlocks++; iPts = 0;
2438 pWETE = pWETE->nextWETE;
2440 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
2444 * recompute the winding active edge table if
2445 * we just resorted or have exited an edge.
2447 if (REGION_InsertionSort(&AET) || fixWAET) {
2448 REGION_computeWAET(&AET);
2449 fixWAET = FALSE;
2453 REGION_FreeStorage(SLLBlock.next);
2454 REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
2455 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
2456 tmpPtBlock = curPtBlock->next;
2457 HeapFree( SystemHeap, 0, curPtBlock );
2458 curPtBlock = tmpPtBlock;
2460 HeapFree( SystemHeap, 0, pETEs );
2461 GDI_HEAP_UNLOCK( hrgn );
2462 return hrgn;
2466 /***********************************************************************
2467 * CreatePolygonRgn16 (GDI.63)
2469 HRGN16 WINAPI CreatePolygonRgn16( const POINT16 * points, INT16 count,
2470 INT16 mode )
2472 return CreatePolyPolygonRgn16( points, &count, 1, mode );
2475 /***********************************************************************
2476 * CreatePolyPolygonRgn16 (GDI.451)
2478 HRGN16 WINAPI CreatePolyPolygonRgn16( const POINT16 *points,
2479 const INT16 *count, INT16 nbpolygons, INT16 mode )
2481 HRGN32 hrgn;
2482 int i, npts = 0;
2483 INT32 *count32;
2484 POINT32 *points32;
2486 for (i = 0; i < nbpolygons; i++)
2487 npts += count[i];
2488 points32 = HeapAlloc( SystemHeap, 0, npts * sizeof(POINT32) );
2489 for (i = 0; i < npts; i++)
2490 CONV_POINT16TO32( &(points[i]), &(points32[i]) );
2492 count32 = HeapAlloc( SystemHeap, 0, nbpolygons * sizeof(INT32) );
2493 for (i = 0; i < nbpolygons; i++)
2494 count32[i] = count[i];
2495 hrgn = CreatePolyPolygonRgn32( points32, count32, nbpolygons, mode );
2496 HeapFree( SystemHeap, 0, count32 );
2497 HeapFree( SystemHeap, 0, points32 );
2498 return hrgn;
2501 /***********************************************************************
2502 * CreatePolygonRgn32 (GDI32.58)
2504 HRGN32 WINAPI CreatePolygonRgn32( const POINT32 *points, INT32 count,
2505 INT32 mode )
2507 return CreatePolyPolygonRgn32( points, &count, 1, mode );