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...
91 typedef void (*voidProcp
)();
93 /* Note the parameter order is different from the X11 equivalents */
95 static void REGION_CopyRegion(WINEREGION
*d
, WINEREGION
*s
);
96 static void REGION_IntersectRegion(WINEREGION
*d
, WINEREGION
*s1
, WINEREGION
*s2
);
97 static void REGION_UnionRegion(WINEREGION
*d
, WINEREGION
*s1
, WINEREGION
*s2
);
98 static void REGION_SubtractRegion(WINEREGION
*d
, WINEREGION
*s1
, WINEREGION
*s2
);
99 static void REGION_XorRegion(WINEREGION
*d
, WINEREGION
*s1
, WINEREGION
*s2
);
100 static void REGION_UnionRectWithRegion(const RECT
*rect
, WINEREGION
*rgn
);
103 /***********************************************************************
105 * Outputs the contents of a WINEREGION
107 static void REGION_DumpRegion(WINEREGION
*pReg
)
109 RECT
*pRect
, *pRectEnd
= pReg
->rects
+ pReg
->numRects
;
111 TRACE(region
, "Region %p: %d,%d - %d,%d %d rects\n", pReg
,
112 pReg
->extents
.left
, pReg
->extents
.top
,
113 pReg
->extents
.right
, pReg
->extents
.bottom
, pReg
->numRects
);
114 for(pRect
= pReg
->rects
; pRect
< pRectEnd
; pRect
++)
115 TRACE(region
, "\t%d,%d - %d,%d\n", pRect
->left
, pRect
->top
,
116 pRect
->right
, pRect
->bottom
);
120 /***********************************************************************
121 * REGION_AllocWineRegion
122 * Create a new empty WINEREGION.
124 static WINEREGION
*REGION_AllocWineRegion( void )
128 if ((pReg
= HeapAlloc(SystemHeap
, 0, sizeof( WINEREGION
))))
130 if ((pReg
->rects
= HeapAlloc(SystemHeap
, 0, sizeof( RECT
))))
136 HeapFree(SystemHeap
, 0, pReg
);
141 /***********************************************************************
142 * REGION_CreateRegion
143 * Create a new empty region.
145 static HRGN
REGION_CreateRegion(void)
150 if(!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
)))
152 obj
= (RGNOBJ
*) GDI_HEAP_LOCK( hrgn
);
153 if(!(obj
->rgn
= REGION_AllocWineRegion())) {
154 GDI_FreeObject( hrgn
);
157 GDI_HEAP_UNLOCK( hrgn
);
161 /***********************************************************************
162 * REGION_DestroyWineRegion
164 static void REGION_DestroyWineRegion( WINEREGION
* pReg
)
166 HeapFree( SystemHeap
, 0, pReg
->rects
);
167 HeapFree( SystemHeap
, 0, pReg
);
171 /***********************************************************************
172 * REGION_DeleteObject
174 BOOL
REGION_DeleteObject( HRGN hrgn
, RGNOBJ
* obj
)
176 TRACE(region
, " %04x\n", hrgn
);
178 REGION_DestroyWineRegion( obj
->rgn
);
179 return GDI_FreeObject( hrgn
);
182 /***********************************************************************
183 * OffsetRgn16 (GDI.101)
185 INT16 WINAPI
OffsetRgn16( HRGN16 hrgn
, INT16 x
, INT16 y
)
187 return OffsetRgn( hrgn
, x
, y
);
190 /***********************************************************************
191 * OffsetRgn32 (GDI32.256)
193 INT WINAPI
OffsetRgn( HRGN hrgn
, INT x
, INT y
)
195 RGNOBJ
* obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
200 int nbox
= obj
->rgn
->numRects
;
201 RECT
*pbox
= obj
->rgn
->rects
;
203 TRACE(region
, " %04x %d,%d\n", hrgn
, x
, y
);
204 if(nbox
&& (x
|| y
)) {
212 obj
->rgn
->extents
.left
+= x
;
213 obj
->rgn
->extents
.right
+= x
;
214 obj
->rgn
->extents
.top
+= y
;
215 obj
->rgn
->extents
.bottom
+= y
;
217 ret
= obj
->rgn
->type
;
218 GDI_HEAP_UNLOCK( hrgn
);
225 /***********************************************************************
226 * GetRgnBox16 (GDI.134)
228 INT16 WINAPI
GetRgnBox16( HRGN16 hrgn
, LPRECT16 rect
)
231 INT16 ret
= (INT16
)GetRgnBox( hrgn
, &r
);
232 CONV_RECT32TO16( &r
, rect
);
236 /***********************************************************************
237 * GetRgnBox32 (GDI32.219)
239 INT WINAPI
GetRgnBox( HRGN hrgn
, LPRECT rect
)
241 RGNOBJ
* obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
245 TRACE(region
, " %04x\n", hrgn
);
246 rect
->left
= obj
->rgn
->extents
.left
;
247 rect
->top
= obj
->rgn
->extents
.top
;
248 rect
->right
= obj
->rgn
->extents
.right
;
249 rect
->bottom
= obj
->rgn
->extents
.bottom
;
250 ret
= obj
->rgn
->type
;
251 GDI_HEAP_UNLOCK(hrgn
);
258 /***********************************************************************
259 * CreateRectRgn16 (GDI.64)
261 * NOTE: Doesn't call CreateRectRgn32 because of differences in SetRectRgn16/32
263 HRGN16 WINAPI
CreateRectRgn16(INT16 left
, INT16 top
, INT16 right
, INT16 bottom
)
267 if (!(hrgn
= (HRGN16
)REGION_CreateRegion()))
270 SetRectRgn16(hrgn
, left
, top
, right
, bottom
);
275 /***********************************************************************
276 * CreateRectRgn32 (GDI32.59)
278 HRGN WINAPI
CreateRectRgn(INT left
, INT top
, INT right
, INT bottom
)
282 if (!(hrgn
= REGION_CreateRegion()))
285 SetRectRgn(hrgn
, left
, top
, right
, bottom
);
289 /***********************************************************************
290 * CreateRectRgnIndirect16 (GDI.65)
292 HRGN16 WINAPI
CreateRectRgnIndirect16( const RECT16
* rect
)
294 return CreateRectRgn16( rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
298 /***********************************************************************
299 * CreateRectRgnIndirect32 (GDI32.60)
301 HRGN WINAPI
CreateRectRgnIndirect( const RECT
* rect
)
303 return CreateRectRgn( rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
307 /***********************************************************************
308 * SetRectRgn16 (GDI.172)
310 * NOTE: Win 3.1 sets region to empty if left > right
312 VOID WINAPI
SetRectRgn16( HRGN16 hrgn
, INT16 left
, INT16 top
,
313 INT16 right
, INT16 bottom
)
316 SetRectRgn( hrgn
, left
, top
, right
, bottom
);
318 SetRectRgn( hrgn
, 0, 0, 0, 0 );
322 /***********************************************************************
323 * SetRectRgn32 (GDI32.332)
325 * Allows either or both left and top to be greater than right or bottom.
327 VOID WINAPI
SetRectRgn( HRGN hrgn
, INT left
, INT top
,
328 INT right
, INT bottom
)
332 TRACE(region
, " %04x %d,%d-%d,%d\n",
333 hrgn
, left
, top
, right
, bottom
);
335 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return;
337 if (left
> right
) { INT tmp
= left
; left
= right
; right
= tmp
; }
338 if (top
> bottom
) { INT tmp
= top
; top
= bottom
; bottom
= tmp
; }
340 if((left
!= right
) && (top
!= bottom
))
342 obj
->rgn
->rects
->left
= obj
->rgn
->extents
.left
= left
;
343 obj
->rgn
->rects
->top
= obj
->rgn
->extents
.top
= top
;
344 obj
->rgn
->rects
->right
= obj
->rgn
->extents
.right
= right
;
345 obj
->rgn
->rects
->bottom
= obj
->rgn
->extents
.bottom
= bottom
;
346 obj
->rgn
->numRects
= 1;
347 obj
->rgn
->type
= SIMPLEREGION
;
350 EMPTY_REGION(obj
->rgn
);
352 GDI_HEAP_UNLOCK( hrgn
);
356 /***********************************************************************
357 * CreateRoundRectRgn16 (GDI.444)
359 * If either ellipse dimension is zero we call CreateRectRgn16 for its
360 * `special' behaviour. -ve ellipse dimensions can result in GPFs under win3.1
361 * we just let CreateRoundRectRgn32 convert them to +ve values.
364 HRGN16 WINAPI
CreateRoundRectRgn16( INT16 left
, INT16 top
,
365 INT16 right
, INT16 bottom
,
366 INT16 ellipse_width
, INT16 ellipse_height
)
368 if( ellipse_width
== 0 || ellipse_height
== 0 )
369 return CreateRectRgn16( left
, top
, right
, bottom
);
371 return (HRGN16
)CreateRoundRectRgn( left
, top
, right
, bottom
,
372 ellipse_width
, ellipse_height
);
375 /***********************************************************************
376 * CreateRoundRectRgn32 (GDI32.61)
378 HRGN WINAPI
CreateRoundRectRgn( INT left
, INT top
,
379 INT right
, INT bottom
,
380 INT ellipse_width
, INT ellipse_height
)
384 int asq
, bsq
, d
, xd
, yd
;
387 /* Check if we can do a normal rectangle instead */
389 if ((ellipse_width
== 0) || (ellipse_height
== 0))
390 return CreateRectRgn( left
, top
, right
, bottom
);
392 /* Make the dimensions sensible */
394 if (left
> right
) { INT tmp
= left
; left
= right
; right
= tmp
; }
395 if (top
> bottom
) { INT tmp
= top
; top
= bottom
; bottom
= tmp
; }
397 ellipse_width
= abs(ellipse_width
);
398 ellipse_height
= abs(ellipse_height
);
402 if (!(hrgn
= REGION_CreateRegion())) return 0;
403 obj
= (RGNOBJ
*) GDI_HEAP_LOCK( hrgn
);
404 TRACE(region
,"(%d,%d-%d,%d %dx%d): ret=%04x\n",
405 left
, top
, right
, bottom
, ellipse_width
, ellipse_height
, hrgn
);
407 /* Check parameters */
409 if (ellipse_width
> right
-left
) ellipse_width
= right
-left
;
410 if (ellipse_height
> bottom
-top
) ellipse_height
= bottom
-top
;
412 /* Ellipse algorithm, based on an article by K. Porter */
413 /* in DDJ Graphics Programming Column, 8/89 */
415 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
416 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
417 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
419 yd
= asq
* ellipse_height
; /* 2a^2b */
421 rect
.left
= left
+ ellipse_width
/ 2;
422 rect
.right
= right
- ellipse_width
/ 2;
424 /* Loop to draw first half of quadrant */
428 if (d
> 0) /* if nearest pixel is toward the center */
430 /* move toward center */
432 rect
.bottom
= rect
.top
+ 1;
433 REGION_UnionRectWithRegion( &rect
, obj
->rgn
);
435 rect
.bottom
= rect
.top
+ 1;
436 REGION_UnionRectWithRegion( &rect
, obj
->rgn
);
440 rect
.left
--; /* next horiz point */
446 /* Loop to draw second half of quadrant */
448 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
451 /* next vertical point */
453 rect
.bottom
= rect
.top
+ 1;
454 REGION_UnionRectWithRegion( &rect
, obj
->rgn
);
456 rect
.bottom
= rect
.top
+ 1;
457 REGION_UnionRectWithRegion( &rect
, obj
->rgn
);
458 if (d
< 0) /* if nearest pixel is outside ellipse */
460 rect
.left
--; /* move away from center */
469 /* Add the inside rectangle */
474 rect
.bottom
= bottom
;
475 REGION_UnionRectWithRegion( &rect
, obj
->rgn
);
477 obj
->rgn
->type
= SIMPLEREGION
; /* FIXME? */
478 GDI_HEAP_UNLOCK( hrgn
);
483 /***********************************************************************
484 * CreateEllipticRgn16 (GDI.54)
486 HRGN16 WINAPI
CreateEllipticRgn16( INT16 left
, INT16 top
,
487 INT16 right
, INT16 bottom
)
489 return (HRGN16
)CreateRoundRectRgn( left
, top
, right
, bottom
,
490 right
-left
, bottom
-top
);
494 /***********************************************************************
495 * CreateEllipticRgn32 (GDI32.39)
497 HRGN WINAPI
CreateEllipticRgn( INT left
, INT top
,
498 INT right
, INT bottom
)
500 return CreateRoundRectRgn( left
, top
, right
, bottom
,
501 right
-left
, bottom
-top
);
505 /***********************************************************************
506 * CreateEllipticRgnIndirect16 (GDI.55)
508 HRGN16 WINAPI
CreateEllipticRgnIndirect16( const RECT16
*rect
)
510 return CreateRoundRectRgn( rect
->left
, rect
->top
, rect
->right
,
511 rect
->bottom
, rect
->right
- rect
->left
,
512 rect
->bottom
- rect
->top
);
516 /***********************************************************************
517 * CreateEllipticRgnIndirect32 (GDI32.40)
519 HRGN WINAPI
CreateEllipticRgnIndirect( const RECT
*rect
)
521 return CreateRoundRectRgn( rect
->left
, rect
->top
, rect
->right
,
522 rect
->bottom
, rect
->right
- rect
->left
,
523 rect
->bottom
- rect
->top
);
526 /***********************************************************************
527 * GetRegionData32 (GDI32.217)
530 DWORD WINAPI
GetRegionData(HRGN hrgn
, DWORD count
, LPRGNDATA rgndata
)
533 RGNOBJ
*obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
535 TRACE(region
, " %04x count = %ld, rgndata = %p\n",
536 hrgn
, count
, rgndata
);
540 size
= obj
->rgn
->numRects
* sizeof(RECT
);
541 if(count
< (size
+ sizeof(RGNDATAHEADER
)) || rgndata
== NULL
)
543 GDI_HEAP_UNLOCK( hrgn
);
544 return size
+ sizeof(RGNDATAHEADER
);
547 rgndata
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
548 rgndata
->rdh
.iType
= RDH_RECTANGLES
;
549 rgndata
->rdh
.nCount
= obj
->rgn
->numRects
;
550 rgndata
->rdh
.nRgnSize
= size
;
551 rgndata
->rdh
.rcBound
.left
= obj
->rgn
->extents
.left
;
552 rgndata
->rdh
.rcBound
.top
= obj
->rgn
->extents
.top
;
553 rgndata
->rdh
.rcBound
.right
= obj
->rgn
->extents
.right
;
554 rgndata
->rdh
.rcBound
.bottom
= obj
->rgn
->extents
.bottom
;
556 memcpy( rgndata
->Buffer
, obj
->rgn
->rects
, size
);
558 GDI_HEAP_UNLOCK( hrgn
);
562 /***********************************************************************
563 * GetRegionData16 (GDI.607)
564 * FIXME: is LPRGNDATA the same in Win16 and Win32 ?
566 DWORD WINAPI
GetRegionData16(HRGN16 hrgn
, DWORD count
, LPRGNDATA rgndata
)
568 return GetRegionData((HRGN
)hrgn
, count
, rgndata
);
571 /***********************************************************************
572 * ExtCreateRegion (GDI32.94)
575 HRGN WINAPI
ExtCreateRegion( const XFORM
* lpXform
, DWORD dwCount
, const RGNDATA
* rgndata
)
577 HRGN hrgn
= CreateRectRgn(0, 0, 0, 0);
578 RGNOBJ
*obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
579 RECT
*pCurRect
, *pEndRect
;
581 TRACE(region
, " %p %ld %p. Returning %04x\n",
582 lpXform
, dwCount
, rgndata
, hrgn
);
585 WARN(region
, "Can't create a region!\n");
589 WARN(region
, "Xform not implemented - ignoring\n");
591 if(rgndata
->rdh
.iType
!= RDH_RECTANGLES
)
593 WARN(region
, "Type not RDH_RECTANGLES\n");
594 GDI_HEAP_UNLOCK( hrgn
);
595 DeleteObject( hrgn
);
599 pEndRect
= (RECT
*)rgndata
->Buffer
+ rgndata
->rdh
.nCount
;
600 for(pCurRect
= (RECT
*)rgndata
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
601 REGION_UnionRectWithRegion( pCurRect
, obj
->rgn
);
603 GDI_HEAP_UNLOCK( hrgn
);
607 /***********************************************************************
608 * PtInRegion16 (GDI.161)
610 BOOL16 WINAPI
PtInRegion16( HRGN16 hrgn
, INT16 x
, INT16 y
)
612 return PtInRegion( hrgn
, x
, y
);
616 /***********************************************************************
617 * PtInRegion32 (GDI32.278)
619 BOOL WINAPI
PtInRegion( HRGN hrgn
, INT x
, INT y
)
623 if ((obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
)))
628 if (obj
->rgn
->numRects
> 0 && INRECT(obj
->rgn
->extents
, x
, y
))
629 for (i
= 0; i
< obj
->rgn
->numRects
; i
++)
630 if (INRECT (obj
->rgn
->rects
[i
], x
, y
))
632 GDI_HEAP_UNLOCK( hrgn
);
639 /***********************************************************************
640 * RectInRegion16 (GDI.181)
642 BOOL16 WINAPI
RectInRegion16( HRGN16 hrgn
, const RECT16
*rect
)
646 CONV_RECT16TO32(rect
, &r32
);
647 return (BOOL16
)RectInRegion(hrgn
, &r32
);
651 /***********************************************************************
652 * RectInRegion32 (GDI32.281)
654 * Returns TRUE if rect is at least partly inside hrgn
656 BOOL WINAPI
RectInRegion( HRGN hrgn
, const RECT
*rect
)
660 if ((obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
)))
662 RECT
*pCurRect
, *pRectEnd
;
665 /* this is (just) a useful optimization */
666 if ((obj
->rgn
->numRects
> 0) && EXTENTCHECK(&obj
->rgn
->extents
,
669 for (pCurRect
= obj
->rgn
->rects
, pRectEnd
= pCurRect
+
670 obj
->rgn
->numRects
; pCurRect
< pRectEnd
; pCurRect
++)
672 if (pCurRect
->bottom
<= rect
->top
)
673 continue; /* not far enough down yet */
675 if (pCurRect
->top
>= rect
->bottom
) {
676 ret
= FALSE
; /* too far down */
680 if (pCurRect
->right
<= rect
->left
)
681 continue; /* not far enough over yet */
683 if (pCurRect
->left
>= rect
->right
) {
691 GDI_HEAP_UNLOCK(hrgn
);
697 /***********************************************************************
698 * EqualRgn16 (GDI.72)
700 BOOL16 WINAPI
EqualRgn16( HRGN16 rgn1
, HRGN16 rgn2
)
702 return EqualRgn( rgn1
, rgn2
);
706 /***********************************************************************
707 * EqualRgn32 (GDI32.90)
709 BOOL WINAPI
EqualRgn( HRGN hrgn1
, HRGN hrgn2
)
714 if ((obj1
= (RGNOBJ
*) GDI_GetObjPtr( hrgn1
, REGION_MAGIC
)))
716 if ((obj2
= (RGNOBJ
*) GDI_GetObjPtr( hrgn2
, REGION_MAGIC
)))
721 if ( obj1
->rgn
->numRects
!= obj2
->rgn
->numRects
) ret
= FALSE
;
722 else if ( obj1
->rgn
->numRects
== 0 ) ret
= TRUE
;
723 else if ( !EqualRect(&obj1
->rgn
->extents
, &obj2
->rgn
->extents
) )
725 else for( i
= 0; i
< obj1
->rgn
->numRects
; i
++ ) {
726 if (!EqualRect(obj1
->rgn
->rects
+ i
, obj2
->rgn
->rects
+ i
)) {
731 GDI_HEAP_UNLOCK(hrgn2
);
733 GDI_HEAP_UNLOCK(hrgn1
);
737 /***********************************************************************
738 * REGION_UnionRectWithRegion
739 * Adds a rectangle to a WINEREGION
740 * See below for REGION_UnionRectWithRgn
742 static void REGION_UnionRectWithRegion(const RECT
*rect
, WINEREGION
*rgn
)
746 region
.rects
= ®ion
.extents
;
749 region
.type
= SIMPLEREGION
;
750 CopyRect(&(region
.extents
), rect
);
751 REGION_UnionRegion(rgn
, rgn
, ®ion
);
755 /***********************************************************************
756 * REGION_UnionRectWithRgn
757 * Adds a rectangle to a HRGN32
758 * A helper used by scroll.c
760 BOOL
REGION_UnionRectWithRgn( HRGN hrgn
, const RECT
*lpRect
)
762 RGNOBJ
*obj
= (RGNOBJ
*) GDI_HEAP_LOCK( hrgn
);
764 if(!obj
) return FALSE
;
765 REGION_UnionRectWithRegion( lpRect
, obj
->rgn
);
766 GDI_HEAP_UNLOCK(hrgn
);
770 /***********************************************************************
771 * REGION_CreateFrameRgn
773 * Create a region that is a frame around another region.
774 * Expand all rectangles by +/- x and y, then subtract original region.
776 BOOL
REGION_FrameRgn( HRGN hDest
, HRGN hSrc
, INT x
, INT y
)
779 RGNOBJ
*srcObj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc
, REGION_MAGIC
);
781 if (srcObj
->rgn
->numRects
!= 0)
783 RGNOBJ
* destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
);
784 RECT
*pRect
, *pEndRect
;
787 EMPTY_REGION( destObj
->rgn
);
789 pEndRect
= srcObj
->rgn
->rects
+ srcObj
->rgn
->numRects
;
790 for(pRect
= srcObj
->rgn
->rects
; pRect
< pEndRect
; pRect
++)
792 tempRect
.left
= pRect
->left
- x
;
793 tempRect
.top
= pRect
->top
- y
;
794 tempRect
.right
= pRect
->right
+ x
;
795 tempRect
.bottom
= pRect
->bottom
+ y
;
796 REGION_UnionRectWithRegion( &tempRect
, destObj
->rgn
);
798 REGION_SubtractRegion( destObj
->rgn
, destObj
->rgn
, srcObj
->rgn
);
799 GDI_HEAP_UNLOCK ( hDest
);
804 GDI_HEAP_UNLOCK( hSrc
);
808 /***********************************************************************
811 * Convert region to device co-ords for the supplied dc.
812 * Used by X11DRV_PaintRgn.
814 BOOL
REGION_LPTODP( HDC hdc
, HRGN hDest
, HRGN hSrc
)
816 RECT
*pCurRect
, *pEndRect
;
817 RGNOBJ
*srcObj
, *destObj
;
818 DC
* dc
= DC_GetDCPtr( hdc
);
821 TRACE(region
, " hdc=%04x dest=%04x src=%04x\n",
824 if (dc
->w
.MapMode
== MM_TEXT
) /* Requires only a translation */
826 if( CombineRgn( hDest
, hSrc
, 0, RGN_COPY
) == ERROR
) return FALSE
;
827 OffsetRgn( hDest
, dc
->vportOrgX
- dc
->wndOrgX
,
828 dc
->vportOrgY
- dc
->wndOrgY
);
832 if(!( srcObj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc
, REGION_MAGIC
) ))
834 if(!( destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
) ))
836 GDI_HEAP_UNLOCK( hSrc
);
839 EMPTY_REGION( destObj
->rgn
);
841 pEndRect
= srcObj
->rgn
->rects
+ srcObj
->rgn
->numRects
;
842 for(pCurRect
= srcObj
->rgn
->rects
; pCurRect
< pEndRect
; pCurRect
++)
845 tmpRect
.left
= XLPTODP( dc
, tmpRect
.left
);
846 tmpRect
.top
= YLPTODP( dc
, tmpRect
.top
);
847 tmpRect
.right
= XLPTODP( dc
, tmpRect
.right
);
848 tmpRect
.bottom
= YLPTODP( dc
, tmpRect
.bottom
);
849 REGION_UnionRectWithRegion( &tmpRect
, destObj
->rgn
);
852 GDI_HEAP_UNLOCK( hDest
);
853 GDI_HEAP_UNLOCK( hSrc
);
857 /***********************************************************************
858 * CombineRgn16 (GDI.451)
860 INT16 WINAPI
CombineRgn16(HRGN16 hDest
, HRGN16 hSrc1
, HRGN16 hSrc2
, INT16 mode
)
862 return (INT16
)CombineRgn( hDest
, hSrc1
, hSrc2
, mode
);
866 /***********************************************************************
867 * CombineRgn32 (GDI32.19)
869 * Note: The behavior is correct even if src and dest regions are the same.
871 INT WINAPI
CombineRgn(HRGN hDest
, HRGN hSrc1
, HRGN hSrc2
, INT mode
)
873 RGNOBJ
*destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
);
876 TRACE(region
, " %04x,%04x -> %04x mode=%x\n",
877 hSrc1
, hSrc2
, hDest
, mode
);
880 RGNOBJ
*src1Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc1
, REGION_MAGIC
);
884 TRACE(region
, "dump:\n");
886 REGION_DumpRegion(src1Obj
->rgn
);
887 if (mode
== RGN_COPY
)
889 REGION_CopyRegion( destObj
->rgn
, src1Obj
->rgn
);
890 result
= destObj
->rgn
->type
;
894 RGNOBJ
*src2Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc2
, REGION_MAGIC
);
898 TRACE(region
, "dump:\n");
900 REGION_DumpRegion(src2Obj
->rgn
);
904 REGION_IntersectRegion( destObj
->rgn
, src1Obj
->rgn
, src2Obj
->rgn
);
907 REGION_UnionRegion( destObj
->rgn
, src1Obj
->rgn
, src2Obj
->rgn
);
910 REGION_XorRegion( destObj
->rgn
, src1Obj
->rgn
, src2Obj
->rgn
);
913 REGION_SubtractRegion( destObj
->rgn
, src1Obj
->rgn
, src2Obj
->rgn
);
916 result
= destObj
->rgn
->type
;
917 GDI_HEAP_UNLOCK( hSrc2
);
920 GDI_HEAP_UNLOCK( hSrc1
);
922 TRACE(region
, "dump:\n");
924 REGION_DumpRegion(destObj
->rgn
);
926 GDI_HEAP_UNLOCK( hDest
);
931 /***********************************************************************
933 * Re-calculate the extents of a region
935 static void REGION_SetExtents (WINEREGION
*pReg
)
937 RECT
*pRect
, *pRectEnd
, *pExtents
;
939 if (pReg
->numRects
== 0)
941 pReg
->extents
.left
= 0;
942 pReg
->extents
.top
= 0;
943 pReg
->extents
.right
= 0;
944 pReg
->extents
.bottom
= 0;
948 pExtents
= &pReg
->extents
;
950 pRectEnd
= &pRect
[pReg
->numRects
- 1];
953 * Since pRect is the first rectangle in the region, it must have the
954 * smallest top and since pRectEnd is the last rectangle in the region,
955 * it must have the largest bottom, because of banding. Initialize left and
956 * right from pRect and pRectEnd, resp., as good things to initialize them
959 pExtents
->left
= pRect
->left
;
960 pExtents
->top
= pRect
->top
;
961 pExtents
->right
= pRectEnd
->right
;
962 pExtents
->bottom
= pRectEnd
->bottom
;
964 while (pRect
<= pRectEnd
)
966 if (pRect
->left
< pExtents
->left
)
967 pExtents
->left
= pRect
->left
;
968 if (pRect
->right
> pExtents
->right
)
969 pExtents
->right
= pRect
->right
;
974 /***********************************************************************
977 static void REGION_CopyRegion(WINEREGION
*dst
, WINEREGION
*src
)
979 if (dst
!= src
) /* don't want to copy to itself */
981 if (dst
->size
< src
->numRects
)
983 if (! (dst
->rects
= HeapReAlloc( SystemHeap
, 0, dst
->rects
,
984 src
->numRects
* sizeof(RECT
) )))
986 dst
->size
= src
->numRects
;
988 dst
->numRects
= src
->numRects
;
989 dst
->extents
.left
= src
->extents
.left
;
990 dst
->extents
.top
= src
->extents
.top
;
991 dst
->extents
.right
= src
->extents
.right
;
992 dst
->extents
.bottom
= src
->extents
.bottom
;
993 dst
->type
= src
->type
;
995 memcpy((char *) dst
->rects
, (char *) src
->rects
,
996 (int) (src
->numRects
* sizeof(RECT
)));
1001 /***********************************************************************
1004 * Attempt to merge the rects in the current band with those in the
1005 * previous one. Used only by REGION_RegionOp.
1008 * The new index for the previous band.
1011 * If coalescing takes place:
1012 * - rectangles in the previous band will have their bottom fields
1014 * - pReg->numRects will be decreased.
1017 static INT
REGION_Coalesce (
1018 WINEREGION
*pReg
, /* Region to coalesce */
1019 INT prevStart
, /* Index of start of previous band */
1020 INT curStart
/* Index of start of current band */
1022 RECT
*pPrevRect
; /* Current rect in previous band */
1023 RECT
*pCurRect
; /* Current rect in current band */
1024 RECT
*pRegEnd
; /* End of region */
1025 INT curNumRects
; /* Number of rectangles in current band */
1026 INT prevNumRects
; /* Number of rectangles in previous band */
1027 INT bandtop
; /* top coordinate for current band */
1029 pRegEnd
= &pReg
->rects
[pReg
->numRects
];
1031 pPrevRect
= &pReg
->rects
[prevStart
];
1032 prevNumRects
= curStart
- prevStart
;
1035 * Figure out how many rectangles are in the current band. Have to do
1036 * this because multiple bands could have been added in REGION_RegionOp
1037 * at the end when one region has been exhausted.
1039 pCurRect
= &pReg
->rects
[curStart
];
1040 bandtop
= pCurRect
->top
;
1041 for (curNumRects
= 0;
1042 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
1048 if (pCurRect
!= pRegEnd
)
1051 * If more than one band was added, we have to find the start
1052 * of the last band added so the next coalescing job can start
1053 * at the right place... (given when multiple bands are added,
1054 * this may be pointless -- see above).
1057 while (pRegEnd
[-1].top
== pRegEnd
->top
)
1061 curStart
= pRegEnd
- pReg
->rects
;
1062 pRegEnd
= pReg
->rects
+ pReg
->numRects
;
1065 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0)) {
1066 pCurRect
-= curNumRects
;
1068 * The bands may only be coalesced if the bottom of the previous
1069 * matches the top scanline of the current.
1071 if (pPrevRect
->bottom
== pCurRect
->top
)
1074 * Make sure the bands have rects in the same places. This
1075 * assumes that rects have been added in such a way that they
1076 * cover the most area possible. I.e. two rects in a band must
1077 * have some horizontal space between them.
1081 if ((pPrevRect
->left
!= pCurRect
->left
) ||
1082 (pPrevRect
->right
!= pCurRect
->right
))
1085 * The bands don't line up so they can't be coalesced.
1092 } while (prevNumRects
!= 0);
1094 pReg
->numRects
-= curNumRects
;
1095 pCurRect
-= curNumRects
;
1096 pPrevRect
-= curNumRects
;
1099 * The bands may be merged, so set the bottom of each rect
1100 * in the previous band to that of the corresponding rect in
1105 pPrevRect
->bottom
= pCurRect
->bottom
;
1109 } while (curNumRects
!= 0);
1112 * If only one band was added to the region, we have to backup
1113 * curStart to the start of the previous band.
1115 * If more than one band was added to the region, copy the
1116 * other bands down. The assumption here is that the other bands
1117 * came from the same region as the current one and no further
1118 * coalescing can be done on them since it's all been done
1119 * already... curStart is already in the right place.
1121 if (pCurRect
== pRegEnd
)
1123 curStart
= prevStart
;
1129 *pPrevRect
++ = *pCurRect
++;
1130 } while (pCurRect
!= pRegEnd
);
1138 /***********************************************************************
1141 * Apply an operation to two regions. Called by REGION_Union,
1142 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
1148 * The new region is overwritten.
1151 * The idea behind this function is to view the two regions as sets.
1152 * Together they cover a rectangle of area that this function divides
1153 * into horizontal bands where points are covered only by one region
1154 * or by both. For the first case, the nonOverlapFunc is called with
1155 * each the band and the band's upper and lower extents. For the
1156 * second, the overlapFunc is called to process the entire band. It
1157 * is responsible for clipping the rectangles in the band, though
1158 * this function provides the boundaries.
1159 * At the end of each band, the new region is coalesced, if possible,
1160 * to reduce the number of rectangles in the region.
1163 static void REGION_RegionOp(
1164 WINEREGION
*newReg
, /* Place to store result */
1165 WINEREGION
*reg1
, /* First region in operation */
1166 WINEREGION
*reg2
, /* 2nd region in operation */
1167 void (*overlapFunc
)(), /* Function to call for over-lapping bands */
1168 void (*nonOverlap1Func
)(), /* Function to call for non-overlapping bands in region 1 */
1169 void (*nonOverlap2Func
)() /* Function to call for non-overlapping bands in region 2 */
1171 RECT
*r1
; /* Pointer into first region */
1172 RECT
*r2
; /* Pointer into 2d region */
1173 RECT
*r1End
; /* End of 1st region */
1174 RECT
*r2End
; /* End of 2d region */
1175 INT ybot
; /* Bottom of intersection */
1176 INT ytop
; /* Top of intersection */
1177 RECT
*oldRects
; /* Old rects for newReg */
1178 INT prevBand
; /* Index of start of
1179 * previous band in newReg */
1180 INT curBand
; /* Index of start of current
1182 RECT
*r1BandEnd
; /* End of current band in r1 */
1183 RECT
*r2BandEnd
; /* End of current band in r2 */
1184 INT top
; /* Top of non-overlapping band */
1185 INT bot
; /* Bottom of non-overlapping band */
1189 * set r1, r2, r1End and r2End appropriately, preserve the important
1190 * parts of the destination region until the end in case it's one of
1191 * the two source regions, then mark the "new" region empty, allocating
1192 * another array of rectangles for it to use.
1196 r1End
= r1
+ reg1
->numRects
;
1197 r2End
= r2
+ reg2
->numRects
;
1201 * newReg may be one of the src regions so we can't empty it. We keep a
1202 * note of its rects pointer (so that we can free them later), preserve its
1203 * extents and simply set numRects to zero.
1206 oldRects
= newReg
->rects
;
1207 newReg
->numRects
= 0;
1210 * Allocate a reasonable number of rectangles for the new region. The idea
1211 * is to allocate enough so the individual functions don't need to
1212 * reallocate and copy the array, which is time consuming, yet we don't
1213 * have to worry about using too much memory. I hope to be able to
1214 * nuke the Xrealloc() at the end of this function eventually.
1216 newReg
->size
= MAX(reg1
->numRects
,reg2
->numRects
) * 2;
1218 if (! (newReg
->rects
= HeapAlloc( SystemHeap
, 0,
1219 sizeof(RECT
) * newReg
->size
)))
1226 * Initialize ybot and ytop.
1227 * In the upcoming loop, ybot and ytop serve different functions depending
1228 * on whether the band being handled is an overlapping or non-overlapping
1230 * In the case of a non-overlapping band (only one of the regions
1231 * has points in the band), ybot is the bottom of the most recent
1232 * intersection and thus clips the top of the rectangles in that band.
1233 * ytop is the top of the next intersection between the two regions and
1234 * serves to clip the bottom of the rectangles in the current band.
1235 * For an overlapping band (where the two regions intersect), ytop clips
1236 * the top of the rectangles of both regions and ybot clips the bottoms.
1238 if (reg1
->extents
.top
< reg2
->extents
.top
)
1239 ybot
= reg1
->extents
.top
;
1241 ybot
= reg2
->extents
.top
;
1244 * prevBand serves to mark the start of the previous band so rectangles
1245 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1246 * In the beginning, there is no previous band, so prevBand == curBand
1247 * (curBand is set later on, of course, but the first band will always
1248 * start at index 0). prevBand and curBand must be indices because of
1249 * the possible expansion, and resultant moving, of the new region's
1250 * array of rectangles.
1256 curBand
= newReg
->numRects
;
1259 * This algorithm proceeds one source-band (as opposed to a
1260 * destination band, which is determined by where the two regions
1261 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1262 * rectangle after the last one in the current band for their
1263 * respective regions.
1266 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
1272 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
1278 * First handle the band that doesn't intersect, if any.
1280 * Note that attention is restricted to one band in the
1281 * non-intersecting region at once, so if a region has n
1282 * bands between the current position and the next place it overlaps
1283 * the other, this entire loop will be passed through n times.
1285 if (r1
->top
< r2
->top
)
1287 top
= MAX(r1
->top
,ybot
);
1288 bot
= MIN(r1
->bottom
,r2
->top
);
1290 if ((top
!= bot
) && (nonOverlap1Func
!= (void (*)())NULL
))
1292 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
, top
, bot
);
1297 else if (r2
->top
< r1
->top
)
1299 top
= MAX(r2
->top
,ybot
);
1300 bot
= MIN(r2
->bottom
,r1
->top
);
1302 if ((top
!= bot
) && (nonOverlap2Func
!= (void (*)())NULL
))
1304 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
, top
, bot
);
1315 * If any rectangles got added to the region, try and coalesce them
1316 * with rectangles from the previous band. Note we could just do
1317 * this test in miCoalesce, but some machines incur a not
1318 * inconsiderable cost for function calls, so...
1320 if (newReg
->numRects
!= curBand
)
1322 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1326 * Now see if we've hit an intersecting band. The two bands only
1327 * intersect if ybot > ytop
1329 ybot
= MIN(r1
->bottom
, r2
->bottom
);
1330 curBand
= newReg
->numRects
;
1333 (* overlapFunc
) (newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
1337 if (newReg
->numRects
!= curBand
)
1339 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1343 * If we've finished with a band (bottom == ybot) we skip forward
1344 * in the region to the next band.
1346 if (r1
->bottom
== ybot
)
1350 if (r2
->bottom
== ybot
)
1354 } while ((r1
!= r1End
) && (r2
!= r2End
));
1357 * Deal with whichever region still has rectangles left.
1359 curBand
= newReg
->numRects
;
1362 if (nonOverlap1Func
!= (void (*)())NULL
)
1367 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
1371 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
,
1372 MAX(r1
->top
,ybot
), r1
->bottom
);
1374 } while (r1
!= r1End
);
1377 else if ((r2
!= r2End
) && (nonOverlap2Func
!= (void (*)())NULL
))
1382 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
1386 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
,
1387 MAX(r2
->top
,ybot
), r2
->bottom
);
1389 } while (r2
!= r2End
);
1392 if (newReg
->numRects
!= curBand
)
1394 (void) REGION_Coalesce (newReg
, prevBand
, curBand
);
1398 * A bit of cleanup. To keep regions from growing without bound,
1399 * we shrink the array of rectangles to match the new number of
1400 * rectangles in the region. This never goes to 0, however...
1402 * Only do this stuff if the number of rectangles allocated is more than
1403 * twice the number of rectangles in the region (a simple optimization...).
1405 if (newReg
->numRects
< (newReg
->size
>> 1))
1407 if (REGION_NOT_EMPTY(newReg
))
1409 RECT
*prev_rects
= newReg
->rects
;
1410 newReg
->size
= newReg
->numRects
;
1411 newReg
->rects
= HeapReAlloc( SystemHeap
, 0, newReg
->rects
,
1412 sizeof(RECT
) * newReg
->size
);
1413 if (! newReg
->rects
)
1414 newReg
->rects
= prev_rects
;
1419 * No point in doing the extra work involved in an Xrealloc if
1420 * the region is empty
1423 HeapFree( SystemHeap
, 0, newReg
->rects
);
1424 newReg
->rects
= HeapAlloc( SystemHeap
, 0, sizeof(RECT
) );
1427 HeapFree( SystemHeap
, 0, oldRects
);
1431 /***********************************************************************
1432 * Region Intersection
1433 ***********************************************************************/
1436 /***********************************************************************
1439 * Handle an overlapping band for REGION_Intersect.
1445 * Rectangles may be added to the region.
1448 static void REGION_IntersectO(WINEREGION
*pReg
, RECT
*r1
, RECT
*r1End
,
1449 RECT
*r2
, RECT
*r2End
, INT top
, INT bottom
)
1455 pNextRect
= &pReg
->rects
[pReg
->numRects
];
1457 while ((r1
!= r1End
) && (r2
!= r2End
))
1459 left
= MAX(r1
->left
, r2
->left
);
1460 right
= MIN(r1
->right
, r2
->right
);
1463 * If there's any overlap between the two rectangles, add that
1464 * overlap to the new region.
1465 * There's no need to check for subsumption because the only way
1466 * such a need could arise is if some region has two rectangles
1467 * right next to each other. Since that should never happen...
1471 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1472 pNextRect
->left
= left
;
1473 pNextRect
->top
= top
;
1474 pNextRect
->right
= right
;
1475 pNextRect
->bottom
= bottom
;
1476 pReg
->numRects
+= 1;
1481 * Need to advance the pointers. Shift the one that extends
1482 * to the right the least, since the other still has a chance to
1483 * overlap with that region's next rectangle, if you see what I mean.
1485 if (r1
->right
< r2
->right
)
1489 else if (r2
->right
< r1
->right
)
1502 /***********************************************************************
1503 * REGION_IntersectRegion
1505 static void REGION_IntersectRegion(WINEREGION
*newReg
, WINEREGION
*reg1
,
1508 /* check for trivial reject */
1509 if ( (!(reg1
->numRects
)) || (!(reg2
->numRects
)) ||
1510 (!EXTENTCHECK(®1
->extents
, ®2
->extents
)))
1511 newReg
->numRects
= 0;
1513 REGION_RegionOp (newReg
, reg1
, reg2
,
1514 (voidProcp
) REGION_IntersectO
, (voidProcp
) NULL
, (voidProcp
) NULL
);
1517 * Can't alter newReg's extents before we call miRegionOp because
1518 * it might be one of the source regions and miRegionOp depends
1519 * on the extents of those regions being the same. Besides, this
1520 * way there's no checking against rectangles that will be nuked
1521 * due to coalescing, so we have to examine fewer rectangles.
1523 REGION_SetExtents(newReg
);
1524 newReg
->type
= (newReg
->numRects
) ? COMPLEXREGION
: NULLREGION
;
1528 /***********************************************************************
1530 ***********************************************************************/
1532 /***********************************************************************
1535 * Handle a non-overlapping band for the union operation. Just
1536 * Adds the rectangles into the region. Doesn't have to check for
1537 * subsumption or anything.
1543 * pReg->numRects is incremented and the final rectangles overwritten
1544 * with the rectangles we're passed.
1547 static void REGION_UnionNonO (WINEREGION
*pReg
, RECT
*r
, RECT
*rEnd
,
1548 INT top
, INT bottom
)
1552 pNextRect
= &pReg
->rects
[pReg
->numRects
];
1556 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1557 pNextRect
->left
= r
->left
;
1558 pNextRect
->top
= top
;
1559 pNextRect
->right
= r
->right
;
1560 pNextRect
->bottom
= bottom
;
1561 pReg
->numRects
+= 1;
1568 /***********************************************************************
1571 * Handle an overlapping band for the union operation. Picks the
1572 * left-most rectangle each time and merges it into the region.
1578 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1582 static void REGION_UnionO (WINEREGION
*pReg
, RECT
*r1
, RECT
*r1End
,
1583 RECT
*r2
, RECT
*r2End
, INT top
, INT bottom
)
1587 pNextRect
= &pReg
->rects
[pReg
->numRects
];
1589 #define MERGERECT(r) \
1590 if ((pReg->numRects != 0) && \
1591 (pNextRect[-1].top == top) && \
1592 (pNextRect[-1].bottom == bottom) && \
1593 (pNextRect[-1].right >= r->left)) \
1595 if (pNextRect[-1].right < r->right) \
1597 pNextRect[-1].right = r->right; \
1602 MEMCHECK(pReg, pNextRect, pReg->rects); \
1603 pNextRect->top = top; \
1604 pNextRect->bottom = bottom; \
1605 pNextRect->left = r->left; \
1606 pNextRect->right = r->right; \
1607 pReg->numRects += 1; \
1612 while ((r1
!= r1End
) && (r2
!= r2End
))
1614 if (r1
->left
< r2
->left
)
1629 } while (r1
!= r1End
);
1631 else while (r2
!= r2End
)
1638 /***********************************************************************
1639 * REGION_UnionRegion
1641 static void REGION_UnionRegion(WINEREGION
*newReg
, WINEREGION
*reg1
,
1644 /* checks all the simple cases */
1647 * Region 1 and 2 are the same or region 1 is empty
1649 if ( (reg1
== reg2
) || (!(reg1
->numRects
)) )
1652 REGION_CopyRegion(newReg
, reg2
);
1657 * if nothing to union (region 2 empty)
1659 if (!(reg2
->numRects
))
1662 REGION_CopyRegion(newReg
, reg1
);
1667 * Region 1 completely subsumes region 2
1669 if ((reg1
->numRects
== 1) &&
1670 (reg1
->extents
.left
<= reg2
->extents
.left
) &&
1671 (reg1
->extents
.top
<= reg2
->extents
.top
) &&
1672 (reg1
->extents
.right
>= reg2
->extents
.right
) &&
1673 (reg1
->extents
.bottom
>= reg2
->extents
.bottom
))
1676 REGION_CopyRegion(newReg
, reg1
);
1681 * Region 2 completely subsumes region 1
1683 if ((reg2
->numRects
== 1) &&
1684 (reg2
->extents
.left
<= reg1
->extents
.left
) &&
1685 (reg2
->extents
.top
<= reg1
->extents
.top
) &&
1686 (reg2
->extents
.right
>= reg1
->extents
.right
) &&
1687 (reg2
->extents
.bottom
>= reg1
->extents
.bottom
))
1690 REGION_CopyRegion(newReg
, reg2
);
1694 REGION_RegionOp (newReg
, reg1
, reg2
, (voidProcp
) REGION_UnionO
,
1695 (voidProcp
) REGION_UnionNonO
, (voidProcp
) REGION_UnionNonO
);
1697 newReg
->extents
.left
= MIN(reg1
->extents
.left
, reg2
->extents
.left
);
1698 newReg
->extents
.top
= MIN(reg1
->extents
.top
, reg2
->extents
.top
);
1699 newReg
->extents
.right
= MAX(reg1
->extents
.right
, reg2
->extents
.right
);
1700 newReg
->extents
.bottom
= MAX(reg1
->extents
.bottom
, reg2
->extents
.bottom
);
1701 newReg
->type
= (newReg
->numRects
) ? COMPLEXREGION
: NULLREGION
;
1705 /***********************************************************************
1706 * Region Subtraction
1707 ***********************************************************************/
1709 /***********************************************************************
1710 * REGION_SubtractNonO1
1712 * Deal with non-overlapping band for subtraction. Any parts from
1713 * region 2 we discard. Anything from region 1 we add to the region.
1719 * pReg may be affected.
1722 static void REGION_SubtractNonO1 (WINEREGION
*pReg
, RECT
*r
, RECT
*rEnd
,
1723 INT top
, INT bottom
)
1727 pNextRect
= &pReg
->rects
[pReg
->numRects
];
1731 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1732 pNextRect
->left
= r
->left
;
1733 pNextRect
->top
= top
;
1734 pNextRect
->right
= r
->right
;
1735 pNextRect
->bottom
= bottom
;
1736 pReg
->numRects
+= 1;
1744 /***********************************************************************
1747 * Overlapping band subtraction. x1 is the left-most point not yet
1754 * pReg may have rectangles added to it.
1757 static void REGION_SubtractO (WINEREGION
*pReg
, RECT
*r1
, RECT
*r1End
,
1758 RECT
*r2
, RECT
*r2End
, INT top
, INT bottom
)
1764 pNextRect
= &pReg
->rects
[pReg
->numRects
];
1766 while ((r1
!= r1End
) && (r2
!= r2End
))
1768 if (r2
->right
<= left
)
1771 * Subtrahend missed the boat: go to next subtrahend.
1775 else if (r2
->left
<= left
)
1778 * Subtrahend preceeds minuend: nuke left edge of minuend.
1781 if (left
>= r1
->right
)
1784 * Minuend completely covered: advance to next minuend and
1785 * reset left fence to edge of new minuend.
1794 * Subtrahend now used up since it doesn't extend beyond
1800 else if (r2
->left
< r1
->right
)
1803 * Left part of subtrahend covers part of minuend: add uncovered
1804 * part of minuend to region and skip to next subtrahend.
1806 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1807 pNextRect
->left
= left
;
1808 pNextRect
->top
= top
;
1809 pNextRect
->right
= r2
->left
;
1810 pNextRect
->bottom
= bottom
;
1811 pReg
->numRects
+= 1;
1814 if (left
>= r1
->right
)
1817 * Minuend used up: advance to new...
1826 * Subtrahend used up
1834 * Minuend used up: add any remaining piece before advancing.
1836 if (r1
->right
> left
)
1838 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1839 pNextRect
->left
= left
;
1840 pNextRect
->top
= top
;
1841 pNextRect
->right
= r1
->right
;
1842 pNextRect
->bottom
= bottom
;
1843 pReg
->numRects
+= 1;
1852 * Add remaining minuend rectangles to region.
1856 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1857 pNextRect
->left
= left
;
1858 pNextRect
->top
= top
;
1859 pNextRect
->right
= r1
->right
;
1860 pNextRect
->bottom
= bottom
;
1861 pReg
->numRects
+= 1;
1872 /***********************************************************************
1873 * REGION_SubtractRegion
1875 * Subtract regS from regM and leave the result in regD.
1876 * S stands for subtrahend, M for minuend and D for difference.
1882 * regD is overwritten.
1885 static void REGION_SubtractRegion(WINEREGION
*regD
, WINEREGION
*regM
,
1888 /* check for trivial reject */
1889 if ( (!(regM
->numRects
)) || (!(regS
->numRects
)) ||
1890 (!EXTENTCHECK(®M
->extents
, ®S
->extents
)) )
1892 REGION_CopyRegion(regD
, regM
);
1896 REGION_RegionOp (regD
, regM
, regS
, (voidProcp
) REGION_SubtractO
,
1897 (voidProcp
) REGION_SubtractNonO1
, (voidProcp
) NULL
);
1900 * Can't alter newReg's extents before we call miRegionOp because
1901 * it might be one of the source regions and miRegionOp depends
1902 * on the extents of those regions being the unaltered. Besides, this
1903 * way there's no checking against rectangles that will be nuked
1904 * due to coalescing, so we have to examine fewer rectangles.
1906 REGION_SetExtents (regD
);
1907 regD
->type
= (regD
->numRects
) ? COMPLEXREGION
: NULLREGION
;
1911 /***********************************************************************
1914 static void REGION_XorRegion(WINEREGION
*dr
, WINEREGION
*sra
,
1917 WINEREGION
*tra
, *trb
;
1919 if ((! (tra
= REGION_AllocWineRegion())) ||
1920 (! (trb
= REGION_AllocWineRegion())))
1922 REGION_SubtractRegion(tra
,sra
,srb
);
1923 REGION_SubtractRegion(trb
,srb
,sra
);
1924 REGION_UnionRegion(dr
,tra
,trb
);
1925 REGION_DestroyWineRegion(tra
);
1926 REGION_DestroyWineRegion(trb
);
1930 /**************************************************************************
1934 *************************************************************************/
1936 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
1937 #define SMALL_COORDINATE 0x80000000
1939 /***********************************************************************
1940 * REGION_InsertEdgeInET
1942 * Insert the given edge into the edge table.
1943 * First we must find the correct bucket in the
1944 * Edge table, then find the right slot in the
1945 * bucket. Finally, we can insert it.
1948 static void REGION_InsertEdgeInET(EdgeTable
*ET
, EdgeTableEntry
*ETE
,
1949 INT scanline
, ScanLineListBlock
**SLLBlock
, INT
*iSLLBlock
)
1952 EdgeTableEntry
*start
, *prev
;
1953 ScanLineList
*pSLL
, *pPrevSLL
;
1954 ScanLineListBlock
*tmpSLLBlock
;
1957 * find the right bucket to put the edge into
1959 pPrevSLL
= &ET
->scanlines
;
1960 pSLL
= pPrevSLL
->next
;
1961 while (pSLL
&& (pSLL
->scanline
< scanline
))
1968 * reassign pSLL (pointer to ScanLineList) if necessary
1970 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
1972 if (*iSLLBlock
> SLLSPERBLOCK
-1)
1974 tmpSLLBlock
= HeapAlloc( SystemHeap
, 0, sizeof(ScanLineListBlock
));
1977 WARN(region
, "Can't alloc SLLB\n");
1980 (*SLLBlock
)->next
= tmpSLLBlock
;
1981 tmpSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
1982 *SLLBlock
= tmpSLLBlock
;
1985 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
1987 pSLL
->next
= pPrevSLL
->next
;
1988 pSLL
->edgelist
= (EdgeTableEntry
*)NULL
;
1989 pPrevSLL
->next
= pSLL
;
1991 pSLL
->scanline
= scanline
;
1994 * now insert the edge in the right bucket
1996 prev
= (EdgeTableEntry
*)NULL
;
1997 start
= pSLL
->edgelist
;
1998 while (start
&& (start
->bres
.minor_axis
< ETE
->bres
.minor_axis
))
2001 start
= start
->next
;
2008 pSLL
->edgelist
= ETE
;
2011 /***********************************************************************
2012 * REGION_CreateEdgeTable
2014 * This routine creates the edge table for
2015 * scan converting polygons.
2016 * The Edge Table (ET) looks like:
2020 * | ymax | ScanLineLists
2021 * |scanline|-->------------>-------------->...
2022 * -------- |scanline| |scanline|
2023 * |edgelist| |edgelist|
2024 * --------- ---------
2028 * list of ETEs list of ETEs
2030 * where ETE is an EdgeTableEntry data structure,
2031 * and there is one ScanLineList per scanline at
2032 * which an edge is initially entered.
2035 static void REGION_CreateETandAET(const INT
*Count
, INT nbpolygons
,
2036 const POINT
*pts
, EdgeTable
*ET
, EdgeTableEntry
*AET
,
2037 EdgeTableEntry
*pETEs
, ScanLineListBlock
*pSLLBlock
)
2039 const POINT
*top
, *bottom
;
2040 const POINT
*PrevPt
, *CurrPt
, *EndPt
;
2047 * initialize the Active Edge Table
2049 AET
->next
= (EdgeTableEntry
*)NULL
;
2050 AET
->back
= (EdgeTableEntry
*)NULL
;
2051 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2052 AET
->bres
.minor_axis
= SMALL_COORDINATE
;
2055 * initialize the Edge Table.
2057 ET
->scanlines
.next
= (ScanLineList
*)NULL
;
2058 ET
->ymax
= SMALL_COORDINATE
;
2059 ET
->ymin
= LARGE_COORDINATE
;
2060 pSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
2063 for(poly
= 0; poly
< nbpolygons
; poly
++)
2065 count
= Count
[poly
];
2073 * for each vertex in the array of points.
2074 * In this loop we are dealing with two vertices at
2075 * a time -- these make up one edge of the polygon.
2082 * find out which point is above and which is below.
2084 if (PrevPt
->y
> CurrPt
->y
)
2086 bottom
= PrevPt
, top
= CurrPt
;
2087 pETEs
->ClockWise
= 0;
2091 bottom
= CurrPt
, top
= PrevPt
;
2092 pETEs
->ClockWise
= 1;
2096 * don't add horizontal edges to the Edge table.
2098 if (bottom
->y
!= top
->y
)
2100 pETEs
->ymax
= bottom
->y
-1;
2101 /* -1 so we don't get last scanline */
2104 * initialize integer edge algorithm
2106 dy
= bottom
->y
- top
->y
;
2107 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
2109 REGION_InsertEdgeInET(ET
, pETEs
, top
->y
, &pSLLBlock
,
2112 if (PrevPt
->y
> ET
->ymax
)
2113 ET
->ymax
= PrevPt
->y
;
2114 if (PrevPt
->y
< ET
->ymin
)
2115 ET
->ymin
= PrevPt
->y
;
2124 /***********************************************************************
2127 * This routine moves EdgeTableEntries from the
2128 * EdgeTable into the Active Edge Table,
2129 * leaving them sorted by smaller x coordinate.
2132 static void REGION_loadAET(EdgeTableEntry
*AET
, EdgeTableEntry
*ETEs
)
2134 EdgeTableEntry
*pPrevAET
;
2135 EdgeTableEntry
*tmp
;
2141 while (AET
&& (AET
->bres
.minor_axis
< ETEs
->bres
.minor_axis
))
2150 ETEs
->back
= pPrevAET
;
2151 pPrevAET
->next
= ETEs
;
2158 /***********************************************************************
2159 * REGION_computeWAET
2161 * This routine links the AET by the
2162 * nextWETE (winding EdgeTableEntry) link for
2163 * use by the winding number rule. The final
2164 * Active Edge Table (AET) might look something
2168 * ---------- --------- ---------
2169 * |ymax | |ymax | |ymax |
2170 * | ... | |... | |... |
2171 * |next |->|next |->|next |->...
2172 * |nextWETE| |nextWETE| |nextWETE|
2173 * --------- --------- ^--------
2175 * V-------------------> V---> ...
2178 static void REGION_computeWAET(EdgeTableEntry
*AET
)
2180 register EdgeTableEntry
*pWETE
;
2181 register int inside
= 1;
2182 register int isInside
= 0;
2184 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2194 if ((!inside
&& !isInside
) ||
2195 ( inside
&& isInside
))
2197 pWETE
->nextWETE
= AET
;
2203 pWETE
->nextWETE
= (EdgeTableEntry
*)NULL
;
2206 /***********************************************************************
2207 * REGION_InsertionSort
2209 * Just a simple insertion sort using
2210 * pointers and back pointers to sort the Active
2214 static BOOL
REGION_InsertionSort(EdgeTableEntry
*AET
)
2216 EdgeTableEntry
*pETEchase
;
2217 EdgeTableEntry
*pETEinsert
;
2218 EdgeTableEntry
*pETEchaseBackTMP
;
2219 BOOL changed
= FALSE
;
2226 while (pETEchase
->back
->bres
.minor_axis
> AET
->bres
.minor_axis
)
2227 pETEchase
= pETEchase
->back
;
2230 if (pETEchase
!= pETEinsert
)
2232 pETEchaseBackTMP
= pETEchase
->back
;
2233 pETEinsert
->back
->next
= AET
;
2235 AET
->back
= pETEinsert
->back
;
2236 pETEinsert
->next
= pETEchase
;
2237 pETEchase
->back
->next
= pETEinsert
;
2238 pETEchase
->back
= pETEinsert
;
2239 pETEinsert
->back
= pETEchaseBackTMP
;
2246 /***********************************************************************
2247 * REGION_FreeStorage
2251 static void REGION_FreeStorage(ScanLineListBlock
*pSLLBlock
)
2253 ScanLineListBlock
*tmpSLLBlock
;
2257 tmpSLLBlock
= pSLLBlock
->next
;
2258 HeapFree( SystemHeap
, 0, pSLLBlock
);
2259 pSLLBlock
= tmpSLLBlock
;
2264 /***********************************************************************
2265 * REGION_PtsToRegion
2267 * Create an array of rectangles from a list of points.
2269 static int REGION_PtsToRegion(int numFullPtBlocks
, int iCurPtBlock
,
2270 POINTBLOCK
*FirstPtBlock
, WINEREGION
*reg
)
2274 POINTBLOCK
*CurPtBlock
;
2279 extents
= ®
->extents
;
2281 numRects
= ((numFullPtBlocks
* NUMPTSTOBUFFER
) + iCurPtBlock
) >> 1;
2283 if (!(reg
->rects
= HeapReAlloc( SystemHeap
, 0, reg
->rects
,
2284 sizeof(RECT
) * numRects
)))
2287 reg
->size
= numRects
;
2288 CurPtBlock
= FirstPtBlock
;
2289 rects
= reg
->rects
- 1;
2291 extents
->left
= LARGE_COORDINATE
, extents
->right
= SMALL_COORDINATE
;
2293 for ( ; numFullPtBlocks
>= 0; numFullPtBlocks
--) {
2294 /* the loop uses 2 points per iteration */
2295 i
= NUMPTSTOBUFFER
>> 1;
2296 if (!numFullPtBlocks
)
2297 i
= iCurPtBlock
>> 1;
2298 for (pts
= CurPtBlock
->pts
; i
--; pts
+= 2) {
2299 if (pts
->x
== pts
[1].x
)
2301 if (numRects
&& pts
->x
== rects
->left
&& pts
->y
== rects
->bottom
&&
2302 pts
[1].x
== rects
->right
&&
2303 (numRects
== 1 || rects
[-1].top
!= rects
->top
) &&
2304 (i
&& pts
[2].y
> pts
[1].y
)) {
2305 rects
->bottom
= pts
[1].y
+ 1;
2310 rects
->left
= pts
->x
; rects
->top
= pts
->y
;
2311 rects
->right
= pts
[1].x
; rects
->bottom
= pts
[1].y
+ 1;
2312 if (rects
->left
< extents
->left
)
2313 extents
->left
= rects
->left
;
2314 if (rects
->right
> extents
->right
)
2315 extents
->right
= rects
->right
;
2317 CurPtBlock
= CurPtBlock
->next
;
2321 extents
->top
= reg
->rects
->top
;
2322 extents
->bottom
= rects
->bottom
;
2327 extents
->bottom
= 0;
2329 reg
->numRects
= numRects
;
2334 /***********************************************************************
2335 * CreatePolyPolygonRgn32 (GDI32.57)
2337 HRGN WINAPI
CreatePolyPolygonRgn(const POINT
*Pts
, const INT
*Count
,
2338 INT nbpolygons
, INT mode
)
2343 register EdgeTableEntry
*pAET
; /* Active Edge Table */
2344 register INT y
; /* current scanline */
2345 register int iPts
= 0; /* number of pts in buffer */
2346 register EdgeTableEntry
*pWETE
; /* Winding Edge Table Entry*/
2347 register ScanLineList
*pSLL
; /* current scanLineList */
2348 register POINT
*pts
; /* output buffer */
2349 EdgeTableEntry
*pPrevAET
; /* ptr to previous AET */
2350 EdgeTable ET
; /* header node for ET */
2351 EdgeTableEntry AET
; /* header node for AET */
2352 EdgeTableEntry
*pETEs
; /* EdgeTableEntries pool */
2353 ScanLineListBlock SLLBlock
; /* header for scanlinelist */
2354 int fixWAET
= FALSE
;
2355 POINTBLOCK FirstPtBlock
, *curPtBlock
; /* PtBlock buffers */
2356 POINTBLOCK
*tmpPtBlock
;
2357 int numFullPtBlocks
= 0;
2360 if(!(hrgn
= REGION_CreateRegion()))
2362 obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
2365 /* special case a rectangle */
2367 if (((nbpolygons
== 1) && ((*Count
== 4) ||
2368 ((*Count
== 5) && (Pts
[4].x
== Pts
[0].x
) && (Pts
[4].y
== Pts
[0].y
)))) &&
2369 (((Pts
[0].y
== Pts
[1].y
) &&
2370 (Pts
[1].x
== Pts
[2].x
) &&
2371 (Pts
[2].y
== Pts
[3].y
) &&
2372 (Pts
[3].x
== Pts
[0].x
)) ||
2373 ((Pts
[0].x
== Pts
[1].x
) &&
2374 (Pts
[1].y
== Pts
[2].y
) &&
2375 (Pts
[2].x
== Pts
[3].x
) &&
2376 (Pts
[3].y
== Pts
[0].y
))))
2378 SetRectRgn( hrgn
, MIN(Pts
[0].x
, Pts
[2].x
), MIN(Pts
[0].y
, Pts
[2].y
),
2379 MAX(Pts
[0].x
, Pts
[2].x
), MAX(Pts
[0].y
, Pts
[2].y
) );
2380 GDI_HEAP_UNLOCK( hrgn
);
2384 for(poly
= total
= 0; poly
< nbpolygons
; poly
++)
2385 total
+= Count
[poly
];
2386 if (! (pETEs
= HeapAlloc( SystemHeap
, 0, sizeof(EdgeTableEntry
) * total
)))
2388 REGION_DeleteObject( hrgn
, obj
);
2391 pts
= FirstPtBlock
.pts
;
2392 REGION_CreateETandAET(Count
, nbpolygons
, Pts
, &ET
, &AET
, pETEs
, &SLLBlock
);
2393 pSLL
= ET
.scanlines
.next
;
2394 curPtBlock
= &FirstPtBlock
;
2396 if (mode
!= WINDING
) {
2400 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++) {
2402 * Add a new edge to the active edge table when we
2403 * get to the next edge.
2405 if (pSLL
!= NULL
&& y
== pSLL
->scanline
) {
2406 REGION_loadAET(&AET
, pSLL
->edgelist
);
2413 * for each active edge
2416 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
2420 * send out the buffer
2422 if (iPts
== NUMPTSTOBUFFER
) {
2423 tmpPtBlock
= HeapAlloc( SystemHeap
, 0, sizeof(POINTBLOCK
));
2425 WARN(region
, "Can't alloc tPB\n");
2428 curPtBlock
->next
= tmpPtBlock
;
2429 curPtBlock
= tmpPtBlock
;
2430 pts
= curPtBlock
->pts
;
2434 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
2436 REGION_InsertionSort(&AET
);
2443 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++) {
2445 * Add a new edge to the active edge table when we
2446 * get to the next edge.
2448 if (pSLL
!= NULL
&& y
== pSLL
->scanline
) {
2449 REGION_loadAET(&AET
, pSLL
->edgelist
);
2450 REGION_computeWAET(&AET
);
2458 * for each active edge
2462 * add to the buffer only those edges that
2463 * are in the Winding active edge table.
2465 if (pWETE
== pAET
) {
2466 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
2470 * send out the buffer
2472 if (iPts
== NUMPTSTOBUFFER
) {
2473 tmpPtBlock
= HeapAlloc( SystemHeap
, 0,
2474 sizeof(POINTBLOCK
) );
2476 WARN(region
, "Can't alloc tPB\n");
2479 curPtBlock
->next
= tmpPtBlock
;
2480 curPtBlock
= tmpPtBlock
;
2481 pts
= curPtBlock
->pts
;
2482 numFullPtBlocks
++; iPts
= 0;
2484 pWETE
= pWETE
->nextWETE
;
2486 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
2490 * recompute the winding active edge table if
2491 * we just resorted or have exited an edge.
2493 if (REGION_InsertionSort(&AET
) || fixWAET
) {
2494 REGION_computeWAET(&AET
);
2499 REGION_FreeStorage(SLLBlock
.next
);
2500 REGION_PtsToRegion(numFullPtBlocks
, iPts
, &FirstPtBlock
, region
);
2501 for (curPtBlock
= FirstPtBlock
.next
; --numFullPtBlocks
>= 0;) {
2502 tmpPtBlock
= curPtBlock
->next
;
2503 HeapFree( SystemHeap
, 0, curPtBlock
);
2504 curPtBlock
= tmpPtBlock
;
2506 HeapFree( SystemHeap
, 0, pETEs
);
2507 GDI_HEAP_UNLOCK( hrgn
);
2512 /***********************************************************************
2513 * CreatePolygonRgn16 (GDI.63)
2515 HRGN16 WINAPI
CreatePolygonRgn16( const POINT16
* points
, INT16 count
,
2518 return CreatePolyPolygonRgn16( points
, &count
, 1, mode
);
2521 /***********************************************************************
2522 * CreatePolyPolygonRgn16 (GDI.451)
2524 HRGN16 WINAPI
CreatePolyPolygonRgn16( const POINT16
*points
,
2525 const INT16
*count
, INT16 nbpolygons
, INT16 mode
)
2532 for (i
= 0; i
< nbpolygons
; i
++)
2534 points32
= HeapAlloc( SystemHeap
, 0, npts
* sizeof(POINT
) );
2535 for (i
= 0; i
< npts
; i
++)
2536 CONV_POINT16TO32( &(points
[i
]), &(points32
[i
]) );
2538 count32
= HeapAlloc( SystemHeap
, 0, nbpolygons
* sizeof(INT
) );
2539 for (i
= 0; i
< nbpolygons
; i
++)
2540 count32
[i
] = count
[i
];
2541 hrgn
= CreatePolyPolygonRgn( points32
, count32
, nbpolygons
, mode
);
2542 HeapFree( SystemHeap
, 0, count32
);
2543 HeapFree( SystemHeap
, 0, points32
);
2547 /***********************************************************************
2548 * CreatePolygonRgn32 (GDI32.58)
2550 HRGN WINAPI
CreatePolygonRgn( const POINT
*points
, INT count
,
2553 return CreatePolyPolygonRgn( points
, &count
, 1, mode
);
2557 /***********************************************************************
2558 * GetRandomRgn [GDI32.215]
2561 * This function is UNDOCUMENTED, it isn't even in the header file.
2562 * I assume that it will return a HRGN32!??
2564 HRGN WINAPI
GetRandomRgn(DWORD dwArg1
, DWORD dwArg2
, DWORD dwArg3
)
2566 FIXME (region
, "(0x%08lx 0x%08lx 0x%08lx): empty stub!\n",
2567 dwArg1
, dwArg2
, dwArg3
);