Release 980927
[wine.git] / objects / region.c
blob062bb27b4deffbfe3a65f37ffc7bd4ad8208f6cc
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 ))))
127 if ((pReg->rects = HeapAlloc(SystemHeap, 0, sizeof( RECT32 ))))
129 pReg->size = 1;
130 EMPTY_REGION(pReg);
131 return pReg;
133 HeapFree(SystemHeap, 0, pReg);
135 return NULL;
138 /***********************************************************************
139 * REGION_CreateRegion
140 * Create a new empty region.
142 static HRGN32 REGION_CreateRegion(void)
144 HRGN32 hrgn;
145 RGNOBJ *obj;
147 if(!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
148 return 0;
149 obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
150 if(!(obj->rgn = REGION_AllocWineRegion())) {
151 GDI_FreeObject( hrgn );
152 return 0;
154 GDI_HEAP_UNLOCK( hrgn );
155 return hrgn;
158 /***********************************************************************
159 * REGION_DestroyWineRegion
161 static void REGION_DestroyWineRegion( WINEREGION* pReg )
163 HeapFree( SystemHeap, 0, pReg->rects );
164 HeapFree( SystemHeap, 0, pReg );
165 return;
168 /***********************************************************************
169 * REGION_DeleteObject
171 BOOL32 REGION_DeleteObject( HRGN32 hrgn, RGNOBJ * obj )
173 TRACE(region, " %04x\n", hrgn );
175 REGION_DestroyWineRegion( obj->rgn );
176 return GDI_FreeObject( hrgn );
179 /***********************************************************************
180 * OffsetRgn16 (GDI.101)
182 INT16 WINAPI OffsetRgn16( HRGN16 hrgn, INT16 x, INT16 y )
184 return OffsetRgn32( hrgn, x, y );
187 /***********************************************************************
188 * OffsetRgn32 (GDI32.256)
190 INT32 WINAPI OffsetRgn32( HRGN32 hrgn, INT32 x, INT32 y )
192 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
194 if (obj)
196 INT32 ret;
197 int nbox = obj->rgn->numRects;
198 RECT32 *pbox = obj->rgn->rects;
200 TRACE(region, " %04x %d,%d\n", hrgn, x, y );
201 if(nbox && (x || y)) {
202 while(nbox--) {
203 pbox->left += x;
204 pbox->right += x;
205 pbox->top += y;
206 pbox->bottom += y;
207 pbox++;
209 obj->rgn->extents.left += x;
210 obj->rgn->extents.right += x;
211 obj->rgn->extents.top += y;
212 obj->rgn->extents.bottom += y;
214 ret = obj->rgn->type;
215 GDI_HEAP_UNLOCK( hrgn );
216 return ret;
218 return ERROR;
222 /***********************************************************************
223 * GetRgnBox16 (GDI.134)
225 INT16 WINAPI GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
227 RECT32 r;
228 INT16 ret = (INT16)GetRgnBox32( hrgn, &r );
229 CONV_RECT32TO16( &r, rect );
230 return ret;
233 /***********************************************************************
234 * GetRgnBox32 (GDI32.219)
236 INT32 WINAPI GetRgnBox32( HRGN32 hrgn, LPRECT32 rect )
238 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
239 if (obj)
241 INT32 ret;
242 TRACE(region, " %04x\n", hrgn );
243 rect->left = obj->rgn->extents.left;
244 rect->top = obj->rgn->extents.top;
245 rect->right = obj->rgn->extents.right;
246 rect->bottom = obj->rgn->extents.bottom;
247 ret = obj->rgn->type;
248 GDI_HEAP_UNLOCK(hrgn);
249 return ret;
251 return ERROR;
255 /***********************************************************************
256 * CreateRectRgn16 (GDI.64)
258 HRGN16 WINAPI CreateRectRgn16(INT16 left, INT16 top, INT16 right, INT16 bottom)
260 return (HRGN16)CreateRectRgn32( left, top, right, bottom );
264 /***********************************************************************
265 * CreateRectRgn32 (GDI32.59)
267 HRGN32 WINAPI CreateRectRgn32(INT32 left, INT32 top, INT32 right, INT32 bottom)
269 HRGN32 hrgn;
271 if (!(hrgn = REGION_CreateRegion()))
272 return 0;
273 TRACE(region, " \n");
274 SetRectRgn32(hrgn, left, top, right, bottom);
275 return hrgn;
278 /***********************************************************************
279 * CreateRectRgnIndirect16 (GDI.65)
281 HRGN16 WINAPI CreateRectRgnIndirect16( const RECT16* rect )
283 return CreateRectRgn32( rect->left, rect->top, rect->right, rect->bottom );
287 /***********************************************************************
288 * CreateRectRgnIndirect32 (GDI32.60)
290 HRGN32 WINAPI CreateRectRgnIndirect32( const RECT32* rect )
292 return CreateRectRgn32( rect->left, rect->top, rect->right, rect->bottom );
296 /***********************************************************************
297 * SetRectRgn16 (GDI.172)
299 VOID WINAPI SetRectRgn16( HRGN16 hrgn, INT16 left, INT16 top,
300 INT16 right, INT16 bottom )
302 SetRectRgn32( hrgn, left, top, right, bottom );
306 /***********************************************************************
307 * SetRectRgn32 (GDI32.332)
309 VOID WINAPI SetRectRgn32( HRGN32 hrgn, INT32 left, INT32 top,
310 INT32 right, INT32 bottom )
312 RGNOBJ * obj;
314 TRACE(region, " %04x %d,%d-%d,%d\n",
315 hrgn, left, top, right, bottom );
317 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
318 if ((right > left) && (bottom > top))
320 obj->rgn->rects->left = obj->rgn->extents.left = left;
321 obj->rgn->rects->top = obj->rgn->extents.top = top;
322 obj->rgn->rects->right = obj->rgn->extents.right = right;
323 obj->rgn->rects->bottom = obj->rgn->extents.bottom = bottom;
324 obj->rgn->numRects = 1;
325 obj->rgn->type = SIMPLEREGION;
327 else
328 EMPTY_REGION(obj->rgn);
330 GDI_HEAP_UNLOCK( hrgn );
334 /***********************************************************************
335 * CreateRoundRectRgn16 (GDI.444)
337 HRGN16 WINAPI CreateRoundRectRgn16( INT16 left, INT16 top,
338 INT16 right, INT16 bottom,
339 INT16 ellipse_width, INT16 ellipse_height )
341 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
342 ellipse_width, ellipse_height );
345 /***********************************************************************
346 * CreateRoundRectRgn32 (GDI32.61)
348 HRGN32 WINAPI CreateRoundRectRgn32( INT32 left, INT32 top,
349 INT32 right, INT32 bottom,
350 INT32 ellipse_width, INT32 ellipse_height )
352 RGNOBJ * obj;
353 HRGN32 hrgn;
354 int asq, bsq, d, xd, yd;
355 RECT32 rect;
357 /* Check if we can do a normal rectangle instead */
359 if ((right <= left) || (bottom <= top) ||
360 (ellipse_width <= 0) || (ellipse_height <= 0))
361 return CreateRectRgn32( left, top, right, bottom );
363 /* Create region */
365 if (!(hrgn = REGION_CreateRegion())) return 0;
366 obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
367 TRACE(region,"(%d,%d-%d,%d %dx%d): ret=%04x\n",
368 left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
370 /* Check parameters */
372 if (ellipse_width > right-left) ellipse_width = right-left;
373 if (ellipse_height > bottom-top) ellipse_height = bottom-top;
375 /* Ellipse algorithm, based on an article by K. Porter */
376 /* in DDJ Graphics Programming Column, 8/89 */
378 asq = ellipse_width * ellipse_width / 4; /* a^2 */
379 bsq = ellipse_height * ellipse_height / 4; /* b^2 */
380 d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
381 xd = 0;
382 yd = asq * ellipse_height; /* 2a^2b */
384 rect.left = left + ellipse_width / 2;
385 rect.right = right - ellipse_width;
387 /* Loop to draw first half of quadrant */
389 while (xd < yd)
391 if (d > 0) /* if nearest pixel is toward the center */
393 /* move toward center */
394 rect.top = top++;
395 rect.bottom = rect.top + 1;
396 REGION_UnionRectWithRegion( &rect, obj->rgn );
397 rect.top = --bottom;
398 rect.bottom = rect.top + 1;
399 REGION_UnionRectWithRegion( &rect, obj->rgn );
400 yd -= 2*asq;
401 d -= yd;
403 rect.left--; /* next horiz point */
404 rect.right++;
405 xd += 2*bsq;
406 d += bsq + xd;
409 /* Loop to draw second half of quadrant */
411 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
412 while (yd >= 0)
414 /* next vertical point */
415 rect.top = top++;
416 rect.bottom = rect.top + 1;
417 REGION_UnionRectWithRegion( &rect, obj->rgn );
418 rect.top = --bottom;
419 rect.bottom = rect.top + 1;
420 REGION_UnionRectWithRegion( &rect, obj->rgn );
421 if (d < 0) /* if nearest pixel is outside ellipse */
423 rect.left--; /* move away from center */
424 rect.right++;
425 xd += 2*bsq;
426 d += xd;
428 yd -= 2*asq;
429 d += asq - yd;
432 /* Add the inside rectangle */
434 if (top <= bottom)
436 rect.top = top;
437 rect.bottom = bottom;
438 REGION_UnionRectWithRegion( &rect, obj->rgn );
440 obj->rgn->type = SIMPLEREGION; /* FIXME? */
441 GDI_HEAP_UNLOCK( hrgn );
442 return hrgn;
446 /***********************************************************************
447 * CreateEllipticRgn16 (GDI.54)
449 HRGN16 WINAPI CreateEllipticRgn16( INT16 left, INT16 top,
450 INT16 right, INT16 bottom )
452 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
453 right-left, bottom-top );
457 /***********************************************************************
458 * CreateEllipticRgn32 (GDI32.39)
460 HRGN32 WINAPI CreateEllipticRgn32( INT32 left, INT32 top,
461 INT32 right, INT32 bottom )
463 return CreateRoundRectRgn32( left, top, right, bottom,
464 right-left, bottom-top );
468 /***********************************************************************
469 * CreateEllipticRgnIndirect16 (GDI.55)
471 HRGN16 WINAPI CreateEllipticRgnIndirect16( const RECT16 *rect )
473 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
474 rect->bottom, rect->right - rect->left,
475 rect->bottom - rect->top );
479 /***********************************************************************
480 * CreateEllipticRgnIndirect32 (GDI32.40)
482 HRGN32 WINAPI CreateEllipticRgnIndirect32( const RECT32 *rect )
484 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
485 rect->bottom, rect->right - rect->left,
486 rect->bottom - rect->top );
489 /***********************************************************************
490 * GetRegionData (GDI32.217)
493 DWORD WINAPI GetRegionData(HRGN32 hrgn, DWORD count, LPRGNDATA rgndata)
495 DWORD size;
496 RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
498 TRACE(region, " %04x count = %ld, rgndata = %p\n",
499 hrgn, count, rgndata);
501 if(!obj) return 0;
503 size = obj->rgn->numRects * sizeof(RECT32);
504 if(count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
506 GDI_HEAP_UNLOCK( hrgn );
507 return size + sizeof(RGNDATAHEADER);
510 rgndata->rdh.dwSize = sizeof(RGNDATAHEADER);
511 rgndata->rdh.iType = RDH_RECTANGLES;
512 rgndata->rdh.nCount = obj->rgn->numRects;
513 rgndata->rdh.nRgnSize = size;
514 rgndata->rdh.rcBound.left = obj->rgn->extents.left;
515 rgndata->rdh.rcBound.top = obj->rgn->extents.top;
516 rgndata->rdh.rcBound.right = obj->rgn->extents.right;
517 rgndata->rdh.rcBound.bottom = obj->rgn->extents.bottom;
519 memcpy( rgndata->Buffer, obj->rgn->rects, size );
521 GDI_HEAP_UNLOCK( hrgn );
522 return 1;
525 /***********************************************************************
526 * ExtCreateRegion (GDI32.94)
529 HRGN32 WINAPI ExtCreateRegion( XFORM *lpXform, DWORD dwCount, RGNDATA *rgndata)
531 HRGN32 hrgn = CreateRectRgn32(0, 0, 0, 0);
532 RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
533 RECT32 *pCurRect, *pEndRect;
535 TRACE(region, " %p %ld %p. Returning %04x\n",
536 lpXform, dwCount, rgndata, hrgn);
537 if(!hrgn)
539 WARN(region, "Can't create a region!\n");
540 return 0;
542 if(lpXform)
543 WARN(region, "Xform not implemented - ignoring\n");
545 if(rgndata->rdh.iType != RDH_RECTANGLES)
547 WARN(region, "Type not RDH_RECTANGLES\n");
548 GDI_HEAP_UNLOCK( hrgn );
549 DeleteObject32( hrgn );
550 return 0;
553 pEndRect = (RECT32 *)rgndata->Buffer + rgndata->rdh.nCount;
554 for(pCurRect = (RECT32 *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
555 REGION_UnionRectWithRegion( pCurRect, obj->rgn );
557 GDI_HEAP_UNLOCK( hrgn );
558 return hrgn;
561 /***********************************************************************
562 * PtInRegion16 (GDI.161)
564 BOOL16 WINAPI PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
566 return PtInRegion32( hrgn, x, y );
570 /***********************************************************************
571 * PtInRegion32 (GDI32.278)
573 BOOL32 WINAPI PtInRegion32( HRGN32 hrgn, INT32 x, INT32 y )
575 RGNOBJ * obj;
577 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
579 BOOL32 ret = FALSE;
580 int i;
582 if (obj->rgn->numRects > 0 && INRECT(obj->rgn->extents, x, y))
583 for (i = 0; i < obj->rgn->numRects; i++)
584 if (INRECT (obj->rgn->rects[i], x, y))
585 ret = TRUE;
586 GDI_HEAP_UNLOCK( hrgn );
587 return ret;
589 return FALSE;
593 /***********************************************************************
594 * RectInRegion16 (GDI.181)
596 BOOL16 WINAPI RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
598 RECT32 r32;
600 CONV_RECT16TO32(rect, &r32);
601 return (BOOL16)RectInRegion32(hrgn, &r32);
605 /***********************************************************************
606 * RectInRegion32 (GDI32.281)
608 * Returns TRUE if rect is at least partly inside hrgn
610 BOOL32 WINAPI RectInRegion32( HRGN32 hrgn, const RECT32 *rect )
612 RGNOBJ * obj;
614 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
616 RECT32 *pCurRect, *pRectEnd;
617 BOOL32 ret = FALSE;
619 /* this is (just) a useful optimization */
620 if ((obj->rgn->numRects > 0) && EXTENTCHECK(&obj->rgn->extents,
621 rect))
623 for (pCurRect = obj->rgn->rects, pRectEnd = pCurRect +
624 obj->rgn->numRects; pCurRect < pRectEnd; pCurRect++)
626 if (pCurRect->bottom <= rect->top)
627 continue; /* not far enough down yet */
629 if (pCurRect->top >= rect->bottom) {
630 ret = FALSE; /* too far down */
631 break;
634 if (pCurRect->right <= rect->left)
635 continue; /* not far enough over yet */
637 if (pCurRect->left >= rect->right) {
638 ret = FALSE; /* too far over */
639 break;
642 ret = TRUE;
643 break;
646 GDI_HEAP_UNLOCK(hrgn);
647 return ret;
649 return FALSE;
652 /***********************************************************************
653 * EqualRgn16 (GDI.72)
655 BOOL16 WINAPI EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
657 return EqualRgn32( rgn1, rgn2 );
661 /***********************************************************************
662 * EqualRgn32 (GDI32.90)
664 BOOL32 WINAPI EqualRgn32( HRGN32 hrgn1, HRGN32 hrgn2 )
666 RGNOBJ *obj1, *obj2;
667 BOOL32 ret = FALSE;
669 if ((obj1 = (RGNOBJ *) GDI_GetObjPtr( hrgn1, REGION_MAGIC )))
671 if ((obj2 = (RGNOBJ *) GDI_GetObjPtr( hrgn2, REGION_MAGIC )))
673 int i;
675 ret = TRUE;
676 if ( obj1->rgn->numRects != obj2->rgn->numRects ) ret = FALSE;
677 else if ( obj1->rgn->numRects == 0 ) ret = TRUE;
678 else if ( !EqualRect32(&obj1->rgn->extents, &obj2->rgn->extents) )
679 ret = FALSE;
680 else for( i = 0; i < obj1->rgn->numRects; i++ ) {
681 if (!EqualRect32(obj1->rgn->rects + i, obj2->rgn->rects + i)) {
682 ret = FALSE;
683 break;
686 GDI_HEAP_UNLOCK(hrgn2);
688 GDI_HEAP_UNLOCK(hrgn1);
690 return ret;
692 /***********************************************************************
693 * REGION_UnionRectWithRegion
694 * Adds a rectangle to a WINEREGION
695 * See below for REGION_UnionRectWithRgn
697 static void REGION_UnionRectWithRegion(const RECT32 *rect, WINEREGION *rgn)
699 WINEREGION region;
701 region.rects = &region.extents;
702 region.numRects = 1;
703 region.size = 1;
704 region.type = SIMPLEREGION;
705 CopyRect32(&(region.extents), rect);
706 REGION_UnionRegion(rgn, rgn, &region);
707 return;
710 /***********************************************************************
711 * REGION_UnionRectWithRgn
712 * Adds a rectangle to a HRGN32
713 * A helper used by scroll.c
715 BOOL32 REGION_UnionRectWithRgn( HRGN32 hrgn, const RECT32 *lpRect )
717 RGNOBJ *obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
719 if(!obj) return FALSE;
720 REGION_UnionRectWithRegion( lpRect, obj->rgn );
721 GDI_HEAP_UNLOCK(hrgn);
722 return TRUE;
725 /***********************************************************************
726 * REGION_CreateFrameRgn
728 * Create a region that is a frame around another region.
729 * Expand all rectangles by +/- x and y, then subtract original region.
731 BOOL32 REGION_FrameRgn( HRGN32 hDest, HRGN32 hSrc, INT32 x, INT32 y )
733 BOOL32 bRet;
734 RGNOBJ *srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
736 if (srcObj->rgn->numRects != 0)
738 RGNOBJ* destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
739 RECT32 *pRect, *pEndRect;
740 RECT32 tempRect;
742 EMPTY_REGION( destObj->rgn );
744 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
745 for(pRect = srcObj->rgn->rects; pRect < pEndRect; pRect++)
747 tempRect.left = pRect->left - x;
748 tempRect.top = pRect->top - y;
749 tempRect.right = pRect->right + x;
750 tempRect.bottom = pRect->bottom + y;
751 REGION_UnionRectWithRegion( &tempRect, destObj->rgn );
753 REGION_SubtractRegion( destObj->rgn, destObj->rgn, srcObj->rgn );
754 GDI_HEAP_UNLOCK ( hDest );
755 bRet = TRUE;
757 else
758 bRet = FALSE;
759 GDI_HEAP_UNLOCK( hSrc );
760 return bRet;
763 /***********************************************************************
764 * REGION_LPTODP
766 * Convert region to device co-ords for the supplied dc.
767 * Used by X11DRV_PaintRgn.
769 BOOL32 REGION_LPTODP( HDC32 hdc, HRGN32 hDest, HRGN32 hSrc )
771 RECT32 *pCurRect, *pEndRect;
772 RGNOBJ *srcObj, *destObj;
773 DC * dc = DC_GetDCPtr( hdc );
774 RECT32 tmpRect;
776 TRACE(region, " hdc=%04x dest=%04x src=%04x\n",
777 hdc, hDest, hSrc) ;
779 if (dc->w.MapMode == MM_TEXT) /* Requires only a translation */
781 if( CombineRgn32( hDest, hSrc, 0, RGN_COPY ) == ERROR ) return FALSE;
782 OffsetRgn32( hDest, dc->vportOrgX - dc->wndOrgX,
783 dc->vportOrgY - dc->wndOrgY );
784 return TRUE;
787 if(!( srcObj = (RGNOBJ *) GDI_GetObjPtr( hSrc, REGION_MAGIC) ))
788 return FALSE;
789 if(!( destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC) ))
791 GDI_HEAP_UNLOCK( hSrc );
792 return FALSE;
794 EMPTY_REGION( destObj->rgn );
796 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
797 for(pCurRect = srcObj->rgn->rects; pCurRect < pEndRect; pCurRect++)
799 tmpRect = *pCurRect;
800 tmpRect.left = XLPTODP( dc, tmpRect.left );
801 tmpRect.top = YLPTODP( dc, tmpRect.top );
802 tmpRect.right = XLPTODP( dc, tmpRect.right );
803 tmpRect.bottom = YLPTODP( dc, tmpRect.bottom );
804 REGION_UnionRectWithRegion( &tmpRect, destObj->rgn );
807 GDI_HEAP_UNLOCK( hDest );
808 GDI_HEAP_UNLOCK( hSrc );
809 return TRUE;
812 /***********************************************************************
813 * CombineRgn16 (GDI.451)
815 INT16 WINAPI CombineRgn16(HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode)
817 return (INT16)CombineRgn32( hDest, hSrc1, hSrc2, mode );
821 /***********************************************************************
822 * CombineRgn32 (GDI32.19)
824 * Note: The behavior is correct even if src and dest regions are the same.
826 INT32 WINAPI CombineRgn32(HRGN32 hDest, HRGN32 hSrc1, HRGN32 hSrc2, INT32 mode)
828 RGNOBJ *destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC);
829 INT32 result = ERROR;
831 TRACE(region, " %04x,%04x -> %04x mode=%x\n",
832 hSrc1, hSrc2, hDest, mode );
833 if (destObj)
835 RGNOBJ *src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC);
837 if (src1Obj)
839 TRACE(region, "dump:\n");
840 if(TRACE_ON(region))
841 REGION_DumpRegion(src1Obj->rgn);
842 if (mode == RGN_COPY)
844 REGION_CopyRegion( destObj->rgn, src1Obj->rgn );
845 result = destObj->rgn->type;
847 else
849 RGNOBJ *src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC);
851 if (src2Obj)
853 TRACE(region, "dump:\n");
854 if(TRACE_ON(region))
855 REGION_DumpRegion(src2Obj->rgn);
856 switch (mode)
858 case RGN_AND:
859 REGION_IntersectRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn);
860 break;
861 case RGN_OR:
862 REGION_UnionRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
863 break;
864 case RGN_XOR:
865 REGION_XorRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
866 break;
867 case RGN_DIFF:
868 REGION_SubtractRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
869 break;
871 result = destObj->rgn->type;
872 GDI_HEAP_UNLOCK( hSrc2 );
875 GDI_HEAP_UNLOCK( hSrc1 );
877 TRACE(region, "dump:\n");
878 if(TRACE_ON(region))
879 REGION_DumpRegion(destObj->rgn);
881 GDI_HEAP_UNLOCK( hDest );
883 return result;
886 /***********************************************************************
887 * REGION_SetExtents
888 * Re-calculate the extents of a region
890 static void REGION_SetExtents (WINEREGION *pReg)
892 RECT32 *pRect, *pRectEnd, *pExtents;
894 if (pReg->numRects == 0)
896 pReg->extents.left = 0;
897 pReg->extents.top = 0;
898 pReg->extents.right = 0;
899 pReg->extents.bottom = 0;
900 return;
903 pExtents = &pReg->extents;
904 pRect = pReg->rects;
905 pRectEnd = &pRect[pReg->numRects - 1];
908 * Since pRect is the first rectangle in the region, it must have the
909 * smallest top and since pRectEnd is the last rectangle in the region,
910 * it must have the largest bottom, because of banding. Initialize left and
911 * right from pRect and pRectEnd, resp., as good things to initialize them
912 * to...
914 pExtents->left = pRect->left;
915 pExtents->top = pRect->top;
916 pExtents->right = pRectEnd->right;
917 pExtents->bottom = pRectEnd->bottom;
919 while (pRect <= pRectEnd)
921 if (pRect->left < pExtents->left)
922 pExtents->left = pRect->left;
923 if (pRect->right > pExtents->right)
924 pExtents->right = pRect->right;
925 pRect++;
929 /***********************************************************************
930 * REGION_CopyRegion
932 static void REGION_CopyRegion(WINEREGION *dst, WINEREGION *src)
934 if (dst != src) /* don't want to copy to itself */
936 if (dst->size < src->numRects)
938 if (! (dst->rects = HeapReAlloc( SystemHeap, 0, dst->rects,
939 src->numRects * sizeof(RECT32) )))
940 return;
941 dst->size = src->numRects;
943 dst->numRects = src->numRects;
944 dst->extents.left = src->extents.left;
945 dst->extents.top = src->extents.top;
946 dst->extents.right = src->extents.right;
947 dst->extents.bottom = src->extents.bottom;
948 dst->type = src->type;
950 memcpy((char *) dst->rects, (char *) src->rects,
951 (int) (src->numRects * sizeof(RECT32)));
953 return;
956 /***********************************************************************
957 * REGION_Coalesce
959 * Attempt to merge the rects in the current band with those in the
960 * previous one. Used only by REGION_RegionOp.
962 * Results:
963 * The new index for the previous band.
965 * Side Effects:
966 * If coalescing takes place:
967 * - rectangles in the previous band will have their bottom fields
968 * altered.
969 * - pReg->numRects will be decreased.
972 static INT32 REGION_Coalesce (
973 WINEREGION *pReg, /* Region to coalesce */
974 INT32 prevStart, /* Index of start of previous band */
975 INT32 curStart /* Index of start of current band */
977 RECT32 *pPrevRect; /* Current rect in previous band */
978 RECT32 *pCurRect; /* Current rect in current band */
979 RECT32 *pRegEnd; /* End of region */
980 INT32 curNumRects; /* Number of rectangles in current band */
981 INT32 prevNumRects; /* Number of rectangles in previous band */
982 INT32 bandtop; /* top coordinate for current band */
984 pRegEnd = &pReg->rects[pReg->numRects];
986 pPrevRect = &pReg->rects[prevStart];
987 prevNumRects = curStart - prevStart;
990 * Figure out how many rectangles are in the current band. Have to do
991 * this because multiple bands could have been added in REGION_RegionOp
992 * at the end when one region has been exhausted.
994 pCurRect = &pReg->rects[curStart];
995 bandtop = pCurRect->top;
996 for (curNumRects = 0;
997 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
998 curNumRects++)
1000 pCurRect++;
1003 if (pCurRect != pRegEnd)
1006 * If more than one band was added, we have to find the start
1007 * of the last band added so the next coalescing job can start
1008 * at the right place... (given when multiple bands are added,
1009 * this may be pointless -- see above).
1011 pRegEnd--;
1012 while (pRegEnd[-1].top == pRegEnd->top)
1014 pRegEnd--;
1016 curStart = pRegEnd - pReg->rects;
1017 pRegEnd = pReg->rects + pReg->numRects;
1020 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
1021 pCurRect -= curNumRects;
1023 * The bands may only be coalesced if the bottom of the previous
1024 * matches the top scanline of the current.
1026 if (pPrevRect->bottom == pCurRect->top)
1029 * Make sure the bands have rects in the same places. This
1030 * assumes that rects have been added in such a way that they
1031 * cover the most area possible. I.e. two rects in a band must
1032 * have some horizontal space between them.
1036 if ((pPrevRect->left != pCurRect->left) ||
1037 (pPrevRect->right != pCurRect->right))
1040 * The bands don't line up so they can't be coalesced.
1042 return (curStart);
1044 pPrevRect++;
1045 pCurRect++;
1046 prevNumRects -= 1;
1047 } while (prevNumRects != 0);
1049 pReg->numRects -= curNumRects;
1050 pCurRect -= curNumRects;
1051 pPrevRect -= curNumRects;
1054 * The bands may be merged, so set the bottom of each rect
1055 * in the previous band to that of the corresponding rect in
1056 * the current band.
1060 pPrevRect->bottom = pCurRect->bottom;
1061 pPrevRect++;
1062 pCurRect++;
1063 curNumRects -= 1;
1064 } while (curNumRects != 0);
1067 * If only one band was added to the region, we have to backup
1068 * curStart to the start of the previous band.
1070 * If more than one band was added to the region, copy the
1071 * other bands down. The assumption here is that the other bands
1072 * came from the same region as the current one and no further
1073 * coalescing can be done on them since it's all been done
1074 * already... curStart is already in the right place.
1076 if (pCurRect == pRegEnd)
1078 curStart = prevStart;
1080 else
1084 *pPrevRect++ = *pCurRect++;
1085 } while (pCurRect != pRegEnd);
1090 return (curStart);
1093 /***********************************************************************
1094 * REGION_RegionOp
1096 * Apply an operation to two regions. Called by REGION_Union,
1097 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
1099 * Results:
1100 * None.
1102 * Side Effects:
1103 * The new region is overwritten.
1105 * Notes:
1106 * The idea behind this function is to view the two regions as sets.
1107 * Together they cover a rectangle of area that this function divides
1108 * into horizontal bands where points are covered only by one region
1109 * or by both. For the first case, the nonOverlapFunc is called with
1110 * each the band and the band's upper and lower extents. For the
1111 * second, the overlapFunc is called to process the entire band. It
1112 * is responsible for clipping the rectangles in the band, though
1113 * this function provides the boundaries.
1114 * At the end of each band, the new region is coalesced, if possible,
1115 * to reduce the number of rectangles in the region.
1118 static void REGION_RegionOp(
1119 WINEREGION *newReg, /* Place to store result */
1120 WINEREGION *reg1, /* First region in operation */
1121 WINEREGION *reg2, /* 2nd region in operation */
1122 void (*overlapFunc)(), /* Function to call for over-lapping bands */
1123 void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
1124 void (*nonOverlap2Func)() /* Function to call for non-overlapping bands in region 2 */
1126 RECT32 *r1; /* Pointer into first region */
1127 RECT32 *r2; /* Pointer into 2d region */
1128 RECT32 *r1End; /* End of 1st region */
1129 RECT32 *r2End; /* End of 2d region */
1130 INT32 ybot; /* Bottom of intersection */
1131 INT32 ytop; /* Top of intersection */
1132 RECT32 *oldRects; /* Old rects for newReg */
1133 INT32 prevBand; /* Index of start of
1134 * previous band in newReg */
1135 INT32 curBand; /* Index of start of current
1136 * band in newReg */
1137 RECT32 *r1BandEnd; /* End of current band in r1 */
1138 RECT32 *r2BandEnd; /* End of current band in r2 */
1139 INT32 top; /* Top of non-overlapping band */
1140 INT32 bot; /* Bottom of non-overlapping band */
1143 * Initialization:
1144 * set r1, r2, r1End and r2End appropriately, preserve the important
1145 * parts of the destination region until the end in case it's one of
1146 * the two source regions, then mark the "new" region empty, allocating
1147 * another array of rectangles for it to use.
1149 r1 = reg1->rects;
1150 r2 = reg2->rects;
1151 r1End = r1 + reg1->numRects;
1152 r2End = r2 + reg2->numRects;
1156 * newReg may be one of the src regions so we can't empty it. We keep a
1157 * note of its rects pointer (so that we can free them later), preserve its
1158 * extents and simply set numRects to zero.
1161 oldRects = newReg->rects;
1162 newReg->numRects = 0;
1165 * Allocate a reasonable number of rectangles for the new region. The idea
1166 * is to allocate enough so the individual functions don't need to
1167 * reallocate and copy the array, which is time consuming, yet we don't
1168 * have to worry about using too much memory. I hope to be able to
1169 * nuke the Xrealloc() at the end of this function eventually.
1171 newReg->size = MAX(reg1->numRects,reg2->numRects) * 2;
1173 if (! (newReg->rects = HeapAlloc( SystemHeap, 0,
1174 sizeof(RECT32) * newReg->size )))
1176 newReg->size = 0;
1177 return;
1181 * Initialize ybot and ytop.
1182 * In the upcoming loop, ybot and ytop serve different functions depending
1183 * on whether the band being handled is an overlapping or non-overlapping
1184 * band.
1185 * In the case of a non-overlapping band (only one of the regions
1186 * has points in the band), ybot is the bottom of the most recent
1187 * intersection and thus clips the top of the rectangles in that band.
1188 * ytop is the top of the next intersection between the two regions and
1189 * serves to clip the bottom of the rectangles in the current band.
1190 * For an overlapping band (where the two regions intersect), ytop clips
1191 * the top of the rectangles of both regions and ybot clips the bottoms.
1193 if (reg1->extents.top < reg2->extents.top)
1194 ybot = reg1->extents.top;
1195 else
1196 ybot = reg2->extents.top;
1199 * prevBand serves to mark the start of the previous band so rectangles
1200 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1201 * In the beginning, there is no previous band, so prevBand == curBand
1202 * (curBand is set later on, of course, but the first band will always
1203 * start at index 0). prevBand and curBand must be indices because of
1204 * the possible expansion, and resultant moving, of the new region's
1205 * array of rectangles.
1207 prevBand = 0;
1211 curBand = newReg->numRects;
1214 * This algorithm proceeds one source-band (as opposed to a
1215 * destination band, which is determined by where the two regions
1216 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1217 * rectangle after the last one in the current band for their
1218 * respective regions.
1220 r1BandEnd = r1;
1221 while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
1223 r1BandEnd++;
1226 r2BandEnd = r2;
1227 while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
1229 r2BandEnd++;
1233 * First handle the band that doesn't intersect, if any.
1235 * Note that attention is restricted to one band in the
1236 * non-intersecting region at once, so if a region has n
1237 * bands between the current position and the next place it overlaps
1238 * the other, this entire loop will be passed through n times.
1240 if (r1->top < r2->top)
1242 top = MAX(r1->top,ybot);
1243 bot = MIN(r1->bottom,r2->top);
1245 if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
1247 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
1250 ytop = r2->top;
1252 else if (r2->top < r1->top)
1254 top = MAX(r2->top,ybot);
1255 bot = MIN(r2->bottom,r1->top);
1257 if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
1259 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
1262 ytop = r1->top;
1264 else
1266 ytop = r1->top;
1270 * If any rectangles got added to the region, try and coalesce them
1271 * with rectangles from the previous band. Note we could just do
1272 * this test in miCoalesce, but some machines incur a not
1273 * inconsiderable cost for function calls, so...
1275 if (newReg->numRects != curBand)
1277 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1281 * Now see if we've hit an intersecting band. The two bands only
1282 * intersect if ybot > ytop
1284 ybot = MIN(r1->bottom, r2->bottom);
1285 curBand = newReg->numRects;
1286 if (ybot > ytop)
1288 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1292 if (newReg->numRects != curBand)
1294 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1298 * If we've finished with a band (bottom == ybot) we skip forward
1299 * in the region to the next band.
1301 if (r1->bottom == ybot)
1303 r1 = r1BandEnd;
1305 if (r2->bottom == ybot)
1307 r2 = r2BandEnd;
1309 } while ((r1 != r1End) && (r2 != r2End));
1312 * Deal with whichever region still has rectangles left.
1314 curBand = newReg->numRects;
1315 if (r1 != r1End)
1317 if (nonOverlap1Func != (void (*)())NULL)
1321 r1BandEnd = r1;
1322 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
1324 r1BandEnd++;
1326 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
1327 MAX(r1->top,ybot), r1->bottom);
1328 r1 = r1BandEnd;
1329 } while (r1 != r1End);
1332 else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
1336 r2BandEnd = r2;
1337 while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
1339 r2BandEnd++;
1341 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
1342 MAX(r2->top,ybot), r2->bottom);
1343 r2 = r2BandEnd;
1344 } while (r2 != r2End);
1347 if (newReg->numRects != curBand)
1349 (void) REGION_Coalesce (newReg, prevBand, curBand);
1353 * A bit of cleanup. To keep regions from growing without bound,
1354 * we shrink the array of rectangles to match the new number of
1355 * rectangles in the region. This never goes to 0, however...
1357 * Only do this stuff if the number of rectangles allocated is more than
1358 * twice the number of rectangles in the region (a simple optimization...).
1360 if (newReg->numRects < (newReg->size >> 1))
1362 if (REGION_NOT_EMPTY(newReg))
1364 RECT32 *prev_rects = newReg->rects;
1365 newReg->size = newReg->numRects;
1366 newReg->rects = HeapReAlloc( SystemHeap, 0, newReg->rects,
1367 sizeof(RECT32) * newReg->size );
1368 if (! newReg->rects)
1369 newReg->rects = prev_rects;
1371 else
1374 * No point in doing the extra work involved in an Xrealloc if
1375 * the region is empty
1377 newReg->size = 1;
1378 HeapFree( SystemHeap, 0, newReg->rects );
1379 newReg->rects = HeapAlloc( SystemHeap, 0, sizeof(RECT32) );
1382 HeapFree( SystemHeap, 0, oldRects );
1383 return;
1386 /***********************************************************************
1387 * Region Intersection
1388 ***********************************************************************/
1391 /***********************************************************************
1392 * REGION_IntersectO
1394 * Handle an overlapping band for REGION_Intersect.
1396 * Results:
1397 * None.
1399 * Side Effects:
1400 * Rectangles may be added to the region.
1403 static void REGION_IntersectO(WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1404 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1407 INT32 left, right;
1408 RECT32 *pNextRect;
1410 pNextRect = &pReg->rects[pReg->numRects];
1412 while ((r1 != r1End) && (r2 != r2End))
1414 left = MAX(r1->left, r2->left);
1415 right = MIN(r1->right, r2->right);
1418 * If there's any overlap between the two rectangles, add that
1419 * overlap to the new region.
1420 * There's no need to check for subsumption because the only way
1421 * such a need could arise is if some region has two rectangles
1422 * right next to each other. Since that should never happen...
1424 if (left < right)
1426 MEMCHECK(pReg, pNextRect, pReg->rects);
1427 pNextRect->left = left;
1428 pNextRect->top = top;
1429 pNextRect->right = right;
1430 pNextRect->bottom = bottom;
1431 pReg->numRects += 1;
1432 pNextRect++;
1436 * Need to advance the pointers. Shift the one that extends
1437 * to the right the least, since the other still has a chance to
1438 * overlap with that region's next rectangle, if you see what I mean.
1440 if (r1->right < r2->right)
1442 r1++;
1444 else if (r2->right < r1->right)
1446 r2++;
1448 else
1450 r1++;
1451 r2++;
1454 return;
1457 /***********************************************************************
1458 * REGION_IntersectRegion
1460 static void REGION_IntersectRegion(WINEREGION *newReg, WINEREGION *reg1,
1461 WINEREGION *reg2)
1463 /* check for trivial reject */
1464 if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
1465 (!EXTENTCHECK(&reg1->extents, &reg2->extents)))
1466 newReg->numRects = 0;
1467 else
1468 REGION_RegionOp (newReg, reg1, reg2,
1469 (voidProcp) REGION_IntersectO, (voidProcp) NULL, (voidProcp) NULL);
1472 * Can't alter newReg's extents before we call miRegionOp because
1473 * it might be one of the source regions and miRegionOp depends
1474 * on the extents of those regions being the same. Besides, this
1475 * way there's no checking against rectangles that will be nuked
1476 * due to coalescing, so we have to examine fewer rectangles.
1478 REGION_SetExtents(newReg);
1479 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1480 return;
1483 /***********************************************************************
1484 * Region Union
1485 ***********************************************************************/
1487 /***********************************************************************
1488 * REGION_UnionNonO
1490 * Handle a non-overlapping band for the union operation. Just
1491 * Adds the rectangles into the region. Doesn't have to check for
1492 * subsumption or anything.
1494 * Results:
1495 * None.
1497 * Side Effects:
1498 * pReg->numRects is incremented and the final rectangles overwritten
1499 * with the rectangles we're passed.
1502 static void REGION_UnionNonO (WINEREGION *pReg, RECT32 *r, RECT32 *rEnd,
1503 INT32 top, INT32 bottom)
1505 RECT32 *pNextRect;
1507 pNextRect = &pReg->rects[pReg->numRects];
1509 while (r != rEnd)
1511 MEMCHECK(pReg, pNextRect, pReg->rects);
1512 pNextRect->left = r->left;
1513 pNextRect->top = top;
1514 pNextRect->right = r->right;
1515 pNextRect->bottom = bottom;
1516 pReg->numRects += 1;
1517 pNextRect++;
1518 r++;
1520 return;
1523 /***********************************************************************
1524 * REGION_UnionO
1526 * Handle an overlapping band for the union operation. Picks the
1527 * left-most rectangle each time and merges it into the region.
1529 * Results:
1530 * None.
1532 * Side Effects:
1533 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1534 * be changed.
1537 static void REGION_UnionO (WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1538 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1540 RECT32 *pNextRect;
1542 pNextRect = &pReg->rects[pReg->numRects];
1544 #define MERGERECT(r) \
1545 if ((pReg->numRects != 0) && \
1546 (pNextRect[-1].top == top) && \
1547 (pNextRect[-1].bottom == bottom) && \
1548 (pNextRect[-1].right >= r->left)) \
1550 if (pNextRect[-1].right < r->right) \
1552 pNextRect[-1].right = r->right; \
1555 else \
1557 MEMCHECK(pReg, pNextRect, pReg->rects); \
1558 pNextRect->top = top; \
1559 pNextRect->bottom = bottom; \
1560 pNextRect->left = r->left; \
1561 pNextRect->right = r->right; \
1562 pReg->numRects += 1; \
1563 pNextRect += 1; \
1565 r++;
1567 while ((r1 != r1End) && (r2 != r2End))
1569 if (r1->left < r2->left)
1571 MERGERECT(r1);
1573 else
1575 MERGERECT(r2);
1579 if (r1 != r1End)
1583 MERGERECT(r1);
1584 } while (r1 != r1End);
1586 else while (r2 != r2End)
1588 MERGERECT(r2);
1590 return;
1593 /***********************************************************************
1594 * REGION_UnionRegion
1596 static void REGION_UnionRegion(WINEREGION *newReg, WINEREGION *reg1,
1597 WINEREGION *reg2)
1599 /* checks all the simple cases */
1602 * Region 1 and 2 are the same or region 1 is empty
1604 if ( (reg1 == reg2) || (!(reg1->numRects)) )
1606 if (newReg != reg2)
1607 REGION_CopyRegion(newReg, reg2);
1608 return;
1612 * if nothing to union (region 2 empty)
1614 if (!(reg2->numRects))
1616 if (newReg != reg1)
1617 REGION_CopyRegion(newReg, reg1);
1618 return;
1622 * Region 1 completely subsumes region 2
1624 if ((reg1->numRects == 1) &&
1625 (reg1->extents.left <= reg2->extents.left) &&
1626 (reg1->extents.top <= reg2->extents.top) &&
1627 (reg1->extents.right >= reg2->extents.right) &&
1628 (reg1->extents.bottom >= reg2->extents.bottom))
1630 if (newReg != reg1)
1631 REGION_CopyRegion(newReg, reg1);
1632 return;
1636 * Region 2 completely subsumes region 1
1638 if ((reg2->numRects == 1) &&
1639 (reg2->extents.left <= reg1->extents.left) &&
1640 (reg2->extents.top <= reg1->extents.top) &&
1641 (reg2->extents.right >= reg1->extents.right) &&
1642 (reg2->extents.bottom >= reg1->extents.bottom))
1644 if (newReg != reg2)
1645 REGION_CopyRegion(newReg, reg2);
1646 return;
1649 REGION_RegionOp (newReg, reg1, reg2, (voidProcp) REGION_UnionO,
1650 (voidProcp) REGION_UnionNonO, (voidProcp) REGION_UnionNonO);
1652 newReg->extents.left = MIN(reg1->extents.left, reg2->extents.left);
1653 newReg->extents.top = MIN(reg1->extents.top, reg2->extents.top);
1654 newReg->extents.right = MAX(reg1->extents.right, reg2->extents.right);
1655 newReg->extents.bottom = MAX(reg1->extents.bottom, reg2->extents.bottom);
1656 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1657 return;
1660 /***********************************************************************
1661 * Region Subtraction
1662 ***********************************************************************/
1664 /***********************************************************************
1665 * REGION_SubtractNonO1
1667 * Deal with non-overlapping band for subtraction. Any parts from
1668 * region 2 we discard. Anything from region 1 we add to the region.
1670 * Results:
1671 * None.
1673 * Side Effects:
1674 * pReg may be affected.
1677 static void REGION_SubtractNonO1 (WINEREGION *pReg, RECT32 *r, RECT32 *rEnd,
1678 INT32 top, INT32 bottom)
1680 RECT32 *pNextRect;
1682 pNextRect = &pReg->rects[pReg->numRects];
1684 while (r != rEnd)
1686 MEMCHECK(pReg, pNextRect, pReg->rects);
1687 pNextRect->left = r->left;
1688 pNextRect->top = top;
1689 pNextRect->right = r->right;
1690 pNextRect->bottom = bottom;
1691 pReg->numRects += 1;
1692 pNextRect++;
1693 r++;
1695 return;
1699 /***********************************************************************
1700 * REGION_SubtractO
1702 * Overlapping band subtraction. x1 is the left-most point not yet
1703 * checked.
1705 * Results:
1706 * None.
1708 * Side Effects:
1709 * pReg may have rectangles added to it.
1712 static void REGION_SubtractO (WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1713 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1715 RECT32 *pNextRect;
1716 INT32 left;
1718 left = r1->left;
1719 pNextRect = &pReg->rects[pReg->numRects];
1721 while ((r1 != r1End) && (r2 != r2End))
1723 if (r2->right <= left)
1726 * Subtrahend missed the boat: go to next subtrahend.
1728 r2++;
1730 else if (r2->left <= left)
1733 * Subtrahend preceeds minuend: nuke left edge of minuend.
1735 left = r2->right;
1736 if (left >= r1->right)
1739 * Minuend completely covered: advance to next minuend and
1740 * reset left fence to edge of new minuend.
1742 r1++;
1743 if (r1 != r1End)
1744 left = r1->left;
1746 else
1749 * Subtrahend now used up since it doesn't extend beyond
1750 * minuend
1752 r2++;
1755 else if (r2->left < r1->right)
1758 * Left part of subtrahend covers part of minuend: add uncovered
1759 * part of minuend to region and skip to next subtrahend.
1761 MEMCHECK(pReg, pNextRect, pReg->rects);
1762 pNextRect->left = left;
1763 pNextRect->top = top;
1764 pNextRect->right = r2->left;
1765 pNextRect->bottom = bottom;
1766 pReg->numRects += 1;
1767 pNextRect++;
1768 left = r2->right;
1769 if (left >= r1->right)
1772 * Minuend used up: advance to new...
1774 r1++;
1775 if (r1 != r1End)
1776 left = r1->left;
1778 else
1781 * Subtrahend used up
1783 r2++;
1786 else
1789 * Minuend used up: add any remaining piece before advancing.
1791 if (r1->right > left)
1793 MEMCHECK(pReg, pNextRect, pReg->rects);
1794 pNextRect->left = left;
1795 pNextRect->top = top;
1796 pNextRect->right = r1->right;
1797 pNextRect->bottom = bottom;
1798 pReg->numRects += 1;
1799 pNextRect++;
1801 r1++;
1802 left = r1->left;
1807 * Add remaining minuend rectangles to region.
1809 while (r1 != r1End)
1811 MEMCHECK(pReg, pNextRect, pReg->rects);
1812 pNextRect->left = left;
1813 pNextRect->top = top;
1814 pNextRect->right = r1->right;
1815 pNextRect->bottom = bottom;
1816 pReg->numRects += 1;
1817 pNextRect++;
1818 r1++;
1819 if (r1 != r1End)
1821 left = r1->left;
1824 return;
1827 /***********************************************************************
1828 * REGION_SubtractRegion
1830 * Subtract regS from regM and leave the result in regD.
1831 * S stands for subtrahend, M for minuend and D for difference.
1833 * Results:
1834 * TRUE.
1836 * Side Effects:
1837 * regD is overwritten.
1840 static void REGION_SubtractRegion(WINEREGION *regD, WINEREGION *regM,
1841 WINEREGION *regS )
1843 /* check for trivial reject */
1844 if ( (!(regM->numRects)) || (!(regS->numRects)) ||
1845 (!EXTENTCHECK(&regM->extents, &regS->extents)) )
1847 REGION_CopyRegion(regD, regM);
1848 return;
1851 REGION_RegionOp (regD, regM, regS, (voidProcp) REGION_SubtractO,
1852 (voidProcp) REGION_SubtractNonO1, (voidProcp) NULL);
1855 * Can't alter newReg's extents before we call miRegionOp because
1856 * it might be one of the source regions and miRegionOp depends
1857 * on the extents of those regions being the unaltered. Besides, this
1858 * way there's no checking against rectangles that will be nuked
1859 * due to coalescing, so we have to examine fewer rectangles.
1861 REGION_SetExtents (regD);
1862 regD->type = (regD->numRects) ? COMPLEXREGION : NULLREGION ;
1863 return;
1866 /***********************************************************************
1867 * REGION_XorRegion
1869 static void REGION_XorRegion(WINEREGION *dr, WINEREGION *sra,
1870 WINEREGION *srb)
1872 WINEREGION *tra, *trb;
1874 if ((! (tra = REGION_AllocWineRegion())) ||
1875 (! (trb = REGION_AllocWineRegion())))
1876 return;
1877 REGION_SubtractRegion(tra,sra,srb);
1878 REGION_SubtractRegion(trb,srb,sra);
1879 REGION_UnionRegion(dr,tra,trb);
1880 REGION_DestroyWineRegion(tra);
1881 REGION_DestroyWineRegion(trb);
1882 return;
1885 /**************************************************************************
1887 * Poly Regions
1889 *************************************************************************/
1891 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
1892 #define SMALL_COORDINATE 0x80000000
1894 /***********************************************************************
1895 * REGION_InsertEdgeInET
1897 * Insert the given edge into the edge table.
1898 * First we must find the correct bucket in the
1899 * Edge table, then find the right slot in the
1900 * bucket. Finally, we can insert it.
1903 static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
1904 INT32 scanline, ScanLineListBlock **SLLBlock, INT32 *iSLLBlock)
1907 EdgeTableEntry *start, *prev;
1908 ScanLineList *pSLL, *pPrevSLL;
1909 ScanLineListBlock *tmpSLLBlock;
1912 * find the right bucket to put the edge into
1914 pPrevSLL = &ET->scanlines;
1915 pSLL = pPrevSLL->next;
1916 while (pSLL && (pSLL->scanline < scanline))
1918 pPrevSLL = pSLL;
1919 pSLL = pSLL->next;
1923 * reassign pSLL (pointer to ScanLineList) if necessary
1925 if ((!pSLL) || (pSLL->scanline > scanline))
1927 if (*iSLLBlock > SLLSPERBLOCK-1)
1929 tmpSLLBlock = HeapAlloc( SystemHeap, 0, sizeof(ScanLineListBlock));
1930 if(!tmpSLLBlock)
1932 WARN(region, "Can't alloc SLLB\n");
1933 return;
1935 (*SLLBlock)->next = tmpSLLBlock;
1936 tmpSLLBlock->next = (ScanLineListBlock *)NULL;
1937 *SLLBlock = tmpSLLBlock;
1938 *iSLLBlock = 0;
1940 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
1942 pSLL->next = pPrevSLL->next;
1943 pSLL->edgelist = (EdgeTableEntry *)NULL;
1944 pPrevSLL->next = pSLL;
1946 pSLL->scanline = scanline;
1949 * now insert the edge in the right bucket
1951 prev = (EdgeTableEntry *)NULL;
1952 start = pSLL->edgelist;
1953 while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
1955 prev = start;
1956 start = start->next;
1958 ETE->next = start;
1960 if (prev)
1961 prev->next = ETE;
1962 else
1963 pSLL->edgelist = ETE;
1966 /***********************************************************************
1967 * REGION_CreateEdgeTable
1969 * This routine creates the edge table for
1970 * scan converting polygons.
1971 * The Edge Table (ET) looks like:
1973 * EdgeTable
1974 * --------
1975 * | ymax | ScanLineLists
1976 * |scanline|-->------------>-------------->...
1977 * -------- |scanline| |scanline|
1978 * |edgelist| |edgelist|
1979 * --------- ---------
1980 * | |
1981 * | |
1982 * V V
1983 * list of ETEs list of ETEs
1985 * where ETE is an EdgeTableEntry data structure,
1986 * and there is one ScanLineList per scanline at
1987 * which an edge is initially entered.
1990 static void REGION_CreateETandAET(const INT32 *Count, INT32 nbpolygons,
1991 const POINT32 *pts, EdgeTable *ET, EdgeTableEntry *AET,
1992 EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
1994 const POINT32 *top, *bottom;
1995 const POINT32 *PrevPt, *CurrPt, *EndPt;
1996 INT32 poly, count;
1997 int iSLLBlock = 0;
1998 int dy;
2002 * initialize the Active Edge Table
2004 AET->next = (EdgeTableEntry *)NULL;
2005 AET->back = (EdgeTableEntry *)NULL;
2006 AET->nextWETE = (EdgeTableEntry *)NULL;
2007 AET->bres.minor_axis = SMALL_COORDINATE;
2010 * initialize the Edge Table.
2012 ET->scanlines.next = (ScanLineList *)NULL;
2013 ET->ymax = SMALL_COORDINATE;
2014 ET->ymin = LARGE_COORDINATE;
2015 pSLLBlock->next = (ScanLineListBlock *)NULL;
2017 EndPt = pts - 1;
2018 for(poly = 0; poly < nbpolygons; poly++)
2020 count = Count[poly];
2021 EndPt += count;
2022 if(count < 2)
2023 continue;
2025 PrevPt = EndPt;
2028 * for each vertex in the array of points.
2029 * In this loop we are dealing with two vertices at
2030 * a time -- these make up one edge of the polygon.
2032 while (count--)
2034 CurrPt = pts++;
2037 * find out which point is above and which is below.
2039 if (PrevPt->y > CurrPt->y)
2041 bottom = PrevPt, top = CurrPt;
2042 pETEs->ClockWise = 0;
2044 else
2046 bottom = CurrPt, top = PrevPt;
2047 pETEs->ClockWise = 1;
2051 * don't add horizontal edges to the Edge table.
2053 if (bottom->y != top->y)
2055 pETEs->ymax = bottom->y-1;
2056 /* -1 so we don't get last scanline */
2059 * initialize integer edge algorithm
2061 dy = bottom->y - top->y;
2062 BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
2064 REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
2065 &iSLLBlock);
2067 if (PrevPt->y > ET->ymax)
2068 ET->ymax = PrevPt->y;
2069 if (PrevPt->y < ET->ymin)
2070 ET->ymin = PrevPt->y;
2071 pETEs++;
2074 PrevPt = CurrPt;
2079 /***********************************************************************
2080 * REGION_loadAET
2082 * This routine moves EdgeTableEntries from the
2083 * EdgeTable into the Active Edge Table,
2084 * leaving them sorted by smaller x coordinate.
2087 static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
2089 EdgeTableEntry *pPrevAET;
2090 EdgeTableEntry *tmp;
2092 pPrevAET = AET;
2093 AET = AET->next;
2094 while (ETEs)
2096 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
2098 pPrevAET = AET;
2099 AET = AET->next;
2101 tmp = ETEs->next;
2102 ETEs->next = AET;
2103 if (AET)
2104 AET->back = ETEs;
2105 ETEs->back = pPrevAET;
2106 pPrevAET->next = ETEs;
2107 pPrevAET = ETEs;
2109 ETEs = tmp;
2113 /***********************************************************************
2114 * REGION_computeWAET
2116 * This routine links the AET by the
2117 * nextWETE (winding EdgeTableEntry) link for
2118 * use by the winding number rule. The final
2119 * Active Edge Table (AET) might look something
2120 * like:
2122 * AET
2123 * ---------- --------- ---------
2124 * |ymax | |ymax | |ymax |
2125 * | ... | |... | |... |
2126 * |next |->|next |->|next |->...
2127 * |nextWETE| |nextWETE| |nextWETE|
2128 * --------- --------- ^--------
2129 * | | |
2130 * V-------------------> V---> ...
2133 static void REGION_computeWAET(EdgeTableEntry *AET)
2135 register EdgeTableEntry *pWETE;
2136 register int inside = 1;
2137 register int isInside = 0;
2139 AET->nextWETE = (EdgeTableEntry *)NULL;
2140 pWETE = AET;
2141 AET = AET->next;
2142 while (AET)
2144 if (AET->ClockWise)
2145 isInside++;
2146 else
2147 isInside--;
2149 if ((!inside && !isInside) ||
2150 ( inside && isInside))
2152 pWETE->nextWETE = AET;
2153 pWETE = AET;
2154 inside = !inside;
2156 AET = AET->next;
2158 pWETE->nextWETE = (EdgeTableEntry *)NULL;
2161 /***********************************************************************
2162 * REGION_InsertionSort
2164 * Just a simple insertion sort using
2165 * pointers and back pointers to sort the Active
2166 * Edge Table.
2169 static BOOL32 REGION_InsertionSort(EdgeTableEntry *AET)
2171 EdgeTableEntry *pETEchase;
2172 EdgeTableEntry *pETEinsert;
2173 EdgeTableEntry *pETEchaseBackTMP;
2174 BOOL32 changed = FALSE;
2176 AET = AET->next;
2177 while (AET)
2179 pETEinsert = AET;
2180 pETEchase = AET;
2181 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
2182 pETEchase = pETEchase->back;
2184 AET = AET->next;
2185 if (pETEchase != pETEinsert)
2187 pETEchaseBackTMP = pETEchase->back;
2188 pETEinsert->back->next = AET;
2189 if (AET)
2190 AET->back = pETEinsert->back;
2191 pETEinsert->next = pETEchase;
2192 pETEchase->back->next = pETEinsert;
2193 pETEchase->back = pETEinsert;
2194 pETEinsert->back = pETEchaseBackTMP;
2195 changed = TRUE;
2198 return changed;
2201 /***********************************************************************
2202 * REGION_FreeStorage
2204 * Clean up our act.
2206 static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
2208 ScanLineListBlock *tmpSLLBlock;
2210 while (pSLLBlock)
2212 tmpSLLBlock = pSLLBlock->next;
2213 HeapFree( SystemHeap, 0, pSLLBlock );
2214 pSLLBlock = tmpSLLBlock;
2219 /***********************************************************************
2220 * REGION_PtsToRegion
2222 * Create an array of rectangles from a list of points.
2224 static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
2225 POINTBLOCK *FirstPtBlock, WINEREGION *reg)
2227 RECT32 *rects;
2228 POINT32 *pts;
2229 POINTBLOCK *CurPtBlock;
2230 int i;
2231 RECT32 *extents;
2232 INT32 numRects;
2234 extents = &reg->extents;
2236 numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
2238 if (!(reg->rects = HeapReAlloc( SystemHeap, 0, reg->rects,
2239 sizeof(RECT32) * numRects )))
2240 return(0);
2242 reg->size = numRects;
2243 CurPtBlock = FirstPtBlock;
2244 rects = reg->rects - 1;
2245 numRects = 0;
2246 extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
2248 for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
2249 /* the loop uses 2 points per iteration */
2250 i = NUMPTSTOBUFFER >> 1;
2251 if (!numFullPtBlocks)
2252 i = iCurPtBlock >> 1;
2253 for (pts = CurPtBlock->pts; i--; pts += 2) {
2254 if (pts->x == pts[1].x)
2255 continue;
2256 if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
2257 pts[1].x == rects->right &&
2258 (numRects == 1 || rects[-1].top != rects->top) &&
2259 (i && pts[2].y > pts[1].y)) {
2260 rects->bottom = pts[1].y + 1;
2261 continue;
2263 numRects++;
2264 rects++;
2265 rects->left = pts->x; rects->top = pts->y;
2266 rects->right = pts[1].x; rects->bottom = pts[1].y + 1;
2267 if (rects->left < extents->left)
2268 extents->left = rects->left;
2269 if (rects->right > extents->right)
2270 extents->right = rects->right;
2272 CurPtBlock = CurPtBlock->next;
2275 if (numRects) {
2276 extents->top = reg->rects->top;
2277 extents->bottom = rects->bottom;
2278 } else {
2279 extents->left = 0;
2280 extents->top = 0;
2281 extents->right = 0;
2282 extents->bottom = 0;
2284 reg->numRects = numRects;
2286 return(TRUE);
2289 /***********************************************************************
2290 * CreatePolyPolygonRgn32 (GDI32.57)
2292 HRGN32 WINAPI CreatePolyPolygonRgn32(const POINT32 *Pts, const INT32 *Count,
2293 INT32 nbpolygons, INT32 mode)
2295 HRGN32 hrgn;
2296 RGNOBJ *obj;
2297 WINEREGION *region;
2298 register EdgeTableEntry *pAET; /* Active Edge Table */
2299 register INT32 y; /* current scanline */
2300 register int iPts = 0; /* number of pts in buffer */
2301 register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
2302 register ScanLineList *pSLL; /* current scanLineList */
2303 register POINT32 *pts; /* output buffer */
2304 EdgeTableEntry *pPrevAET; /* ptr to previous AET */
2305 EdgeTable ET; /* header node for ET */
2306 EdgeTableEntry AET; /* header node for AET */
2307 EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
2308 ScanLineListBlock SLLBlock; /* header for scanlinelist */
2309 int fixWAET = FALSE;
2310 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
2311 POINTBLOCK *tmpPtBlock;
2312 int numFullPtBlocks = 0;
2313 INT32 poly, total;
2315 if(!(hrgn = REGION_CreateRegion()))
2316 return 0;
2317 obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
2318 region = obj->rgn;
2320 /* special case a rectangle */
2322 if (((nbpolygons == 1) && ((*Count == 4) ||
2323 ((*Count == 5) && (Pts[4].x == Pts[0].x) && (Pts[4].y == Pts[0].y)))) &&
2324 (((Pts[0].y == Pts[1].y) &&
2325 (Pts[1].x == Pts[2].x) &&
2326 (Pts[2].y == Pts[3].y) &&
2327 (Pts[3].x == Pts[0].x)) ||
2328 ((Pts[0].x == Pts[1].x) &&
2329 (Pts[1].y == Pts[2].y) &&
2330 (Pts[2].x == Pts[3].x) &&
2331 (Pts[3].y == Pts[0].y))))
2333 SetRectRgn32( hrgn, MIN(Pts[0].x, Pts[2].x), MIN(Pts[0].y, Pts[2].y),
2334 MAX(Pts[0].x, Pts[2].x), MAX(Pts[0].y, Pts[2].y) );
2335 GDI_HEAP_UNLOCK( hrgn );
2336 return hrgn;
2339 for(poly = total = 0; poly < nbpolygons; poly++)
2340 total += Count[poly];
2341 if (! (pETEs = HeapAlloc( SystemHeap, 0, sizeof(EdgeTableEntry) * total )))
2343 REGION_DeleteObject( hrgn, obj );
2344 return 0;
2346 pts = FirstPtBlock.pts;
2347 REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
2348 pSLL = ET.scanlines.next;
2349 curPtBlock = &FirstPtBlock;
2351 if (mode != WINDING) {
2353 * for each scanline
2355 for (y = ET.ymin; y < ET.ymax; y++) {
2357 * Add a new edge to the active edge table when we
2358 * get to the next edge.
2360 if (pSLL != NULL && y == pSLL->scanline) {
2361 REGION_loadAET(&AET, pSLL->edgelist);
2362 pSLL = pSLL->next;
2364 pPrevAET = &AET;
2365 pAET = AET.next;
2368 * for each active edge
2370 while (pAET) {
2371 pts->x = pAET->bres.minor_axis, pts->y = y;
2372 pts++, iPts++;
2375 * send out the buffer
2377 if (iPts == NUMPTSTOBUFFER) {
2378 tmpPtBlock = HeapAlloc( SystemHeap, 0, sizeof(POINTBLOCK));
2379 if(!tmpPtBlock) {
2380 WARN(region, "Can't alloc tPB\n");
2381 return 0;
2383 curPtBlock->next = tmpPtBlock;
2384 curPtBlock = tmpPtBlock;
2385 pts = curPtBlock->pts;
2386 numFullPtBlocks++;
2387 iPts = 0;
2389 EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
2391 REGION_InsertionSort(&AET);
2394 else {
2396 * for each scanline
2398 for (y = ET.ymin; y < ET.ymax; y++) {
2400 * Add a new edge to the active edge table when we
2401 * get to the next edge.
2403 if (pSLL != NULL && y == pSLL->scanline) {
2404 REGION_loadAET(&AET, pSLL->edgelist);
2405 REGION_computeWAET(&AET);
2406 pSLL = pSLL->next;
2408 pPrevAET = &AET;
2409 pAET = AET.next;
2410 pWETE = pAET;
2413 * for each active edge
2415 while (pAET) {
2417 * add to the buffer only those edges that
2418 * are in the Winding active edge table.
2420 if (pWETE == pAET) {
2421 pts->x = pAET->bres.minor_axis, pts->y = y;
2422 pts++, iPts++;
2425 * send out the buffer
2427 if (iPts == NUMPTSTOBUFFER) {
2428 tmpPtBlock = HeapAlloc( SystemHeap, 0,
2429 sizeof(POINTBLOCK) );
2430 if(!tmpPtBlock) {
2431 WARN(region, "Can't alloc tPB\n");
2432 return 0;
2434 curPtBlock->next = tmpPtBlock;
2435 curPtBlock = tmpPtBlock;
2436 pts = curPtBlock->pts;
2437 numFullPtBlocks++; iPts = 0;
2439 pWETE = pWETE->nextWETE;
2441 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
2445 * recompute the winding active edge table if
2446 * we just resorted or have exited an edge.
2448 if (REGION_InsertionSort(&AET) || fixWAET) {
2449 REGION_computeWAET(&AET);
2450 fixWAET = FALSE;
2454 REGION_FreeStorage(SLLBlock.next);
2455 REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
2456 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
2457 tmpPtBlock = curPtBlock->next;
2458 HeapFree( SystemHeap, 0, curPtBlock );
2459 curPtBlock = tmpPtBlock;
2461 HeapFree( SystemHeap, 0, pETEs );
2462 GDI_HEAP_UNLOCK( hrgn );
2463 return hrgn;
2467 /***********************************************************************
2468 * CreatePolygonRgn16 (GDI.63)
2470 HRGN16 WINAPI CreatePolygonRgn16( const POINT16 * points, INT16 count,
2471 INT16 mode )
2473 return CreatePolyPolygonRgn16( points, &count, 1, mode );
2476 /***********************************************************************
2477 * CreatePolyPolygonRgn16 (GDI.451)
2479 HRGN16 WINAPI CreatePolyPolygonRgn16( const POINT16 *points,
2480 const INT16 *count, INT16 nbpolygons, INT16 mode )
2482 HRGN32 hrgn;
2483 int i, npts = 0;
2484 INT32 *count32;
2485 POINT32 *points32;
2487 for (i = 0; i < nbpolygons; i++)
2488 npts += count[i];
2489 points32 = HeapAlloc( SystemHeap, 0, npts * sizeof(POINT32) );
2490 for (i = 0; i < npts; i++)
2491 CONV_POINT16TO32( &(points[i]), &(points32[i]) );
2493 count32 = HeapAlloc( SystemHeap, 0, nbpolygons * sizeof(INT32) );
2494 for (i = 0; i < nbpolygons; i++)
2495 count32[i] = count[i];
2496 hrgn = CreatePolyPolygonRgn32( points32, count32, nbpolygons, mode );
2497 HeapFree( SystemHeap, 0, count32 );
2498 HeapFree( SystemHeap, 0, points32 );
2499 return hrgn;
2502 /***********************************************************************
2503 * CreatePolygonRgn32 (GDI32.58)
2505 HRGN32 WINAPI CreatePolygonRgn32( const POINT32 *points, INT32 count,
2506 INT32 mode )
2508 return CreatePolyPolygonRgn32( points, &count, 1, mode );
2512 /***********************************************************************
2513 * GetRandomRgn [GDI32.215]
2515 * NOTES
2516 * This function is UNDOCUMENTED, it isn't even in the header file.
2517 * I assume that it will return a HRGN32!??
2519 HRGN32 WINAPI GetRandomRgn(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3)
2521 FIXME (region, "(0x%08lx 0x%08lx 0x%08lx): empty stub!\n",
2522 dwArg1, dwArg2, dwArg3);
2524 return 0;