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