Initialize lpdwNeeded.
[wine/multimedia.git] / objects / region.c
blob732dbba38f6e77645ab9d4228d5b7d451147f2b7
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 * GetRegionData32 (GDI32.217)
527 DWORD WINAPI GetRegionData32(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 * GetRegionData16 (GDI.607)
561 * FIXME: is LPRGNDATA the same in Win16 and Win32 ?
563 DWORD WINAPI GetRegionData16(HRGN16 hrgn, DWORD count, LPRGNDATA rgndata)
565 return GetRegionData32((HRGN32)hrgn, count, rgndata);
568 /***********************************************************************
569 * ExtCreateRegion (GDI32.94)
572 HRGN32 WINAPI ExtCreateRegion( const XFORM* lpXform, DWORD dwCount, const RGNDATA* rgndata)
574 HRGN32 hrgn = CreateRectRgn32(0, 0, 0, 0);
575 RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
576 RECT32 *pCurRect, *pEndRect;
578 TRACE(region, " %p %ld %p. Returning %04x\n",
579 lpXform, dwCount, rgndata, hrgn);
580 if(!hrgn)
582 WARN(region, "Can't create a region!\n");
583 return 0;
585 if(lpXform)
586 WARN(region, "Xform not implemented - ignoring\n");
588 if(rgndata->rdh.iType != RDH_RECTANGLES)
590 WARN(region, "Type not RDH_RECTANGLES\n");
591 GDI_HEAP_UNLOCK( hrgn );
592 DeleteObject32( hrgn );
593 return 0;
596 pEndRect = (RECT32 *)rgndata->Buffer + rgndata->rdh.nCount;
597 for(pCurRect = (RECT32 *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
598 REGION_UnionRectWithRegion( pCurRect, obj->rgn );
600 GDI_HEAP_UNLOCK( hrgn );
601 return hrgn;
604 /***********************************************************************
605 * PtInRegion16 (GDI.161)
607 BOOL16 WINAPI PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
609 return PtInRegion32( hrgn, x, y );
613 /***********************************************************************
614 * PtInRegion32 (GDI32.278)
616 BOOL32 WINAPI PtInRegion32( HRGN32 hrgn, INT32 x, INT32 y )
618 RGNOBJ * obj;
620 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
622 BOOL32 ret = FALSE;
623 int i;
625 if (obj->rgn->numRects > 0 && INRECT(obj->rgn->extents, x, y))
626 for (i = 0; i < obj->rgn->numRects; i++)
627 if (INRECT (obj->rgn->rects[i], x, y))
628 ret = TRUE;
629 GDI_HEAP_UNLOCK( hrgn );
630 return ret;
632 return FALSE;
636 /***********************************************************************
637 * RectInRegion16 (GDI.181)
639 BOOL16 WINAPI RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
641 RECT32 r32;
643 CONV_RECT16TO32(rect, &r32);
644 return (BOOL16)RectInRegion32(hrgn, &r32);
648 /***********************************************************************
649 * RectInRegion32 (GDI32.281)
651 * Returns TRUE if rect is at least partly inside hrgn
653 BOOL32 WINAPI RectInRegion32( HRGN32 hrgn, const RECT32 *rect )
655 RGNOBJ * obj;
657 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
659 RECT32 *pCurRect, *pRectEnd;
660 BOOL32 ret = FALSE;
662 /* this is (just) a useful optimization */
663 if ((obj->rgn->numRects > 0) && EXTENTCHECK(&obj->rgn->extents,
664 rect))
666 for (pCurRect = obj->rgn->rects, pRectEnd = pCurRect +
667 obj->rgn->numRects; pCurRect < pRectEnd; pCurRect++)
669 if (pCurRect->bottom <= rect->top)
670 continue; /* not far enough down yet */
672 if (pCurRect->top >= rect->bottom) {
673 ret = FALSE; /* too far down */
674 break;
677 if (pCurRect->right <= rect->left)
678 continue; /* not far enough over yet */
680 if (pCurRect->left >= rect->right) {
681 continue;
684 ret = TRUE;
685 break;
688 GDI_HEAP_UNLOCK(hrgn);
689 return ret;
691 return FALSE;
694 /***********************************************************************
695 * EqualRgn16 (GDI.72)
697 BOOL16 WINAPI EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
699 return EqualRgn32( rgn1, rgn2 );
703 /***********************************************************************
704 * EqualRgn32 (GDI32.90)
706 BOOL32 WINAPI EqualRgn32( HRGN32 hrgn1, HRGN32 hrgn2 )
708 RGNOBJ *obj1, *obj2;
709 BOOL32 ret = FALSE;
711 if ((obj1 = (RGNOBJ *) GDI_GetObjPtr( hrgn1, REGION_MAGIC )))
713 if ((obj2 = (RGNOBJ *) GDI_GetObjPtr( hrgn2, REGION_MAGIC )))
715 int i;
717 ret = TRUE;
718 if ( obj1->rgn->numRects != obj2->rgn->numRects ) ret = FALSE;
719 else if ( obj1->rgn->numRects == 0 ) ret = TRUE;
720 else if ( !EqualRect32(&obj1->rgn->extents, &obj2->rgn->extents) )
721 ret = FALSE;
722 else for( i = 0; i < obj1->rgn->numRects; i++ ) {
723 if (!EqualRect32(obj1->rgn->rects + i, obj2->rgn->rects + i)) {
724 ret = FALSE;
725 break;
728 GDI_HEAP_UNLOCK(hrgn2);
730 GDI_HEAP_UNLOCK(hrgn1);
732 return ret;
734 /***********************************************************************
735 * REGION_UnionRectWithRegion
736 * Adds a rectangle to a WINEREGION
737 * See below for REGION_UnionRectWithRgn
739 static void REGION_UnionRectWithRegion(const RECT32 *rect, WINEREGION *rgn)
741 WINEREGION region;
743 region.rects = &region.extents;
744 region.numRects = 1;
745 region.size = 1;
746 region.type = SIMPLEREGION;
747 CopyRect32(&(region.extents), rect);
748 REGION_UnionRegion(rgn, rgn, &region);
749 return;
752 /***********************************************************************
753 * REGION_UnionRectWithRgn
754 * Adds a rectangle to a HRGN32
755 * A helper used by scroll.c
757 BOOL32 REGION_UnionRectWithRgn( HRGN32 hrgn, const RECT32 *lpRect )
759 RGNOBJ *obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
761 if(!obj) return FALSE;
762 REGION_UnionRectWithRegion( lpRect, obj->rgn );
763 GDI_HEAP_UNLOCK(hrgn);
764 return TRUE;
767 /***********************************************************************
768 * REGION_CreateFrameRgn
770 * Create a region that is a frame around another region.
771 * Expand all rectangles by +/- x and y, then subtract original region.
773 BOOL32 REGION_FrameRgn( HRGN32 hDest, HRGN32 hSrc, INT32 x, INT32 y )
775 BOOL32 bRet;
776 RGNOBJ *srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
778 if (srcObj->rgn->numRects != 0)
780 RGNOBJ* destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
781 RECT32 *pRect, *pEndRect;
782 RECT32 tempRect;
784 EMPTY_REGION( destObj->rgn );
786 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
787 for(pRect = srcObj->rgn->rects; pRect < pEndRect; pRect++)
789 tempRect.left = pRect->left - x;
790 tempRect.top = pRect->top - y;
791 tempRect.right = pRect->right + x;
792 tempRect.bottom = pRect->bottom + y;
793 REGION_UnionRectWithRegion( &tempRect, destObj->rgn );
795 REGION_SubtractRegion( destObj->rgn, destObj->rgn, srcObj->rgn );
796 GDI_HEAP_UNLOCK ( hDest );
797 bRet = TRUE;
799 else
800 bRet = FALSE;
801 GDI_HEAP_UNLOCK( hSrc );
802 return bRet;
805 /***********************************************************************
806 * REGION_LPTODP
808 * Convert region to device co-ords for the supplied dc.
809 * Used by X11DRV_PaintRgn.
811 BOOL32 REGION_LPTODP( HDC32 hdc, HRGN32 hDest, HRGN32 hSrc )
813 RECT32 *pCurRect, *pEndRect;
814 RGNOBJ *srcObj, *destObj;
815 DC * dc = DC_GetDCPtr( hdc );
816 RECT32 tmpRect;
818 TRACE(region, " hdc=%04x dest=%04x src=%04x\n",
819 hdc, hDest, hSrc) ;
821 if (dc->w.MapMode == MM_TEXT) /* Requires only a translation */
823 if( CombineRgn32( hDest, hSrc, 0, RGN_COPY ) == ERROR ) return FALSE;
824 OffsetRgn32( hDest, dc->vportOrgX - dc->wndOrgX,
825 dc->vportOrgY - dc->wndOrgY );
826 return TRUE;
829 if(!( srcObj = (RGNOBJ *) GDI_GetObjPtr( hSrc, REGION_MAGIC) ))
830 return FALSE;
831 if(!( destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC) ))
833 GDI_HEAP_UNLOCK( hSrc );
834 return FALSE;
836 EMPTY_REGION( destObj->rgn );
838 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
839 for(pCurRect = srcObj->rgn->rects; pCurRect < pEndRect; pCurRect++)
841 tmpRect = *pCurRect;
842 tmpRect.left = XLPTODP( dc, tmpRect.left );
843 tmpRect.top = YLPTODP( dc, tmpRect.top );
844 tmpRect.right = XLPTODP( dc, tmpRect.right );
845 tmpRect.bottom = YLPTODP( dc, tmpRect.bottom );
846 REGION_UnionRectWithRegion( &tmpRect, destObj->rgn );
849 GDI_HEAP_UNLOCK( hDest );
850 GDI_HEAP_UNLOCK( hSrc );
851 return TRUE;
854 /***********************************************************************
855 * CombineRgn16 (GDI.451)
857 INT16 WINAPI CombineRgn16(HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode)
859 return (INT16)CombineRgn32( hDest, hSrc1, hSrc2, mode );
863 /***********************************************************************
864 * CombineRgn32 (GDI32.19)
866 * Note: The behavior is correct even if src and dest regions are the same.
868 INT32 WINAPI CombineRgn32(HRGN32 hDest, HRGN32 hSrc1, HRGN32 hSrc2, INT32 mode)
870 RGNOBJ *destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC);
871 INT32 result = ERROR;
873 TRACE(region, " %04x,%04x -> %04x mode=%x\n",
874 hSrc1, hSrc2, hDest, mode );
875 if (destObj)
877 RGNOBJ *src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC);
879 if (src1Obj)
881 TRACE(region, "dump:\n");
882 if(TRACE_ON(region))
883 REGION_DumpRegion(src1Obj->rgn);
884 if (mode == RGN_COPY)
886 REGION_CopyRegion( destObj->rgn, src1Obj->rgn );
887 result = destObj->rgn->type;
889 else
891 RGNOBJ *src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC);
893 if (src2Obj)
895 TRACE(region, "dump:\n");
896 if(TRACE_ON(region))
897 REGION_DumpRegion(src2Obj->rgn);
898 switch (mode)
900 case RGN_AND:
901 REGION_IntersectRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn);
902 break;
903 case RGN_OR:
904 REGION_UnionRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
905 break;
906 case RGN_XOR:
907 REGION_XorRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
908 break;
909 case RGN_DIFF:
910 REGION_SubtractRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
911 break;
913 result = destObj->rgn->type;
914 GDI_HEAP_UNLOCK( hSrc2 );
917 GDI_HEAP_UNLOCK( hSrc1 );
919 TRACE(region, "dump:\n");
920 if(TRACE_ON(region))
921 REGION_DumpRegion(destObj->rgn);
923 GDI_HEAP_UNLOCK( hDest );
925 return result;
928 /***********************************************************************
929 * REGION_SetExtents
930 * Re-calculate the extents of a region
932 static void REGION_SetExtents (WINEREGION *pReg)
934 RECT32 *pRect, *pRectEnd, *pExtents;
936 if (pReg->numRects == 0)
938 pReg->extents.left = 0;
939 pReg->extents.top = 0;
940 pReg->extents.right = 0;
941 pReg->extents.bottom = 0;
942 return;
945 pExtents = &pReg->extents;
946 pRect = pReg->rects;
947 pRectEnd = &pRect[pReg->numRects - 1];
950 * Since pRect is the first rectangle in the region, it must have the
951 * smallest top and since pRectEnd is the last rectangle in the region,
952 * it must have the largest bottom, because of banding. Initialize left and
953 * right from pRect and pRectEnd, resp., as good things to initialize them
954 * to...
956 pExtents->left = pRect->left;
957 pExtents->top = pRect->top;
958 pExtents->right = pRectEnd->right;
959 pExtents->bottom = pRectEnd->bottom;
961 while (pRect <= pRectEnd)
963 if (pRect->left < pExtents->left)
964 pExtents->left = pRect->left;
965 if (pRect->right > pExtents->right)
966 pExtents->right = pRect->right;
967 pRect++;
971 /***********************************************************************
972 * REGION_CopyRegion
974 static void REGION_CopyRegion(WINEREGION *dst, WINEREGION *src)
976 if (dst != src) /* don't want to copy to itself */
978 if (dst->size < src->numRects)
980 if (! (dst->rects = HeapReAlloc( SystemHeap, 0, dst->rects,
981 src->numRects * sizeof(RECT32) )))
982 return;
983 dst->size = src->numRects;
985 dst->numRects = src->numRects;
986 dst->extents.left = src->extents.left;
987 dst->extents.top = src->extents.top;
988 dst->extents.right = src->extents.right;
989 dst->extents.bottom = src->extents.bottom;
990 dst->type = src->type;
992 memcpy((char *) dst->rects, (char *) src->rects,
993 (int) (src->numRects * sizeof(RECT32)));
995 return;
998 /***********************************************************************
999 * REGION_Coalesce
1001 * Attempt to merge the rects in the current band with those in the
1002 * previous one. Used only by REGION_RegionOp.
1004 * Results:
1005 * The new index for the previous band.
1007 * Side Effects:
1008 * If coalescing takes place:
1009 * - rectangles in the previous band will have their bottom fields
1010 * altered.
1011 * - pReg->numRects will be decreased.
1014 static INT32 REGION_Coalesce (
1015 WINEREGION *pReg, /* Region to coalesce */
1016 INT32 prevStart, /* Index of start of previous band */
1017 INT32 curStart /* Index of start of current band */
1019 RECT32 *pPrevRect; /* Current rect in previous band */
1020 RECT32 *pCurRect; /* Current rect in current band */
1021 RECT32 *pRegEnd; /* End of region */
1022 INT32 curNumRects; /* Number of rectangles in current band */
1023 INT32 prevNumRects; /* Number of rectangles in previous band */
1024 INT32 bandtop; /* top coordinate for current band */
1026 pRegEnd = &pReg->rects[pReg->numRects];
1028 pPrevRect = &pReg->rects[prevStart];
1029 prevNumRects = curStart - prevStart;
1032 * Figure out how many rectangles are in the current band. Have to do
1033 * this because multiple bands could have been added in REGION_RegionOp
1034 * at the end when one region has been exhausted.
1036 pCurRect = &pReg->rects[curStart];
1037 bandtop = pCurRect->top;
1038 for (curNumRects = 0;
1039 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
1040 curNumRects++)
1042 pCurRect++;
1045 if (pCurRect != pRegEnd)
1048 * If more than one band was added, we have to find the start
1049 * of the last band added so the next coalescing job can start
1050 * at the right place... (given when multiple bands are added,
1051 * this may be pointless -- see above).
1053 pRegEnd--;
1054 while (pRegEnd[-1].top == pRegEnd->top)
1056 pRegEnd--;
1058 curStart = pRegEnd - pReg->rects;
1059 pRegEnd = pReg->rects + pReg->numRects;
1062 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
1063 pCurRect -= curNumRects;
1065 * The bands may only be coalesced if the bottom of the previous
1066 * matches the top scanline of the current.
1068 if (pPrevRect->bottom == pCurRect->top)
1071 * Make sure the bands have rects in the same places. This
1072 * assumes that rects have been added in such a way that they
1073 * cover the most area possible. I.e. two rects in a band must
1074 * have some horizontal space between them.
1078 if ((pPrevRect->left != pCurRect->left) ||
1079 (pPrevRect->right != pCurRect->right))
1082 * The bands don't line up so they can't be coalesced.
1084 return (curStart);
1086 pPrevRect++;
1087 pCurRect++;
1088 prevNumRects -= 1;
1089 } while (prevNumRects != 0);
1091 pReg->numRects -= curNumRects;
1092 pCurRect -= curNumRects;
1093 pPrevRect -= curNumRects;
1096 * The bands may be merged, so set the bottom of each rect
1097 * in the previous band to that of the corresponding rect in
1098 * the current band.
1102 pPrevRect->bottom = pCurRect->bottom;
1103 pPrevRect++;
1104 pCurRect++;
1105 curNumRects -= 1;
1106 } while (curNumRects != 0);
1109 * If only one band was added to the region, we have to backup
1110 * curStart to the start of the previous band.
1112 * If more than one band was added to the region, copy the
1113 * other bands down. The assumption here is that the other bands
1114 * came from the same region as the current one and no further
1115 * coalescing can be done on them since it's all been done
1116 * already... curStart is already in the right place.
1118 if (pCurRect == pRegEnd)
1120 curStart = prevStart;
1122 else
1126 *pPrevRect++ = *pCurRect++;
1127 } while (pCurRect != pRegEnd);
1132 return (curStart);
1135 /***********************************************************************
1136 * REGION_RegionOp
1138 * Apply an operation to two regions. Called by REGION_Union,
1139 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
1141 * Results:
1142 * None.
1144 * Side Effects:
1145 * The new region is overwritten.
1147 * Notes:
1148 * The idea behind this function is to view the two regions as sets.
1149 * Together they cover a rectangle of area that this function divides
1150 * into horizontal bands where points are covered only by one region
1151 * or by both. For the first case, the nonOverlapFunc is called with
1152 * each the band and the band's upper and lower extents. For the
1153 * second, the overlapFunc is called to process the entire band. It
1154 * is responsible for clipping the rectangles in the band, though
1155 * this function provides the boundaries.
1156 * At the end of each band, the new region is coalesced, if possible,
1157 * to reduce the number of rectangles in the region.
1160 static void REGION_RegionOp(
1161 WINEREGION *newReg, /* Place to store result */
1162 WINEREGION *reg1, /* First region in operation */
1163 WINEREGION *reg2, /* 2nd region in operation */
1164 void (*overlapFunc)(), /* Function to call for over-lapping bands */
1165 void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
1166 void (*nonOverlap2Func)() /* Function to call for non-overlapping bands in region 2 */
1168 RECT32 *r1; /* Pointer into first region */
1169 RECT32 *r2; /* Pointer into 2d region */
1170 RECT32 *r1End; /* End of 1st region */
1171 RECT32 *r2End; /* End of 2d region */
1172 INT32 ybot; /* Bottom of intersection */
1173 INT32 ytop; /* Top of intersection */
1174 RECT32 *oldRects; /* Old rects for newReg */
1175 INT32 prevBand; /* Index of start of
1176 * previous band in newReg */
1177 INT32 curBand; /* Index of start of current
1178 * band in newReg */
1179 RECT32 *r1BandEnd; /* End of current band in r1 */
1180 RECT32 *r2BandEnd; /* End of current band in r2 */
1181 INT32 top; /* Top of non-overlapping band */
1182 INT32 bot; /* Bottom of non-overlapping band */
1185 * Initialization:
1186 * set r1, r2, r1End and r2End appropriately, preserve the important
1187 * parts of the destination region until the end in case it's one of
1188 * the two source regions, then mark the "new" region empty, allocating
1189 * another array of rectangles for it to use.
1191 r1 = reg1->rects;
1192 r2 = reg2->rects;
1193 r1End = r1 + reg1->numRects;
1194 r2End = r2 + reg2->numRects;
1198 * newReg may be one of the src regions so we can't empty it. We keep a
1199 * note of its rects pointer (so that we can free them later), preserve its
1200 * extents and simply set numRects to zero.
1203 oldRects = newReg->rects;
1204 newReg->numRects = 0;
1207 * Allocate a reasonable number of rectangles for the new region. The idea
1208 * is to allocate enough so the individual functions don't need to
1209 * reallocate and copy the array, which is time consuming, yet we don't
1210 * have to worry about using too much memory. I hope to be able to
1211 * nuke the Xrealloc() at the end of this function eventually.
1213 newReg->size = MAX(reg1->numRects,reg2->numRects) * 2;
1215 if (! (newReg->rects = HeapAlloc( SystemHeap, 0,
1216 sizeof(RECT32) * newReg->size )))
1218 newReg->size = 0;
1219 return;
1223 * Initialize ybot and ytop.
1224 * In the upcoming loop, ybot and ytop serve different functions depending
1225 * on whether the band being handled is an overlapping or non-overlapping
1226 * band.
1227 * In the case of a non-overlapping band (only one of the regions
1228 * has points in the band), ybot is the bottom of the most recent
1229 * intersection and thus clips the top of the rectangles in that band.
1230 * ytop is the top of the next intersection between the two regions and
1231 * serves to clip the bottom of the rectangles in the current band.
1232 * For an overlapping band (where the two regions intersect), ytop clips
1233 * the top of the rectangles of both regions and ybot clips the bottoms.
1235 if (reg1->extents.top < reg2->extents.top)
1236 ybot = reg1->extents.top;
1237 else
1238 ybot = reg2->extents.top;
1241 * prevBand serves to mark the start of the previous band so rectangles
1242 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1243 * In the beginning, there is no previous band, so prevBand == curBand
1244 * (curBand is set later on, of course, but the first band will always
1245 * start at index 0). prevBand and curBand must be indices because of
1246 * the possible expansion, and resultant moving, of the new region's
1247 * array of rectangles.
1249 prevBand = 0;
1253 curBand = newReg->numRects;
1256 * This algorithm proceeds one source-band (as opposed to a
1257 * destination band, which is determined by where the two regions
1258 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1259 * rectangle after the last one in the current band for their
1260 * respective regions.
1262 r1BandEnd = r1;
1263 while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
1265 r1BandEnd++;
1268 r2BandEnd = r2;
1269 while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
1271 r2BandEnd++;
1275 * First handle the band that doesn't intersect, if any.
1277 * Note that attention is restricted to one band in the
1278 * non-intersecting region at once, so if a region has n
1279 * bands between the current position and the next place it overlaps
1280 * the other, this entire loop will be passed through n times.
1282 if (r1->top < r2->top)
1284 top = MAX(r1->top,ybot);
1285 bot = MIN(r1->bottom,r2->top);
1287 if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
1289 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
1292 ytop = r2->top;
1294 else if (r2->top < r1->top)
1296 top = MAX(r2->top,ybot);
1297 bot = MIN(r2->bottom,r1->top);
1299 if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
1301 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
1304 ytop = r1->top;
1306 else
1308 ytop = r1->top;
1312 * If any rectangles got added to the region, try and coalesce them
1313 * with rectangles from the previous band. Note we could just do
1314 * this test in miCoalesce, but some machines incur a not
1315 * inconsiderable cost for function calls, so...
1317 if (newReg->numRects != curBand)
1319 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1323 * Now see if we've hit an intersecting band. The two bands only
1324 * intersect if ybot > ytop
1326 ybot = MIN(r1->bottom, r2->bottom);
1327 curBand = newReg->numRects;
1328 if (ybot > ytop)
1330 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1334 if (newReg->numRects != curBand)
1336 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1340 * If we've finished with a band (bottom == ybot) we skip forward
1341 * in the region to the next band.
1343 if (r1->bottom == ybot)
1345 r1 = r1BandEnd;
1347 if (r2->bottom == ybot)
1349 r2 = r2BandEnd;
1351 } while ((r1 != r1End) && (r2 != r2End));
1354 * Deal with whichever region still has rectangles left.
1356 curBand = newReg->numRects;
1357 if (r1 != r1End)
1359 if (nonOverlap1Func != (void (*)())NULL)
1363 r1BandEnd = r1;
1364 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
1366 r1BandEnd++;
1368 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
1369 MAX(r1->top,ybot), r1->bottom);
1370 r1 = r1BandEnd;
1371 } while (r1 != r1End);
1374 else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
1378 r2BandEnd = r2;
1379 while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
1381 r2BandEnd++;
1383 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
1384 MAX(r2->top,ybot), r2->bottom);
1385 r2 = r2BandEnd;
1386 } while (r2 != r2End);
1389 if (newReg->numRects != curBand)
1391 (void) REGION_Coalesce (newReg, prevBand, curBand);
1395 * A bit of cleanup. To keep regions from growing without bound,
1396 * we shrink the array of rectangles to match the new number of
1397 * rectangles in the region. This never goes to 0, however...
1399 * Only do this stuff if the number of rectangles allocated is more than
1400 * twice the number of rectangles in the region (a simple optimization...).
1402 if (newReg->numRects < (newReg->size >> 1))
1404 if (REGION_NOT_EMPTY(newReg))
1406 RECT32 *prev_rects = newReg->rects;
1407 newReg->size = newReg->numRects;
1408 newReg->rects = HeapReAlloc( SystemHeap, 0, newReg->rects,
1409 sizeof(RECT32) * newReg->size );
1410 if (! newReg->rects)
1411 newReg->rects = prev_rects;
1413 else
1416 * No point in doing the extra work involved in an Xrealloc if
1417 * the region is empty
1419 newReg->size = 1;
1420 HeapFree( SystemHeap, 0, newReg->rects );
1421 newReg->rects = HeapAlloc( SystemHeap, 0, sizeof(RECT32) );
1424 HeapFree( SystemHeap, 0, oldRects );
1425 return;
1428 /***********************************************************************
1429 * Region Intersection
1430 ***********************************************************************/
1433 /***********************************************************************
1434 * REGION_IntersectO
1436 * Handle an overlapping band for REGION_Intersect.
1438 * Results:
1439 * None.
1441 * Side Effects:
1442 * Rectangles may be added to the region.
1445 static void REGION_IntersectO(WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1446 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1449 INT32 left, right;
1450 RECT32 *pNextRect;
1452 pNextRect = &pReg->rects[pReg->numRects];
1454 while ((r1 != r1End) && (r2 != r2End))
1456 left = MAX(r1->left, r2->left);
1457 right = MIN(r1->right, r2->right);
1460 * If there's any overlap between the two rectangles, add that
1461 * overlap to the new region.
1462 * There's no need to check for subsumption because the only way
1463 * such a need could arise is if some region has two rectangles
1464 * right next to each other. Since that should never happen...
1466 if (left < right)
1468 MEMCHECK(pReg, pNextRect, pReg->rects);
1469 pNextRect->left = left;
1470 pNextRect->top = top;
1471 pNextRect->right = right;
1472 pNextRect->bottom = bottom;
1473 pReg->numRects += 1;
1474 pNextRect++;
1478 * Need to advance the pointers. Shift the one that extends
1479 * to the right the least, since the other still has a chance to
1480 * overlap with that region's next rectangle, if you see what I mean.
1482 if (r1->right < r2->right)
1484 r1++;
1486 else if (r2->right < r1->right)
1488 r2++;
1490 else
1492 r1++;
1493 r2++;
1496 return;
1499 /***********************************************************************
1500 * REGION_IntersectRegion
1502 static void REGION_IntersectRegion(WINEREGION *newReg, WINEREGION *reg1,
1503 WINEREGION *reg2)
1505 /* check for trivial reject */
1506 if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
1507 (!EXTENTCHECK(&reg1->extents, &reg2->extents)))
1508 newReg->numRects = 0;
1509 else
1510 REGION_RegionOp (newReg, reg1, reg2,
1511 (voidProcp) REGION_IntersectO, (voidProcp) NULL, (voidProcp) NULL);
1514 * Can't alter newReg's extents before we call miRegionOp because
1515 * it might be one of the source regions and miRegionOp depends
1516 * on the extents of those regions being the same. Besides, this
1517 * way there's no checking against rectangles that will be nuked
1518 * due to coalescing, so we have to examine fewer rectangles.
1520 REGION_SetExtents(newReg);
1521 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1522 return;
1525 /***********************************************************************
1526 * Region Union
1527 ***********************************************************************/
1529 /***********************************************************************
1530 * REGION_UnionNonO
1532 * Handle a non-overlapping band for the union operation. Just
1533 * Adds the rectangles into the region. Doesn't have to check for
1534 * subsumption or anything.
1536 * Results:
1537 * None.
1539 * Side Effects:
1540 * pReg->numRects is incremented and the final rectangles overwritten
1541 * with the rectangles we're passed.
1544 static void REGION_UnionNonO (WINEREGION *pReg, RECT32 *r, RECT32 *rEnd,
1545 INT32 top, INT32 bottom)
1547 RECT32 *pNextRect;
1549 pNextRect = &pReg->rects[pReg->numRects];
1551 while (r != rEnd)
1553 MEMCHECK(pReg, pNextRect, pReg->rects);
1554 pNextRect->left = r->left;
1555 pNextRect->top = top;
1556 pNextRect->right = r->right;
1557 pNextRect->bottom = bottom;
1558 pReg->numRects += 1;
1559 pNextRect++;
1560 r++;
1562 return;
1565 /***********************************************************************
1566 * REGION_UnionO
1568 * Handle an overlapping band for the union operation. Picks the
1569 * left-most rectangle each time and merges it into the region.
1571 * Results:
1572 * None.
1574 * Side Effects:
1575 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1576 * be changed.
1579 static void REGION_UnionO (WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1580 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1582 RECT32 *pNextRect;
1584 pNextRect = &pReg->rects[pReg->numRects];
1586 #define MERGERECT(r) \
1587 if ((pReg->numRects != 0) && \
1588 (pNextRect[-1].top == top) && \
1589 (pNextRect[-1].bottom == bottom) && \
1590 (pNextRect[-1].right >= r->left)) \
1592 if (pNextRect[-1].right < r->right) \
1594 pNextRect[-1].right = r->right; \
1597 else \
1599 MEMCHECK(pReg, pNextRect, pReg->rects); \
1600 pNextRect->top = top; \
1601 pNextRect->bottom = bottom; \
1602 pNextRect->left = r->left; \
1603 pNextRect->right = r->right; \
1604 pReg->numRects += 1; \
1605 pNextRect += 1; \
1607 r++;
1609 while ((r1 != r1End) && (r2 != r2End))
1611 if (r1->left < r2->left)
1613 MERGERECT(r1);
1615 else
1617 MERGERECT(r2);
1621 if (r1 != r1End)
1625 MERGERECT(r1);
1626 } while (r1 != r1End);
1628 else while (r2 != r2End)
1630 MERGERECT(r2);
1632 return;
1635 /***********************************************************************
1636 * REGION_UnionRegion
1638 static void REGION_UnionRegion(WINEREGION *newReg, WINEREGION *reg1,
1639 WINEREGION *reg2)
1641 /* checks all the simple cases */
1644 * Region 1 and 2 are the same or region 1 is empty
1646 if ( (reg1 == reg2) || (!(reg1->numRects)) )
1648 if (newReg != reg2)
1649 REGION_CopyRegion(newReg, reg2);
1650 return;
1654 * if nothing to union (region 2 empty)
1656 if (!(reg2->numRects))
1658 if (newReg != reg1)
1659 REGION_CopyRegion(newReg, reg1);
1660 return;
1664 * Region 1 completely subsumes region 2
1666 if ((reg1->numRects == 1) &&
1667 (reg1->extents.left <= reg2->extents.left) &&
1668 (reg1->extents.top <= reg2->extents.top) &&
1669 (reg1->extents.right >= reg2->extents.right) &&
1670 (reg1->extents.bottom >= reg2->extents.bottom))
1672 if (newReg != reg1)
1673 REGION_CopyRegion(newReg, reg1);
1674 return;
1678 * Region 2 completely subsumes region 1
1680 if ((reg2->numRects == 1) &&
1681 (reg2->extents.left <= reg1->extents.left) &&
1682 (reg2->extents.top <= reg1->extents.top) &&
1683 (reg2->extents.right >= reg1->extents.right) &&
1684 (reg2->extents.bottom >= reg1->extents.bottom))
1686 if (newReg != reg2)
1687 REGION_CopyRegion(newReg, reg2);
1688 return;
1691 REGION_RegionOp (newReg, reg1, reg2, (voidProcp) REGION_UnionO,
1692 (voidProcp) REGION_UnionNonO, (voidProcp) REGION_UnionNonO);
1694 newReg->extents.left = MIN(reg1->extents.left, reg2->extents.left);
1695 newReg->extents.top = MIN(reg1->extents.top, reg2->extents.top);
1696 newReg->extents.right = MAX(reg1->extents.right, reg2->extents.right);
1697 newReg->extents.bottom = MAX(reg1->extents.bottom, reg2->extents.bottom);
1698 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1699 return;
1702 /***********************************************************************
1703 * Region Subtraction
1704 ***********************************************************************/
1706 /***********************************************************************
1707 * REGION_SubtractNonO1
1709 * Deal with non-overlapping band for subtraction. Any parts from
1710 * region 2 we discard. Anything from region 1 we add to the region.
1712 * Results:
1713 * None.
1715 * Side Effects:
1716 * pReg may be affected.
1719 static void REGION_SubtractNonO1 (WINEREGION *pReg, RECT32 *r, RECT32 *rEnd,
1720 INT32 top, INT32 bottom)
1722 RECT32 *pNextRect;
1724 pNextRect = &pReg->rects[pReg->numRects];
1726 while (r != rEnd)
1728 MEMCHECK(pReg, pNextRect, pReg->rects);
1729 pNextRect->left = r->left;
1730 pNextRect->top = top;
1731 pNextRect->right = r->right;
1732 pNextRect->bottom = bottom;
1733 pReg->numRects += 1;
1734 pNextRect++;
1735 r++;
1737 return;
1741 /***********************************************************************
1742 * REGION_SubtractO
1744 * Overlapping band subtraction. x1 is the left-most point not yet
1745 * checked.
1747 * Results:
1748 * None.
1750 * Side Effects:
1751 * pReg may have rectangles added to it.
1754 static void REGION_SubtractO (WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
1755 RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
1757 RECT32 *pNextRect;
1758 INT32 left;
1760 left = r1->left;
1761 pNextRect = &pReg->rects[pReg->numRects];
1763 while ((r1 != r1End) && (r2 != r2End))
1765 if (r2->right <= left)
1768 * Subtrahend missed the boat: go to next subtrahend.
1770 r2++;
1772 else if (r2->left <= left)
1775 * Subtrahend preceeds minuend: nuke left edge of minuend.
1777 left = r2->right;
1778 if (left >= r1->right)
1781 * Minuend completely covered: advance to next minuend and
1782 * reset left fence to edge of new minuend.
1784 r1++;
1785 if (r1 != r1End)
1786 left = r1->left;
1788 else
1791 * Subtrahend now used up since it doesn't extend beyond
1792 * minuend
1794 r2++;
1797 else if (r2->left < r1->right)
1800 * Left part of subtrahend covers part of minuend: add uncovered
1801 * part of minuend to region and skip to next subtrahend.
1803 MEMCHECK(pReg, pNextRect, pReg->rects);
1804 pNextRect->left = left;
1805 pNextRect->top = top;
1806 pNextRect->right = r2->left;
1807 pNextRect->bottom = bottom;
1808 pReg->numRects += 1;
1809 pNextRect++;
1810 left = r2->right;
1811 if (left >= r1->right)
1814 * Minuend used up: advance to new...
1816 r1++;
1817 if (r1 != r1End)
1818 left = r1->left;
1820 else
1823 * Subtrahend used up
1825 r2++;
1828 else
1831 * Minuend used up: add any remaining piece before advancing.
1833 if (r1->right > left)
1835 MEMCHECK(pReg, pNextRect, pReg->rects);
1836 pNextRect->left = left;
1837 pNextRect->top = top;
1838 pNextRect->right = r1->right;
1839 pNextRect->bottom = bottom;
1840 pReg->numRects += 1;
1841 pNextRect++;
1843 r1++;
1844 left = r1->left;
1849 * Add remaining minuend rectangles to region.
1851 while (r1 != r1End)
1853 MEMCHECK(pReg, pNextRect, pReg->rects);
1854 pNextRect->left = left;
1855 pNextRect->top = top;
1856 pNextRect->right = r1->right;
1857 pNextRect->bottom = bottom;
1858 pReg->numRects += 1;
1859 pNextRect++;
1860 r1++;
1861 if (r1 != r1End)
1863 left = r1->left;
1866 return;
1869 /***********************************************************************
1870 * REGION_SubtractRegion
1872 * Subtract regS from regM and leave the result in regD.
1873 * S stands for subtrahend, M for minuend and D for difference.
1875 * Results:
1876 * TRUE.
1878 * Side Effects:
1879 * regD is overwritten.
1882 static void REGION_SubtractRegion(WINEREGION *regD, WINEREGION *regM,
1883 WINEREGION *regS )
1885 /* check for trivial reject */
1886 if ( (!(regM->numRects)) || (!(regS->numRects)) ||
1887 (!EXTENTCHECK(&regM->extents, &regS->extents)) )
1889 REGION_CopyRegion(regD, regM);
1890 return;
1893 REGION_RegionOp (regD, regM, regS, (voidProcp) REGION_SubtractO,
1894 (voidProcp) REGION_SubtractNonO1, (voidProcp) NULL);
1897 * Can't alter newReg's extents before we call miRegionOp because
1898 * it might be one of the source regions and miRegionOp depends
1899 * on the extents of those regions being the unaltered. Besides, this
1900 * way there's no checking against rectangles that will be nuked
1901 * due to coalescing, so we have to examine fewer rectangles.
1903 REGION_SetExtents (regD);
1904 regD->type = (regD->numRects) ? COMPLEXREGION : NULLREGION ;
1905 return;
1908 /***********************************************************************
1909 * REGION_XorRegion
1911 static void REGION_XorRegion(WINEREGION *dr, WINEREGION *sra,
1912 WINEREGION *srb)
1914 WINEREGION *tra, *trb;
1916 if ((! (tra = REGION_AllocWineRegion())) ||
1917 (! (trb = REGION_AllocWineRegion())))
1918 return;
1919 REGION_SubtractRegion(tra,sra,srb);
1920 REGION_SubtractRegion(trb,srb,sra);
1921 REGION_UnionRegion(dr,tra,trb);
1922 REGION_DestroyWineRegion(tra);
1923 REGION_DestroyWineRegion(trb);
1924 return;
1927 /**************************************************************************
1929 * Poly Regions
1931 *************************************************************************/
1933 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
1934 #define SMALL_COORDINATE 0x80000000
1936 /***********************************************************************
1937 * REGION_InsertEdgeInET
1939 * Insert the given edge into the edge table.
1940 * First we must find the correct bucket in the
1941 * Edge table, then find the right slot in the
1942 * bucket. Finally, we can insert it.
1945 static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
1946 INT32 scanline, ScanLineListBlock **SLLBlock, INT32 *iSLLBlock)
1949 EdgeTableEntry *start, *prev;
1950 ScanLineList *pSLL, *pPrevSLL;
1951 ScanLineListBlock *tmpSLLBlock;
1954 * find the right bucket to put the edge into
1956 pPrevSLL = &ET->scanlines;
1957 pSLL = pPrevSLL->next;
1958 while (pSLL && (pSLL->scanline < scanline))
1960 pPrevSLL = pSLL;
1961 pSLL = pSLL->next;
1965 * reassign pSLL (pointer to ScanLineList) if necessary
1967 if ((!pSLL) || (pSLL->scanline > scanline))
1969 if (*iSLLBlock > SLLSPERBLOCK-1)
1971 tmpSLLBlock = HeapAlloc( SystemHeap, 0, sizeof(ScanLineListBlock));
1972 if(!tmpSLLBlock)
1974 WARN(region, "Can't alloc SLLB\n");
1975 return;
1977 (*SLLBlock)->next = tmpSLLBlock;
1978 tmpSLLBlock->next = (ScanLineListBlock *)NULL;
1979 *SLLBlock = tmpSLLBlock;
1980 *iSLLBlock = 0;
1982 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
1984 pSLL->next = pPrevSLL->next;
1985 pSLL->edgelist = (EdgeTableEntry *)NULL;
1986 pPrevSLL->next = pSLL;
1988 pSLL->scanline = scanline;
1991 * now insert the edge in the right bucket
1993 prev = (EdgeTableEntry *)NULL;
1994 start = pSLL->edgelist;
1995 while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
1997 prev = start;
1998 start = start->next;
2000 ETE->next = start;
2002 if (prev)
2003 prev->next = ETE;
2004 else
2005 pSLL->edgelist = ETE;
2008 /***********************************************************************
2009 * REGION_CreateEdgeTable
2011 * This routine creates the edge table for
2012 * scan converting polygons.
2013 * The Edge Table (ET) looks like:
2015 * EdgeTable
2016 * --------
2017 * | ymax | ScanLineLists
2018 * |scanline|-->------------>-------------->...
2019 * -------- |scanline| |scanline|
2020 * |edgelist| |edgelist|
2021 * --------- ---------
2022 * | |
2023 * | |
2024 * V V
2025 * list of ETEs list of ETEs
2027 * where ETE is an EdgeTableEntry data structure,
2028 * and there is one ScanLineList per scanline at
2029 * which an edge is initially entered.
2032 static void REGION_CreateETandAET(const INT32 *Count, INT32 nbpolygons,
2033 const POINT32 *pts, EdgeTable *ET, EdgeTableEntry *AET,
2034 EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
2036 const POINT32 *top, *bottom;
2037 const POINT32 *PrevPt, *CurrPt, *EndPt;
2038 INT32 poly, count;
2039 int iSLLBlock = 0;
2040 int dy;
2044 * initialize the Active Edge Table
2046 AET->next = (EdgeTableEntry *)NULL;
2047 AET->back = (EdgeTableEntry *)NULL;
2048 AET->nextWETE = (EdgeTableEntry *)NULL;
2049 AET->bres.minor_axis = SMALL_COORDINATE;
2052 * initialize the Edge Table.
2054 ET->scanlines.next = (ScanLineList *)NULL;
2055 ET->ymax = SMALL_COORDINATE;
2056 ET->ymin = LARGE_COORDINATE;
2057 pSLLBlock->next = (ScanLineListBlock *)NULL;
2059 EndPt = pts - 1;
2060 for(poly = 0; poly < nbpolygons; poly++)
2062 count = Count[poly];
2063 EndPt += count;
2064 if(count < 2)
2065 continue;
2067 PrevPt = EndPt;
2070 * for each vertex in the array of points.
2071 * In this loop we are dealing with two vertices at
2072 * a time -- these make up one edge of the polygon.
2074 while (count--)
2076 CurrPt = pts++;
2079 * find out which point is above and which is below.
2081 if (PrevPt->y > CurrPt->y)
2083 bottom = PrevPt, top = CurrPt;
2084 pETEs->ClockWise = 0;
2086 else
2088 bottom = CurrPt, top = PrevPt;
2089 pETEs->ClockWise = 1;
2093 * don't add horizontal edges to the Edge table.
2095 if (bottom->y != top->y)
2097 pETEs->ymax = bottom->y-1;
2098 /* -1 so we don't get last scanline */
2101 * initialize integer edge algorithm
2103 dy = bottom->y - top->y;
2104 BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
2106 REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
2107 &iSLLBlock);
2109 if (PrevPt->y > ET->ymax)
2110 ET->ymax = PrevPt->y;
2111 if (PrevPt->y < ET->ymin)
2112 ET->ymin = PrevPt->y;
2113 pETEs++;
2116 PrevPt = CurrPt;
2121 /***********************************************************************
2122 * REGION_loadAET
2124 * This routine moves EdgeTableEntries from the
2125 * EdgeTable into the Active Edge Table,
2126 * leaving them sorted by smaller x coordinate.
2129 static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
2131 EdgeTableEntry *pPrevAET;
2132 EdgeTableEntry *tmp;
2134 pPrevAET = AET;
2135 AET = AET->next;
2136 while (ETEs)
2138 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
2140 pPrevAET = AET;
2141 AET = AET->next;
2143 tmp = ETEs->next;
2144 ETEs->next = AET;
2145 if (AET)
2146 AET->back = ETEs;
2147 ETEs->back = pPrevAET;
2148 pPrevAET->next = ETEs;
2149 pPrevAET = ETEs;
2151 ETEs = tmp;
2155 /***********************************************************************
2156 * REGION_computeWAET
2158 * This routine links the AET by the
2159 * nextWETE (winding EdgeTableEntry) link for
2160 * use by the winding number rule. The final
2161 * Active Edge Table (AET) might look something
2162 * like:
2164 * AET
2165 * ---------- --------- ---------
2166 * |ymax | |ymax | |ymax |
2167 * | ... | |... | |... |
2168 * |next |->|next |->|next |->...
2169 * |nextWETE| |nextWETE| |nextWETE|
2170 * --------- --------- ^--------
2171 * | | |
2172 * V-------------------> V---> ...
2175 static void REGION_computeWAET(EdgeTableEntry *AET)
2177 register EdgeTableEntry *pWETE;
2178 register int inside = 1;
2179 register int isInside = 0;
2181 AET->nextWETE = (EdgeTableEntry *)NULL;
2182 pWETE = AET;
2183 AET = AET->next;
2184 while (AET)
2186 if (AET->ClockWise)
2187 isInside++;
2188 else
2189 isInside--;
2191 if ((!inside && !isInside) ||
2192 ( inside && isInside))
2194 pWETE->nextWETE = AET;
2195 pWETE = AET;
2196 inside = !inside;
2198 AET = AET->next;
2200 pWETE->nextWETE = (EdgeTableEntry *)NULL;
2203 /***********************************************************************
2204 * REGION_InsertionSort
2206 * Just a simple insertion sort using
2207 * pointers and back pointers to sort the Active
2208 * Edge Table.
2211 static BOOL32 REGION_InsertionSort(EdgeTableEntry *AET)
2213 EdgeTableEntry *pETEchase;
2214 EdgeTableEntry *pETEinsert;
2215 EdgeTableEntry *pETEchaseBackTMP;
2216 BOOL32 changed = FALSE;
2218 AET = AET->next;
2219 while (AET)
2221 pETEinsert = AET;
2222 pETEchase = AET;
2223 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
2224 pETEchase = pETEchase->back;
2226 AET = AET->next;
2227 if (pETEchase != pETEinsert)
2229 pETEchaseBackTMP = pETEchase->back;
2230 pETEinsert->back->next = AET;
2231 if (AET)
2232 AET->back = pETEinsert->back;
2233 pETEinsert->next = pETEchase;
2234 pETEchase->back->next = pETEinsert;
2235 pETEchase->back = pETEinsert;
2236 pETEinsert->back = pETEchaseBackTMP;
2237 changed = TRUE;
2240 return changed;
2243 /***********************************************************************
2244 * REGION_FreeStorage
2246 * Clean up our act.
2248 static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
2250 ScanLineListBlock *tmpSLLBlock;
2252 while (pSLLBlock)
2254 tmpSLLBlock = pSLLBlock->next;
2255 HeapFree( SystemHeap, 0, pSLLBlock );
2256 pSLLBlock = tmpSLLBlock;
2261 /***********************************************************************
2262 * REGION_PtsToRegion
2264 * Create an array of rectangles from a list of points.
2266 static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
2267 POINTBLOCK *FirstPtBlock, WINEREGION *reg)
2269 RECT32 *rects;
2270 POINT32 *pts;
2271 POINTBLOCK *CurPtBlock;
2272 int i;
2273 RECT32 *extents;
2274 INT32 numRects;
2276 extents = &reg->extents;
2278 numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
2280 if (!(reg->rects = HeapReAlloc( SystemHeap, 0, reg->rects,
2281 sizeof(RECT32) * numRects )))
2282 return(0);
2284 reg->size = numRects;
2285 CurPtBlock = FirstPtBlock;
2286 rects = reg->rects - 1;
2287 numRects = 0;
2288 extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
2290 for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
2291 /* the loop uses 2 points per iteration */
2292 i = NUMPTSTOBUFFER >> 1;
2293 if (!numFullPtBlocks)
2294 i = iCurPtBlock >> 1;
2295 for (pts = CurPtBlock->pts; i--; pts += 2) {
2296 if (pts->x == pts[1].x)
2297 continue;
2298 if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
2299 pts[1].x == rects->right &&
2300 (numRects == 1 || rects[-1].top != rects->top) &&
2301 (i && pts[2].y > pts[1].y)) {
2302 rects->bottom = pts[1].y + 1;
2303 continue;
2305 numRects++;
2306 rects++;
2307 rects->left = pts->x; rects->top = pts->y;
2308 rects->right = pts[1].x; rects->bottom = pts[1].y + 1;
2309 if (rects->left < extents->left)
2310 extents->left = rects->left;
2311 if (rects->right > extents->right)
2312 extents->right = rects->right;
2314 CurPtBlock = CurPtBlock->next;
2317 if (numRects) {
2318 extents->top = reg->rects->top;
2319 extents->bottom = rects->bottom;
2320 } else {
2321 extents->left = 0;
2322 extents->top = 0;
2323 extents->right = 0;
2324 extents->bottom = 0;
2326 reg->numRects = numRects;
2328 return(TRUE);
2331 /***********************************************************************
2332 * CreatePolyPolygonRgn32 (GDI32.57)
2334 HRGN32 WINAPI CreatePolyPolygonRgn32(const POINT32 *Pts, const INT32 *Count,
2335 INT32 nbpolygons, INT32 mode)
2337 HRGN32 hrgn;
2338 RGNOBJ *obj;
2339 WINEREGION *region;
2340 register EdgeTableEntry *pAET; /* Active Edge Table */
2341 register INT32 y; /* current scanline */
2342 register int iPts = 0; /* number of pts in buffer */
2343 register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
2344 register ScanLineList *pSLL; /* current scanLineList */
2345 register POINT32 *pts; /* output buffer */
2346 EdgeTableEntry *pPrevAET; /* ptr to previous AET */
2347 EdgeTable ET; /* header node for ET */
2348 EdgeTableEntry AET; /* header node for AET */
2349 EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
2350 ScanLineListBlock SLLBlock; /* header for scanlinelist */
2351 int fixWAET = FALSE;
2352 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
2353 POINTBLOCK *tmpPtBlock;
2354 int numFullPtBlocks = 0;
2355 INT32 poly, total;
2357 if(!(hrgn = REGION_CreateRegion()))
2358 return 0;
2359 obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
2360 region = obj->rgn;
2362 /* special case a rectangle */
2364 if (((nbpolygons == 1) && ((*Count == 4) ||
2365 ((*Count == 5) && (Pts[4].x == Pts[0].x) && (Pts[4].y == Pts[0].y)))) &&
2366 (((Pts[0].y == Pts[1].y) &&
2367 (Pts[1].x == Pts[2].x) &&
2368 (Pts[2].y == Pts[3].y) &&
2369 (Pts[3].x == Pts[0].x)) ||
2370 ((Pts[0].x == Pts[1].x) &&
2371 (Pts[1].y == Pts[2].y) &&
2372 (Pts[2].x == Pts[3].x) &&
2373 (Pts[3].y == Pts[0].y))))
2375 SetRectRgn32( hrgn, MIN(Pts[0].x, Pts[2].x), MIN(Pts[0].y, Pts[2].y),
2376 MAX(Pts[0].x, Pts[2].x), MAX(Pts[0].y, Pts[2].y) );
2377 GDI_HEAP_UNLOCK( hrgn );
2378 return hrgn;
2381 for(poly = total = 0; poly < nbpolygons; poly++)
2382 total += Count[poly];
2383 if (! (pETEs = HeapAlloc( SystemHeap, 0, sizeof(EdgeTableEntry) * total )))
2385 REGION_DeleteObject( hrgn, obj );
2386 return 0;
2388 pts = FirstPtBlock.pts;
2389 REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
2390 pSLL = ET.scanlines.next;
2391 curPtBlock = &FirstPtBlock;
2393 if (mode != WINDING) {
2395 * for each scanline
2397 for (y = ET.ymin; y < ET.ymax; y++) {
2399 * Add a new edge to the active edge table when we
2400 * get to the next edge.
2402 if (pSLL != NULL && y == pSLL->scanline) {
2403 REGION_loadAET(&AET, pSLL->edgelist);
2404 pSLL = pSLL->next;
2406 pPrevAET = &AET;
2407 pAET = AET.next;
2410 * for each active edge
2412 while (pAET) {
2413 pts->x = pAET->bres.minor_axis, pts->y = y;
2414 pts++, iPts++;
2417 * send out the buffer
2419 if (iPts == NUMPTSTOBUFFER) {
2420 tmpPtBlock = HeapAlloc( SystemHeap, 0, sizeof(POINTBLOCK));
2421 if(!tmpPtBlock) {
2422 WARN(region, "Can't alloc tPB\n");
2423 return 0;
2425 curPtBlock->next = tmpPtBlock;
2426 curPtBlock = tmpPtBlock;
2427 pts = curPtBlock->pts;
2428 numFullPtBlocks++;
2429 iPts = 0;
2431 EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
2433 REGION_InsertionSort(&AET);
2436 else {
2438 * for each scanline
2440 for (y = ET.ymin; y < ET.ymax; y++) {
2442 * Add a new edge to the active edge table when we
2443 * get to the next edge.
2445 if (pSLL != NULL && y == pSLL->scanline) {
2446 REGION_loadAET(&AET, pSLL->edgelist);
2447 REGION_computeWAET(&AET);
2448 pSLL = pSLL->next;
2450 pPrevAET = &AET;
2451 pAET = AET.next;
2452 pWETE = pAET;
2455 * for each active edge
2457 while (pAET) {
2459 * add to the buffer only those edges that
2460 * are in the Winding active edge table.
2462 if (pWETE == pAET) {
2463 pts->x = pAET->bres.minor_axis, pts->y = y;
2464 pts++, iPts++;
2467 * send out the buffer
2469 if (iPts == NUMPTSTOBUFFER) {
2470 tmpPtBlock = HeapAlloc( SystemHeap, 0,
2471 sizeof(POINTBLOCK) );
2472 if(!tmpPtBlock) {
2473 WARN(region, "Can't alloc tPB\n");
2474 return 0;
2476 curPtBlock->next = tmpPtBlock;
2477 curPtBlock = tmpPtBlock;
2478 pts = curPtBlock->pts;
2479 numFullPtBlocks++; iPts = 0;
2481 pWETE = pWETE->nextWETE;
2483 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
2487 * recompute the winding active edge table if
2488 * we just resorted or have exited an edge.
2490 if (REGION_InsertionSort(&AET) || fixWAET) {
2491 REGION_computeWAET(&AET);
2492 fixWAET = FALSE;
2496 REGION_FreeStorage(SLLBlock.next);
2497 REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
2498 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
2499 tmpPtBlock = curPtBlock->next;
2500 HeapFree( SystemHeap, 0, curPtBlock );
2501 curPtBlock = tmpPtBlock;
2503 HeapFree( SystemHeap, 0, pETEs );
2504 GDI_HEAP_UNLOCK( hrgn );
2505 return hrgn;
2509 /***********************************************************************
2510 * CreatePolygonRgn16 (GDI.63)
2512 HRGN16 WINAPI CreatePolygonRgn16( const POINT16 * points, INT16 count,
2513 INT16 mode )
2515 return CreatePolyPolygonRgn16( points, &count, 1, mode );
2518 /***********************************************************************
2519 * CreatePolyPolygonRgn16 (GDI.451)
2521 HRGN16 WINAPI CreatePolyPolygonRgn16( const POINT16 *points,
2522 const INT16 *count, INT16 nbpolygons, INT16 mode )
2524 HRGN32 hrgn;
2525 int i, npts = 0;
2526 INT32 *count32;
2527 POINT32 *points32;
2529 for (i = 0; i < nbpolygons; i++)
2530 npts += count[i];
2531 points32 = HeapAlloc( SystemHeap, 0, npts * sizeof(POINT32) );
2532 for (i = 0; i < npts; i++)
2533 CONV_POINT16TO32( &(points[i]), &(points32[i]) );
2535 count32 = HeapAlloc( SystemHeap, 0, nbpolygons * sizeof(INT32) );
2536 for (i = 0; i < nbpolygons; i++)
2537 count32[i] = count[i];
2538 hrgn = CreatePolyPolygonRgn32( points32, count32, nbpolygons, mode );
2539 HeapFree( SystemHeap, 0, count32 );
2540 HeapFree( SystemHeap, 0, points32 );
2541 return hrgn;
2544 /***********************************************************************
2545 * CreatePolygonRgn32 (GDI32.58)
2547 HRGN32 WINAPI CreatePolygonRgn32( const POINT32 *points, INT32 count,
2548 INT32 mode )
2550 return CreatePolyPolygonRgn32( points, &count, 1, mode );
2554 /***********************************************************************
2555 * GetRandomRgn [GDI32.215]
2557 * NOTES
2558 * This function is UNDOCUMENTED, it isn't even in the header file.
2559 * I assume that it will return a HRGN32!??
2561 HRGN32 WINAPI GetRandomRgn(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3)
2563 FIXME (region, "(0x%08lx 0x%08lx 0x%08lx): empty stub!\n",
2564 dwArg1, dwArg2, dwArg3);
2566 return 0;