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...
89 typedef void (*voidProcp
)();
91 /* Note the parameter order is different from the X11 equivalents */
93 static void REGION_CopyRegion(WINEREGION
*d
, WINEREGION
*s
);
94 static void REGION_IntersectRegion(WINEREGION
*d
, WINEREGION
*s1
, WINEREGION
*s2
);
95 static void REGION_UnionRegion(WINEREGION
*d
, WINEREGION
*s1
, WINEREGION
*s2
);
96 static void REGION_SubtractRegion(WINEREGION
*d
, WINEREGION
*s1
, WINEREGION
*s2
);
97 static void REGION_XorRegion(WINEREGION
*d
, WINEREGION
*s1
, WINEREGION
*s2
);
98 static void REGION_UnionRectWithRegion(const RECT32
*rect
, WINEREGION
*rgn
);
101 /***********************************************************************
103 * Outputs the contents of a WINEREGION
105 static void REGION_DumpRegion(WINEREGION
*pReg
)
107 RECT32
*pRect
, *pRectEnd
= pReg
->rects
+ pReg
->numRects
;
109 TRACE(region
, "Region %p: %d,%d - %d,%d %d rects\n", pReg
,
110 pReg
->extents
.left
, pReg
->extents
.top
,
111 pReg
->extents
.right
, pReg
->extents
.bottom
, pReg
->numRects
);
112 for(pRect
= pReg
->rects
; pRect
< pRectEnd
; pRect
++)
113 TRACE(region
, "\t%d,%d - %d,%d\n", pRect
->left
, pRect
->top
,
114 pRect
->right
, pRect
->bottom
);
118 /***********************************************************************
119 * REGION_AllocWineRegion
120 * Create a new empty WINEREGION.
122 static WINEREGION
*REGION_AllocWineRegion( void )
126 if (!(pReg
= HeapAlloc(SystemHeap
, 0, sizeof( WINEREGION
))))
128 if (!(pReg
->rects
= HeapAlloc(SystemHeap
, 0, sizeof( RECT32
))))
130 HeapFree(SystemHeap
, 0, pReg
);
138 /***********************************************************************
139 * REGION_CreateRegion
140 * Create a new empty region.
142 static HRGN32
REGION_CreateRegion(void)
147 if(!(hrgn
= GDI_AllocObject( sizeof(RGNOBJ
), REGION_MAGIC
)))
149 obj
= (RGNOBJ
*) GDI_HEAP_LOCK( hrgn
);
150 if(!(obj
->rgn
= REGION_AllocWineRegion())) {
151 GDI_FreeObject( hrgn
);
154 GDI_HEAP_UNLOCK( hrgn
);
158 /***********************************************************************
159 * REGION_DestroyWineRegion
161 static void REGION_DestroyWineRegion( WINEREGION
* pReg
)
163 HeapFree( SystemHeap
, 0, pReg
->rects
);
164 HeapFree( SystemHeap
, 0, pReg
);
168 /***********************************************************************
169 * REGION_DeleteObject
171 BOOL32
REGION_DeleteObject( HRGN32 hrgn
, RGNOBJ
* obj
)
173 TRACE(region
, " %04x\n", hrgn
);
175 REGION_DestroyWineRegion( obj
->rgn
);
176 return GDI_FreeObject( hrgn
);
179 /***********************************************************************
180 * OffsetRgn16 (GDI.101)
182 INT16 WINAPI
OffsetRgn16( HRGN16 hrgn
, INT16 x
, INT16 y
)
184 return OffsetRgn32( hrgn
, x
, y
);
187 /***********************************************************************
188 * OffsetRgn32 (GDI32.256)
190 INT32 WINAPI
OffsetRgn32( HRGN32 hrgn
, INT32 x
, INT32 y
)
192 RGNOBJ
* obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
197 int nbox
= obj
->rgn
->numRects
;
198 RECT32
*pbox
= obj
->rgn
->rects
;
200 TRACE(region
, " %04x %d,%d\n", hrgn
, x
, y
);
201 if(nbox
&& (x
|| y
)) {
209 obj
->rgn
->extents
.left
+= x
;
210 obj
->rgn
->extents
.right
+= x
;
211 obj
->rgn
->extents
.top
+= y
;
212 obj
->rgn
->extents
.bottom
+= y
;
214 ret
= obj
->rgn
->type
;
215 GDI_HEAP_UNLOCK( hrgn
);
222 /***********************************************************************
223 * GetRgnBox16 (GDI.134)
225 INT16 WINAPI
GetRgnBox16( HRGN16 hrgn
, LPRECT16 rect
)
228 INT16 ret
= (INT16
)GetRgnBox32( hrgn
, &r
);
229 CONV_RECT32TO16( &r
, rect
);
233 /***********************************************************************
234 * GetRgnBox32 (GDI32.219)
236 INT32 WINAPI
GetRgnBox32( HRGN32 hrgn
, LPRECT32 rect
)
238 RGNOBJ
* obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
242 TRACE(region
, " %04x\n", hrgn
);
243 rect
->left
= obj
->rgn
->extents
.left
;
244 rect
->top
= obj
->rgn
->extents
.top
;
245 rect
->right
= obj
->rgn
->extents
.right
;
246 rect
->bottom
= obj
->rgn
->extents
.bottom
;
247 ret
= obj
->rgn
->type
;
248 GDI_HEAP_UNLOCK(hrgn
);
255 /***********************************************************************
256 * CreateRectRgn16 (GDI.64)
258 HRGN16 WINAPI
CreateRectRgn16(INT16 left
, INT16 top
, INT16 right
, INT16 bottom
)
260 return (HRGN16
)CreateRectRgn32( left
, top
, right
, bottom
);
264 /***********************************************************************
265 * CreateRectRgn32 (GDI32.59)
267 HRGN32 WINAPI
CreateRectRgn32(INT32 left
, INT32 top
, INT32 right
, INT32 bottom
)
271 if (!(hrgn
= REGION_CreateRegion()))
273 TRACE(region
, " \n");
274 SetRectRgn32(hrgn
, left
, top
, right
, bottom
);
278 /***********************************************************************
279 * CreateRectRgnIndirect16 (GDI.65)
281 HRGN16 WINAPI
CreateRectRgnIndirect16( const RECT16
* rect
)
283 return CreateRectRgn32( rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
287 /***********************************************************************
288 * CreateRectRgnIndirect32 (GDI32.60)
290 HRGN32 WINAPI
CreateRectRgnIndirect32( const RECT32
* rect
)
292 return CreateRectRgn32( rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
296 /***********************************************************************
297 * SetRectRgn16 (GDI.172)
299 VOID WINAPI
SetRectRgn16( HRGN16 hrgn
, INT16 left
, INT16 top
,
300 INT16 right
, INT16 bottom
)
302 SetRectRgn32( hrgn
, left
, top
, right
, bottom
);
306 /***********************************************************************
307 * SetRectRgn32 (GDI32.332)
309 VOID WINAPI
SetRectRgn32( HRGN32 hrgn
, INT32 left
, INT32 top
,
310 INT32 right
, INT32 bottom
)
314 TRACE(region
, " %04x %d,%d-%d,%d\n",
315 hrgn
, left
, top
, right
, bottom
);
317 if (!(obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
))) return;
318 if ((right
> left
) && (bottom
> top
))
320 obj
->rgn
->rects
->left
= obj
->rgn
->extents
.left
= left
;
321 obj
->rgn
->rects
->top
= obj
->rgn
->extents
.top
= top
;
322 obj
->rgn
->rects
->right
= obj
->rgn
->extents
.right
= right
;
323 obj
->rgn
->rects
->bottom
= obj
->rgn
->extents
.bottom
= bottom
;
324 obj
->rgn
->numRects
= 1;
325 obj
->rgn
->type
= SIMPLEREGION
;
328 EMPTY_REGION(obj
->rgn
);
330 GDI_HEAP_UNLOCK( hrgn
);
334 /***********************************************************************
335 * CreateRoundRectRgn16 (GDI.444)
337 HRGN16 WINAPI
CreateRoundRectRgn16( INT16 left
, INT16 top
,
338 INT16 right
, INT16 bottom
,
339 INT16 ellipse_width
, INT16 ellipse_height
)
341 return (HRGN16
)CreateRoundRectRgn32( left
, top
, right
, bottom
,
342 ellipse_width
, ellipse_height
);
345 /***********************************************************************
346 * CreateRoundRectRgn32 (GDI32.61)
348 HRGN32 WINAPI
CreateRoundRectRgn32( INT32 left
, INT32 top
,
349 INT32 right
, INT32 bottom
,
350 INT32 ellipse_width
, INT32 ellipse_height
)
354 int asq
, bsq
, d
, xd
, yd
;
357 /* Check if we can do a normal rectangle instead */
359 if ((right
<= left
) || (bottom
<= top
) ||
360 (ellipse_width
<= 0) || (ellipse_height
<= 0))
361 return CreateRectRgn32( left
, top
, right
, bottom
);
365 if (!(hrgn
= REGION_CreateRegion())) return 0;
366 obj
= (RGNOBJ
*) GDI_HEAP_LOCK( hrgn
);
367 TRACE(region
,"(%d,%d-%d,%d %dx%d): ret=%04x\n",
368 left
, top
, right
, bottom
, ellipse_width
, ellipse_height
, hrgn
);
370 /* Check parameters */
372 if (ellipse_width
> right
-left
) ellipse_width
= right
-left
;
373 if (ellipse_height
> bottom
-top
) ellipse_height
= bottom
-top
;
375 /* Ellipse algorithm, based on an article by K. Porter */
376 /* in DDJ Graphics Programming Column, 8/89 */
378 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
379 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
380 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
382 yd
= asq
* ellipse_height
; /* 2a^2b */
384 rect
.left
= left
+ ellipse_width
/ 2;
385 rect
.right
= right
- ellipse_width
;
387 /* Loop to draw first half of quadrant */
391 if (d
> 0) /* if nearest pixel is toward the center */
393 /* move toward center */
395 rect
.bottom
= rect
.top
+ 1;
396 REGION_UnionRectWithRegion( &rect
, obj
->rgn
);
398 rect
.bottom
= rect
.top
+ 1;
399 REGION_UnionRectWithRegion( &rect
, obj
->rgn
);
403 rect
.left
--; /* next horiz point */
409 /* Loop to draw second half of quadrant */
411 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
414 /* next vertical point */
416 rect
.bottom
= rect
.top
+ 1;
417 REGION_UnionRectWithRegion( &rect
, obj
->rgn
);
419 rect
.bottom
= rect
.top
+ 1;
420 REGION_UnionRectWithRegion( &rect
, obj
->rgn
);
421 if (d
< 0) /* if nearest pixel is outside ellipse */
423 rect
.left
--; /* move away from center */
432 /* Add the inside rectangle */
437 rect
.bottom
= bottom
;
438 REGION_UnionRectWithRegion( &rect
, obj
->rgn
);
440 obj
->rgn
->type
= SIMPLEREGION
; /* FIXME? */
441 GDI_HEAP_UNLOCK( hrgn
);
446 /***********************************************************************
447 * CreateEllipticRgn16 (GDI.54)
449 HRGN16 WINAPI
CreateEllipticRgn16( INT16 left
, INT16 top
,
450 INT16 right
, INT16 bottom
)
452 return (HRGN16
)CreateRoundRectRgn32( left
, top
, right
, bottom
,
453 right
-left
, bottom
-top
);
457 /***********************************************************************
458 * CreateEllipticRgn32 (GDI32.39)
460 HRGN32 WINAPI
CreateEllipticRgn32( INT32 left
, INT32 top
,
461 INT32 right
, INT32 bottom
)
463 return CreateRoundRectRgn32( left
, top
, right
, bottom
,
464 right
-left
, bottom
-top
);
468 /***********************************************************************
469 * CreateEllipticRgnIndirect16 (GDI.55)
471 HRGN16 WINAPI
CreateEllipticRgnIndirect16( const RECT16
*rect
)
473 return CreateRoundRectRgn32( rect
->left
, rect
->top
, rect
->right
,
474 rect
->bottom
, rect
->right
- rect
->left
,
475 rect
->bottom
- rect
->top
);
479 /***********************************************************************
480 * CreateEllipticRgnIndirect32 (GDI32.40)
482 HRGN32 WINAPI
CreateEllipticRgnIndirect32( const RECT32
*rect
)
484 return CreateRoundRectRgn32( rect
->left
, rect
->top
, rect
->right
,
485 rect
->bottom
, rect
->right
- rect
->left
,
486 rect
->bottom
- rect
->top
);
489 /***********************************************************************
490 * GetRegionData (GDI32.217)
493 DWORD WINAPI
GetRegionData(HRGN32 hrgn
, DWORD count
, LPRGNDATA rgndata
)
496 RGNOBJ
*obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
498 TRACE(region
, " %04x count = %ld, rgndata = %p\n",
499 hrgn
, count
, rgndata
);
503 size
= obj
->rgn
->numRects
* sizeof(RECT32
);
504 if(count
< (size
+ sizeof(RGNDATAHEADER
)) || rgndata
== NULL
)
506 GDI_HEAP_UNLOCK( hrgn
);
507 return size
+ sizeof(RGNDATAHEADER
);
510 rgndata
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
511 rgndata
->rdh
.iType
= RDH_RECTANGLES
;
512 rgndata
->rdh
.nCount
= obj
->rgn
->numRects
;
513 rgndata
->rdh
.nRgnSize
= size
;
514 rgndata
->rdh
.rcBound
.left
= obj
->rgn
->extents
.left
;
515 rgndata
->rdh
.rcBound
.top
= obj
->rgn
->extents
.top
;
516 rgndata
->rdh
.rcBound
.right
= obj
->rgn
->extents
.right
;
517 rgndata
->rdh
.rcBound
.bottom
= obj
->rgn
->extents
.bottom
;
519 memcpy( rgndata
->Buffer
, obj
->rgn
->rects
, size
);
521 GDI_HEAP_UNLOCK( hrgn
);
525 /***********************************************************************
526 * ExtCreateRegion (GDI32.94)
529 HRGN32 WINAPI
ExtCreateRegion( XFORM
*lpXform
, DWORD dwCount
, RGNDATA
*rgndata
)
531 HRGN32 hrgn
= CreateRectRgn32(0, 0, 0, 0);
532 RGNOBJ
*obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
533 RECT32
*pCurRect
, *pEndRect
;
535 TRACE(region
, " %p %ld %p. Returning %04x\n",
536 lpXform
, dwCount
, rgndata
, hrgn
);
539 WARN(region
, "Can't create a region!\n");
543 WARN(region
, "Xform not implemented - ignoring\n");
545 if(rgndata
->rdh
.iType
!= RDH_RECTANGLES
)
547 WARN(region
, "Type not RDH_RECTANGLES\n");
548 GDI_HEAP_UNLOCK( hrgn
);
549 DeleteObject32( hrgn
);
553 pEndRect
= (RECT32
*)rgndata
->Buffer
+ rgndata
->rdh
.nCount
;
554 for(pCurRect
= (RECT32
*)rgndata
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
555 REGION_UnionRectWithRegion( pCurRect
, obj
->rgn
);
557 GDI_HEAP_UNLOCK( hrgn
);
561 /***********************************************************************
562 * PtInRegion16 (GDI.161)
564 BOOL16 WINAPI
PtInRegion16( HRGN16 hrgn
, INT16 x
, INT16 y
)
566 return PtInRegion32( hrgn
, x
, y
);
570 /***********************************************************************
571 * PtInRegion32 (GDI32.278)
573 BOOL32 WINAPI
PtInRegion32( HRGN32 hrgn
, INT32 x
, INT32 y
)
577 if ((obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
)))
582 if (obj
->rgn
->numRects
> 0 && INRECT(obj
->rgn
->extents
, x
, y
))
583 for (i
= 0; i
< obj
->rgn
->numRects
; i
++)
584 if (INRECT (obj
->rgn
->rects
[i
], x
, y
))
586 GDI_HEAP_UNLOCK( hrgn
);
593 /***********************************************************************
594 * RectInRegion16 (GDI.181)
596 BOOL16 WINAPI
RectInRegion16( HRGN16 hrgn
, const RECT16
*rect
)
600 CONV_RECT16TO32(rect
, &r32
);
601 return (BOOL16
)RectInRegion32(hrgn
, &r32
);
605 /***********************************************************************
606 * RectInRegion32 (GDI32.281)
608 * Returns TRUE if rect is at least partly inside hrgn
610 BOOL32 WINAPI
RectInRegion32( HRGN32 hrgn
, const RECT32
*rect
)
614 if ((obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
)))
616 RECT32
*pCurRect
, *pRectEnd
;
619 /* this is (just) a useful optimization */
620 if ((obj
->rgn
->numRects
> 0) && EXTENTCHECK(&obj
->rgn
->extents
,
623 for (pCurRect
= obj
->rgn
->rects
, pRectEnd
= pCurRect
+
624 obj
->rgn
->numRects
; pCurRect
< pRectEnd
; pCurRect
++)
626 if (pCurRect
->bottom
<= rect
->top
)
627 continue; /* not far enough down yet */
629 if (pCurRect
->top
>= rect
->bottom
) {
630 ret
= FALSE
; /* too far down */
634 if (pCurRect
->right
<= rect
->left
)
635 continue; /* not far enough over yet */
637 if (pCurRect
->left
>= rect
->right
) {
638 ret
= FALSE
; /* too far over */
646 GDI_HEAP_UNLOCK(hrgn
);
652 /***********************************************************************
653 * EqualRgn16 (GDI.72)
655 BOOL16 WINAPI
EqualRgn16( HRGN16 rgn1
, HRGN16 rgn2
)
657 return EqualRgn32( rgn1
, rgn2
);
661 /***********************************************************************
662 * EqualRgn32 (GDI32.90)
664 BOOL32 WINAPI
EqualRgn32( HRGN32 hrgn1
, HRGN32 hrgn2
)
669 if ((obj1
= (RGNOBJ
*) GDI_GetObjPtr( hrgn1
, REGION_MAGIC
)))
671 if ((obj2
= (RGNOBJ
*) GDI_GetObjPtr( hrgn2
, REGION_MAGIC
)))
676 if ( obj1
->rgn
->numRects
!= obj2
->rgn
->numRects
) ret
= FALSE
;
677 else if ( obj1
->rgn
->numRects
== 0 ) ret
= TRUE
;
678 else if ( !EqualRect32(&obj1
->rgn
->extents
, &obj2
->rgn
->extents
) )
680 else for( i
= 0; i
< obj1
->rgn
->numRects
; i
++ ) {
681 if (!EqualRect32(obj1
->rgn
->rects
+ i
, obj2
->rgn
->rects
+ i
)) {
686 GDI_HEAP_UNLOCK(hrgn2
);
688 GDI_HEAP_UNLOCK(hrgn1
);
692 /***********************************************************************
693 * REGION_UnionRectWithRegion
694 * Adds a rectangle to a WINEREGION
695 * See below for REGION_UnionRectWithRgn
697 static void REGION_UnionRectWithRegion(const RECT32
*rect
, WINEREGION
*rgn
)
701 region
.rects
= ®ion
.extents
;
704 region
.type
= SIMPLEREGION
;
705 CopyRect32(&(region
.extents
), rect
);
706 REGION_UnionRegion(rgn
, rgn
, ®ion
);
710 /***********************************************************************
711 * REGION_UnionRectWithRgn
712 * Adds a rectangle to a HRGN32
713 * A helper used by scroll.c
715 BOOL32
REGION_UnionRectWithRgn( HRGN32 hrgn
, const RECT32
*lpRect
)
717 RGNOBJ
*obj
= (RGNOBJ
*) GDI_HEAP_LOCK( hrgn
);
719 if(!obj
) return FALSE
;
720 REGION_UnionRectWithRegion( lpRect
, obj
->rgn
);
721 GDI_HEAP_UNLOCK(hrgn
);
725 /***********************************************************************
726 * REGION_CreateFrameRgn
728 * Create a region that is a frame around another region.
729 * Expand all rectangles by +/- x and y, then subtract original region.
731 BOOL32
REGION_FrameRgn( HRGN32 hDest
, HRGN32 hSrc
, INT32 x
, INT32 y
)
734 RGNOBJ
*srcObj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc
, REGION_MAGIC
);
736 if (srcObj
->rgn
->numRects
!= 0)
738 RGNOBJ
* destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
);
739 RECT32
*pRect
, *pEndRect
;
742 EMPTY_REGION( destObj
->rgn
);
744 pEndRect
= srcObj
->rgn
->rects
+ srcObj
->rgn
->numRects
;
745 for(pRect
= srcObj
->rgn
->rects
; pRect
< pEndRect
; pRect
++)
747 tempRect
.left
= pRect
->left
- x
;
748 tempRect
.top
= pRect
->top
- y
;
749 tempRect
.right
= pRect
->right
+ x
;
750 tempRect
.bottom
= pRect
->bottom
+ y
;
751 REGION_UnionRectWithRegion( &tempRect
, destObj
->rgn
);
753 REGION_SubtractRegion( destObj
->rgn
, destObj
->rgn
, srcObj
->rgn
);
754 GDI_HEAP_UNLOCK ( hDest
);
759 GDI_HEAP_UNLOCK( hSrc
);
763 /***********************************************************************
766 * Convert region to device co-ords for the supplied dc.
767 * Used by X11DRV_PaintRgn.
769 BOOL32
REGION_LPTODP( HDC32 hdc
, HRGN32 hDest
, HRGN32 hSrc
)
771 RECT32
*pCurRect
, *pEndRect
;
772 RGNOBJ
*srcObj
, *destObj
;
773 DC
* dc
= DC_GetDCPtr( hdc
);
776 TRACE(region
, " hdc=%04x dest=%04x src=%04x\n",
779 if (dc
->w
.MapMode
== MM_TEXT
) /* Requires only a translation */
781 if( CombineRgn32( hDest
, hSrc
, 0, RGN_COPY
) == ERROR
) return FALSE
;
782 OffsetRgn32( hDest
, dc
->vportOrgX
- dc
->wndOrgX
,
783 dc
->vportOrgY
- dc
->wndOrgY
);
787 if(!( srcObj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc
, REGION_MAGIC
) ))
789 if(!( destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
) ))
791 GDI_HEAP_UNLOCK( hSrc
);
794 EMPTY_REGION( destObj
->rgn
);
796 pEndRect
= srcObj
->rgn
->rects
+ srcObj
->rgn
->numRects
;
797 for(pCurRect
= srcObj
->rgn
->rects
; pCurRect
< pEndRect
; pCurRect
++)
800 tmpRect
.left
= XLPTODP( dc
, tmpRect
.left
);
801 tmpRect
.top
= YLPTODP( dc
, tmpRect
.top
);
802 tmpRect
.right
= XLPTODP( dc
, tmpRect
.right
);
803 tmpRect
.bottom
= YLPTODP( dc
, tmpRect
.bottom
);
804 REGION_UnionRectWithRegion( &tmpRect
, destObj
->rgn
);
807 GDI_HEAP_UNLOCK( hDest
);
808 GDI_HEAP_UNLOCK( hSrc
);
812 /***********************************************************************
813 * CombineRgn16 (GDI.451)
815 INT16 WINAPI
CombineRgn16(HRGN16 hDest
, HRGN16 hSrc1
, HRGN16 hSrc2
, INT16 mode
)
817 return (INT16
)CombineRgn32( hDest
, hSrc1
, hSrc2
, mode
);
821 /***********************************************************************
822 * CombineRgn32 (GDI32.19)
824 * Note: The behavior is correct even if src and dest regions are the same.
826 INT32 WINAPI
CombineRgn32(HRGN32 hDest
, HRGN32 hSrc1
, HRGN32 hSrc2
, INT32 mode
)
828 RGNOBJ
*destObj
= (RGNOBJ
*) GDI_GetObjPtr( hDest
, REGION_MAGIC
);
829 INT32 result
= ERROR
;
831 TRACE(region
, " %04x,%04x -> %04x mode=%x\n",
832 hSrc1
, hSrc2
, hDest
, mode
);
835 RGNOBJ
*src1Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc1
, REGION_MAGIC
);
839 TRACE(region
, "dump:\n");
841 REGION_DumpRegion(src1Obj
->rgn
);
842 if (mode
== RGN_COPY
)
844 REGION_CopyRegion( destObj
->rgn
, src1Obj
->rgn
);
845 result
= destObj
->rgn
->type
;
849 RGNOBJ
*src2Obj
= (RGNOBJ
*) GDI_GetObjPtr( hSrc2
, REGION_MAGIC
);
853 TRACE(region
, "dump:\n");
855 REGION_DumpRegion(src2Obj
->rgn
);
859 REGION_IntersectRegion( destObj
->rgn
, src1Obj
->rgn
, src2Obj
->rgn
);
862 REGION_UnionRegion( destObj
->rgn
, src1Obj
->rgn
, src2Obj
->rgn
);
865 REGION_XorRegion( destObj
->rgn
, src1Obj
->rgn
, src2Obj
->rgn
);
868 REGION_SubtractRegion( destObj
->rgn
, src1Obj
->rgn
, src2Obj
->rgn
);
871 result
= destObj
->rgn
->type
;
872 GDI_HEAP_UNLOCK( hSrc2
);
875 GDI_HEAP_UNLOCK( hSrc1
);
877 TRACE(region
, "dump:\n");
879 REGION_DumpRegion(destObj
->rgn
);
881 GDI_HEAP_UNLOCK( hDest
);
886 /***********************************************************************
888 * Re-calculate the extents of a region
890 static void REGION_SetExtents (WINEREGION
*pReg
)
892 RECT32
*pRect
, *pRectEnd
, *pExtents
;
894 if (pReg
->numRects
== 0)
896 pReg
->extents
.left
= 0;
897 pReg
->extents
.top
= 0;
898 pReg
->extents
.right
= 0;
899 pReg
->extents
.bottom
= 0;
903 pExtents
= &pReg
->extents
;
905 pRectEnd
= &pRect
[pReg
->numRects
- 1];
908 * Since pRect is the first rectangle in the region, it must have the
909 * smallest top and since pRectEnd is the last rectangle in the region,
910 * it must have the largest bottom, because of banding. Initialize left and
911 * right from pRect and pRectEnd, resp., as good things to initialize them
914 pExtents
->left
= pRect
->left
;
915 pExtents
->top
= pRect
->top
;
916 pExtents
->right
= pRectEnd
->right
;
917 pExtents
->bottom
= pRectEnd
->bottom
;
919 while (pRect
<= pRectEnd
)
921 if (pRect
->left
< pExtents
->left
)
922 pExtents
->left
= pRect
->left
;
923 if (pRect
->right
> pExtents
->right
)
924 pExtents
->right
= pRect
->right
;
929 /***********************************************************************
932 static void REGION_CopyRegion(WINEREGION
*dst
, WINEREGION
*src
)
934 if (dst
!= src
) /* don't want to copy to itself */
936 if (dst
->size
< src
->numRects
)
938 if (! (dst
->rects
= HeapReAlloc( SystemHeap
, 0, dst
->rects
,
939 src
->numRects
* sizeof(RECT32
) )))
941 dst
->size
= src
->numRects
;
943 dst
->numRects
= src
->numRects
;
944 dst
->extents
.left
= src
->extents
.left
;
945 dst
->extents
.top
= src
->extents
.top
;
946 dst
->extents
.right
= src
->extents
.right
;
947 dst
->extents
.bottom
= src
->extents
.bottom
;
948 dst
->type
= src
->type
;
950 memcpy((char *) dst
->rects
, (char *) src
->rects
,
951 (int) (src
->numRects
* sizeof(RECT32
)));
956 /***********************************************************************
959 * Attempt to merge the rects in the current band with those in the
960 * previous one. Used only by REGION_RegionOp.
963 * The new index for the previous band.
966 * If coalescing takes place:
967 * - rectangles in the previous band will have their bottom fields
969 * - pReg->numRects will be decreased.
972 static INT32
REGION_Coalesce (
973 WINEREGION
*pReg
, /* Region to coalesce */
974 INT32 prevStart
, /* Index of start of previous band */
975 INT32 curStart
/* Index of start of current band */
977 RECT32
*pPrevRect
; /* Current rect in previous band */
978 RECT32
*pCurRect
; /* Current rect in current band */
979 RECT32
*pRegEnd
; /* End of region */
980 INT32 curNumRects
; /* Number of rectangles in current band */
981 INT32 prevNumRects
; /* Number of rectangles in previous band */
982 INT32 bandtop
; /* top coordinate for current band */
984 pRegEnd
= &pReg
->rects
[pReg
->numRects
];
986 pPrevRect
= &pReg
->rects
[prevStart
];
987 prevNumRects
= curStart
- prevStart
;
990 * Figure out how many rectangles are in the current band. Have to do
991 * this because multiple bands could have been added in REGION_RegionOp
992 * at the end when one region has been exhausted.
994 pCurRect
= &pReg
->rects
[curStart
];
995 bandtop
= pCurRect
->top
;
996 for (curNumRects
= 0;
997 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
1003 if (pCurRect
!= pRegEnd
)
1006 * If more than one band was added, we have to find the start
1007 * of the last band added so the next coalescing job can start
1008 * at the right place... (given when multiple bands are added,
1009 * this may be pointless -- see above).
1012 while (pRegEnd
[-1].top
== pRegEnd
->top
)
1016 curStart
= pRegEnd
- pReg
->rects
;
1017 pRegEnd
= pReg
->rects
+ pReg
->numRects
;
1020 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0)) {
1021 pCurRect
-= curNumRects
;
1023 * The bands may only be coalesced if the bottom of the previous
1024 * matches the top scanline of the current.
1026 if (pPrevRect
->bottom
== pCurRect
->top
)
1029 * Make sure the bands have rects in the same places. This
1030 * assumes that rects have been added in such a way that they
1031 * cover the most area possible. I.e. two rects in a band must
1032 * have some horizontal space between them.
1036 if ((pPrevRect
->left
!= pCurRect
->left
) ||
1037 (pPrevRect
->right
!= pCurRect
->right
))
1040 * The bands don't line up so they can't be coalesced.
1047 } while (prevNumRects
!= 0);
1049 pReg
->numRects
-= curNumRects
;
1050 pCurRect
-= curNumRects
;
1051 pPrevRect
-= curNumRects
;
1054 * The bands may be merged, so set the bottom of each rect
1055 * in the previous band to that of the corresponding rect in
1060 pPrevRect
->bottom
= pCurRect
->bottom
;
1064 } while (curNumRects
!= 0);
1067 * If only one band was added to the region, we have to backup
1068 * curStart to the start of the previous band.
1070 * If more than one band was added to the region, copy the
1071 * other bands down. The assumption here is that the other bands
1072 * came from the same region as the current one and no further
1073 * coalescing can be done on them since it's all been done
1074 * already... curStart is already in the right place.
1076 if (pCurRect
== pRegEnd
)
1078 curStart
= prevStart
;
1084 *pPrevRect
++ = *pCurRect
++;
1085 } while (pCurRect
!= pRegEnd
);
1093 /***********************************************************************
1096 * Apply an operation to two regions. Called by REGION_Union,
1097 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
1103 * The new region is overwritten.
1106 * The idea behind this function is to view the two regions as sets.
1107 * Together they cover a rectangle of area that this function divides
1108 * into horizontal bands where points are covered only by one region
1109 * or by both. For the first case, the nonOverlapFunc is called with
1110 * each the band and the band's upper and lower extents. For the
1111 * second, the overlapFunc is called to process the entire band. It
1112 * is responsible for clipping the rectangles in the band, though
1113 * this function provides the boundaries.
1114 * At the end of each band, the new region is coalesced, if possible,
1115 * to reduce the number of rectangles in the region.
1118 static void REGION_RegionOp(
1119 WINEREGION
*newReg
, /* Place to store result */
1120 WINEREGION
*reg1
, /* First region in operation */
1121 WINEREGION
*reg2
, /* 2nd region in operation */
1122 void (*overlapFunc
)(), /* Function to call for over-lapping bands */
1123 void (*nonOverlap1Func
)(), /* Function to call for non-overlapping bands in region 1 */
1124 void (*nonOverlap2Func
)() /* Function to call for non-overlapping bands in region 2 */
1126 RECT32
*r1
; /* Pointer into first region */
1127 RECT32
*r2
; /* Pointer into 2d region */
1128 RECT32
*r1End
; /* End of 1st region */
1129 RECT32
*r2End
; /* End of 2d region */
1130 INT32 ybot
; /* Bottom of intersection */
1131 INT32 ytop
; /* Top of intersection */
1132 RECT32
*oldRects
; /* Old rects for newReg */
1133 INT32 prevBand
; /* Index of start of
1134 * previous band in newReg */
1135 INT32 curBand
; /* Index of start of current
1137 RECT32
*r1BandEnd
; /* End of current band in r1 */
1138 RECT32
*r2BandEnd
; /* End of current band in r2 */
1139 INT32 top
; /* Top of non-overlapping band */
1140 INT32 bot
; /* Bottom of non-overlapping band */
1144 * set r1, r2, r1End and r2End appropriately, preserve the important
1145 * parts of the destination region until the end in case it's one of
1146 * the two source regions, then mark the "new" region empty, allocating
1147 * another array of rectangles for it to use.
1151 r1End
= r1
+ reg1
->numRects
;
1152 r2End
= r2
+ reg2
->numRects
;
1154 oldRects
= newReg
->rects
;
1156 EMPTY_REGION(newReg
);
1159 * Allocate a reasonable number of rectangles for the new region. The idea
1160 * is to allocate enough so the individual functions don't need to
1161 * reallocate and copy the array, which is time consuming, yet we don't
1162 * have to worry about using too much memory. I hope to be able to
1163 * nuke the Xrealloc() at the end of this function eventually.
1165 newReg
->size
= MAX(reg1
->numRects
,reg2
->numRects
) * 2;
1167 if (! (newReg
->rects
= HeapAlloc( SystemHeap
, 0,
1168 sizeof(RECT32
) * newReg
->size
)))
1175 * Initialize ybot and ytop.
1176 * In the upcoming loop, ybot and ytop serve different functions depending
1177 * on whether the band being handled is an overlapping or non-overlapping
1179 * In the case of a non-overlapping band (only one of the regions
1180 * has points in the band), ybot is the bottom of the most recent
1181 * intersection and thus clips the top of the rectangles in that band.
1182 * ytop is the top of the next intersection between the two regions and
1183 * serves to clip the bottom of the rectangles in the current band.
1184 * For an overlapping band (where the two regions intersect), ytop clips
1185 * the top of the rectangles of both regions and ybot clips the bottoms.
1187 if (reg1
->extents
.top
< reg2
->extents
.top
)
1188 ybot
= reg1
->extents
.top
;
1190 ybot
= reg2
->extents
.top
;
1193 * prevBand serves to mark the start of the previous band so rectangles
1194 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1195 * In the beginning, there is no previous band, so prevBand == curBand
1196 * (curBand is set later on, of course, but the first band will always
1197 * start at index 0). prevBand and curBand must be indices because of
1198 * the possible expansion, and resultant moving, of the new region's
1199 * array of rectangles.
1205 curBand
= newReg
->numRects
;
1208 * This algorithm proceeds one source-band (as opposed to a
1209 * destination band, which is determined by where the two regions
1210 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1211 * rectangle after the last one in the current band for their
1212 * respective regions.
1215 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
1221 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
1227 * First handle the band that doesn't intersect, if any.
1229 * Note that attention is restricted to one band in the
1230 * non-intersecting region at once, so if a region has n
1231 * bands between the current position and the next place it overlaps
1232 * the other, this entire loop will be passed through n times.
1234 if (r1
->top
< r2
->top
)
1236 top
= MAX(r1
->top
,ybot
);
1237 bot
= MIN(r1
->bottom
,r2
->top
);
1239 if ((top
!= bot
) && (nonOverlap1Func
!= (void (*)())NULL
))
1241 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
, top
, bot
);
1246 else if (r2
->top
< r1
->top
)
1248 top
= MAX(r2
->top
,ybot
);
1249 bot
= MIN(r2
->bottom
,r1
->top
);
1251 if ((top
!= bot
) && (nonOverlap2Func
!= (void (*)())NULL
))
1253 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
, top
, bot
);
1264 * If any rectangles got added to the region, try and coalesce them
1265 * with rectangles from the previous band. Note we could just do
1266 * this test in miCoalesce, but some machines incur a not
1267 * inconsiderable cost for function calls, so...
1269 if (newReg
->numRects
!= curBand
)
1271 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1275 * Now see if we've hit an intersecting band. The two bands only
1276 * intersect if ybot > ytop
1278 ybot
= MIN(r1
->bottom
, r2
->bottom
);
1279 curBand
= newReg
->numRects
;
1282 (* overlapFunc
) (newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
1286 if (newReg
->numRects
!= curBand
)
1288 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1292 * If we've finished with a band (bottom == ybot) we skip forward
1293 * in the region to the next band.
1295 if (r1
->bottom
== ybot
)
1299 if (r2
->bottom
== ybot
)
1303 } while ((r1
!= r1End
) && (r2
!= r2End
));
1306 * Deal with whichever region still has rectangles left.
1308 curBand
= newReg
->numRects
;
1311 if (nonOverlap1Func
!= (void (*)())NULL
)
1316 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
1320 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
,
1321 MAX(r1
->top
,ybot
), r1
->bottom
);
1323 } while (r1
!= r1End
);
1326 else if ((r2
!= r2End
) && (nonOverlap2Func
!= (void (*)())NULL
))
1331 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
1335 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
,
1336 MAX(r2
->top
,ybot
), r2
->bottom
);
1338 } while (r2
!= r2End
);
1341 if (newReg
->numRects
!= curBand
)
1343 (void) REGION_Coalesce (newReg
, prevBand
, curBand
);
1347 * A bit of cleanup. To keep regions from growing without bound,
1348 * we shrink the array of rectangles to match the new number of
1349 * rectangles in the region. This never goes to 0, however...
1351 * Only do this stuff if the number of rectangles allocated is more than
1352 * twice the number of rectangles in the region (a simple optimization...).
1354 if (newReg
->numRects
< (newReg
->size
>> 1))
1356 if (REGION_NOT_EMPTY(newReg
))
1358 RECT32
*prev_rects
= newReg
->rects
;
1359 newReg
->size
= newReg
->numRects
;
1360 newReg
->rects
= HeapReAlloc( SystemHeap
, 0, newReg
->rects
,
1361 sizeof(RECT32
) * newReg
->size
);
1362 if (! newReg
->rects
)
1363 newReg
->rects
= prev_rects
;
1368 * No point in doing the extra work involved in an Xrealloc if
1369 * the region is empty
1372 HeapFree( SystemHeap
, 0, newReg
->rects
);
1373 newReg
->rects
= HeapAlloc( SystemHeap
, 0, sizeof(RECT32
) );
1376 HeapFree( SystemHeap
, 0, oldRects
);
1380 /***********************************************************************
1381 * Region Intersection
1382 ***********************************************************************/
1385 /***********************************************************************
1388 * Handle an overlapping band for REGION_Intersect.
1394 * Rectangles may be added to the region.
1397 static void REGION_IntersectO(WINEREGION
*pReg
, RECT32
*r1
, RECT32
*r1End
,
1398 RECT32
*r2
, RECT32
*r2End
, INT32 top
, INT32 bottom
)
1404 pNextRect
= &pReg
->rects
[pReg
->numRects
];
1406 while ((r1
!= r1End
) && (r2
!= r2End
))
1408 left
= MAX(r1
->left
, r2
->left
);
1409 right
= MIN(r1
->right
, r2
->right
);
1412 * If there's any overlap between the two rectangles, add that
1413 * overlap to the new region.
1414 * There's no need to check for subsumption because the only way
1415 * such a need could arise is if some region has two rectangles
1416 * right next to each other. Since that should never happen...
1420 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1421 pNextRect
->left
= left
;
1422 pNextRect
->top
= top
;
1423 pNextRect
->right
= right
;
1424 pNextRect
->bottom
= bottom
;
1425 pReg
->numRects
+= 1;
1430 * Need to advance the pointers. Shift the one that extends
1431 * to the right the least, since the other still has a chance to
1432 * overlap with that region's next rectangle, if you see what I mean.
1434 if (r1
->right
< r2
->right
)
1438 else if (r2
->right
< r1
->right
)
1451 /***********************************************************************
1452 * REGION_IntersectRegion
1454 static void REGION_IntersectRegion(WINEREGION
*newReg
, WINEREGION
*reg1
,
1457 /* check for trivial reject */
1458 if ( (!(reg1
->numRects
)) || (!(reg2
->numRects
)) ||
1459 (!EXTENTCHECK(®1
->extents
, ®2
->extents
)))
1460 newReg
->numRects
= 0;
1462 REGION_RegionOp (newReg
, reg1
, reg2
,
1463 (voidProcp
) REGION_IntersectO
, (voidProcp
) NULL
, (voidProcp
) NULL
);
1466 * Can't alter newReg's extents before we call miRegionOp because
1467 * it might be one of the source regions and miRegionOp depends
1468 * on the extents of those regions being the same. Besides, this
1469 * way there's no checking against rectangles that will be nuked
1470 * due to coalescing, so we have to examine fewer rectangles.
1472 REGION_SetExtents(newReg
);
1473 newReg
->type
= (newReg
->numRects
) ? COMPLEXREGION
: NULLREGION
;
1477 /***********************************************************************
1479 ***********************************************************************/
1481 /***********************************************************************
1484 * Handle a non-overlapping band for the union operation. Just
1485 * Adds the rectangles into the region. Doesn't have to check for
1486 * subsumption or anything.
1492 * pReg->numRects is incremented and the final rectangles overwritten
1493 * with the rectangles we're passed.
1496 static void REGION_UnionNonO (WINEREGION
*pReg
, RECT32
*r
, RECT32
*rEnd
,
1497 INT32 top
, INT32 bottom
)
1501 pNextRect
= &pReg
->rects
[pReg
->numRects
];
1505 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1506 pNextRect
->left
= r
->left
;
1507 pNextRect
->top
= top
;
1508 pNextRect
->right
= r
->right
;
1509 pNextRect
->bottom
= bottom
;
1510 pReg
->numRects
+= 1;
1517 /***********************************************************************
1520 * Handle an overlapping band for the union operation. Picks the
1521 * left-most rectangle each time and merges it into the region.
1527 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1531 static void REGION_UnionO (WINEREGION
*pReg
, RECT32
*r1
, RECT32
*r1End
,
1532 RECT32
*r2
, RECT32
*r2End
, INT32 top
, INT32 bottom
)
1536 pNextRect
= &pReg
->rects
[pReg
->numRects
];
1538 #define MERGERECT(r) \
1539 if ((pReg->numRects != 0) && \
1540 (pNextRect[-1].top == top) && \
1541 (pNextRect[-1].bottom == bottom) && \
1542 (pNextRect[-1].right >= r->left)) \
1544 if (pNextRect[-1].right < r->right) \
1546 pNextRect[-1].right = r->right; \
1551 MEMCHECK(pReg, pNextRect, pReg->rects); \
1552 pNextRect->top = top; \
1553 pNextRect->bottom = bottom; \
1554 pNextRect->left = r->left; \
1555 pNextRect->right = r->right; \
1556 pReg->numRects += 1; \
1561 while ((r1
!= r1End
) && (r2
!= r2End
))
1563 if (r1
->left
< r2
->left
)
1578 } while (r1
!= r1End
);
1580 else while (r2
!= r2End
)
1587 /***********************************************************************
1588 * REGION_UnionRegion
1590 static void REGION_UnionRegion(WINEREGION
*newReg
, WINEREGION
*reg1
,
1593 /* checks all the simple cases */
1596 * Region 1 and 2 are the same or region 1 is empty
1598 if ( (reg1
== reg2
) || (!(reg1
->numRects
)) )
1601 REGION_CopyRegion(newReg
, reg2
);
1606 * if nothing to union (region 2 empty)
1608 if (!(reg2
->numRects
))
1611 REGION_CopyRegion(newReg
, reg1
);
1616 * Region 1 completely subsumes region 2
1618 if ((reg1
->numRects
== 1) &&
1619 (reg1
->extents
.left
<= reg2
->extents
.left
) &&
1620 (reg1
->extents
.top
<= reg2
->extents
.top
) &&
1621 (reg1
->extents
.right
>= reg2
->extents
.right
) &&
1622 (reg1
->extents
.bottom
>= reg2
->extents
.bottom
))
1625 REGION_CopyRegion(newReg
, reg1
);
1630 * Region 2 completely subsumes region 1
1632 if ((reg2
->numRects
== 1) &&
1633 (reg2
->extents
.left
<= reg1
->extents
.left
) &&
1634 (reg2
->extents
.top
<= reg1
->extents
.top
) &&
1635 (reg2
->extents
.right
>= reg1
->extents
.right
) &&
1636 (reg2
->extents
.bottom
>= reg1
->extents
.bottom
))
1639 REGION_CopyRegion(newReg
, reg2
);
1643 REGION_RegionOp (newReg
, reg1
, reg2
, (voidProcp
) REGION_UnionO
,
1644 (voidProcp
) REGION_UnionNonO
, (voidProcp
) REGION_UnionNonO
);
1646 newReg
->extents
.left
= MIN(reg1
->extents
.left
, reg2
->extents
.left
);
1647 newReg
->extents
.top
= MIN(reg1
->extents
.top
, reg2
->extents
.top
);
1648 newReg
->extents
.right
= MAX(reg1
->extents
.right
, reg2
->extents
.right
);
1649 newReg
->extents
.bottom
= MAX(reg1
->extents
.bottom
, reg2
->extents
.bottom
);
1650 newReg
->type
= (newReg
->numRects
) ? COMPLEXREGION
: NULLREGION
;
1654 /***********************************************************************
1655 * Region Subtraction
1656 ***********************************************************************/
1658 /***********************************************************************
1659 * REGION_SubtractNonO1
1661 * Deal with non-overlapping band for subtraction. Any parts from
1662 * region 2 we discard. Anything from region 1 we add to the region.
1668 * pReg may be affected.
1671 static void REGION_SubtractNonO1 (WINEREGION
*pReg
, RECT32
*r
, RECT32
*rEnd
,
1672 INT32 top
, INT32 bottom
)
1676 pNextRect
= &pReg
->rects
[pReg
->numRects
];
1680 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1681 pNextRect
->left
= r
->left
;
1682 pNextRect
->top
= top
;
1683 pNextRect
->right
= r
->right
;
1684 pNextRect
->bottom
= bottom
;
1685 pReg
->numRects
+= 1;
1693 /***********************************************************************
1696 * Overlapping band subtraction. x1 is the left-most point not yet
1703 * pReg may have rectangles added to it.
1706 static void REGION_SubtractO (WINEREGION
*pReg
, RECT32
*r1
, RECT32
*r1End
,
1707 RECT32
*r2
, RECT32
*r2End
, INT32 top
, INT32 bottom
)
1713 pNextRect
= &pReg
->rects
[pReg
->numRects
];
1715 while ((r1
!= r1End
) && (r2
!= r2End
))
1717 if (r2
->right
<= left
)
1720 * Subtrahend missed the boat: go to next subtrahend.
1724 else if (r2
->left
<= left
)
1727 * Subtrahend preceeds minuend: nuke left edge of minuend.
1730 if (left
>= r1
->right
)
1733 * Minuend completely covered: advance to next minuend and
1734 * reset left fence to edge of new minuend.
1743 * Subtrahend now used up since it doesn't extend beyond
1749 else if (r2
->left
< r1
->right
)
1752 * Left part of subtrahend covers part of minuend: add uncovered
1753 * part of minuend to region and skip to next subtrahend.
1755 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1756 pNextRect
->left
= left
;
1757 pNextRect
->top
= top
;
1758 pNextRect
->right
= r2
->left
;
1759 pNextRect
->bottom
= bottom
;
1760 pReg
->numRects
+= 1;
1763 if (left
>= r1
->right
)
1766 * Minuend used up: advance to new...
1775 * Subtrahend used up
1783 * Minuend used up: add any remaining piece before advancing.
1785 if (r1
->right
> left
)
1787 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1788 pNextRect
->left
= left
;
1789 pNextRect
->top
= top
;
1790 pNextRect
->right
= r1
->right
;
1791 pNextRect
->bottom
= bottom
;
1792 pReg
->numRects
+= 1;
1801 * Add remaining minuend rectangles to region.
1805 MEMCHECK(pReg
, pNextRect
, pReg
->rects
);
1806 pNextRect
->left
= left
;
1807 pNextRect
->top
= top
;
1808 pNextRect
->right
= r1
->right
;
1809 pNextRect
->bottom
= bottom
;
1810 pReg
->numRects
+= 1;
1821 /***********************************************************************
1822 * REGION_SubtractRegion
1824 * Subtract regS from regM and leave the result in regD.
1825 * S stands for subtrahend, M for minuend and D for difference.
1831 * regD is overwritten.
1834 static void REGION_SubtractRegion(WINEREGION
*regD
, WINEREGION
*regM
,
1837 /* check for trivial reject */
1838 if ( (!(regM
->numRects
)) || (!(regS
->numRects
)) ||
1839 (!EXTENTCHECK(®M
->extents
, ®S
->extents
)) )
1841 REGION_CopyRegion(regD
, regM
);
1845 REGION_RegionOp (regD
, regM
, regS
, (voidProcp
) REGION_SubtractO
,
1846 (voidProcp
) REGION_SubtractNonO1
, (voidProcp
) NULL
);
1849 * Can't alter newReg's extents before we call miRegionOp because
1850 * it might be one of the source regions and miRegionOp depends
1851 * on the extents of those regions being the unaltered. Besides, this
1852 * way there's no checking against rectangles that will be nuked
1853 * due to coalescing, so we have to examine fewer rectangles.
1855 REGION_SetExtents (regD
);
1856 regD
->type
= (regD
->numRects
) ? COMPLEXREGION
: NULLREGION
;
1860 /***********************************************************************
1863 static void REGION_XorRegion(WINEREGION
*dr
, WINEREGION
*sra
,
1866 WINEREGION
*tra
, *trb
;
1868 if ((! (tra
= REGION_AllocWineRegion())) ||
1869 (! (trb
= REGION_AllocWineRegion())))
1871 REGION_SubtractRegion(tra
,sra
,srb
);
1872 REGION_SubtractRegion(trb
,srb
,sra
);
1873 REGION_UnionRegion(dr
,tra
,trb
);
1874 REGION_DestroyWineRegion(tra
);
1875 REGION_DestroyWineRegion(trb
);
1879 /**************************************************************************
1883 *************************************************************************/
1885 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
1886 #define SMALL_COORDINATE 0x80000000
1888 /***********************************************************************
1889 * REGION_InsertEdgeInET
1891 * Insert the given edge into the edge table.
1892 * First we must find the correct bucket in the
1893 * Edge table, then find the right slot in the
1894 * bucket. Finally, we can insert it.
1897 static void REGION_InsertEdgeInET(EdgeTable
*ET
, EdgeTableEntry
*ETE
,
1898 INT32 scanline
, ScanLineListBlock
**SLLBlock
, INT32
*iSLLBlock
)
1901 EdgeTableEntry
*start
, *prev
;
1902 ScanLineList
*pSLL
, *pPrevSLL
;
1903 ScanLineListBlock
*tmpSLLBlock
;
1906 * find the right bucket to put the edge into
1908 pPrevSLL
= &ET
->scanlines
;
1909 pSLL
= pPrevSLL
->next
;
1910 while (pSLL
&& (pSLL
->scanline
< scanline
))
1917 * reassign pSLL (pointer to ScanLineList) if necessary
1919 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
1921 if (*iSLLBlock
> SLLSPERBLOCK
-1)
1923 tmpSLLBlock
= HeapAlloc( SystemHeap
, 0, sizeof(ScanLineListBlock
));
1926 WARN(region
, "Can't alloc SLLB\n");
1929 (*SLLBlock
)->next
= tmpSLLBlock
;
1930 tmpSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
1931 *SLLBlock
= tmpSLLBlock
;
1934 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
1936 pSLL
->next
= pPrevSLL
->next
;
1937 pSLL
->edgelist
= (EdgeTableEntry
*)NULL
;
1938 pPrevSLL
->next
= pSLL
;
1940 pSLL
->scanline
= scanline
;
1943 * now insert the edge in the right bucket
1945 prev
= (EdgeTableEntry
*)NULL
;
1946 start
= pSLL
->edgelist
;
1947 while (start
&& (start
->bres
.minor_axis
< ETE
->bres
.minor_axis
))
1950 start
= start
->next
;
1957 pSLL
->edgelist
= ETE
;
1960 /***********************************************************************
1961 * REGION_CreateEdgeTable
1963 * This routine creates the edge table for
1964 * scan converting polygons.
1965 * The Edge Table (ET) looks like:
1969 * | ymax | ScanLineLists
1970 * |scanline|-->------------>-------------->...
1971 * -------- |scanline| |scanline|
1972 * |edgelist| |edgelist|
1973 * --------- ---------
1977 * list of ETEs list of ETEs
1979 * where ETE is an EdgeTableEntry data structure,
1980 * and there is one ScanLineList per scanline at
1981 * which an edge is initially entered.
1984 static void REGION_CreateETandAET(const INT32
*Count
, INT32 nbpolygons
,
1985 const POINT32
*pts
, EdgeTable
*ET
, EdgeTableEntry
*AET
,
1986 EdgeTableEntry
*pETEs
, ScanLineListBlock
*pSLLBlock
)
1988 const POINT32
*top
, *bottom
;
1989 const POINT32
*PrevPt
, *CurrPt
, *EndPt
;
1996 * initialize the Active Edge Table
1998 AET
->next
= (EdgeTableEntry
*)NULL
;
1999 AET
->back
= (EdgeTableEntry
*)NULL
;
2000 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2001 AET
->bres
.minor_axis
= SMALL_COORDINATE
;
2004 * initialize the Edge Table.
2006 ET
->scanlines
.next
= (ScanLineList
*)NULL
;
2007 ET
->ymax
= SMALL_COORDINATE
;
2008 ET
->ymin
= LARGE_COORDINATE
;
2009 pSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
2012 for(poly
= 0; poly
< nbpolygons
; poly
++)
2014 count
= Count
[poly
];
2022 * for each vertex in the array of points.
2023 * In this loop we are dealing with two vertices at
2024 * a time -- these make up one edge of the polygon.
2031 * find out which point is above and which is below.
2033 if (PrevPt
->y
> CurrPt
->y
)
2035 bottom
= PrevPt
, top
= CurrPt
;
2036 pETEs
->ClockWise
= 0;
2040 bottom
= CurrPt
, top
= PrevPt
;
2041 pETEs
->ClockWise
= 1;
2045 * don't add horizontal edges to the Edge table.
2047 if (bottom
->y
!= top
->y
)
2049 pETEs
->ymax
= bottom
->y
-1;
2050 /* -1 so we don't get last scanline */
2053 * initialize integer edge algorithm
2055 dy
= bottom
->y
- top
->y
;
2056 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
2058 REGION_InsertEdgeInET(ET
, pETEs
, top
->y
, &pSLLBlock
,
2061 if (PrevPt
->y
> ET
->ymax
)
2062 ET
->ymax
= PrevPt
->y
;
2063 if (PrevPt
->y
< ET
->ymin
)
2064 ET
->ymin
= PrevPt
->y
;
2073 /***********************************************************************
2076 * This routine moves EdgeTableEntries from the
2077 * EdgeTable into the Active Edge Table,
2078 * leaving them sorted by smaller x coordinate.
2081 static void REGION_loadAET(EdgeTableEntry
*AET
, EdgeTableEntry
*ETEs
)
2083 EdgeTableEntry
*pPrevAET
;
2084 EdgeTableEntry
*tmp
;
2090 while (AET
&& (AET
->bres
.minor_axis
< ETEs
->bres
.minor_axis
))
2099 ETEs
->back
= pPrevAET
;
2100 pPrevAET
->next
= ETEs
;
2107 /***********************************************************************
2108 * REGION_computeWAET
2110 * This routine links the AET by the
2111 * nextWETE (winding EdgeTableEntry) link for
2112 * use by the winding number rule. The final
2113 * Active Edge Table (AET) might look something
2117 * ---------- --------- ---------
2118 * |ymax | |ymax | |ymax |
2119 * | ... | |... | |... |
2120 * |next |->|next |->|next |->...
2121 * |nextWETE| |nextWETE| |nextWETE|
2122 * --------- --------- ^--------
2124 * V-------------------> V---> ...
2127 static void REGION_computeWAET(EdgeTableEntry
*AET
)
2129 register EdgeTableEntry
*pWETE
;
2130 register int inside
= 1;
2131 register int isInside
= 0;
2133 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2143 if ((!inside
&& !isInside
) ||
2144 ( inside
&& isInside
))
2146 pWETE
->nextWETE
= AET
;
2152 pWETE
->nextWETE
= (EdgeTableEntry
*)NULL
;
2155 /***********************************************************************
2156 * REGION_InsertionSort
2158 * Just a simple insertion sort using
2159 * pointers and back pointers to sort the Active
2163 static BOOL32
REGION_InsertionSort(EdgeTableEntry
*AET
)
2165 EdgeTableEntry
*pETEchase
;
2166 EdgeTableEntry
*pETEinsert
;
2167 EdgeTableEntry
*pETEchaseBackTMP
;
2168 BOOL32 changed
= FALSE
;
2175 while (pETEchase
->back
->bres
.minor_axis
> AET
->bres
.minor_axis
)
2176 pETEchase
= pETEchase
->back
;
2179 if (pETEchase
!= pETEinsert
)
2181 pETEchaseBackTMP
= pETEchase
->back
;
2182 pETEinsert
->back
->next
= AET
;
2184 AET
->back
= pETEinsert
->back
;
2185 pETEinsert
->next
= pETEchase
;
2186 pETEchase
->back
->next
= pETEinsert
;
2187 pETEchase
->back
= pETEinsert
;
2188 pETEinsert
->back
= pETEchaseBackTMP
;
2195 /***********************************************************************
2196 * REGION_FreeStorage
2200 static void REGION_FreeStorage(ScanLineListBlock
*pSLLBlock
)
2202 ScanLineListBlock
*tmpSLLBlock
;
2206 tmpSLLBlock
= pSLLBlock
->next
;
2207 HeapFree( SystemHeap
, 0, pSLLBlock
);
2208 pSLLBlock
= tmpSLLBlock
;
2213 /***********************************************************************
2214 * REGION_PtsToRegion
2216 * Create an array of rectangles from a list of points.
2218 static int REGION_PtsToRegion(int numFullPtBlocks
, int iCurPtBlock
,
2219 POINTBLOCK
*FirstPtBlock
, WINEREGION
*reg
)
2223 POINTBLOCK
*CurPtBlock
;
2228 extents
= ®
->extents
;
2230 numRects
= ((numFullPtBlocks
* NUMPTSTOBUFFER
) + iCurPtBlock
) >> 1;
2232 if (!(reg
->rects
= HeapReAlloc( SystemHeap
, 0, reg
->rects
,
2233 sizeof(RECT32
) * numRects
)))
2236 reg
->size
= numRects
;
2237 CurPtBlock
= FirstPtBlock
;
2238 rects
= reg
->rects
- 1;
2240 extents
->left
= LARGE_COORDINATE
, extents
->right
= SMALL_COORDINATE
;
2242 for ( ; numFullPtBlocks
>= 0; numFullPtBlocks
--) {
2243 /* the loop uses 2 points per iteration */
2244 i
= NUMPTSTOBUFFER
>> 1;
2245 if (!numFullPtBlocks
)
2246 i
= iCurPtBlock
>> 1;
2247 for (pts
= CurPtBlock
->pts
; i
--; pts
+= 2) {
2248 if (pts
->x
== pts
[1].x
)
2250 if (numRects
&& pts
->x
== rects
->left
&& pts
->y
== rects
->bottom
&&
2251 pts
[1].x
== rects
->right
&&
2252 (numRects
== 1 || rects
[-1].top
!= rects
->top
) &&
2253 (i
&& pts
[2].y
> pts
[1].y
)) {
2254 rects
->bottom
= pts
[1].y
+ 1;
2259 rects
->left
= pts
->x
; rects
->top
= pts
->y
;
2260 rects
->right
= pts
[1].x
; rects
->bottom
= pts
[1].y
+ 1;
2261 if (rects
->left
< extents
->left
)
2262 extents
->left
= rects
->left
;
2263 if (rects
->right
> extents
->right
)
2264 extents
->right
= rects
->right
;
2266 CurPtBlock
= CurPtBlock
->next
;
2270 extents
->top
= reg
->rects
->top
;
2271 extents
->bottom
= rects
->bottom
;
2276 extents
->bottom
= 0;
2278 reg
->numRects
= numRects
;
2283 /***********************************************************************
2284 * CreatePolyPolygonRgn32 (GDI32.57)
2286 HRGN32 WINAPI
CreatePolyPolygonRgn32(const POINT32
*Pts
, const INT32
*Count
,
2287 INT32 nbpolygons
, INT32 mode
)
2292 register EdgeTableEntry
*pAET
; /* Active Edge Table */
2293 register INT32 y
; /* current scanline */
2294 register int iPts
= 0; /* number of pts in buffer */
2295 register EdgeTableEntry
*pWETE
; /* Winding Edge Table Entry*/
2296 register ScanLineList
*pSLL
; /* current scanLineList */
2297 register POINT32
*pts
; /* output buffer */
2298 EdgeTableEntry
*pPrevAET
; /* ptr to previous AET */
2299 EdgeTable ET
; /* header node for ET */
2300 EdgeTableEntry AET
; /* header node for AET */
2301 EdgeTableEntry
*pETEs
; /* EdgeTableEntries pool */
2302 ScanLineListBlock SLLBlock
; /* header for scanlinelist */
2303 int fixWAET
= FALSE
;
2304 POINTBLOCK FirstPtBlock
, *curPtBlock
; /* PtBlock buffers */
2305 POINTBLOCK
*tmpPtBlock
;
2306 int numFullPtBlocks
= 0;
2309 if(!(hrgn
= REGION_CreateRegion()))
2311 obj
= (RGNOBJ
*) GDI_GetObjPtr( hrgn
, REGION_MAGIC
);
2314 /* special case a rectangle */
2316 if (((nbpolygons
== 1) && ((*Count
== 4) ||
2317 ((*Count
== 5) && (Pts
[4].x
== Pts
[0].x
) && (Pts
[4].y
== Pts
[0].y
)))) &&
2318 (((Pts
[0].y
== Pts
[1].y
) &&
2319 (Pts
[1].x
== Pts
[2].x
) &&
2320 (Pts
[2].y
== Pts
[3].y
) &&
2321 (Pts
[3].x
== Pts
[0].x
)) ||
2322 ((Pts
[0].x
== Pts
[1].x
) &&
2323 (Pts
[1].y
== Pts
[2].y
) &&
2324 (Pts
[2].x
== Pts
[3].x
) &&
2325 (Pts
[3].y
== Pts
[0].y
))))
2327 SetRectRgn32( hrgn
, MIN(Pts
[0].x
, Pts
[2].x
), MIN(Pts
[0].y
, Pts
[2].y
),
2328 MAX(Pts
[0].x
, Pts
[2].x
), MAX(Pts
[0].y
, Pts
[2].y
) );
2329 GDI_HEAP_UNLOCK( hrgn
);
2333 for(poly
= total
= 0; poly
< nbpolygons
; poly
++)
2334 total
+= Count
[poly
];
2335 if (! (pETEs
= HeapAlloc( SystemHeap
, 0, sizeof(EdgeTableEntry
) * total
)))
2337 REGION_DeleteObject( hrgn
, obj
);
2340 pts
= FirstPtBlock
.pts
;
2341 REGION_CreateETandAET(Count
, nbpolygons
, Pts
, &ET
, &AET
, pETEs
, &SLLBlock
);
2342 pSLL
= ET
.scanlines
.next
;
2343 curPtBlock
= &FirstPtBlock
;
2345 if (mode
!= WINDING
) {
2349 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++) {
2351 * Add a new edge to the active edge table when we
2352 * get to the next edge.
2354 if (pSLL
!= NULL
&& y
== pSLL
->scanline
) {
2355 REGION_loadAET(&AET
, pSLL
->edgelist
);
2362 * for each active edge
2365 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
2369 * send out the buffer
2371 if (iPts
== NUMPTSTOBUFFER
) {
2372 tmpPtBlock
= HeapAlloc( SystemHeap
, 0, sizeof(POINTBLOCK
));
2374 WARN(region
, "Can't alloc tPB\n");
2377 curPtBlock
->next
= tmpPtBlock
;
2378 curPtBlock
= tmpPtBlock
;
2379 pts
= curPtBlock
->pts
;
2383 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
2385 REGION_InsertionSort(&AET
);
2392 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++) {
2394 * Add a new edge to the active edge table when we
2395 * get to the next edge.
2397 if (pSLL
!= NULL
&& y
== pSLL
->scanline
) {
2398 REGION_loadAET(&AET
, pSLL
->edgelist
);
2399 REGION_computeWAET(&AET
);
2407 * for each active edge
2411 * add to the buffer only those edges that
2412 * are in the Winding active edge table.
2414 if (pWETE
== pAET
) {
2415 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
2419 * send out the buffer
2421 if (iPts
== NUMPTSTOBUFFER
) {
2422 tmpPtBlock
= HeapAlloc( SystemHeap
, 0,
2423 sizeof(POINTBLOCK
) );
2425 WARN(region
, "Can't alloc tPB\n");
2428 curPtBlock
->next
= tmpPtBlock
;
2429 curPtBlock
= tmpPtBlock
;
2430 pts
= curPtBlock
->pts
;
2431 numFullPtBlocks
++; iPts
= 0;
2433 pWETE
= pWETE
->nextWETE
;
2435 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
2439 * recompute the winding active edge table if
2440 * we just resorted or have exited an edge.
2442 if (REGION_InsertionSort(&AET
) || fixWAET
) {
2443 REGION_computeWAET(&AET
);
2448 REGION_FreeStorage(SLLBlock
.next
);
2449 REGION_PtsToRegion(numFullPtBlocks
, iPts
, &FirstPtBlock
, region
);
2450 for (curPtBlock
= FirstPtBlock
.next
; --numFullPtBlocks
>= 0;) {
2451 tmpPtBlock
= curPtBlock
->next
;
2452 HeapFree( SystemHeap
, 0, curPtBlock
);
2453 curPtBlock
= tmpPtBlock
;
2455 HeapFree( SystemHeap
, 0, pETEs
);
2456 GDI_HEAP_UNLOCK( hrgn
);
2461 /***********************************************************************
2462 * CreatePolygonRgn16 (GDI.63)
2464 HRGN16 WINAPI
CreatePolygonRgn16( const POINT16
* points
, INT16 count
,
2467 return CreatePolyPolygonRgn16( points
, &count
, 1, mode
);
2470 /***********************************************************************
2471 * CreatePolyPolygonRgn16 (GDI.451)
2473 HRGN16 WINAPI
CreatePolyPolygonRgn16( const POINT16
*points
,
2474 const INT16
*count
, INT16 nbpolygons
, INT16 mode
)
2481 for (i
= 0; i
< nbpolygons
; i
++)
2483 points32
= HeapAlloc( SystemHeap
, 0, npts
* sizeof(POINT32
) );
2484 for (i
= 0; i
< npts
; i
++)
2485 CONV_POINT16TO32( &(points
[i
]), &(points32
[i
]) );
2487 count32
= HeapAlloc( SystemHeap
, 0, nbpolygons
* sizeof(INT32
) );
2488 for (i
= 0; i
< nbpolygons
; i
++)
2489 count32
[i
] = count
[i
];
2490 hrgn
= CreatePolyPolygonRgn32( points32
, count32
, nbpolygons
, mode
);
2491 HeapFree( SystemHeap
, 0, count32
);
2492 HeapFree( SystemHeap
, 0, points32
);
2496 /***********************************************************************
2497 * CreatePolygonRgn32 (GDI32.58)
2499 HRGN32 WINAPI
CreatePolygonRgn32( const POINT32
*points
, INT32 count
,
2502 return CreatePolyPolygonRgn32( points
, &count
, 1, mode
);