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
11 /************************************************************************
13 Copyright (c) 1987, 1988 X Consortium
15 Permission is hereby granted, free of charge, to any person obtaining a copy
16 of this software and associated documentation files (the "Software"), to deal
17 in the Software without restriction, including without limitation the rights
18 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19 copies of the Software, and to permit persons to whom the Software is
20 furnished to do so, subject to the following conditions:
22 The above copyright notice and this permission notice shall be included in
23 all copies or substantial portions of the Software.
25 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
29 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 Except as contained in this notice, the name of the X Consortium shall not be
33 used in advertising or otherwise to promote the sale, use or other dealings
34 in this Software without prior written authorization from the X Consortium.
37 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
41 Permission to use, copy, modify, and distribute this software and its
42 documentation for any purpose and without fee is hereby granted,
43 provided that the above copyright notice appear in all copies and that
44 both that copyright notice and this permission notice appear in
45 supporting documentation, and that the name of Digital not be
46 used in advertising or publicity pertaining to distribution of the
47 software without specific, written prior permission.
49 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
50 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
51 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
52 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
53 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
54 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
57 ************************************************************************/
59 * The functions in this file implement the Region abstraction, similar to one
60 * used in the X11 sample server. A Region is simply an area, as the name
61 * implies, and is implemented as a "y-x-banded" array of rectangles. To
62 * explain: Each Region is made up of a certain number of rectangles sorted
63 * by y coordinate first, and then by x coordinate.
65 * Furthermore, the rectangles are banded such that every rectangle with a
66 * given upper-left y coordinate (y1) will have the same lower-right y
67 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
68 * will span the entire vertical distance of the band. This means that some
69 * areas that could be merged into a taller rectangle will be represented as
70 * several shorter rectangles to account for shorter rectangles to its left
71 * or right but within its "vertical scope".
73 * An added constraint on the rectangles is that they must cover as much
74 * horizontal area as possible. E.g. no two rectangles in a band are allowed
77 * Whenever possible, bands will be merged together to cover a greater vertical
78 * distance (and thus reduce the number of rectangles). Two bands can be merged
79 * only if the bottom of one touches the top of the other and they have
80 * rectangles in the same places (of the same width, of course). This maintains
81 * the y-x-banding that's so nice to have...
92 DEFAULT_DEBUG_CHANNEL(region)
94 typedef void (*voidProcp)();
96 /* Note the parameter order is different from the X11 equivalents */
98 static void REGION_CopyRegion(WINEREGION *d, WINEREGION *s);
99 static void REGION_IntersectRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
100 static void REGION_UnionRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
101 static void REGION_SubtractRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
102 static void REGION_XorRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
103 static void REGION_UnionRectWithRegion(const RECT *rect, WINEREGION *rgn);
105 #define RGN_DEFAULT_RECTS 2
107 /***********************************************************************
109 * Outputs the contents of a WINEREGION
111 static void REGION_DumpRegion(WINEREGION *pReg)
113 RECT *pRect, *pRectEnd = pReg->rects + pReg->numRects;
115 TRACE(region, "Region %p: %d,%d - %d,%d %d rects\n", pReg,
116 pReg->extents.left, pReg->extents.top,
117 pReg->extents.right, pReg->extents.bottom, pReg->numRects);
118 for(pRect = pReg->rects; pRect < pRectEnd; pRect++)
119 TRACE(region, "\t%d,%d - %d,%d\n", pRect->left, pRect->top,
120 pRect->right, pRect->bottom);
125 /***********************************************************************
126 * REGION_AllocWineRegion
127 * Create a new empty WINEREGION.
129 static WINEREGION *REGION_AllocWineRegion( INT n )
133 if ((pReg = HeapAlloc(SystemHeap, 0, sizeof( WINEREGION ))))
135 if ((pReg->rects = HeapAlloc(SystemHeap, 0, n * sizeof( RECT ))))
141 HeapFree(SystemHeap, 0, pReg);
147 /***********************************************************************
148 * REGION_CreateRegion
149 * Create a new empty region.
151 static HRGN REGION_CreateRegion( INT n )
156 if(!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
158 obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
159 if(!(obj->rgn = REGION_AllocWineRegion(n))) {
160 GDI_FreeObject( hrgn );
163 GDI_HEAP_UNLOCK( hrgn );
168 /***********************************************************************
169 * REGION_DestroyWineRegion
171 static void REGION_DestroyWineRegion( WINEREGION* pReg )
173 HeapFree( SystemHeap, 0, pReg->rects );
174 HeapFree( SystemHeap, 0, pReg );
178 /***********************************************************************
179 * REGION_DeleteObject
181 BOOL REGION_DeleteObject( HRGN hrgn, RGNOBJ * obj )
183 TRACE(region, " %04x\n", hrgn );
185 REGION_DestroyWineRegion( obj->rgn );
186 return GDI_FreeObject( hrgn );
189 /***********************************************************************
190 * OffsetRgn16 (GDI.101)
192 INT16 WINAPI OffsetRgn16( HRGN16 hrgn, INT16 x, INT16 y )
194 return OffsetRgn( hrgn, x, y );
197 /***********************************************************************
198 * OffsetRgn32 (GDI32.256)
200 INT WINAPI OffsetRgn( HRGN hrgn, INT x, INT y )
202 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
207 int nbox = obj->rgn->numRects;
208 RECT *pbox = obj->rgn->rects;
210 TRACE(region, " %04x %d,%d\n", hrgn, x, y );
219 obj->rgn->extents.left += x;
220 obj->rgn->extents.right += x;
221 obj->rgn->extents.top += y;
222 obj->rgn->extents.bottom += y;
224 ret = obj->rgn->type;
225 GDI_HEAP_UNLOCK( hrgn );
232 /***********************************************************************
233 * GetRgnBox16 (GDI.134)
235 INT16 WINAPI GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
238 INT16 ret = (INT16)GetRgnBox( hrgn, &r );
239 CONV_RECT32TO16( &r, rect );
243 /***********************************************************************
244 * GetRgnBox32 (GDI32.219)
246 INT WINAPI GetRgnBox( HRGN hrgn, LPRECT rect )
248 RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
252 TRACE(region, " %04x\n", hrgn );
253 rect->left = obj->rgn->extents.left;
254 rect->top = obj->rgn->extents.top;
255 rect->right = obj->rgn->extents.right;
256 rect->bottom = obj->rgn->extents.bottom;
257 ret = obj->rgn->type;
258 GDI_HEAP_UNLOCK(hrgn);
265 /***********************************************************************
266 * CreateRectRgn16 (GDI.64)
268 * NOTE: Doesn't call CreateRectRgn32 because of differences in SetRectRgn16/32
270 HRGN16 WINAPI CreateRectRgn16(INT16 left, INT16 top, INT16 right, INT16 bottom)
274 if (!(hrgn = (HRGN16)REGION_CreateRegion(RGN_DEFAULT_RECTS)))
277 SetRectRgn16(hrgn, left, top, right, bottom);
282 /***********************************************************************
283 * CreateRectRgn32 (GDI32.59)
285 HRGN WINAPI CreateRectRgn(INT left, INT top, INT right, INT bottom)
289 /* Allocate 2 rects by default to reduce the number of reallocs */
291 if (!(hrgn = REGION_CreateRegion(RGN_DEFAULT_RECTS)))
294 SetRectRgn(hrgn, left, top, right, bottom);
298 /***********************************************************************
299 * CreateRectRgnIndirect16 (GDI.65)
301 HRGN16 WINAPI CreateRectRgnIndirect16( const RECT16* rect )
303 return CreateRectRgn16( rect->left, rect->top, rect->right, rect->bottom );
307 /***********************************************************************
308 * CreateRectRgnIndirect32 (GDI32.60)
310 HRGN WINAPI CreateRectRgnIndirect( const RECT* rect )
312 return CreateRectRgn( rect->left, rect->top, rect->right, rect->bottom );
316 /***********************************************************************
317 * SetRectRgn16 (GDI.172)
319 * NOTE: Win 3.1 sets region to empty if left > right
321 VOID WINAPI SetRectRgn16( HRGN16 hrgn, INT16 left, INT16 top,
322 INT16 right, INT16 bottom )
325 SetRectRgn( hrgn, left, top, right, bottom );
327 SetRectRgn( hrgn, 0, 0, 0, 0 );
331 /***********************************************************************
332 * SetRectRgn32 (GDI32.332)
334 * Allows either or both left and top to be greater than right or bottom.
336 VOID WINAPI SetRectRgn( HRGN hrgn, INT left, INT top,
337 INT right, INT bottom )
341 TRACE(region, " %04x %d,%d-%d,%d\n",
342 hrgn, left, top, right, bottom );
344 if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
346 if (left > right) { INT tmp = left; left = right; right = tmp; }
347 if (top > bottom) { INT tmp = top; top = bottom; bottom = tmp; }
349 if((left != right) && (top != bottom))
351 obj->rgn->rects->left = obj->rgn->extents.left = left;
352 obj->rgn->rects->top = obj->rgn->extents.top = top;
353 obj->rgn->rects->right = obj->rgn->extents.right = right;
354 obj->rgn->rects->bottom = obj->rgn->extents.bottom = bottom;
355 obj->rgn->numRects = 1;
356 obj->rgn->type = SIMPLEREGION;
359 EMPTY_REGION(obj->rgn);
361 GDI_HEAP_UNLOCK( hrgn );
365 /***********************************************************************
366 * CreateRoundRectRgn16 (GDI.444)
368 * If either ellipse dimension is zero we call CreateRectRgn16 for its
369 * `special' behaviour. -ve ellipse dimensions can result in GPFs under win3.1
370 * we just let CreateRoundRectRgn32 convert them to +ve values.
373 HRGN16 WINAPI CreateRoundRectRgn16( INT16 left, INT16 top,
374 INT16 right, INT16 bottom,
375 INT16 ellipse_width, INT16 ellipse_height )
377 if( ellipse_width == 0 || ellipse_height == 0 )
378 return CreateRectRgn16( left, top, right, bottom );
380 return (HRGN16)CreateRoundRectRgn( left, top, right, bottom,
381 ellipse_width, ellipse_height );
384 /***********************************************************************
385 * CreateRoundRectRgn32 (GDI32.61)
387 HRGN WINAPI CreateRoundRectRgn( INT left, INT top,
388 INT right, INT bottom,
389 INT ellipse_width, INT ellipse_height )
393 int asq, bsq, d, xd, yd;
396 /* Check if we can do a normal rectangle instead */
398 if ((ellipse_width == 0) || (ellipse_height == 0))
399 return CreateRectRgn( left, top, right, bottom );
401 /* Make the dimensions sensible */
403 if (left > right) { INT tmp = left; left = right; right = tmp; }
404 if (top > bottom) { INT tmp = top; top = bottom; bottom = tmp; }
406 ellipse_width = abs(ellipse_width);
407 ellipse_height = abs(ellipse_height);
411 d = (ellipse_height < 128) ? ((3 * ellipse_height) >> 2) : 64;
412 if (!(hrgn = REGION_CreateRegion(d))) return 0;
413 obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
414 TRACE(region,"(%d,%d-%d,%d %dx%d): ret=%04x\n",
415 left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
417 /* Check parameters */
419 if (ellipse_width > right-left) ellipse_width = right-left;
420 if (ellipse_height > bottom-top) ellipse_height = bottom-top;
422 /* Ellipse algorithm, based on an article by K. Porter */
423 /* in DDJ Graphics Programming Column, 8/89 */
425 asq = ellipse_width * ellipse_width / 4; /* a^2 */
426 bsq = ellipse_height * ellipse_height / 4; /* b^2 */
427 d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
429 yd = asq * ellipse_height; /* 2a^2b */
431 rect.left = left + ellipse_width / 2;
432 rect.right = right - ellipse_width / 2;
434 /* Loop to draw first half of quadrant */
438 if (d > 0) /* if nearest pixel is toward the center */
440 /* move toward center */
442 rect.bottom = rect.top + 1;
443 REGION_UnionRectWithRegion( &rect, obj->rgn );
445 rect.bottom = rect.top + 1;
446 REGION_UnionRectWithRegion( &rect, obj->rgn );
450 rect.left--; /* next horiz point */
456 /* Loop to draw second half of quadrant */
458 d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
461 /* next vertical point */
463 rect.bottom = rect.top + 1;
464 REGION_UnionRectWithRegion( &rect, obj->rgn );
466 rect.bottom = rect.top + 1;
467 REGION_UnionRectWithRegion( &rect, obj->rgn );
468 if (d < 0) /* if nearest pixel is outside ellipse */
470 rect.left--; /* move away from center */
479 /* Add the inside rectangle */
484 rect.bottom = bottom;
485 REGION_UnionRectWithRegion( &rect, obj->rgn );
487 obj->rgn->type = SIMPLEREGION; /* FIXME? */
488 GDI_HEAP_UNLOCK( hrgn );
493 /***********************************************************************
494 * CreateEllipticRgn16 (GDI.54)
496 HRGN16 WINAPI CreateEllipticRgn16( INT16 left, INT16 top,
497 INT16 right, INT16 bottom )
499 return (HRGN16)CreateRoundRectRgn( left, top, right, bottom,
500 right-left, bottom-top );
504 /***********************************************************************
505 * CreateEllipticRgn32 (GDI32.39)
507 HRGN WINAPI CreateEllipticRgn( INT left, INT top,
508 INT right, INT bottom )
510 return CreateRoundRectRgn( left, top, right, bottom,
511 right-left, bottom-top );
515 /***********************************************************************
516 * CreateEllipticRgnIndirect16 (GDI.55)
518 HRGN16 WINAPI CreateEllipticRgnIndirect16( const RECT16 *rect )
520 return CreateRoundRectRgn( rect->left, rect->top, rect->right,
521 rect->bottom, rect->right - rect->left,
522 rect->bottom - rect->top );
526 /***********************************************************************
527 * CreateEllipticRgnIndirect32 (GDI32.40)
529 HRGN WINAPI CreateEllipticRgnIndirect( const RECT *rect )
531 return CreateRoundRectRgn( rect->left, rect->top, rect->right,
532 rect->bottom, rect->right - rect->left,
533 rect->bottom - rect->top );
536 /***********************************************************************
537 * GetRegionData32 (GDI32.217)
540 DWORD WINAPI GetRegionData(HRGN hrgn, DWORD count, LPRGNDATA rgndata)
543 RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
545 TRACE(region, " %04x count = %ld, rgndata = %p\n",
546 hrgn, count, rgndata);
550 size = obj->rgn->numRects * sizeof(RECT);
551 if(count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
553 GDI_HEAP_UNLOCK( hrgn );
554 return size + sizeof(RGNDATAHEADER);
557 rgndata->rdh.dwSize = sizeof(RGNDATAHEADER);
558 rgndata->rdh.iType = RDH_RECTANGLES;
559 rgndata->rdh.nCount = obj->rgn->numRects;
560 rgndata->rdh.nRgnSize = size;
561 rgndata->rdh.rcBound.left = obj->rgn->extents.left;
562 rgndata->rdh.rcBound.top = obj->rgn->extents.top;
563 rgndata->rdh.rcBound.right = obj->rgn->extents.right;
564 rgndata->rdh.rcBound.bottom = obj->rgn->extents.bottom;
566 memcpy( rgndata->Buffer, obj->rgn->rects, size );
568 GDI_HEAP_UNLOCK( hrgn );
572 /***********************************************************************
573 * GetRegionData16 (GDI.607)
574 * FIXME: is LPRGNDATA the same in Win16 and Win32 ?
576 DWORD WINAPI GetRegionData16(HRGN16 hrgn, DWORD count, LPRGNDATA rgndata)
578 return GetRegionData((HRGN)hrgn, count, rgndata);
581 /***********************************************************************
582 * ExtCreateRegion (GDI32.94)
585 HRGN WINAPI ExtCreateRegion( const XFORM* lpXform, DWORD dwCount, const RGNDATA* rgndata)
589 TRACE(region, " %p %ld %p = ", lpXform, dwCount, rgndata );
592 WARN(region, "(Xform not implemented - ignored) ");
594 if( rgndata->rdh.iType != RDH_RECTANGLES )
596 /* FIXME: We can use CreatePolyPolygonRgn() here
597 * for trapezoidal data */
599 WARN(region, "(Unsupported region data) ");
603 if( (hrgn = REGION_CreateRegion( rgndata->rdh.nCount )) )
605 RECT *pCurRect, *pEndRect;
606 RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
608 pEndRect = (RECT *)rgndata->Buffer + rgndata->rdh.nCount;
609 for(pCurRect = (RECT *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
610 REGION_UnionRectWithRegion( pCurRect, obj->rgn );
611 GDI_HEAP_UNLOCK( hrgn );
613 TRACE(region,"%04x\n", hrgn );
617 WARN(region, "Failed\n");
621 /***********************************************************************
622 * PtInRegion16 (GDI.161)
624 BOOL16 WINAPI PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
626 return PtInRegion( hrgn, x, y );
630 /***********************************************************************
631 * PtInRegion32 (GDI32.278)
633 BOOL WINAPI PtInRegion( HRGN hrgn, INT x, INT y )
637 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
642 if (obj->rgn->numRects > 0 && INRECT(obj->rgn->extents, x, y))
643 for (i = 0; i < obj->rgn->numRects; i++)
644 if (INRECT (obj->rgn->rects[i], x, y))
646 GDI_HEAP_UNLOCK( hrgn );
653 /***********************************************************************
654 * RectInRegion16 (GDI.181)
656 BOOL16 WINAPI RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
660 CONV_RECT16TO32(rect, &r32);
661 return (BOOL16)RectInRegion(hrgn, &r32);
665 /***********************************************************************
666 * RectInRegion32 (GDI32.281)
668 * Returns TRUE if rect is at least partly inside hrgn
670 BOOL WINAPI RectInRegion( HRGN hrgn, const RECT *rect )
674 if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
676 RECT *pCurRect, *pRectEnd;
679 /* this is (just) a useful optimization */
680 if ((obj->rgn->numRects > 0) && EXTENTCHECK(&obj->rgn->extents,
683 for (pCurRect = obj->rgn->rects, pRectEnd = pCurRect +
684 obj->rgn->numRects; pCurRect < pRectEnd; pCurRect++)
686 if (pCurRect->bottom <= rect->top)
687 continue; /* not far enough down yet */
689 if (pCurRect->top >= rect->bottom) {
690 ret = FALSE; /* too far down */
694 if (pCurRect->right <= rect->left)
695 continue; /* not far enough over yet */
697 if (pCurRect->left >= rect->right) {
705 GDI_HEAP_UNLOCK(hrgn);
711 /***********************************************************************
712 * EqualRgn16 (GDI.72)
714 BOOL16 WINAPI EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
716 return EqualRgn( rgn1, rgn2 );
720 /***********************************************************************
721 * EqualRgn32 (GDI32.90)
723 BOOL WINAPI EqualRgn( HRGN hrgn1, HRGN hrgn2 )
728 if ((obj1 = (RGNOBJ *) GDI_GetObjPtr( hrgn1, REGION_MAGIC )))
730 if ((obj2 = (RGNOBJ *) GDI_GetObjPtr( hrgn2, REGION_MAGIC )))
735 if ( obj1->rgn->numRects != obj2->rgn->numRects ) ret = FALSE;
736 else if ( obj1->rgn->numRects == 0 ) ret = TRUE;
737 else if ( !EqualRect(&obj1->rgn->extents, &obj2->rgn->extents) )
739 else for( i = 0; i < obj1->rgn->numRects; i++ ) {
740 if (!EqualRect(obj1->rgn->rects + i, obj2->rgn->rects + i)) {
745 GDI_HEAP_UNLOCK(hrgn2);
747 GDI_HEAP_UNLOCK(hrgn1);
751 /***********************************************************************
752 * REGION_UnionRectWithRegion
753 * Adds a rectangle to a WINEREGION
754 * See below for REGION_UnionRectWithRgn
756 static void REGION_UnionRectWithRegion(const RECT *rect, WINEREGION *rgn)
760 region.rects = ®ion.extents;
763 region.type = SIMPLEREGION;
764 CopyRect(&(region.extents), rect);
765 REGION_UnionRegion(rgn, rgn, ®ion);
769 /***********************************************************************
770 * REGION_UnionRectWithRgn
771 * Adds a rectangle to a HRGN32
772 * A helper used by scroll.c
774 BOOL REGION_UnionRectWithRgn( HRGN hrgn, const RECT *lpRect )
776 RGNOBJ *obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
778 if(!obj) return FALSE;
779 REGION_UnionRectWithRegion( lpRect, obj->rgn );
780 GDI_HEAP_UNLOCK(hrgn);
784 /***********************************************************************
785 * REGION_CreateFrameRgn
787 * Create a region that is a frame around another region.
788 * Expand all rectangles by +/- x and y, then subtract original region.
790 BOOL REGION_FrameRgn( HRGN hDest, HRGN hSrc, INT x, INT y )
793 RGNOBJ *srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
795 if (srcObj->rgn->numRects != 0)
797 RGNOBJ* destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
798 RECT *pRect, *pEndRect;
801 EMPTY_REGION( destObj->rgn );
803 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
804 for(pRect = srcObj->rgn->rects; pRect < pEndRect; pRect++)
806 tempRect.left = pRect->left - x;
807 tempRect.top = pRect->top - y;
808 tempRect.right = pRect->right + x;
809 tempRect.bottom = pRect->bottom + y;
810 REGION_UnionRectWithRegion( &tempRect, destObj->rgn );
812 REGION_SubtractRegion( destObj->rgn, destObj->rgn, srcObj->rgn );
813 GDI_HEAP_UNLOCK ( hDest );
818 GDI_HEAP_UNLOCK( hSrc );
822 /***********************************************************************
825 * Convert region to device co-ords for the supplied dc.
827 BOOL REGION_LPTODP( HDC hdc, HRGN hDest, HRGN hSrc )
829 RECT *pCurRect, *pEndRect;
830 RGNOBJ *srcObj, *destObj;
831 DC * dc = DC_GetDCPtr( hdc );
834 TRACE(region, " hdc=%04x dest=%04x src=%04x\n",
837 if (dc->w.MapMode == MM_TEXT) /* Requires only a translation */
839 if( CombineRgn( hDest, hSrc, 0, RGN_COPY ) == ERROR ) return FALSE;
840 OffsetRgn( hDest, dc->vportOrgX - dc->wndOrgX,
841 dc->vportOrgY - dc->wndOrgY );
845 if(!( srcObj = (RGNOBJ *) GDI_GetObjPtr( hSrc, REGION_MAGIC) ))
847 if(!( destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC) ))
849 GDI_HEAP_UNLOCK( hSrc );
852 EMPTY_REGION( destObj->rgn );
854 pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
855 for(pCurRect = srcObj->rgn->rects; pCurRect < pEndRect; pCurRect++)
858 tmpRect.left = XLPTODP( dc, tmpRect.left );
859 tmpRect.top = YLPTODP( dc, tmpRect.top );
860 tmpRect.right = XLPTODP( dc, tmpRect.right );
861 tmpRect.bottom = YLPTODP( dc, tmpRect.bottom );
862 REGION_UnionRectWithRegion( &tmpRect, destObj->rgn );
865 GDI_HEAP_UNLOCK( hDest );
866 GDI_HEAP_UNLOCK( hSrc );
870 /***********************************************************************
871 * CombineRgn16 (GDI.451)
873 INT16 WINAPI CombineRgn16(HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode)
875 return (INT16)CombineRgn( hDest, hSrc1, hSrc2, mode );
879 /***********************************************************************
880 * CombineRgn32 (GDI32.19)
882 * Note: The behavior is correct even if src and dest regions are the same.
884 INT WINAPI CombineRgn(HRGN hDest, HRGN hSrc1, HRGN hSrc2, INT mode)
886 RGNOBJ *destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC);
889 TRACE(region, " %04x,%04x -> %04x mode=%x\n",
890 hSrc1, hSrc2, hDest, mode );
893 RGNOBJ *src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC);
897 TRACE(region, "dump:\n");
899 REGION_DumpRegion(src1Obj->rgn);
900 if (mode == RGN_COPY)
902 REGION_CopyRegion( destObj->rgn, src1Obj->rgn );
903 result = destObj->rgn->type;
907 RGNOBJ *src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC);
911 TRACE(region, "dump:\n");
913 REGION_DumpRegion(src2Obj->rgn);
917 REGION_IntersectRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn);
920 REGION_UnionRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
923 REGION_XorRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
926 REGION_SubtractRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
929 result = destObj->rgn->type;
930 GDI_HEAP_UNLOCK( hSrc2 );
933 GDI_HEAP_UNLOCK( hSrc1 );
935 TRACE(region, "dump:\n");
937 REGION_DumpRegion(destObj->rgn);
939 GDI_HEAP_UNLOCK( hDest );
944 /***********************************************************************
946 * Re-calculate the extents of a region
948 static void REGION_SetExtents (WINEREGION *pReg)
950 RECT *pRect, *pRectEnd, *pExtents;
952 if (pReg->numRects == 0)
954 pReg->extents.left = 0;
955 pReg->extents.top = 0;
956 pReg->extents.right = 0;
957 pReg->extents.bottom = 0;
961 pExtents = &pReg->extents;
963 pRectEnd = &pRect[pReg->numRects - 1];
966 * Since pRect is the first rectangle in the region, it must have the
967 * smallest top and since pRectEnd is the last rectangle in the region,
968 * it must have the largest bottom, because of banding. Initialize left and
969 * right from pRect and pRectEnd, resp., as good things to initialize them
972 pExtents->left = pRect->left;
973 pExtents->top = pRect->top;
974 pExtents->right = pRectEnd->right;
975 pExtents->bottom = pRectEnd->bottom;
977 while (pRect <= pRectEnd)
979 if (pRect->left < pExtents->left)
980 pExtents->left = pRect->left;
981 if (pRect->right > pExtents->right)
982 pExtents->right = pRect->right;
987 /***********************************************************************
990 static void REGION_CopyRegion(WINEREGION *dst, WINEREGION *src)
992 if (dst != src) /* don't want to copy to itself */
994 if (dst->size < src->numRects)
996 if (! (dst->rects = HeapReAlloc( SystemHeap, 0, dst->rects,
997 src->numRects * sizeof(RECT) )))
999 dst->size = src->numRects;
1001 dst->numRects = src->numRects;
1002 dst->extents.left = src->extents.left;
1003 dst->extents.top = src->extents.top;
1004 dst->extents.right = src->extents.right;
1005 dst->extents.bottom = src->extents.bottom;
1006 dst->type = src->type;
1008 memcpy((char *) dst->rects, (char *) src->rects,
1009 (int) (src->numRects * sizeof(RECT)));
1014 /***********************************************************************
1017 * Attempt to merge the rects in the current band with those in the
1018 * previous one. Used only by REGION_RegionOp.
1021 * The new index for the previous band.
1024 * If coalescing takes place:
1025 * - rectangles in the previous band will have their bottom fields
1027 * - pReg->numRects will be decreased.
1030 static INT REGION_Coalesce (
1031 WINEREGION *pReg, /* Region to coalesce */
1032 INT prevStart, /* Index of start of previous band */
1033 INT curStart /* Index of start of current band */
1035 RECT *pPrevRect; /* Current rect in previous band */
1036 RECT *pCurRect; /* Current rect in current band */
1037 RECT *pRegEnd; /* End of region */
1038 INT curNumRects; /* Number of rectangles in current band */
1039 INT prevNumRects; /* Number of rectangles in previous band */
1040 INT bandtop; /* top coordinate for current band */
1042 pRegEnd = &pReg->rects[pReg->numRects];
1044 pPrevRect = &pReg->rects[prevStart];
1045 prevNumRects = curStart - prevStart;
1048 * Figure out how many rectangles are in the current band. Have to do
1049 * this because multiple bands could have been added in REGION_RegionOp
1050 * at the end when one region has been exhausted.
1052 pCurRect = &pReg->rects[curStart];
1053 bandtop = pCurRect->top;
1054 for (curNumRects = 0;
1055 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
1061 if (pCurRect != pRegEnd)
1064 * If more than one band was added, we have to find the start
1065 * of the last band added so the next coalescing job can start
1066 * at the right place... (given when multiple bands are added,
1067 * this may be pointless -- see above).
1070 while (pRegEnd[-1].top == pRegEnd->top)
1074 curStart = pRegEnd - pReg->rects;
1075 pRegEnd = pReg->rects + pReg->numRects;
1078 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
1079 pCurRect -= curNumRects;
1081 * The bands may only be coalesced if the bottom of the previous
1082 * matches the top scanline of the current.
1084 if (pPrevRect->bottom == pCurRect->top)
1087 * Make sure the bands have rects in the same places. This
1088 * assumes that rects have been added in such a way that they
1089 * cover the most area possible. I.e. two rects in a band must
1090 * have some horizontal space between them.
1094 if ((pPrevRect->left != pCurRect->left) ||
1095 (pPrevRect->right != pCurRect->right))
1098 * The bands don't line up so they can't be coalesced.
1105 } while (prevNumRects != 0);
1107 pReg->numRects -= curNumRects;
1108 pCurRect -= curNumRects;
1109 pPrevRect -= curNumRects;
1112 * The bands may be merged, so set the bottom of each rect
1113 * in the previous band to that of the corresponding rect in
1118 pPrevRect->bottom = pCurRect->bottom;
1122 } while (curNumRects != 0);
1125 * If only one band was added to the region, we have to backup
1126 * curStart to the start of the previous band.
1128 * If more than one band was added to the region, copy the
1129 * other bands down. The assumption here is that the other bands
1130 * came from the same region as the current one and no further
1131 * coalescing can be done on them since it's all been done
1132 * already... curStart is already in the right place.
1134 if (pCurRect == pRegEnd)
1136 curStart = prevStart;
1142 *pPrevRect++ = *pCurRect++;
1143 } while (pCurRect != pRegEnd);
1151 /***********************************************************************
1154 * Apply an operation to two regions. Called by REGION_Union,
1155 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
1161 * The new region is overwritten.
1164 * The idea behind this function is to view the two regions as sets.
1165 * Together they cover a rectangle of area that this function divides
1166 * into horizontal bands where points are covered only by one region
1167 * or by both. For the first case, the nonOverlapFunc is called with
1168 * each the band and the band's upper and lower extents. For the
1169 * second, the overlapFunc is called to process the entire band. It
1170 * is responsible for clipping the rectangles in the band, though
1171 * this function provides the boundaries.
1172 * At the end of each band, the new region is coalesced, if possible,
1173 * to reduce the number of rectangles in the region.
1176 static void REGION_RegionOp(
1177 WINEREGION *newReg, /* Place to store result */
1178 WINEREGION *reg1, /* First region in operation */
1179 WINEREGION *reg2, /* 2nd region in operation */
1180 void (*overlapFunc)(), /* Function to call for over-lapping bands */
1181 void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
1182 void (*nonOverlap2Func)() /* Function to call for non-overlapping bands in region 2 */
1184 RECT *r1; /* Pointer into first region */
1185 RECT *r2; /* Pointer into 2d region */
1186 RECT *r1End; /* End of 1st region */
1187 RECT *r2End; /* End of 2d region */
1188 INT ybot; /* Bottom of intersection */
1189 INT ytop; /* Top of intersection */
1190 RECT *oldRects; /* Old rects for newReg */
1191 INT prevBand; /* Index of start of
1192 * previous band in newReg */
1193 INT curBand; /* Index of start of current
1195 RECT *r1BandEnd; /* End of current band in r1 */
1196 RECT *r2BandEnd; /* End of current band in r2 */
1197 INT top; /* Top of non-overlapping band */
1198 INT bot; /* Bottom of non-overlapping band */
1202 * set r1, r2, r1End and r2End appropriately, preserve the important
1203 * parts of the destination region until the end in case it's one of
1204 * the two source regions, then mark the "new" region empty, allocating
1205 * another array of rectangles for it to use.
1209 r1End = r1 + reg1->numRects;
1210 r2End = r2 + reg2->numRects;
1214 * newReg may be one of the src regions so we can't empty it. We keep a
1215 * note of its rects pointer (so that we can free them later), preserve its
1216 * extents and simply set numRects to zero.
1219 oldRects = newReg->rects;
1220 newReg->numRects = 0;
1223 * Allocate a reasonable number of rectangles for the new region. The idea
1224 * is to allocate enough so the individual functions don't need to
1225 * reallocate and copy the array, which is time consuming, yet we don't
1226 * have to worry about using too much memory. I hope to be able to
1227 * nuke the Xrealloc() at the end of this function eventually.
1229 newReg->size = MAX(reg1->numRects,reg2->numRects) * 2;
1231 if (! (newReg->rects = HeapAlloc( SystemHeap, 0,
1232 sizeof(RECT) * newReg->size )))
1239 * Initialize ybot and ytop.
1240 * In the upcoming loop, ybot and ytop serve different functions depending
1241 * on whether the band being handled is an overlapping or non-overlapping
1243 * In the case of a non-overlapping band (only one of the regions
1244 * has points in the band), ybot is the bottom of the most recent
1245 * intersection and thus clips the top of the rectangles in that band.
1246 * ytop is the top of the next intersection between the two regions and
1247 * serves to clip the bottom of the rectangles in the current band.
1248 * For an overlapping band (where the two regions intersect), ytop clips
1249 * the top of the rectangles of both regions and ybot clips the bottoms.
1251 if (reg1->extents.top < reg2->extents.top)
1252 ybot = reg1->extents.top;
1254 ybot = reg2->extents.top;
1257 * prevBand serves to mark the start of the previous band so rectangles
1258 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1259 * In the beginning, there is no previous band, so prevBand == curBand
1260 * (curBand is set later on, of course, but the first band will always
1261 * start at index 0). prevBand and curBand must be indices because of
1262 * the possible expansion, and resultant moving, of the new region's
1263 * array of rectangles.
1269 curBand = newReg->numRects;
1272 * This algorithm proceeds one source-band (as opposed to a
1273 * destination band, which is determined by where the two regions
1274 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1275 * rectangle after the last one in the current band for their
1276 * respective regions.
1279 while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
1285 while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
1291 * First handle the band that doesn't intersect, if any.
1293 * Note that attention is restricted to one band in the
1294 * non-intersecting region at once, so if a region has n
1295 * bands between the current position and the next place it overlaps
1296 * the other, this entire loop will be passed through n times.
1298 if (r1->top < r2->top)
1300 top = MAX(r1->top,ybot);
1301 bot = MIN(r1->bottom,r2->top);
1303 if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
1305 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
1310 else if (r2->top < r1->top)
1312 top = MAX(r2->top,ybot);
1313 bot = MIN(r2->bottom,r1->top);
1315 if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
1317 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
1328 * If any rectangles got added to the region, try and coalesce them
1329 * with rectangles from the previous band. Note we could just do
1330 * this test in miCoalesce, but some machines incur a not
1331 * inconsiderable cost for function calls, so...
1333 if (newReg->numRects != curBand)
1335 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1339 * Now see if we've hit an intersecting band. The two bands only
1340 * intersect if ybot > ytop
1342 ybot = MIN(r1->bottom, r2->bottom);
1343 curBand = newReg->numRects;
1346 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1350 if (newReg->numRects != curBand)
1352 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1356 * If we've finished with a band (bottom == ybot) we skip forward
1357 * in the region to the next band.
1359 if (r1->bottom == ybot)
1363 if (r2->bottom == ybot)
1367 } while ((r1 != r1End) && (r2 != r2End));
1370 * Deal with whichever region still has rectangles left.
1372 curBand = newReg->numRects;
1375 if (nonOverlap1Func != (void (*)())NULL)
1380 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
1384 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
1385 MAX(r1->top,ybot), r1->bottom);
1387 } while (r1 != r1End);
1390 else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
1395 while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
1399 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
1400 MAX(r2->top,ybot), r2->bottom);
1402 } while (r2 != r2End);
1405 if (newReg->numRects != curBand)
1407 (void) REGION_Coalesce (newReg, prevBand, curBand);
1411 * A bit of cleanup. To keep regions from growing without bound,
1412 * we shrink the array of rectangles to match the new number of
1413 * rectangles in the region. This never goes to 0, however...
1415 * Only do this stuff if the number of rectangles allocated is more than
1416 * twice the number of rectangles in the region (a simple optimization...).
1418 if ((newReg->numRects < (newReg->size >> 1)) && (newReg->numRects > 2))
1420 if (REGION_NOT_EMPTY(newReg))
1422 RECT *prev_rects = newReg->rects;
1423 newReg->size = newReg->numRects;
1424 newReg->rects = HeapReAlloc( SystemHeap, 0, newReg->rects,
1425 sizeof(RECT) * newReg->size );
1426 if (! newReg->rects)
1427 newReg->rects = prev_rects;
1432 * No point in doing the extra work involved in an Xrealloc if
1433 * the region is empty
1436 HeapFree( SystemHeap, 0, newReg->rects );
1437 newReg->rects = HeapAlloc( SystemHeap, 0, sizeof(RECT) );
1440 HeapFree( SystemHeap, 0, oldRects );
1444 /***********************************************************************
1445 * Region Intersection
1446 ***********************************************************************/
1449 /***********************************************************************
1452 * Handle an overlapping band for REGION_Intersect.
1458 * Rectangles may be added to the region.
1461 static void REGION_IntersectO(WINEREGION *pReg, RECT *r1, RECT *r1End,
1462 RECT *r2, RECT *r2End, INT top, INT bottom)
1468 pNextRect = &pReg->rects[pReg->numRects];
1470 while ((r1 != r1End) && (r2 != r2End))
1472 left = MAX(r1->left, r2->left);
1473 right = MIN(r1->right, r2->right);
1476 * If there's any overlap between the two rectangles, add that
1477 * overlap to the new region.
1478 * There's no need to check for subsumption because the only way
1479 * such a need could arise is if some region has two rectangles
1480 * right next to each other. Since that should never happen...
1484 MEMCHECK(pReg, pNextRect, pReg->rects);
1485 pNextRect->left = left;
1486 pNextRect->top = top;
1487 pNextRect->right = right;
1488 pNextRect->bottom = bottom;
1489 pReg->numRects += 1;
1494 * Need to advance the pointers. Shift the one that extends
1495 * to the right the least, since the other still has a chance to
1496 * overlap with that region's next rectangle, if you see what I mean.
1498 if (r1->right < r2->right)
1502 else if (r2->right < r1->right)
1515 /***********************************************************************
1516 * REGION_IntersectRegion
1518 static void REGION_IntersectRegion(WINEREGION *newReg, WINEREGION *reg1,
1521 /* check for trivial reject */
1522 if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
1523 (!EXTENTCHECK(®1->extents, ®2->extents)))
1524 newReg->numRects = 0;
1526 REGION_RegionOp (newReg, reg1, reg2,
1527 (voidProcp) REGION_IntersectO, (voidProcp) NULL, (voidProcp) NULL);
1530 * Can't alter newReg's extents before we call miRegionOp because
1531 * it might be one of the source regions and miRegionOp depends
1532 * on the extents of those regions being the same. Besides, this
1533 * way there's no checking against rectangles that will be nuked
1534 * due to coalescing, so we have to examine fewer rectangles.
1536 REGION_SetExtents(newReg);
1537 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1541 /***********************************************************************
1543 ***********************************************************************/
1545 /***********************************************************************
1548 * Handle a non-overlapping band for the union operation. Just
1549 * Adds the rectangles into the region. Doesn't have to check for
1550 * subsumption or anything.
1556 * pReg->numRects is incremented and the final rectangles overwritten
1557 * with the rectangles we're passed.
1560 static void REGION_UnionNonO (WINEREGION *pReg, RECT *r, RECT *rEnd,
1561 INT top, INT bottom)
1565 pNextRect = &pReg->rects[pReg->numRects];
1569 MEMCHECK(pReg, pNextRect, pReg->rects);
1570 pNextRect->left = r->left;
1571 pNextRect->top = top;
1572 pNextRect->right = r->right;
1573 pNextRect->bottom = bottom;
1574 pReg->numRects += 1;
1581 /***********************************************************************
1584 * Handle an overlapping band for the union operation. Picks the
1585 * left-most rectangle each time and merges it into the region.
1591 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1595 static void REGION_UnionO (WINEREGION *pReg, RECT *r1, RECT *r1End,
1596 RECT *r2, RECT *r2End, INT top, INT bottom)
1600 pNextRect = &pReg->rects[pReg->numRects];
1602 #define MERGERECT(r) \
1603 if ((pReg->numRects != 0) && \
1604 (pNextRect[-1].top == top) && \
1605 (pNextRect[-1].bottom == bottom) && \
1606 (pNextRect[-1].right >= r->left)) \
1608 if (pNextRect[-1].right < r->right) \
1610 pNextRect[-1].right = r->right; \
1615 MEMCHECK(pReg, pNextRect, pReg->rects); \
1616 pNextRect->top = top; \
1617 pNextRect->bottom = bottom; \
1618 pNextRect->left = r->left; \
1619 pNextRect->right = r->right; \
1620 pReg->numRects += 1; \
1625 while ((r1 != r1End) && (r2 != r2End))
1627 if (r1->left < r2->left)
1642 } while (r1 != r1End);
1644 else while (r2 != r2End)
1651 /***********************************************************************
1652 * REGION_UnionRegion
1654 static void REGION_UnionRegion(WINEREGION *newReg, WINEREGION *reg1,
1657 /* checks all the simple cases */
1660 * Region 1 and 2 are the same or region 1 is empty
1662 if ( (reg1 == reg2) || (!(reg1->numRects)) )
1665 REGION_CopyRegion(newReg, reg2);
1670 * if nothing to union (region 2 empty)
1672 if (!(reg2->numRects))
1675 REGION_CopyRegion(newReg, reg1);
1680 * Region 1 completely subsumes region 2
1682 if ((reg1->numRects == 1) &&
1683 (reg1->extents.left <= reg2->extents.left) &&
1684 (reg1->extents.top <= reg2->extents.top) &&
1685 (reg1->extents.right >= reg2->extents.right) &&
1686 (reg1->extents.bottom >= reg2->extents.bottom))
1689 REGION_CopyRegion(newReg, reg1);
1694 * Region 2 completely subsumes region 1
1696 if ((reg2->numRects == 1) &&
1697 (reg2->extents.left <= reg1->extents.left) &&
1698 (reg2->extents.top <= reg1->extents.top) &&
1699 (reg2->extents.right >= reg1->extents.right) &&
1700 (reg2->extents.bottom >= reg1->extents.bottom))
1703 REGION_CopyRegion(newReg, reg2);
1707 REGION_RegionOp (newReg, reg1, reg2, (voidProcp) REGION_UnionO,
1708 (voidProcp) REGION_UnionNonO, (voidProcp) REGION_UnionNonO);
1710 newReg->extents.left = MIN(reg1->extents.left, reg2->extents.left);
1711 newReg->extents.top = MIN(reg1->extents.top, reg2->extents.top);
1712 newReg->extents.right = MAX(reg1->extents.right, reg2->extents.right);
1713 newReg->extents.bottom = MAX(reg1->extents.bottom, reg2->extents.bottom);
1714 newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1718 /***********************************************************************
1719 * Region Subtraction
1720 ***********************************************************************/
1722 /***********************************************************************
1723 * REGION_SubtractNonO1
1725 * Deal with non-overlapping band for subtraction. Any parts from
1726 * region 2 we discard. Anything from region 1 we add to the region.
1732 * pReg may be affected.
1735 static void REGION_SubtractNonO1 (WINEREGION *pReg, RECT *r, RECT *rEnd,
1736 INT top, INT bottom)
1740 pNextRect = &pReg->rects[pReg->numRects];
1744 MEMCHECK(pReg, pNextRect, pReg->rects);
1745 pNextRect->left = r->left;
1746 pNextRect->top = top;
1747 pNextRect->right = r->right;
1748 pNextRect->bottom = bottom;
1749 pReg->numRects += 1;
1757 /***********************************************************************
1760 * Overlapping band subtraction. x1 is the left-most point not yet
1767 * pReg may have rectangles added to it.
1770 static void REGION_SubtractO (WINEREGION *pReg, RECT *r1, RECT *r1End,
1771 RECT *r2, RECT *r2End, INT top, INT bottom)
1777 pNextRect = &pReg->rects[pReg->numRects];
1779 while ((r1 != r1End) && (r2 != r2End))
1781 if (r2->right <= left)
1784 * Subtrahend missed the boat: go to next subtrahend.
1788 else if (r2->left <= left)
1791 * Subtrahend preceeds minuend: nuke left edge of minuend.
1794 if (left >= r1->right)
1797 * Minuend completely covered: advance to next minuend and
1798 * reset left fence to edge of new minuend.
1807 * Subtrahend now used up since it doesn't extend beyond
1813 else if (r2->left < r1->right)
1816 * Left part of subtrahend covers part of minuend: add uncovered
1817 * part of minuend to region and skip to next subtrahend.
1819 MEMCHECK(pReg, pNextRect, pReg->rects);
1820 pNextRect->left = left;
1821 pNextRect->top = top;
1822 pNextRect->right = r2->left;
1823 pNextRect->bottom = bottom;
1824 pReg->numRects += 1;
1827 if (left >= r1->right)
1830 * Minuend used up: advance to new...
1839 * Subtrahend used up
1847 * Minuend used up: add any remaining piece before advancing.
1849 if (r1->right > left)
1851 MEMCHECK(pReg, pNextRect, pReg->rects);
1852 pNextRect->left = left;
1853 pNextRect->top = top;
1854 pNextRect->right = r1->right;
1855 pNextRect->bottom = bottom;
1856 pReg->numRects += 1;
1865 * Add remaining minuend rectangles to region.
1869 MEMCHECK(pReg, pNextRect, pReg->rects);
1870 pNextRect->left = left;
1871 pNextRect->top = top;
1872 pNextRect->right = r1->right;
1873 pNextRect->bottom = bottom;
1874 pReg->numRects += 1;
1885 /***********************************************************************
1886 * REGION_SubtractRegion
1888 * Subtract regS from regM and leave the result in regD.
1889 * S stands for subtrahend, M for minuend and D for difference.
1895 * regD is overwritten.
1898 static void REGION_SubtractRegion(WINEREGION *regD, WINEREGION *regM,
1901 /* check for trivial reject */
1902 if ( (!(regM->numRects)) || (!(regS->numRects)) ||
1903 (!EXTENTCHECK(®M->extents, ®S->extents)) )
1905 REGION_CopyRegion(regD, regM);
1909 REGION_RegionOp (regD, regM, regS, (voidProcp) REGION_SubtractO,
1910 (voidProcp) REGION_SubtractNonO1, (voidProcp) NULL);
1913 * Can't alter newReg's extents before we call miRegionOp because
1914 * it might be one of the source regions and miRegionOp depends
1915 * on the extents of those regions being the unaltered. Besides, this
1916 * way there's no checking against rectangles that will be nuked
1917 * due to coalescing, so we have to examine fewer rectangles.
1919 REGION_SetExtents (regD);
1920 regD->type = (regD->numRects) ? COMPLEXREGION : NULLREGION ;
1924 /***********************************************************************
1927 static void REGION_XorRegion(WINEREGION *dr, WINEREGION *sra,
1930 WINEREGION *tra, *trb;
1932 if ((! (tra = REGION_AllocWineRegion(sra->numRects + 1))) ||
1933 (! (trb = REGION_AllocWineRegion(srb->numRects + 1))))
1935 REGION_SubtractRegion(tra,sra,srb);
1936 REGION_SubtractRegion(trb,srb,sra);
1937 REGION_UnionRegion(dr,tra,trb);
1938 REGION_DestroyWineRegion(tra);
1939 REGION_DestroyWineRegion(trb);
1943 /**************************************************************************
1947 *************************************************************************/
1949 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
1950 #define SMALL_COORDINATE 0x80000000
1952 /***********************************************************************
1953 * REGION_InsertEdgeInET
1955 * Insert the given edge into the edge table.
1956 * First we must find the correct bucket in the
1957 * Edge table, then find the right slot in the
1958 * bucket. Finally, we can insert it.
1961 static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
1962 INT scanline, ScanLineListBlock **SLLBlock, INT *iSLLBlock)
1965 EdgeTableEntry *start, *prev;
1966 ScanLineList *pSLL, *pPrevSLL;
1967 ScanLineListBlock *tmpSLLBlock;
1970 * find the right bucket to put the edge into
1972 pPrevSLL = &ET->scanlines;
1973 pSLL = pPrevSLL->next;
1974 while (pSLL && (pSLL->scanline < scanline))
1981 * reassign pSLL (pointer to ScanLineList) if necessary
1983 if ((!pSLL) || (pSLL->scanline > scanline))
1985 if (*iSLLBlock > SLLSPERBLOCK-1)
1987 tmpSLLBlock = HeapAlloc( SystemHeap, 0, sizeof(ScanLineListBlock));
1990 WARN(region, "Can't alloc SLLB\n");
1993 (*SLLBlock)->next = tmpSLLBlock;
1994 tmpSLLBlock->next = (ScanLineListBlock *)NULL;
1995 *SLLBlock = tmpSLLBlock;
1998 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
2000 pSLL->next = pPrevSLL->next;
2001 pSLL->edgelist = (EdgeTableEntry *)NULL;
2002 pPrevSLL->next = pSLL;
2004 pSLL->scanline = scanline;
2007 * now insert the edge in the right bucket
2009 prev = (EdgeTableEntry *)NULL;
2010 start = pSLL->edgelist;
2011 while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
2014 start = start->next;
2021 pSLL->edgelist = ETE;
2024 /***********************************************************************
2025 * REGION_CreateEdgeTable
2027 * This routine creates the edge table for
2028 * scan converting polygons.
2029 * The Edge Table (ET) looks like:
2033 * | ymax | ScanLineLists
2034 * |scanline|-->------------>-------------->...
2035 * -------- |scanline| |scanline|
2036 * |edgelist| |edgelist|
2037 * --------- ---------
2041 * list of ETEs list of ETEs
2043 * where ETE is an EdgeTableEntry data structure,
2044 * and there is one ScanLineList per scanline at
2045 * which an edge is initially entered.
2048 static void REGION_CreateETandAET(const INT *Count, INT nbpolygons,
2049 const POINT *pts, EdgeTable *ET, EdgeTableEntry *AET,
2050 EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
2052 const POINT *top, *bottom;
2053 const POINT *PrevPt, *CurrPt, *EndPt;
2060 * initialize the Active Edge Table
2062 AET->next = (EdgeTableEntry *)NULL;
2063 AET->back = (EdgeTableEntry *)NULL;
2064 AET->nextWETE = (EdgeTableEntry *)NULL;
2065 AET->bres.minor_axis = SMALL_COORDINATE;
2068 * initialize the Edge Table.
2070 ET->scanlines.next = (ScanLineList *)NULL;
2071 ET->ymax = SMALL_COORDINATE;
2072 ET->ymin = LARGE_COORDINATE;
2073 pSLLBlock->next = (ScanLineListBlock *)NULL;
2076 for(poly = 0; poly < nbpolygons; poly++)
2078 count = Count[poly];
2086 * for each vertex in the array of points.
2087 * In this loop we are dealing with two vertices at
2088 * a time -- these make up one edge of the polygon.
2095 * find out which point is above and which is below.
2097 if (PrevPt->y > CurrPt->y)
2099 bottom = PrevPt, top = CurrPt;
2100 pETEs->ClockWise = 0;
2104 bottom = CurrPt, top = PrevPt;
2105 pETEs->ClockWise = 1;
2109 * don't add horizontal edges to the Edge table.
2111 if (bottom->y != top->y)
2113 pETEs->ymax = bottom->y-1;
2114 /* -1 so we don't get last scanline */
2117 * initialize integer edge algorithm
2119 dy = bottom->y - top->y;
2120 BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
2122 REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
2125 if (PrevPt->y > ET->ymax)
2126 ET->ymax = PrevPt->y;
2127 if (PrevPt->y < ET->ymin)
2128 ET->ymin = PrevPt->y;
2137 /***********************************************************************
2140 * This routine moves EdgeTableEntries from the
2141 * EdgeTable into the Active Edge Table,
2142 * leaving them sorted by smaller x coordinate.
2145 static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
2147 EdgeTableEntry *pPrevAET;
2148 EdgeTableEntry *tmp;
2154 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
2163 ETEs->back = pPrevAET;
2164 pPrevAET->next = ETEs;
2171 /***********************************************************************
2172 * REGION_computeWAET
2174 * This routine links the AET by the
2175 * nextWETE (winding EdgeTableEntry) link for
2176 * use by the winding number rule. The final
2177 * Active Edge Table (AET) might look something
2181 * ---------- --------- ---------
2182 * |ymax | |ymax | |ymax |
2183 * | ... | |... | |... |
2184 * |next |->|next |->|next |->...
2185 * |nextWETE| |nextWETE| |nextWETE|
2186 * --------- --------- ^--------
2188 * V-------------------> V---> ...
2191 static void REGION_computeWAET(EdgeTableEntry *AET)
2193 register EdgeTableEntry *pWETE;
2194 register int inside = 1;
2195 register int isInside = 0;
2197 AET->nextWETE = (EdgeTableEntry *)NULL;
2207 if ((!inside && !isInside) ||
2208 ( inside && isInside))
2210 pWETE->nextWETE = AET;
2216 pWETE->nextWETE = (EdgeTableEntry *)NULL;
2219 /***********************************************************************
2220 * REGION_InsertionSort
2222 * Just a simple insertion sort using
2223 * pointers and back pointers to sort the Active
2227 static BOOL REGION_InsertionSort(EdgeTableEntry *AET)
2229 EdgeTableEntry *pETEchase;
2230 EdgeTableEntry *pETEinsert;
2231 EdgeTableEntry *pETEchaseBackTMP;
2232 BOOL changed = FALSE;
2239 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
2240 pETEchase = pETEchase->back;
2243 if (pETEchase != pETEinsert)
2245 pETEchaseBackTMP = pETEchase->back;
2246 pETEinsert->back->next = AET;
2248 AET->back = pETEinsert->back;
2249 pETEinsert->next = pETEchase;
2250 pETEchase->back->next = pETEinsert;
2251 pETEchase->back = pETEinsert;
2252 pETEinsert->back = pETEchaseBackTMP;
2259 /***********************************************************************
2260 * REGION_FreeStorage
2264 static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
2266 ScanLineListBlock *tmpSLLBlock;
2270 tmpSLLBlock = pSLLBlock->next;
2271 HeapFree( SystemHeap, 0, pSLLBlock );
2272 pSLLBlock = tmpSLLBlock;
2277 /***********************************************************************
2278 * REGION_PtsToRegion
2280 * Create an array of rectangles from a list of points.
2282 static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
2283 POINTBLOCK *FirstPtBlock, WINEREGION *reg)
2287 POINTBLOCK *CurPtBlock;
2292 extents = ®->extents;
2294 numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
2296 if (!(reg->rects = HeapReAlloc( SystemHeap, 0, reg->rects,
2297 sizeof(RECT) * numRects )))
2300 reg->size = numRects;
2301 CurPtBlock = FirstPtBlock;
2302 rects = reg->rects - 1;
2304 extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
2306 for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
2307 /* the loop uses 2 points per iteration */
2308 i = NUMPTSTOBUFFER >> 1;
2309 if (!numFullPtBlocks)
2310 i = iCurPtBlock >> 1;
2311 for (pts = CurPtBlock->pts; i--; pts += 2) {
2312 if (pts->x == pts[1].x)
2314 if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
2315 pts[1].x == rects->right &&
2316 (numRects == 1 || rects[-1].top != rects->top) &&
2317 (i && pts[2].y > pts[1].y)) {
2318 rects->bottom = pts[1].y + 1;
2323 rects->left = pts->x; rects->top = pts->y;
2324 rects->right = pts[1].x; rects->bottom = pts[1].y + 1;
2325 if (rects->left < extents->left)
2326 extents->left = rects->left;
2327 if (rects->right > extents->right)
2328 extents->right = rects->right;
2330 CurPtBlock = CurPtBlock->next;
2334 extents->top = reg->rects->top;
2335 extents->bottom = rects->bottom;
2340 extents->bottom = 0;
2342 reg->numRects = numRects;
2347 /***********************************************************************
2348 * CreatePolyPolygonRgn32 (GDI32.57)
2350 HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count,
2351 INT nbpolygons, INT mode)
2356 register EdgeTableEntry *pAET; /* Active Edge Table */
2357 register INT y; /* current scanline */
2358 register int iPts = 0; /* number of pts in buffer */
2359 register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
2360 register ScanLineList *pSLL; /* current scanLineList */
2361 register POINT *pts; /* output buffer */
2362 EdgeTableEntry *pPrevAET; /* ptr to previous AET */
2363 EdgeTable ET; /* header node for ET */
2364 EdgeTableEntry AET; /* header node for AET */
2365 EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
2366 ScanLineListBlock SLLBlock; /* header for scanlinelist */
2367 int fixWAET = FALSE;
2368 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
2369 POINTBLOCK *tmpPtBlock;
2370 int numFullPtBlocks = 0;
2373 if(!(hrgn = REGION_CreateRegion(nbpolygons)))
2375 obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
2378 /* special case a rectangle */
2380 if (((nbpolygons == 1) && ((*Count == 4) ||
2381 ((*Count == 5) && (Pts[4].x == Pts[0].x) && (Pts[4].y == Pts[0].y)))) &&
2382 (((Pts[0].y == Pts[1].y) &&
2383 (Pts[1].x == Pts[2].x) &&
2384 (Pts[2].y == Pts[3].y) &&
2385 (Pts[3].x == Pts[0].x)) ||
2386 ((Pts[0].x == Pts[1].x) &&
2387 (Pts[1].y == Pts[2].y) &&
2388 (Pts[2].x == Pts[3].x) &&
2389 (Pts[3].y == Pts[0].y))))
2391 SetRectRgn( hrgn, MIN(Pts[0].x, Pts[2].x), MIN(Pts[0].y, Pts[2].y),
2392 MAX(Pts[0].x, Pts[2].x), MAX(Pts[0].y, Pts[2].y) );
2393 GDI_HEAP_UNLOCK( hrgn );
2397 for(poly = total = 0; poly < nbpolygons; poly++)
2398 total += Count[poly];
2399 if (! (pETEs = HeapAlloc( SystemHeap, 0, sizeof(EdgeTableEntry) * total )))
2401 REGION_DeleteObject( hrgn, obj );
2404 pts = FirstPtBlock.pts;
2405 REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
2406 pSLL = ET.scanlines.next;
2407 curPtBlock = &FirstPtBlock;
2409 if (mode != WINDING) {
2413 for (y = ET.ymin; y < ET.ymax; y++) {
2415 * Add a new edge to the active edge table when we
2416 * get to the next edge.
2418 if (pSLL != NULL && y == pSLL->scanline) {
2419 REGION_loadAET(&AET, pSLL->edgelist);
2426 * for each active edge
2429 pts->x = pAET->bres.minor_axis, pts->y = y;
2433 * send out the buffer
2435 if (iPts == NUMPTSTOBUFFER) {
2436 tmpPtBlock = HeapAlloc( SystemHeap, 0, sizeof(POINTBLOCK));
2438 WARN(region, "Can't alloc tPB\n");
2441 curPtBlock->next = tmpPtBlock;
2442 curPtBlock = tmpPtBlock;
2443 pts = curPtBlock->pts;
2447 EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
2449 REGION_InsertionSort(&AET);
2456 for (y = ET.ymin; y < ET.ymax; y++) {
2458 * Add a new edge to the active edge table when we
2459 * get to the next edge.
2461 if (pSLL != NULL && y == pSLL->scanline) {
2462 REGION_loadAET(&AET, pSLL->edgelist);
2463 REGION_computeWAET(&AET);
2471 * for each active edge
2475 * add to the buffer only those edges that
2476 * are in the Winding active edge table.
2478 if (pWETE == pAET) {
2479 pts->x = pAET->bres.minor_axis, pts->y = y;
2483 * send out the buffer
2485 if (iPts == NUMPTSTOBUFFER) {
2486 tmpPtBlock = HeapAlloc( SystemHeap, 0,
2487 sizeof(POINTBLOCK) );
2489 WARN(region, "Can't alloc tPB\n");
2492 curPtBlock->next = tmpPtBlock;
2493 curPtBlock = tmpPtBlock;
2494 pts = curPtBlock->pts;
2495 numFullPtBlocks++; iPts = 0;
2497 pWETE = pWETE->nextWETE;
2499 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
2503 * recompute the winding active edge table if
2504 * we just resorted or have exited an edge.
2506 if (REGION_InsertionSort(&AET) || fixWAET) {
2507 REGION_computeWAET(&AET);
2512 REGION_FreeStorage(SLLBlock.next);
2513 REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
2514 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
2515 tmpPtBlock = curPtBlock->next;
2516 HeapFree( SystemHeap, 0, curPtBlock );
2517 curPtBlock = tmpPtBlock;
2519 HeapFree( SystemHeap, 0, pETEs );
2520 GDI_HEAP_UNLOCK( hrgn );
2525 /***********************************************************************
2526 * CreatePolygonRgn16 (GDI.63)
2528 HRGN16 WINAPI CreatePolygonRgn16( const POINT16 * points, INT16 count,
2531 return CreatePolyPolygonRgn16( points, &count, 1, mode );
2534 /***********************************************************************
2535 * CreatePolyPolygonRgn16 (GDI.451)
2537 HRGN16 WINAPI CreatePolyPolygonRgn16( const POINT16 *points,
2538 const INT16 *count, INT16 nbpolygons, INT16 mode )
2545 for (i = 0; i < nbpolygons; i++)
2547 points32 = HeapAlloc( SystemHeap, 0, npts * sizeof(POINT) );
2548 for (i = 0; i < npts; i++)
2549 CONV_POINT16TO32( &(points[i]), &(points32[i]) );
2551 count32 = HeapAlloc( SystemHeap, 0, nbpolygons * sizeof(INT) );
2552 for (i = 0; i < nbpolygons; i++)
2553 count32[i] = count[i];
2554 hrgn = CreatePolyPolygonRgn( points32, count32, nbpolygons, mode );
2555 HeapFree( SystemHeap, 0, count32 );
2556 HeapFree( SystemHeap, 0, points32 );
2560 /***********************************************************************
2561 * CreatePolygonRgn32 (GDI32.58)
2563 HRGN WINAPI CreatePolygonRgn( const POINT *points, INT count,
2566 return CreatePolyPolygonRgn( points, &count, 1, mode );
2570 /***********************************************************************
2571 * GetRandomRgn [GDI32.215]
2574 * This function is UNDOCUMENTED, it isn't even in the header file.
2575 * I assume that it will return a HRGN32!??
2577 HRGN WINAPI GetRandomRgn(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3)
2579 FIXME (region, "(0x%08lx 0x%08lx 0x%08lx): empty stub!\n",
2580 dwArg1, dwArg2, dwArg3);
2585 /***********************************************************************
2586 * REGION_CropAndOffsetRegion
2588 static BOOL REGION_CropAndOffsetRegion(const POINT* off, const RECT *rect, WINEREGION *rgnSrc, WINEREGION* rgnDst)
2590 if( IsRectEmpty(rect) || !EXTENTCHECK(rect, &rgnSrc->extents) )
2593 if( !rgnDst->rects )
2595 rgnDst->rects = HeapAlloc(SystemHeap, 0, sizeof( RECT ));
2602 TRACE(region,"cropped to empty!\n");
2603 EMPTY_REGION(rgnDst);
2605 else /* region box and clipping rect appear to intersect */
2608 INT i, j, clipa, clipb;
2609 INT left = rgnSrc->extents.right + off->x;
2610 INT right = rgnSrc->extents.left + off->x;
2612 for( clipa = 0; rgnSrc->rects[clipa].bottom <= rect->top; clipa++ )
2613 ; /* skip bands above the clipping rectangle */
2615 for( clipb = clipa; clipb < rgnSrc->numRects; clipb++ )
2616 if( rgnSrc->rects[clipb].top >= rect->bottom )
2617 break; /* and below it */
2619 /* clipa - index of the first rect in the first intersecting band
2620 * clipb - index of the last rect in the last intersecting band
2623 if((rgnDst != rgnSrc) && (rgnDst->size < (i = (clipb - clipa))))
2625 rgnDst->rects = HeapReAlloc( SystemHeap, 0,
2626 rgnDst->rects, i * sizeof(RECT));
2627 if( !rgnDst->rects ) return FALSE;
2631 if( TRACE_ON(region) )
2633 REGION_DumpRegion( rgnSrc );
2634 TRACE(region,"\tclipa = %i, clipb = %i\n", clipa, clipb );
2637 for( i = clipa, j = 0; i < clipb ; i++ )
2639 /* i - src index, j - dst index, j is always <= i for obvious reasons */
2641 lpr = rgnSrc->rects + i;
2642 if( lpr->left < rect->right && lpr->right > rect->left )
2644 rgnDst->rects[j].top = lpr->top + off->y;
2645 rgnDst->rects[j].bottom = lpr->bottom + off->y;
2646 rgnDst->rects[j].left = ((lpr->left > rect->left) ? lpr->left : rect->left) + off->x;
2647 rgnDst->rects[j].right = ((lpr->right < rect->right) ? lpr->right : rect->right) + off->x;
2649 if( rgnDst->rects[j].left < left ) left = rgnDst->rects[j].left;
2650 if( rgnDst->rects[j].right > right ) right = rgnDst->rects[j].right;
2656 if( j == 0 ) goto empty;
2658 rgnDst->extents.left = left;
2659 rgnDst->extents.right = right;
2661 left = rect->top + off->y;
2662 right = rect->bottom + off->y;
2664 rgnDst->numRects = j--;
2665 for( i = 0; i <= j; i++ ) /* fixup top band */
2666 if( rgnDst->rects[i].top < left )
2667 rgnDst->rects[i].top = left;
2671 for( i = j; i >= 0; i-- ) /* fixup bottom band */
2672 if( rgnDst->rects[i].bottom > right )
2673 rgnDst->rects[i].bottom = right;
2677 rgnDst->extents.top = rgnDst->rects[0].top;
2678 rgnDst->extents.bottom = rgnDst->rects[j].bottom;
2680 rgnDst->type = (j >= 1) ? COMPLEXREGION : SIMPLEREGION;
2682 if( TRACE_ON(region) )
2684 TRACE(region,"result:\n");
2685 REGION_DumpRegion( rgnDst );
2692 /***********************************************************************
2696 * hSrc: Region to crop and offset.
2697 * lpRect: Clipping rectangle.
2698 * lpPt: Points to offset the cropped region. Can be NULL.
2700 * hDst: Region to hold the result (if 0 a new region is created).
2701 * Allowed to be the same region as hSrc (in place, no extra memory needed).
2703 * Returns: hDst if success, 0 otherwise.
2705 HRGN REGION_CropRgn( HRGN hDst, HRGN hSrc, const RECT *lpRect, const POINT *lpPt )
2707 /* Optimization of the following generic code:
2709 HRGN h = CreateRectRgn( lpRect->left, lpRect->top, lpRect->right, lpRect->bottom );
2710 if( hDst == 0 ) hDst = h;
2711 CombineRgn( hDst, hSrc, h, RGN_AND );
2713 OffsetRgn( hDst, lpPt->x, lpPt->y );
2720 RGNOBJ *objSrc = (RGNOBJ *) GDI_HEAP_LOCK( hSrc );
2729 objDst = (RGNOBJ *) GDI_HEAP_LOCK( hDst );
2730 rgnDst = objDst->rgn;
2734 rgnDst = HeapAlloc(SystemHeap, 0, sizeof( WINEREGION ));
2737 rgnDst->size = rgnDst->numRects = 0;
2738 rgnDst->rects = NULL; /* back end will allocate exact number */
2744 POINT pt = { 0, 0 };
2746 if( !lpPt ) lpPt = &pt;
2748 TRACE(region, "src %p -> dst %p (%i,%i)-(%i,%i) by (%li,%li)\n", objSrc->rgn, rgnDst,
2749 lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, lpPt->x, lpPt->y );
2751 if( REGION_CropAndOffsetRegion( lpPt, lpRect, objSrc->rgn, rgnDst ) == FALSE )
2753 if( hDst ) /* existing rgn */
2755 GDI_HEAP_UNLOCK(hDst);
2761 else if( hDst == 0 )
2763 if(!(hDst = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
2767 HeapFree( SystemHeap, 0, rgnDst->rects );
2768 HeapFree( SystemHeap, 0, rgnDst );
2772 objDst = (RGNOBJ *) GDI_HEAP_LOCK( hDst );
2773 objDst->rgn = rgnDst;
2776 GDI_HEAP_UNLOCK(hDst);
2780 GDI_HEAP_UNLOCK(hSrc);