Fixes error handling (SetLastError() and return value).
[wine/multimedia.git] / objects / region.c
blobb34b0aa4611e5504b1b43581b4f7f8b1c4aa2776
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 * NOTE: Doesn't call CreateRectRgn32 because of differences in SetRectRgn16/32
260 HRGN16 WINAPI CreateRectRgn16(INT16 left, INT16 top, INT16 right, INT16 bottom)
262 HRGN16 hrgn;
264 if (!(hrgn = (HRGN16)REGION_CreateRegion()))
265 return 0;
266 TRACE(region, "\n");
267 SetRectRgn16(hrgn, left, top, right, bottom);
268 return hrgn;
272 /***********************************************************************
273 * CreateRectRgn32 (GDI32.59)
275 HRGN32 WINAPI CreateRectRgn32(INT32 left, INT32 top, INT32 right, INT32 bottom)
277 HRGN32 hrgn;
279 if (!(hrgn = REGION_CreateRegion()))
280 return 0;
281 TRACE(region, "\n");
282 SetRectRgn32(hrgn, left, top, right, bottom);
283 return hrgn;
286 /***********************************************************************
287 * CreateRectRgnIndirect16 (GDI.65)
289 HRGN16 WINAPI CreateRectRgnIndirect16( const RECT16* rect )
291 return CreateRectRgn16( rect->left, rect->top, rect->right, rect->bottom );
295 /***********************************************************************
296 * CreateRectRgnIndirect32 (GDI32.60)
298 HRGN32 WINAPI CreateRectRgnIndirect32( const RECT32* rect )
300 return CreateRectRgn32( rect->left, rect->top, rect->right, rect->bottom );
304 /***********************************************************************
305 * SetRectRgn16 (GDI.172)
307 * NOTE: Win 3.1 sets region to empty if left > right
309 VOID WINAPI SetRectRgn16( HRGN16 hrgn, INT16 left, INT16 top,
310 INT16 right, INT16 bottom )
312 if(left < right)
313 SetRectRgn32( hrgn, left, top, right, bottom );
314 else
315 SetRectRgn32( hrgn, 0, 0, 0, 0 );
319 /***********************************************************************
320 * SetRectRgn32 (GDI32.332)
322 * Allows either or both left and top to be greater than right or bottom.
324 VOID WINAPI SetRectRgn32( HRGN32 hrgn, INT32 left, INT32 top,
325 INT32 right, INT32 bottom )
327 RGNOBJ * obj;
329 TRACE(region, " %04x %d,%d-%d,%d\n",
330 hrgn, left, top, right, bottom );
332 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
334 if (left > right) { INT32 tmp = left; left = right; right = tmp; }
335 if (top > bottom) { INT32 tmp = top; top = bottom; bottom = tmp; }
337 if((left != right) && (top != bottom))
339 obj->rgn->rects->left = obj->rgn->extents.left = left;
340 obj->rgn->rects->top = obj->rgn->extents.top = top;
341 obj->rgn->rects->right = obj->rgn->extents.right = right;
342 obj->rgn->rects->bottom = obj->rgn->extents.bottom = bottom;
343 obj->rgn->numRects = 1;
344 obj->rgn->type = SIMPLEREGION;
346 else
347 EMPTY_REGION(obj->rgn);
349 GDI_HEAP_UNLOCK( hrgn );
353 /***********************************************************************
354 * CreateRoundRectRgn16 (GDI.444)
356 * If either ellipse dimension is zero we call CreateRectRgn16 for its
357 * `special' behaviour. -ve ellipse dimensions can result in GPFs under win3.1
358 * we just let CreateRoundRectRgn32 convert them to +ve values.
361 HRGN16 WINAPI CreateRoundRectRgn16( INT16 left, INT16 top,
362 INT16 right, INT16 bottom,
363 INT16 ellipse_width, INT16 ellipse_height )
365 if( ellipse_width == 0 || ellipse_height == 0 )
366 return CreateRectRgn16( left, top, right, bottom );
367 else
368 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
369 ellipse_width, ellipse_height );
372 /***********************************************************************
373 * CreateRoundRectRgn32 (GDI32.61)
375 HRGN32 WINAPI CreateRoundRectRgn32( INT32 left, INT32 top,
376 INT32 right, INT32 bottom,
377 INT32 ellipse_width, INT32 ellipse_height )
379 RGNOBJ * obj;
380 HRGN32 hrgn;
381 int asq, bsq, d, xd, yd;
382 RECT32 rect;
384 /* Check if we can do a normal rectangle instead */
386 if ((ellipse_width == 0) || (ellipse_height == 0))
387 return CreateRectRgn32( left, top, right, bottom );
389 /* Make the dimensions sensible */
391 if (left > right) { INT32 tmp = left; left = right; right = tmp; }
392 if (top > bottom) { INT32 tmp = top; top = bottom; bottom = tmp; }
394 ellipse_width = abs(ellipse_width);
395 ellipse_height = abs(ellipse_height);
397 /* Create region */
399 if (!(hrgn = REGION_CreateRegion())) return 0;
400 obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
401 TRACE(region,"(%d,%d-%d,%d %dx%d): ret=%04x\n",
402 left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
404 /* Check parameters */
406 if (ellipse_width > right-left) ellipse_width = right-left;
407 if (ellipse_height > bottom-top) ellipse_height = bottom-top;
409 /* Ellipse algorithm, based on an article by K. Porter */
410 /* in DDJ Graphics Programming Column, 8/89 */
412 asq = ellipse_width * ellipse_width / 4; /* a^2 */
413 bsq = ellipse_height * ellipse_height / 4; /* b^2 */
414 d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
415 xd = 0;
416 yd = asq * ellipse_height; /* 2a^2b */
418 rect.left = left + ellipse_width / 2;
419 rect.right = right - ellipse_width / 2;
421 /* Loop to draw first half of quadrant */
423 while (xd < yd)
425 if (d > 0) /* if nearest pixel is toward the center */
427 /* move toward center */
428 rect.top = top++;
429 rect.bottom = rect.top + 1;
430 REGION_UnionRectWithRegion( &rect, obj->rgn );
431 rect.top = --bottom;
432 rect.bottom = rect.top + 1;
433 REGION_UnionRectWithRegion( &rect, obj->rgn );
434 yd -= 2*asq;
435 d -= yd;
437 rect.left--; /* next horiz point */
438 rect.right++;
439 xd += 2*bsq;
440 d += bsq + xd;
443 /* Loop to draw second half of quadrant */
445 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
446 while (yd >= 0)
448 /* next vertical point */
449 rect.top = top++;
450 rect.bottom = rect.top + 1;
451 REGION_UnionRectWithRegion( &rect, obj->rgn );
452 rect.top = --bottom;
453 rect.bottom = rect.top + 1;
454 REGION_UnionRectWithRegion( &rect, obj->rgn );
455 if (d < 0) /* if nearest pixel is outside ellipse */
457 rect.left--; /* move away from center */
458 rect.right++;
459 xd += 2*bsq;
460 d += xd;
462 yd -= 2*asq;
463 d += asq - yd;
466 /* Add the inside rectangle */
468 if (top <= bottom)
470 rect.top = top;
471 rect.bottom = bottom;
472 REGION_UnionRectWithRegion( &rect, obj->rgn );
474 obj->rgn->type = SIMPLEREGION; /* FIXME? */
475 GDI_HEAP_UNLOCK( hrgn );
476 return hrgn;
480 /***********************************************************************
481 * CreateEllipticRgn16 (GDI.54)
483 HRGN16 WINAPI CreateEllipticRgn16( INT16 left, INT16 top,
484 INT16 right, INT16 bottom )
486 return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
487 right-left, bottom-top );
491 /***********************************************************************
492 * CreateEllipticRgn32 (GDI32.39)
494 HRGN32 WINAPI CreateEllipticRgn32( INT32 left, INT32 top,
495 INT32 right, INT32 bottom )
497 return CreateRoundRectRgn32( left, top, right, bottom,
498 right-left, bottom-top );
502 /***********************************************************************
503 * CreateEllipticRgnIndirect16 (GDI.55)
505 HRGN16 WINAPI CreateEllipticRgnIndirect16( const RECT16 *rect )
507 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
508 rect->bottom, rect->right - rect->left,
509 rect->bottom - rect->top );
513 /***********************************************************************
514 * CreateEllipticRgnIndirect32 (GDI32.40)
516 HRGN32 WINAPI CreateEllipticRgnIndirect32( const RECT32 *rect )
518 return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
519 rect->bottom, rect->right - rect->left,
520 rect->bottom - rect->top );
523 /***********************************************************************
524 * GetRegionData (GDI32.217)
527 DWORD WINAPI GetRegionData(HRGN32 hrgn, DWORD count, LPRGNDATA rgndata)
529 DWORD size;
530 RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
532 TRACE(region, " %04x count = %ld, rgndata = %p\n",
533 hrgn, count, rgndata);
535 if(!obj) return 0;
537 size = obj->rgn->numRects * sizeof(RECT32);
538 if(count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
540 GDI_HEAP_UNLOCK( hrgn );
541 return size + sizeof(RGNDATAHEADER);
544 rgndata->rdh.dwSize = sizeof(RGNDATAHEADER);
545 rgndata->rdh.iType = RDH_RECTANGLES;
546 rgndata->rdh.nCount = obj->rgn->numRects;
547 rgndata->rdh.nRgnSize = size;
548 rgndata->rdh.rcBound.left = obj->rgn->extents.left;
549 rgndata->rdh.rcBound.top = obj->rgn->extents.top;
550 rgndata->rdh.rcBound.right = obj->rgn->extents.right;
551 rgndata->rdh.rcBound.bottom = obj->rgn->extents.bottom;
553 memcpy( rgndata->Buffer, obj->rgn->rects, size );
555 GDI_HEAP_UNLOCK( hrgn );
556 return 1;
559 /***********************************************************************
560 * ExtCreateRegion (GDI32.94)
563 HRGN32 WINAPI ExtCreateRegion( const XFORM* lpXform, DWORD dwCount, const RGNDATA* rgndata)
565 HRGN32 hrgn = CreateRectRgn32(0, 0, 0, 0);
566 RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
567 RECT32 *pCurRect, *pEndRect;
569 TRACE(region, " %p %ld %p. Returning %04x\n",
570 lpXform, dwCount, rgndata, hrgn);
571 if(!hrgn)
573 WARN(region, "Can't create a region!\n");
574 return 0;
576 if(lpXform)
577 WARN(region, "Xform not implemented - ignoring\n");
579 if(rgndata->rdh.iType != RDH_RECTANGLES)
581 WARN(region, "Type not RDH_RECTANGLES\n");
582 GDI_HEAP_UNLOCK( hrgn );
583 DeleteObject32( hrgn );
584 return 0;
587 pEndRect = (RECT32 *)rgndata->Buffer + rgndata->rdh.nCount;
588 for(pCurRect = (RECT32 *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
589 REGION_UnionRectWithRegion( pCurRect, obj->rgn );
591 GDI_HEAP_UNLOCK( hrgn );
592 return hrgn;
595 /***********************************************************************
596 * PtInRegion16 (GDI.161)
598 BOOL16 WINAPI PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
600 return PtInRegion32( hrgn, x, y );
604 /***********************************************************************
605 * PtInRegion32 (GDI32.278)
607 BOOL32 WINAPI PtInRegion32( HRGN32 hrgn, INT32 x, INT32 y )
609 RGNOBJ * obj;
611 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
613 BOOL32 ret = FALSE;
614 int i;
616 if (obj->rgn->numRects > 0 && INRECT(obj->rgn->extents, x, y))
617 for (i = 0; i < obj->rgn->numRects; i++)
618 if (INRECT (obj->rgn->rects[i], x, y))
619 ret = TRUE;
620 GDI_HEAP_UNLOCK( hrgn );
621 return ret;
623 return FALSE;
627 /***********************************************************************
628 * RectInRegion16 (GDI.181)
630 BOOL16 WINAPI RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
632 RECT32 r32;
634 CONV_RECT16TO32(rect, &r32);
635 return (BOOL16)RectInRegion32(hrgn, &r32);
639 /***********************************************************************
640 * RectInRegion32 (GDI32.281)
642 * Returns TRUE if rect is at least partly inside hrgn
644 BOOL32 WINAPI RectInRegion32( HRGN32 hrgn, const RECT32 *rect )
646 RGNOBJ * obj;
648 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
650 RECT32 *pCurRect, *pRectEnd;
651 BOOL32 ret = FALSE;
653 /* this is (just) a useful optimization */
654 if ((obj->rgn->numRects > 0) && EXTENTCHECK(&obj->rgn->extents,
655 rect))
657 for (pCurRect = obj->rgn->rects, pRectEnd = pCurRect +
658 obj->rgn->numRects; pCurRect < pRectEnd; pCurRect++)
660 if (pCurRect->bottom <= rect->top)
661 continue; /* not far enough down yet */
663 if (pCurRect->top >= rect->bottom) {
664 ret = FALSE; /* too far down */
665 break;
668 if (pCurRect->right <= rect->left)
669 continue; /* not far enough over yet */
671 if (pCurRect->left >= rect->right) {
672 continue;
675 ret = TRUE;
676 break;
679 GDI_HEAP_UNLOCK(hrgn);
680 return ret;
682 return FALSE;
685 /***********************************************************************
686 * EqualRgn16 (GDI.72)
688 BOOL16 WINAPI EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
690 return EqualRgn32( rgn1, rgn2 );
694 /***********************************************************************
695 * EqualRgn32 (GDI32.90)
697 BOOL32 WINAPI EqualRgn32( HRGN32 hrgn1, HRGN32 hrgn2 )
699 RGNOBJ *obj1, *obj2;
700 BOOL32 ret = FALSE;
702 if ((obj1 = (RGNOBJ *) GDI_GetObjPtr( hrgn1, REGION_MAGIC )))
704 if ((obj2 = (RGNOBJ *) GDI_GetObjPtr( hrgn2, REGION_MAGIC )))
706 int i;
708 ret = TRUE;
709 if ( obj1->rgn->numRects != obj2->rgn->numRects ) ret = FALSE;
710 else if ( obj1->rgn->numRects == 0 ) ret = TRUE;
711 else if ( !EqualRect32(&obj1->rgn->extents, &obj2->rgn->extents) )
712 ret = FALSE;
713 else for( i = 0; i < obj1->rgn->numRects; i++ ) {
714 if (!EqualRect32(obj1->rgn->rects + i, obj2->rgn->rects + i)) {
715 ret = FALSE;
716 break;
719 GDI_HEAP_UNLOCK(hrgn2);
721 GDI_HEAP_UNLOCK(hrgn1);
723 return ret;
725 /***********************************************************************
726 * REGION_UnionRectWithRegion
727 * Adds a rectangle to a WINEREGION
728 * See below for REGION_UnionRectWithRgn
730 static void REGION_UnionRectWithRegion(const RECT32 *rect, WINEREGION *rgn)
732 WINEREGION region;
734 region.rects = &region.extents;
735 region.numRects = 1;
736 region.size = 1;
737 region.type = SIMPLEREGION;
738 CopyRect32(&(region.extents), rect);
739 REGION_UnionRegion(rgn, rgn, &region);
740 return;
743 /***********************************************************************
744 * REGION_UnionRectWithRgn
745 * Adds a rectangle to a HRGN32
746 * A helper used by scroll.c
748 BOOL32 REGION_UnionRectWithRgn( HRGN32 hrgn, const RECT32 *lpRect )
750 RGNOBJ *obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
752 if(!obj) return FALSE;
753 REGION_UnionRectWithRegion( lpRect, obj->rgn );
754 GDI_HEAP_UNLOCK(hrgn);
755 return TRUE;
758 /***********************************************************************
759 * REGION_CreateFrameRgn
761 * Create a region that is a frame around another region.
762 * Expand all rectangles by +/- x and y, then subtract original region.
764 BOOL32 REGION_FrameRgn( HRGN32 hDest, HRGN32 hSrc, INT32 x, INT32 y )
766 BOOL32 bRet;
767 RGNOBJ *srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
769 if (srcObj->rgn->numRects != 0)
771 RGNOBJ* destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
772 RECT32 *pRect, *pEndRect;
773 RECT32 tempRect;
775 EMPTY_REGION( destObj->rgn );
777 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
778 for(pRect = srcObj->rgn->rects; pRect < pEndRect; pRect++)
780 tempRect.left = pRect->left - x;
781 tempRect.top = pRect->top - y;
782 tempRect.right = pRect->right + x;
783 tempRect.bottom = pRect->bottom + y;
784 REGION_UnionRectWithRegion( &tempRect, destObj->rgn );
786 REGION_SubtractRegion( destObj->rgn, destObj->rgn, srcObj->rgn );
787 GDI_HEAP_UNLOCK ( hDest );
788 bRet = TRUE;
790 else
791 bRet = FALSE;
792 GDI_HEAP_UNLOCK( hSrc );
793 return bRet;
796 /***********************************************************************
797 * REGION_LPTODP
799 * Convert region to device co-ords for the supplied dc.
800 * Used by X11DRV_PaintRgn.
802 BOOL32 REGION_LPTODP( HDC32 hdc, HRGN32 hDest, HRGN32 hSrc )
804 RECT32 *pCurRect, *pEndRect;
805 RGNOBJ *srcObj, *destObj;
806 DC * dc = DC_GetDCPtr( hdc );
807 RECT32 tmpRect;
809 TRACE(region, " hdc=%04x dest=%04x src=%04x\n",
810 hdc, hDest, hSrc) ;
812 if (dc->w.MapMode == MM_TEXT) /* Requires only a translation */
814 if( CombineRgn32( hDest, hSrc, 0, RGN_COPY ) == ERROR ) return FALSE;
815 OffsetRgn32( hDest, dc->vportOrgX - dc->wndOrgX,
816 dc->vportOrgY - dc->wndOrgY );
817 return TRUE;
820 if(!( srcObj = (RGNOBJ *) GDI_GetObjPtr( hSrc, REGION_MAGIC) ))
821 return FALSE;
822 if(!( destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC) ))
824 GDI_HEAP_UNLOCK( hSrc );
825 return FALSE;
827 EMPTY_REGION( destObj->rgn );
829 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
830 for(pCurRect = srcObj->rgn->rects; pCurRect < pEndRect; pCurRect++)
832 tmpRect = *pCurRect;
833 tmpRect.left = XLPTODP( dc, tmpRect.left );
834 tmpRect.top = YLPTODP( dc, tmpRect.top );
835 tmpRect.right = XLPTODP( dc, tmpRect.right );
836 tmpRect.bottom = YLPTODP( dc, tmpRect.bottom );
837 REGION_UnionRectWithRegion( &tmpRect, destObj->rgn );
840 GDI_HEAP_UNLOCK( hDest );
841 GDI_HEAP_UNLOCK( hSrc );
842 return TRUE;
845 /***********************************************************************
846 * CombineRgn16 (GDI.451)
848 INT16 WINAPI CombineRgn16(HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode)
850 return (INT16)CombineRgn32( hDest, hSrc1, hSrc2, mode );
854 /***********************************************************************
855 * CombineRgn32 (GDI32.19)
857 * Note: The behavior is correct even if src and dest regions are the same.
859 INT32 WINAPI CombineRgn32(HRGN32 hDest, HRGN32 hSrc1, HRGN32 hSrc2, INT32 mode)
861 RGNOBJ *destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC);
862 INT32 result = ERROR;
864 TRACE(region, " %04x,%04x -> %04x mode=%x\n",
865 hSrc1, hSrc2, hDest, mode );
866 if (destObj)
868 RGNOBJ *src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC);
870 if (src1Obj)
872 TRACE(region, "dump:\n");
873 if(TRACE_ON(region))
874 REGION_DumpRegion(src1Obj->rgn);
875 if (mode == RGN_COPY)
877 REGION_CopyRegion( destObj->rgn, src1Obj->rgn );
878 result = destObj->rgn->type;
880 else
882 RGNOBJ *src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC);
884 if (src2Obj)
886 TRACE(region, "dump:\n");
887 if(TRACE_ON(region))
888 REGION_DumpRegion(src2Obj->rgn);
889 switch (mode)
891 case RGN_AND:
892 REGION_IntersectRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn);
893 break;
894 case RGN_OR:
895 REGION_UnionRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
896 break;
897 case RGN_XOR:
898 REGION_XorRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
899 break;
900 case RGN_DIFF:
901 REGION_SubtractRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
902 break;
904 result = destObj->rgn->type;
905 GDI_HEAP_UNLOCK( hSrc2 );
908 GDI_HEAP_UNLOCK( hSrc1 );
910 TRACE(region, "dump:\n");
911 if(TRACE_ON(region))
912 REGION_DumpRegion(destObj->rgn);
914 GDI_HEAP_UNLOCK( hDest );
916 return result;
919 /***********************************************************************
920 * REGION_SetExtents
921 * Re-calculate the extents of a region
923 static void REGION_SetExtents (WINEREGION *pReg)
925 RECT32 *pRect, *pRectEnd, *pExtents;
927 if (pReg->numRects == 0)
929 pReg->extents.left = 0;
930 pReg->extents.top = 0;
931 pReg->extents.right = 0;
932 pReg->extents.bottom = 0;
933 return;
936 pExtents = &pReg->extents;
937 pRect = pReg->rects;
938 pRectEnd = &pRect[pReg->numRects - 1];
941 * Since pRect is the first rectangle in the region, it must have the
942 * smallest top and since pRectEnd is the last rectangle in the region,
943 * it must have the largest bottom, because of banding. Initialize left and
944 * right from pRect and pRectEnd, resp., as good things to initialize them
945 * to...
947 pExtents->left = pRect->left;
948 pExtents->top = pRect->top;
949 pExtents->right = pRectEnd->right;
950 pExtents->bottom = pRectEnd->bottom;
952 while (pRect <= pRectEnd)
954 if (pRect->left < pExtents->left)
955 pExtents->left = pRect->left;
956 if (pRect->right > pExtents->right)
957 pExtents->right = pRect->right;
958 pRect++;
962 /***********************************************************************
963 * REGION_CopyRegion
965 static void REGION_CopyRegion(WINEREGION *dst, WINEREGION *src)
967 if (dst != src) /* don't want to copy to itself */
969 if (dst->size < src->numRects)
971 if (! (dst->rects = HeapReAlloc( SystemHeap, 0, dst->rects,
972 src->numRects * sizeof(RECT32) )))
973 return;
974 dst->size = src->numRects;
976 dst->numRects = src->numRects;
977 dst->extents.left = src->extents.left;
978 dst->extents.top = src->extents.top;
979 dst->extents.right = src->extents.right;
980 dst->extents.bottom = src->extents.bottom;
981 dst->type = src->type;
983 memcpy((char *) dst->rects, (char *) src->rects,
984 (int) (src->numRects * sizeof(RECT32)));
986 return;
989 /***********************************************************************
990 * REGION_Coalesce
992 * Attempt to merge the rects in the current band with those in the
993 * previous one. Used only by REGION_RegionOp.
995 * Results:
996 * The new index for the previous band.
998 * Side Effects:
999 * If coalescing takes place:
1000 * - rectangles in the previous band will have their bottom fields
1001 * altered.
1002 * - pReg->numRects will be decreased.
1005 static INT32 REGION_Coalesce (
1006 WINEREGION *pReg, /* Region to coalesce */
1007 INT32 prevStart, /* Index of start of previous band */
1008 INT32 curStart /* Index of start of current band */
1010 RECT32 *pPrevRect; /* Current rect in previous band */
1011 RECT32 *pCurRect; /* Current rect in current band */
1012 RECT32 *pRegEnd; /* End of region */
1013 INT32 curNumRects; /* Number of rectangles in current band */
1014 INT32 prevNumRects; /* Number of rectangles in previous band */
1015 INT32 bandtop; /* top coordinate for current band */
1017 pRegEnd = &pReg->rects[pReg->numRects];
1019 pPrevRect = &pReg->rects[prevStart];
1020 prevNumRects = curStart - prevStart;
1023 * Figure out how many rectangles are in the current band. Have to do
1024 * this because multiple bands could have been added in REGION_RegionOp
1025 * at the end when one region has been exhausted.
1027 pCurRect = &pReg->rects[curStart];
1028 bandtop = pCurRect->top;
1029 for (curNumRects = 0;
1030 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
1031 curNumRects++)
1033 pCurRect++;
1036 if (pCurRect != pRegEnd)
1039 * If more than one band was added, we have to find the start
1040 * of the last band added so the next coalescing job can start
1041 * at the right place... (given when multiple bands are added,
1042 * this may be pointless -- see above).
1044 pRegEnd--;
1045 while (pRegEnd[-1].top == pRegEnd->top)
1047 pRegEnd--;
1049 curStart = pRegEnd - pReg->rects;
1050 pRegEnd = pReg->rects + pReg->numRects;
1053 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
1054 pCurRect -= curNumRects;
1056 * The bands may only be coalesced if the bottom of the previous
1057 * matches the top scanline of the current.
1059 if (pPrevRect->bottom == pCurRect->top)
1062 * Make sure the bands have rects in the same places. This
1063 * assumes that rects have been added in such a way that they
1064 * cover the most area possible. I.e. two rects in a band must
1065 * have some horizontal space between them.
1069 if ((pPrevRect->left != pCurRect->left) ||
1070 (pPrevRect->right != pCurRect->right))
1073 * The bands don't line up so they can't be coalesced.
1075 return (curStart);
1077 pPrevRect++;
1078 pCurRect++;
1079 prevNumRects -= 1;
1080 } while (prevNumRects != 0);
1082 pReg->numRects -= curNumRects;
1083 pCurRect -= curNumRects;
1084 pPrevRect -= curNumRects;
1087 * The bands may be merged, so set the bottom of each rect
1088 * in the previous band to that of the corresponding rect in
1089 * the current band.
1093 pPrevRect->bottom = pCurRect->bottom;
1094 pPrevRect++;
1095 pCurRect++;
1096 curNumRects -= 1;
1097 } while (curNumRects != 0);
1100 * If only one band was added to the region, we have to backup
1101 * curStart to the start of the previous band.
1103 * If more than one band was added to the region, copy the
1104 * other bands down. The assumption here is that the other bands
1105 * came from the same region as the current one and no further
1106 * coalescing can be done on them since it's all been done
1107 * already... curStart is already in the right place.
1109 if (pCurRect == pRegEnd)
1111 curStart = prevStart;
1113 else
1117 *pPrevRect++ = *pCurRect++;
1118 } while (pCurRect != pRegEnd);
1123 return (curStart);
1126 /***********************************************************************
1127 * REGION_RegionOp
1129 * Apply an operation to two regions. Called by REGION_Union,
1130 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
1132 * Results:
1133 * None.
1135 * Side Effects:
1136 * The new region is overwritten.
1138 * Notes:
1139 * The idea behind this function is to view the two regions as sets.
1140 * Together they cover a rectangle of area that this function divides
1141 * into horizontal bands where points are covered only by one region
1142 * or by both. For the first case, the nonOverlapFunc is called with
1143 * each the band and the band's upper and lower extents. For the
1144 * second, the overlapFunc is called to process the entire band. It
1145 * is responsible for clipping the rectangles in the band, though
1146 * this function provides the boundaries.
1147 * At the end of each band, the new region is coalesced, if possible,
1148 * to reduce the number of rectangles in the region.
1151 static void REGION_RegionOp(
1152 WINEREGION *newReg, /* Place to store result */
1153 WINEREGION *reg1, /* First region in operation */
1154 WINEREGION *reg2, /* 2nd region in operation */
1155 void (*overlapFunc)(), /* Function to call for over-lapping bands */
1156 void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
1157 void (*nonOverlap2Func)() /* Function to call for non-overlapping bands in region 2 */
1159 RECT32 *r1; /* Pointer into first region */
1160 RECT32 *r2; /* Pointer into 2d region */
1161 RECT32 *r1End; /* End of 1st region */
1162 RECT32 *r2End; /* End of 2d region */
1163 INT32 ybot; /* Bottom of intersection */
1164 INT32 ytop; /* Top of intersection */
1165 RECT32 *oldRects; /* Old rects for newReg */
1166 INT32 prevBand; /* Index of start of
1167 * previous band in newReg */
1168 INT32 curBand; /* Index of start of current
1169 * band in newReg */
1170 RECT32 *r1BandEnd; /* End of current band in r1 */
1171 RECT32 *r2BandEnd; /* End of current band in r2 */
1172 INT32 top; /* Top of non-overlapping band */
1173 INT32 bot; /* Bottom of non-overlapping band */
1176 * Initialization:
1177 * set r1, r2, r1End and r2End appropriately, preserve the important
1178 * parts of the destination region until the end in case it's one of
1179 * the two source regions, then mark the "new" region empty, allocating
1180 * another array of rectangles for it to use.
1182 r1 = reg1->rects;
1183 r2 = reg2->rects;
1184 r1End = r1 + reg1->numRects;
1185 r2End = r2 + reg2->numRects;
1189 * newReg may be one of the src regions so we can't empty it. We keep a
1190 * note of its rects pointer (so that we can free them later), preserve its
1191 * extents and simply set numRects to zero.
1194 oldRects = newReg->rects;
1195 newReg->numRects = 0;
1198 * Allocate a reasonable number of rectangles for the new region. The idea
1199 * is to allocate enough so the individual functions don't need to
1200 * reallocate and copy the array, which is time consuming, yet we don't
1201 * have to worry about using too much memory. I hope to be able to
1202 * nuke the Xrealloc() at the end of this function eventually.
1204 newReg->size = MAX(reg1->numRects,reg2->numRects) * 2;
1206 if (! (newReg->rects = HeapAlloc( SystemHeap, 0,
1207 sizeof(RECT32) * newReg->size )))
1209 newReg->size = 0;
1210 return;
1214 * Initialize ybot and ytop.
1215 * In the upcoming loop, ybot and ytop serve different functions depending
1216 * on whether the band being handled is an overlapping or non-overlapping
1217 * band.
1218 * In the case of a non-overlapping band (only one of the regions
1219 * has points in the band), ybot is the bottom of the most recent
1220 * intersection and thus clips the top of the rectangles in that band.
1221 * ytop is the top of the next intersection between the two regions and
1222 * serves to clip the bottom of the rectangles in the current band.
1223 * For an overlapping band (where the two regions intersect), ytop clips
1224 * the top of the rectangles of both regions and ybot clips the bottoms.
1226 if (reg1->extents.top < reg2->extents.top)
1227 ybot = reg1->extents.top;
1228 else
1229 ybot = reg2->extents.top;
1232 * prevBand serves to mark the start of the previous band so rectangles
1233 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1234 * In the beginning, there is no previous band, so prevBand == curBand
1235 * (curBand is set later on, of course, but the first band will always
1236 * start at index 0). prevBand and curBand must be indices because of
1237 * the possible expansion, and resultant moving, of the new region's
1238 * array of rectangles.
1240 prevBand = 0;
1244 curBand = newReg->numRects;
1247 * This algorithm proceeds one source-band (as opposed to a
1248 * destination band, which is determined by where the two regions
1249 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1250 * rectangle after the last one in the current band for their
1251 * respective regions.
1253 r1BandEnd = r1;
1254 while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
1256 r1BandEnd++;
1259 r2BandEnd = r2;
1260 while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
1262 r2BandEnd++;
1266 * First handle the band that doesn't intersect, if any.
1268 * Note that attention is restricted to one band in the
1269 * non-intersecting region at once, so if a region has n
1270 * bands between the current position and the next place it overlaps
1271 * the other, this entire loop will be passed through n times.
1273 if (r1->top < r2->top)
1275 top = MAX(r1->top,ybot);
1276 bot = MIN(r1->bottom,r2->top);
1278 if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
1280 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
1283 ytop = r2->top;
1285 else if (r2->top < r1->top)
1287 top = MAX(r2->top,ybot);
1288 bot = MIN(r2->bottom,r1->top);
1290 if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
1292 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
1295 ytop = r1->top;
1297 else
1299 ytop = r1->top;
1303 * If any rectangles got added to the region, try and coalesce them
1304 * with rectangles from the previous band. Note we could just do
1305 * this test in miCoalesce, but some machines incur a not
1306 * inconsiderable cost for function calls, so...
1308 if (newReg->numRects != curBand)
1310 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1314 * Now see if we've hit an intersecting band. The two bands only
1315 * intersect if ybot > ytop
1317 ybot = MIN(r1->bottom, r2->bottom);
1318 curBand = newReg->numRects;
1319 if (ybot > ytop)
1321 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1325 if (newReg->numRects != curBand)
1327 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1331 * If we've finished with a band (bottom == ybot) we skip forward
1332 * in the region to the next band.
1334 if (r1->bottom == ybot)
1336 r1 = r1BandEnd;
1338 if (r2->bottom == ybot)
1340 r2 = r2BandEnd;
1342 } while ((r1 != r1End) && (r2 != r2End));
1345 * Deal with whichever region still has rectangles left.
1347 curBand = newReg->numRects;
1348 if (r1 != r1End)
1350 if (nonOverlap1Func != (void (*)())NULL)
1354 r1BandEnd = r1;
1355 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
1357 r1BandEnd++;
1359 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
1360 MAX(r1->top,ybot), r1->bottom);
1361 r1 = r1BandEnd;
1362 } while (r1 != r1End);
1365 else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
1369 r2BandEnd = r2;
1370 while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
1372 r2BandEnd++;
1374 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
1375 MAX(r2->top,ybot), r2->bottom);
1376 r2 = r2BandEnd;
1377 } while (r2 != r2End);
1380 if (newReg->numRects != curBand)
1382 (void) REGION_Coalesce (newReg, prevBand, curBand);
1386 * A bit of cleanup. To keep regions from growing without bound,
1387 * we shrink the array of rectangles to match the new number of
1388 * rectangles in the region. This never goes to 0, however...
1390 * Only do this stuff if the number of rectangles allocated is more than
1391 * twice the number of rectangles in the region (a simple optimization...).
1393 if (newReg->numRects < (newReg->size >> 1))
1395 if (REGION_NOT_EMPTY(newReg))
1397 RECT32 *prev_rects = newReg->rects;
1398 newReg->size = newReg->numRects;
1399 newReg->rects = HeapReAlloc( SystemHeap, 0, newReg->rects,
1400 sizeof(RECT32) * newReg->size );
1401 if (! newReg->rects)
1402 newReg->rects = prev_rects;
1404 else
1407 * No point in doing the extra work involved in an Xrealloc if
1408 * the region is empty
1410 newReg->size = 1;
1411 HeapFree( SystemHeap, 0, newReg->rects );
1412 newReg->rects = HeapAlloc( SystemHeap, 0, sizeof(RECT32) );
1415 HeapFree( SystemHeap, 0, oldRects );
1416 return;
1419 /***********************************************************************
1420 * Region Intersection
1421 ***********************************************************************/
1424 /***********************************************************************
1425 * REGION_IntersectO
1427 * Handle an overlapping band for REGION_Intersect.
1429 * Results:
1430 * None.
1432 * Side Effects:
1433 * Rectangles may be added to the region.
1436 static void REGION_IntersectO(WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1437 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1440 INT32 left, right;
1441 RECT32 *pNextRect;
1443 pNextRect = &pReg->rects[pReg->numRects];
1445 while ((r1 != r1End) && (r2 != r2End))
1447 left = MAX(r1->left, r2->left);
1448 right = MIN(r1->right, r2->right);
1451 * If there's any overlap between the two rectangles, add that
1452 * overlap to the new region.
1453 * There's no need to check for subsumption because the only way
1454 * such a need could arise is if some region has two rectangles
1455 * right next to each other. Since that should never happen...
1457 if (left < right)
1459 MEMCHECK(pReg, pNextRect, pReg->rects);
1460 pNextRect->left = left;
1461 pNextRect->top = top;
1462 pNextRect->right = right;
1463 pNextRect->bottom = bottom;
1464 pReg->numRects += 1;
1465 pNextRect++;
1469 * Need to advance the pointers. Shift the one that extends
1470 * to the right the least, since the other still has a chance to
1471 * overlap with that region's next rectangle, if you see what I mean.
1473 if (r1->right < r2->right)
1475 r1++;
1477 else if (r2->right < r1->right)
1479 r2++;
1481 else
1483 r1++;
1484 r2++;
1487 return;
1490 /***********************************************************************
1491 * REGION_IntersectRegion
1493 static void REGION_IntersectRegion(WINEREGION *newReg, WINEREGION *reg1,
1494 WINEREGION *reg2)
1496 /* check for trivial reject */
1497 if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
1498 (!EXTENTCHECK(&reg1->extents, &reg2->extents)))
1499 newReg->numRects = 0;
1500 else
1501 REGION_RegionOp (newReg, reg1, reg2,
1502 (voidProcp) REGION_IntersectO, (voidProcp) NULL, (voidProcp) NULL);
1505 * Can't alter newReg's extents before we call miRegionOp because
1506 * it might be one of the source regions and miRegionOp depends
1507 * on the extents of those regions being the same. Besides, this
1508 * way there's no checking against rectangles that will be nuked
1509 * due to coalescing, so we have to examine fewer rectangles.
1511 REGION_SetExtents(newReg);
1512 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1513 return;
1516 /***********************************************************************
1517 * Region Union
1518 ***********************************************************************/
1520 /***********************************************************************
1521 * REGION_UnionNonO
1523 * Handle a non-overlapping band for the union operation. Just
1524 * Adds the rectangles into the region. Doesn't have to check for
1525 * subsumption or anything.
1527 * Results:
1528 * None.
1530 * Side Effects:
1531 * pReg->numRects is incremented and the final rectangles overwritten
1532 * with the rectangles we're passed.
1535 static void REGION_UnionNonO (WINEREGION *pReg, RECT32 *r, RECT32 *rEnd,
1536 INT32 top, INT32 bottom)
1538 RECT32 *pNextRect;
1540 pNextRect = &pReg->rects[pReg->numRects];
1542 while (r != rEnd)
1544 MEMCHECK(pReg, pNextRect, pReg->rects);
1545 pNextRect->left = r->left;
1546 pNextRect->top = top;
1547 pNextRect->right = r->right;
1548 pNextRect->bottom = bottom;
1549 pReg->numRects += 1;
1550 pNextRect++;
1551 r++;
1553 return;
1556 /***********************************************************************
1557 * REGION_UnionO
1559 * Handle an overlapping band for the union operation. Picks the
1560 * left-most rectangle each time and merges it into the region.
1562 * Results:
1563 * None.
1565 * Side Effects:
1566 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1567 * be changed.
1570 static void REGION_UnionO (WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1571 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1573 RECT32 *pNextRect;
1575 pNextRect = &pReg->rects[pReg->numRects];
1577 #define MERGERECT(r) \
1578 if ((pReg->numRects != 0) && \
1579 (pNextRect[-1].top == top) && \
1580 (pNextRect[-1].bottom == bottom) && \
1581 (pNextRect[-1].right >= r->left)) \
1583 if (pNextRect[-1].right < r->right) \
1585 pNextRect[-1].right = r->right; \
1588 else \
1590 MEMCHECK(pReg, pNextRect, pReg->rects); \
1591 pNextRect->top = top; \
1592 pNextRect->bottom = bottom; \
1593 pNextRect->left = r->left; \
1594 pNextRect->right = r->right; \
1595 pReg->numRects += 1; \
1596 pNextRect += 1; \
1598 r++;
1600 while ((r1 != r1End) && (r2 != r2End))
1602 if (r1->left < r2->left)
1604 MERGERECT(r1);
1606 else
1608 MERGERECT(r2);
1612 if (r1 != r1End)
1616 MERGERECT(r1);
1617 } while (r1 != r1End);
1619 else while (r2 != r2End)
1621 MERGERECT(r2);
1623 return;
1626 /***********************************************************************
1627 * REGION_UnionRegion
1629 static void REGION_UnionRegion(WINEREGION *newReg, WINEREGION *reg1,
1630 WINEREGION *reg2)
1632 /* checks all the simple cases */
1635 * Region 1 and 2 are the same or region 1 is empty
1637 if ( (reg1 == reg2) || (!(reg1->numRects)) )
1639 if (newReg != reg2)
1640 REGION_CopyRegion(newReg, reg2);
1641 return;
1645 * if nothing to union (region 2 empty)
1647 if (!(reg2->numRects))
1649 if (newReg != reg1)
1650 REGION_CopyRegion(newReg, reg1);
1651 return;
1655 * Region 1 completely subsumes region 2
1657 if ((reg1->numRects == 1) &&
1658 (reg1->extents.left <= reg2->extents.left) &&
1659 (reg1->extents.top <= reg2->extents.top) &&
1660 (reg1->extents.right >= reg2->extents.right) &&
1661 (reg1->extents.bottom >= reg2->extents.bottom))
1663 if (newReg != reg1)
1664 REGION_CopyRegion(newReg, reg1);
1665 return;
1669 * Region 2 completely subsumes region 1
1671 if ((reg2->numRects == 1) &&
1672 (reg2->extents.left <= reg1->extents.left) &&
1673 (reg2->extents.top <= reg1->extents.top) &&
1674 (reg2->extents.right >= reg1->extents.right) &&
1675 (reg2->extents.bottom >= reg1->extents.bottom))
1677 if (newReg != reg2)
1678 REGION_CopyRegion(newReg, reg2);
1679 return;
1682 REGION_RegionOp (newReg, reg1, reg2, (voidProcp) REGION_UnionO,
1683 (voidProcp) REGION_UnionNonO, (voidProcp) REGION_UnionNonO);
1685 newReg->extents.left = MIN(reg1->extents.left, reg2->extents.left);
1686 newReg->extents.top = MIN(reg1->extents.top, reg2->extents.top);
1687 newReg->extents.right = MAX(reg1->extents.right, reg2->extents.right);
1688 newReg->extents.bottom = MAX(reg1->extents.bottom, reg2->extents.bottom);
1689 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1690 return;
1693 /***********************************************************************
1694 * Region Subtraction
1695 ***********************************************************************/
1697 /***********************************************************************
1698 * REGION_SubtractNonO1
1700 * Deal with non-overlapping band for subtraction. Any parts from
1701 * region 2 we discard. Anything from region 1 we add to the region.
1703 * Results:
1704 * None.
1706 * Side Effects:
1707 * pReg may be affected.
1710 static void REGION_SubtractNonO1 (WINEREGION *pReg, RECT32 *r, RECT32 *rEnd,
1711 INT32 top, INT32 bottom)
1713 RECT32 *pNextRect;
1715 pNextRect = &pReg->rects[pReg->numRects];
1717 while (r != rEnd)
1719 MEMCHECK(pReg, pNextRect, pReg->rects);
1720 pNextRect->left = r->left;
1721 pNextRect->top = top;
1722 pNextRect->right = r->right;
1723 pNextRect->bottom = bottom;
1724 pReg->numRects += 1;
1725 pNextRect++;
1726 r++;
1728 return;
1732 /***********************************************************************
1733 * REGION_SubtractO
1735 * Overlapping band subtraction. x1 is the left-most point not yet
1736 * checked.
1738 * Results:
1739 * None.
1741 * Side Effects:
1742 * pReg may have rectangles added to it.
1745 static void REGION_SubtractO (WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1746 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1748 RECT32 *pNextRect;
1749 INT32 left;
1751 left = r1->left;
1752 pNextRect = &pReg->rects[pReg->numRects];
1754 while ((r1 != r1End) && (r2 != r2End))
1756 if (r2->right <= left)
1759 * Subtrahend missed the boat: go to next subtrahend.
1761 r2++;
1763 else if (r2->left <= left)
1766 * Subtrahend preceeds minuend: nuke left edge of minuend.
1768 left = r2->right;
1769 if (left >= r1->right)
1772 * Minuend completely covered: advance to next minuend and
1773 * reset left fence to edge of new minuend.
1775 r1++;
1776 if (r1 != r1End)
1777 left = r1->left;
1779 else
1782 * Subtrahend now used up since it doesn't extend beyond
1783 * minuend
1785 r2++;
1788 else if (r2->left < r1->right)
1791 * Left part of subtrahend covers part of minuend: add uncovered
1792 * part of minuend to region and skip to next subtrahend.
1794 MEMCHECK(pReg, pNextRect, pReg->rects);
1795 pNextRect->left = left;
1796 pNextRect->top = top;
1797 pNextRect->right = r2->left;
1798 pNextRect->bottom = bottom;
1799 pReg->numRects += 1;
1800 pNextRect++;
1801 left = r2->right;
1802 if (left >= r1->right)
1805 * Minuend used up: advance to new...
1807 r1++;
1808 if (r1 != r1End)
1809 left = r1->left;
1811 else
1814 * Subtrahend used up
1816 r2++;
1819 else
1822 * Minuend used up: add any remaining piece before advancing.
1824 if (r1->right > left)
1826 MEMCHECK(pReg, pNextRect, pReg->rects);
1827 pNextRect->left = left;
1828 pNextRect->top = top;
1829 pNextRect->right = r1->right;
1830 pNextRect->bottom = bottom;
1831 pReg->numRects += 1;
1832 pNextRect++;
1834 r1++;
1835 left = r1->left;
1840 * Add remaining minuend rectangles to region.
1842 while (r1 != r1End)
1844 MEMCHECK(pReg, pNextRect, pReg->rects);
1845 pNextRect->left = left;
1846 pNextRect->top = top;
1847 pNextRect->right = r1->right;
1848 pNextRect->bottom = bottom;
1849 pReg->numRects += 1;
1850 pNextRect++;
1851 r1++;
1852 if (r1 != r1End)
1854 left = r1->left;
1857 return;
1860 /***********************************************************************
1861 * REGION_SubtractRegion
1863 * Subtract regS from regM and leave the result in regD.
1864 * S stands for subtrahend, M for minuend and D for difference.
1866 * Results:
1867 * TRUE.
1869 * Side Effects:
1870 * regD is overwritten.
1873 static void REGION_SubtractRegion(WINEREGION *regD, WINEREGION *regM,
1874 WINEREGION *regS )
1876 /* check for trivial reject */
1877 if ( (!(regM->numRects)) || (!(regS->numRects)) ||
1878 (!EXTENTCHECK(&regM->extents, &regS->extents)) )
1880 REGION_CopyRegion(regD, regM);
1881 return;
1884 REGION_RegionOp (regD, regM, regS, (voidProcp) REGION_SubtractO,
1885 (voidProcp) REGION_SubtractNonO1, (voidProcp) NULL);
1888 * Can't alter newReg's extents before we call miRegionOp because
1889 * it might be one of the source regions and miRegionOp depends
1890 * on the extents of those regions being the unaltered. Besides, this
1891 * way there's no checking against rectangles that will be nuked
1892 * due to coalescing, so we have to examine fewer rectangles.
1894 REGION_SetExtents (regD);
1895 regD->type = (regD->numRects) ? COMPLEXREGION : NULLREGION ;
1896 return;
1899 /***********************************************************************
1900 * REGION_XorRegion
1902 static void REGION_XorRegion(WINEREGION *dr, WINEREGION *sra,
1903 WINEREGION *srb)
1905 WINEREGION *tra, *trb;
1907 if ((! (tra = REGION_AllocWineRegion())) ||
1908 (! (trb = REGION_AllocWineRegion())))
1909 return;
1910 REGION_SubtractRegion(tra,sra,srb);
1911 REGION_SubtractRegion(trb,srb,sra);
1912 REGION_UnionRegion(dr,tra,trb);
1913 REGION_DestroyWineRegion(tra);
1914 REGION_DestroyWineRegion(trb);
1915 return;
1918 /**************************************************************************
1920 * Poly Regions
1922 *************************************************************************/
1924 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
1925 #define SMALL_COORDINATE 0x80000000
1927 /***********************************************************************
1928 * REGION_InsertEdgeInET
1930 * Insert the given edge into the edge table.
1931 * First we must find the correct bucket in the
1932 * Edge table, then find the right slot in the
1933 * bucket. Finally, we can insert it.
1936 static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
1937 INT32 scanline, ScanLineListBlock **SLLBlock, INT32 *iSLLBlock)
1940 EdgeTableEntry *start, *prev;
1941 ScanLineList *pSLL, *pPrevSLL;
1942 ScanLineListBlock *tmpSLLBlock;
1945 * find the right bucket to put the edge into
1947 pPrevSLL = &ET->scanlines;
1948 pSLL = pPrevSLL->next;
1949 while (pSLL && (pSLL->scanline < scanline))
1951 pPrevSLL = pSLL;
1952 pSLL = pSLL->next;
1956 * reassign pSLL (pointer to ScanLineList) if necessary
1958 if ((!pSLL) || (pSLL->scanline > scanline))
1960 if (*iSLLBlock > SLLSPERBLOCK-1)
1962 tmpSLLBlock = HeapAlloc( SystemHeap, 0, sizeof(ScanLineListBlock));
1963 if(!tmpSLLBlock)
1965 WARN(region, "Can't alloc SLLB\n");
1966 return;
1968 (*SLLBlock)->next = tmpSLLBlock;
1969 tmpSLLBlock->next = (ScanLineListBlock *)NULL;
1970 *SLLBlock = tmpSLLBlock;
1971 *iSLLBlock = 0;
1973 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
1975 pSLL->next = pPrevSLL->next;
1976 pSLL->edgelist = (EdgeTableEntry *)NULL;
1977 pPrevSLL->next = pSLL;
1979 pSLL->scanline = scanline;
1982 * now insert the edge in the right bucket
1984 prev = (EdgeTableEntry *)NULL;
1985 start = pSLL->edgelist;
1986 while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
1988 prev = start;
1989 start = start->next;
1991 ETE->next = start;
1993 if (prev)
1994 prev->next = ETE;
1995 else
1996 pSLL->edgelist = ETE;
1999 /***********************************************************************
2000 * REGION_CreateEdgeTable
2002 * This routine creates the edge table for
2003 * scan converting polygons.
2004 * The Edge Table (ET) looks like:
2006 * EdgeTable
2007 * --------
2008 * | ymax | ScanLineLists
2009 * |scanline|-->------------>-------------->...
2010 * -------- |scanline| |scanline|
2011 * |edgelist| |edgelist|
2012 * --------- ---------
2013 * | |
2014 * | |
2015 * V V
2016 * list of ETEs list of ETEs
2018 * where ETE is an EdgeTableEntry data structure,
2019 * and there is one ScanLineList per scanline at
2020 * which an edge is initially entered.
2023 static void REGION_CreateETandAET(const INT32 *Count, INT32 nbpolygons,
2024 const POINT32 *pts, EdgeTable *ET, EdgeTableEntry *AET,
2025 EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
2027 const POINT32 *top, *bottom;
2028 const POINT32 *PrevPt, *CurrPt, *EndPt;
2029 INT32 poly, count;
2030 int iSLLBlock = 0;
2031 int dy;
2035 * initialize the Active Edge Table
2037 AET->next = (EdgeTableEntry *)NULL;
2038 AET->back = (EdgeTableEntry *)NULL;
2039 AET->nextWETE = (EdgeTableEntry *)NULL;
2040 AET->bres.minor_axis = SMALL_COORDINATE;
2043 * initialize the Edge Table.
2045 ET->scanlines.next = (ScanLineList *)NULL;
2046 ET->ymax = SMALL_COORDINATE;
2047 ET->ymin = LARGE_COORDINATE;
2048 pSLLBlock->next = (ScanLineListBlock *)NULL;
2050 EndPt = pts - 1;
2051 for(poly = 0; poly < nbpolygons; poly++)
2053 count = Count[poly];
2054 EndPt += count;
2055 if(count < 2)
2056 continue;
2058 PrevPt = EndPt;
2061 * for each vertex in the array of points.
2062 * In this loop we are dealing with two vertices at
2063 * a time -- these make up one edge of the polygon.
2065 while (count--)
2067 CurrPt = pts++;
2070 * find out which point is above and which is below.
2072 if (PrevPt->y > CurrPt->y)
2074 bottom = PrevPt, top = CurrPt;
2075 pETEs->ClockWise = 0;
2077 else
2079 bottom = CurrPt, top = PrevPt;
2080 pETEs->ClockWise = 1;
2084 * don't add horizontal edges to the Edge table.
2086 if (bottom->y != top->y)
2088 pETEs->ymax = bottom->y-1;
2089 /* -1 so we don't get last scanline */
2092 * initialize integer edge algorithm
2094 dy = bottom->y - top->y;
2095 BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
2097 REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
2098 &iSLLBlock);
2100 if (PrevPt->y > ET->ymax)
2101 ET->ymax = PrevPt->y;
2102 if (PrevPt->y < ET->ymin)
2103 ET->ymin = PrevPt->y;
2104 pETEs++;
2107 PrevPt = CurrPt;
2112 /***********************************************************************
2113 * REGION_loadAET
2115 * This routine moves EdgeTableEntries from the
2116 * EdgeTable into the Active Edge Table,
2117 * leaving them sorted by smaller x coordinate.
2120 static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
2122 EdgeTableEntry *pPrevAET;
2123 EdgeTableEntry *tmp;
2125 pPrevAET = AET;
2126 AET = AET->next;
2127 while (ETEs)
2129 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
2131 pPrevAET = AET;
2132 AET = AET->next;
2134 tmp = ETEs->next;
2135 ETEs->next = AET;
2136 if (AET)
2137 AET->back = ETEs;
2138 ETEs->back = pPrevAET;
2139 pPrevAET->next = ETEs;
2140 pPrevAET = ETEs;
2142 ETEs = tmp;
2146 /***********************************************************************
2147 * REGION_computeWAET
2149 * This routine links the AET by the
2150 * nextWETE (winding EdgeTableEntry) link for
2151 * use by the winding number rule. The final
2152 * Active Edge Table (AET) might look something
2153 * like:
2155 * AET
2156 * ---------- --------- ---------
2157 * |ymax | |ymax | |ymax |
2158 * | ... | |... | |... |
2159 * |next |->|next |->|next |->...
2160 * |nextWETE| |nextWETE| |nextWETE|
2161 * --------- --------- ^--------
2162 * | | |
2163 * V-------------------> V---> ...
2166 static void REGION_computeWAET(EdgeTableEntry *AET)
2168 register EdgeTableEntry *pWETE;
2169 register int inside = 1;
2170 register int isInside = 0;
2172 AET->nextWETE = (EdgeTableEntry *)NULL;
2173 pWETE = AET;
2174 AET = AET->next;
2175 while (AET)
2177 if (AET->ClockWise)
2178 isInside++;
2179 else
2180 isInside--;
2182 if ((!inside && !isInside) ||
2183 ( inside && isInside))
2185 pWETE->nextWETE = AET;
2186 pWETE = AET;
2187 inside = !inside;
2189 AET = AET->next;
2191 pWETE->nextWETE = (EdgeTableEntry *)NULL;
2194 /***********************************************************************
2195 * REGION_InsertionSort
2197 * Just a simple insertion sort using
2198 * pointers and back pointers to sort the Active
2199 * Edge Table.
2202 static BOOL32 REGION_InsertionSort(EdgeTableEntry *AET)
2204 EdgeTableEntry *pETEchase;
2205 EdgeTableEntry *pETEinsert;
2206 EdgeTableEntry *pETEchaseBackTMP;
2207 BOOL32 changed = FALSE;
2209 AET = AET->next;
2210 while (AET)
2212 pETEinsert = AET;
2213 pETEchase = AET;
2214 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
2215 pETEchase = pETEchase->back;
2217 AET = AET->next;
2218 if (pETEchase != pETEinsert)
2220 pETEchaseBackTMP = pETEchase->back;
2221 pETEinsert->back->next = AET;
2222 if (AET)
2223 AET->back = pETEinsert->back;
2224 pETEinsert->next = pETEchase;
2225 pETEchase->back->next = pETEinsert;
2226 pETEchase->back = pETEinsert;
2227 pETEinsert->back = pETEchaseBackTMP;
2228 changed = TRUE;
2231 return changed;
2234 /***********************************************************************
2235 * REGION_FreeStorage
2237 * Clean up our act.
2239 static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
2241 ScanLineListBlock *tmpSLLBlock;
2243 while (pSLLBlock)
2245 tmpSLLBlock = pSLLBlock->next;
2246 HeapFree( SystemHeap, 0, pSLLBlock );
2247 pSLLBlock = tmpSLLBlock;
2252 /***********************************************************************
2253 * REGION_PtsToRegion
2255 * Create an array of rectangles from a list of points.
2257 static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
2258 POINTBLOCK *FirstPtBlock, WINEREGION *reg)
2260 RECT32 *rects;
2261 POINT32 *pts;
2262 POINTBLOCK *CurPtBlock;
2263 int i;
2264 RECT32 *extents;
2265 INT32 numRects;
2267 extents = &reg->extents;
2269 numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
2271 if (!(reg->rects = HeapReAlloc( SystemHeap, 0, reg->rects,
2272 sizeof(RECT32) * numRects )))
2273 return(0);
2275 reg->size = numRects;
2276 CurPtBlock = FirstPtBlock;
2277 rects = reg->rects - 1;
2278 numRects = 0;
2279 extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
2281 for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
2282 /* the loop uses 2 points per iteration */
2283 i = NUMPTSTOBUFFER >> 1;
2284 if (!numFullPtBlocks)
2285 i = iCurPtBlock >> 1;
2286 for (pts = CurPtBlock->pts; i--; pts += 2) {
2287 if (pts->x == pts[1].x)
2288 continue;
2289 if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
2290 pts[1].x == rects->right &&
2291 (numRects == 1 || rects[-1].top != rects->top) &&
2292 (i && pts[2].y > pts[1].y)) {
2293 rects->bottom = pts[1].y + 1;
2294 continue;
2296 numRects++;
2297 rects++;
2298 rects->left = pts->x; rects->top = pts->y;
2299 rects->right = pts[1].x; rects->bottom = pts[1].y + 1;
2300 if (rects->left < extents->left)
2301 extents->left = rects->left;
2302 if (rects->right > extents->right)
2303 extents->right = rects->right;
2305 CurPtBlock = CurPtBlock->next;
2308 if (numRects) {
2309 extents->top = reg->rects->top;
2310 extents->bottom = rects->bottom;
2311 } else {
2312 extents->left = 0;
2313 extents->top = 0;
2314 extents->right = 0;
2315 extents->bottom = 0;
2317 reg->numRects = numRects;
2319 return(TRUE);
2322 /***********************************************************************
2323 * CreatePolyPolygonRgn32 (GDI32.57)
2325 HRGN32 WINAPI CreatePolyPolygonRgn32(const POINT32 *Pts, const INT32 *Count,
2326 INT32 nbpolygons, INT32 mode)
2328 HRGN32 hrgn;
2329 RGNOBJ *obj;
2330 WINEREGION *region;
2331 register EdgeTableEntry *pAET; /* Active Edge Table */
2332 register INT32 y; /* current scanline */
2333 register int iPts = 0; /* number of pts in buffer */
2334 register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
2335 register ScanLineList *pSLL; /* current scanLineList */
2336 register POINT32 *pts; /* output buffer */
2337 EdgeTableEntry *pPrevAET; /* ptr to previous AET */
2338 EdgeTable ET; /* header node for ET */
2339 EdgeTableEntry AET; /* header node for AET */
2340 EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
2341 ScanLineListBlock SLLBlock; /* header for scanlinelist */
2342 int fixWAET = FALSE;
2343 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
2344 POINTBLOCK *tmpPtBlock;
2345 int numFullPtBlocks = 0;
2346 INT32 poly, total;
2348 if(!(hrgn = REGION_CreateRegion()))
2349 return 0;
2350 obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
2351 region = obj->rgn;
2353 /* special case a rectangle */
2355 if (((nbpolygons == 1) && ((*Count == 4) ||
2356 ((*Count == 5) && (Pts[4].x == Pts[0].x) && (Pts[4].y == Pts[0].y)))) &&
2357 (((Pts[0].y == Pts[1].y) &&
2358 (Pts[1].x == Pts[2].x) &&
2359 (Pts[2].y == Pts[3].y) &&
2360 (Pts[3].x == Pts[0].x)) ||
2361 ((Pts[0].x == Pts[1].x) &&
2362 (Pts[1].y == Pts[2].y) &&
2363 (Pts[2].x == Pts[3].x) &&
2364 (Pts[3].y == Pts[0].y))))
2366 SetRectRgn32( hrgn, MIN(Pts[0].x, Pts[2].x), MIN(Pts[0].y, Pts[2].y),
2367 MAX(Pts[0].x, Pts[2].x), MAX(Pts[0].y, Pts[2].y) );
2368 GDI_HEAP_UNLOCK( hrgn );
2369 return hrgn;
2372 for(poly = total = 0; poly < nbpolygons; poly++)
2373 total += Count[poly];
2374 if (! (pETEs = HeapAlloc( SystemHeap, 0, sizeof(EdgeTableEntry) * total )))
2376 REGION_DeleteObject( hrgn, obj );
2377 return 0;
2379 pts = FirstPtBlock.pts;
2380 REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
2381 pSLL = ET.scanlines.next;
2382 curPtBlock = &FirstPtBlock;
2384 if (mode != WINDING) {
2386 * for each scanline
2388 for (y = ET.ymin; y < ET.ymax; y++) {
2390 * Add a new edge to the active edge table when we
2391 * get to the next edge.
2393 if (pSLL != NULL && y == pSLL->scanline) {
2394 REGION_loadAET(&AET, pSLL->edgelist);
2395 pSLL = pSLL->next;
2397 pPrevAET = &AET;
2398 pAET = AET.next;
2401 * for each active edge
2403 while (pAET) {
2404 pts->x = pAET->bres.minor_axis, pts->y = y;
2405 pts++, iPts++;
2408 * send out the buffer
2410 if (iPts == NUMPTSTOBUFFER) {
2411 tmpPtBlock = HeapAlloc( SystemHeap, 0, sizeof(POINTBLOCK));
2412 if(!tmpPtBlock) {
2413 WARN(region, "Can't alloc tPB\n");
2414 return 0;
2416 curPtBlock->next = tmpPtBlock;
2417 curPtBlock = tmpPtBlock;
2418 pts = curPtBlock->pts;
2419 numFullPtBlocks++;
2420 iPts = 0;
2422 EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
2424 REGION_InsertionSort(&AET);
2427 else {
2429 * for each scanline
2431 for (y = ET.ymin; y < ET.ymax; y++) {
2433 * Add a new edge to the active edge table when we
2434 * get to the next edge.
2436 if (pSLL != NULL && y == pSLL->scanline) {
2437 REGION_loadAET(&AET, pSLL->edgelist);
2438 REGION_computeWAET(&AET);
2439 pSLL = pSLL->next;
2441 pPrevAET = &AET;
2442 pAET = AET.next;
2443 pWETE = pAET;
2446 * for each active edge
2448 while (pAET) {
2450 * add to the buffer only those edges that
2451 * are in the Winding active edge table.
2453 if (pWETE == pAET) {
2454 pts->x = pAET->bres.minor_axis, pts->y = y;
2455 pts++, iPts++;
2458 * send out the buffer
2460 if (iPts == NUMPTSTOBUFFER) {
2461 tmpPtBlock = HeapAlloc( SystemHeap, 0,
2462 sizeof(POINTBLOCK) );
2463 if(!tmpPtBlock) {
2464 WARN(region, "Can't alloc tPB\n");
2465 return 0;
2467 curPtBlock->next = tmpPtBlock;
2468 curPtBlock = tmpPtBlock;
2469 pts = curPtBlock->pts;
2470 numFullPtBlocks++; iPts = 0;
2472 pWETE = pWETE->nextWETE;
2474 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
2478 * recompute the winding active edge table if
2479 * we just resorted or have exited an edge.
2481 if (REGION_InsertionSort(&AET) || fixWAET) {
2482 REGION_computeWAET(&AET);
2483 fixWAET = FALSE;
2487 REGION_FreeStorage(SLLBlock.next);
2488 REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
2489 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
2490 tmpPtBlock = curPtBlock->next;
2491 HeapFree( SystemHeap, 0, curPtBlock );
2492 curPtBlock = tmpPtBlock;
2494 HeapFree( SystemHeap, 0, pETEs );
2495 GDI_HEAP_UNLOCK( hrgn );
2496 return hrgn;
2500 /***********************************************************************
2501 * CreatePolygonRgn16 (GDI.63)
2503 HRGN16 WINAPI CreatePolygonRgn16( const POINT16 * points, INT16 count,
2504 INT16 mode )
2506 return CreatePolyPolygonRgn16( points, &count, 1, mode );
2509 /***********************************************************************
2510 * CreatePolyPolygonRgn16 (GDI.451)
2512 HRGN16 WINAPI CreatePolyPolygonRgn16( const POINT16 *points,
2513 const INT16 *count, INT16 nbpolygons, INT16 mode )
2515 HRGN32 hrgn;
2516 int i, npts = 0;
2517 INT32 *count32;
2518 POINT32 *points32;
2520 for (i = 0; i < nbpolygons; i++)
2521 npts += count[i];
2522 points32 = HeapAlloc( SystemHeap, 0, npts * sizeof(POINT32) );
2523 for (i = 0; i < npts; i++)
2524 CONV_POINT16TO32( &(points[i]), &(points32[i]) );
2526 count32 = HeapAlloc( SystemHeap, 0, nbpolygons * sizeof(INT32) );
2527 for (i = 0; i < nbpolygons; i++)
2528 count32[i] = count[i];
2529 hrgn = CreatePolyPolygonRgn32( points32, count32, nbpolygons, mode );
2530 HeapFree( SystemHeap, 0, count32 );
2531 HeapFree( SystemHeap, 0, points32 );
2532 return hrgn;
2535 /***********************************************************************
2536 * CreatePolygonRgn32 (GDI32.58)
2538 HRGN32 WINAPI CreatePolygonRgn32( const POINT32 *points, INT32 count,
2539 INT32 mode )
2541 return CreatePolyPolygonRgn32( points, &count, 1, mode );
2545 /***********************************************************************
2546 * GetRandomRgn [GDI32.215]
2548 * NOTES
2549 * This function is UNDOCUMENTED, it isn't even in the header file.
2550 * I assume that it will return a HRGN32!??
2552 HRGN32 WINAPI GetRandomRgn(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3)
2554 FIXME (region, "(0x%08lx 0x%08lx 0x%08lx): empty stub!\n",
2555 dwArg1, dwArg2, dwArg3);
2557 return 0;