Bugfix: Always release the Win16Lock in TASK_Reschedule.
[wine] / objects / region.c
1 /*
2  * GDI region objects. Shamelessly ripped out from the X11 distribution
3  * Thanks for the nice licence.
4  *
5  * Copyright 1993, 1994, 1995 Alexandre Julliard
6  * Modifications and additions: Copyright 1998 Huw Davies
7  *                                        1999 Alex Korobka
8  *
9  */
10
11 /************************************************************************
12
13 Copyright (c) 1987, 1988  X Consortium
14
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:
21
22 The above copyright notice and this permission notice shall be included in
23 all copies or substantial portions of the Software.
24
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.
31
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.
35
36
37 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
38
39                         All Rights Reserved
40
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.  
48
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
55 SOFTWARE.
56
57 ************************************************************************/
58 /*
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.
64  *
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".
72  *
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
75  * to touch.
76  *
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...
82  */
83
84 #include <stdlib.h>
85 #include <string.h>
86 #include "region.h"
87 #include "winuser.h"
88 #include "debug.h"
89 #include "heap.h"
90 #include "dc.h"
91
92 typedef void (*voidProcp)();
93
94 /* Note the parameter order is different from the X11 equivalents */
95
96 static void REGION_CopyRegion(WINEREGION *d, WINEREGION *s);
97 static void REGION_IntersectRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
98 static void REGION_UnionRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
99 static void REGION_SubtractRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
100 static void REGION_XorRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
101 static void REGION_UnionRectWithRegion(const RECT *rect, WINEREGION *rgn);
102
103 #define RGN_DEFAULT_RECTS       2
104
105 /***********************************************************************
106  *            REGION_DumpRegion
107  *            Outputs the contents of a WINEREGION
108  */
109 static void REGION_DumpRegion(WINEREGION *pReg)
110 {
111     RECT *pRect, *pRectEnd = pReg->rects + pReg->numRects;
112
113     TRACE(region, "Region %p: %d,%d - %d,%d %d rects\n", pReg,
114             pReg->extents.left, pReg->extents.top,
115             pReg->extents.right, pReg->extents.bottom, pReg->numRects);
116     for(pRect = pReg->rects; pRect < pRectEnd; pRect++)
117         TRACE(region, "\t%d,%d - %d,%d\n", pRect->left, pRect->top,
118                        pRect->right, pRect->bottom);
119     return;
120 }
121
122
123 /***********************************************************************
124  *            REGION_AllocWineRegion
125  *            Create a new empty WINEREGION.
126  */
127 static WINEREGION *REGION_AllocWineRegion( INT n )
128 {
129     WINEREGION *pReg;
130
131     if ((pReg = HeapAlloc(SystemHeap, 0, sizeof( WINEREGION ))))
132     {
133         if ((pReg->rects = HeapAlloc(SystemHeap, 0, n * sizeof( RECT ))))
134         {
135             pReg->size = n;
136             EMPTY_REGION(pReg);
137             return pReg;
138         }
139         HeapFree(SystemHeap, 0, pReg);
140     }
141     return NULL;
142 }
143
144
145 /***********************************************************************
146  *          REGION_CreateRegion
147  *          Create a new empty region.
148  */
149 static HRGN REGION_CreateRegion( INT n )
150 {
151     HRGN hrgn;
152     RGNOBJ *obj;
153
154     if(!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
155         return 0;
156     obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
157     if(!(obj->rgn = REGION_AllocWineRegion(n))) {
158         GDI_FreeObject( hrgn );
159         return 0;
160     }
161     GDI_HEAP_UNLOCK( hrgn );
162     return hrgn;
163 }
164
165
166 /***********************************************************************
167  *           REGION_DestroyWineRegion
168  */
169 static void REGION_DestroyWineRegion( WINEREGION* pReg )
170 {
171     HeapFree( SystemHeap, 0, pReg->rects );
172     HeapFree( SystemHeap, 0, pReg );
173     return;
174 }
175
176 /***********************************************************************
177  *           REGION_DeleteObject
178  */
179 BOOL REGION_DeleteObject( HRGN hrgn, RGNOBJ * obj )
180 {
181     TRACE(region, " %04x\n", hrgn );
182
183     REGION_DestroyWineRegion( obj->rgn );
184     return GDI_FreeObject( hrgn );
185 }
186
187 /***********************************************************************
188  *           OffsetRgn16    (GDI.101)
189  */
190 INT16 WINAPI OffsetRgn16( HRGN16 hrgn, INT16 x, INT16 y )
191 {
192     return OffsetRgn( hrgn, x, y );
193 }
194
195 /***********************************************************************
196  *           OffsetRgn32   (GDI32.256)
197  */
198 INT WINAPI OffsetRgn( HRGN hrgn, INT x, INT y )
199 {
200     RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
201
202     if (obj && (x || y))
203     {
204         INT ret;
205         int nbox = obj->rgn->numRects;
206         RECT *pbox = obj->rgn->rects;
207         
208         TRACE(region, " %04x %d,%d\n", hrgn, x, y );
209         if(nbox) {
210             while(nbox--) {
211                 pbox->left += x;
212                 pbox->right += x;
213                 pbox->top += y;
214                 pbox->bottom += y;
215                 pbox++;
216             }
217             obj->rgn->extents.left += x;
218             obj->rgn->extents.right += x;
219             obj->rgn->extents.top += y;
220             obj->rgn->extents.bottom += y;
221         }
222         ret = obj->rgn->type;
223         GDI_HEAP_UNLOCK( hrgn );
224         return ret;
225     }
226     return ERROR;
227 }
228
229
230 /***********************************************************************
231  *           GetRgnBox16    (GDI.134)
232  */
233 INT16 WINAPI GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
234 {
235     RECT r;
236     INT16 ret = (INT16)GetRgnBox( hrgn, &r );
237     CONV_RECT32TO16( &r, rect );
238     return ret;
239 }
240
241 /***********************************************************************
242  *           GetRgnBox32    (GDI32.219)
243  */
244 INT WINAPI GetRgnBox( HRGN hrgn, LPRECT rect )
245 {
246     RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
247     if (obj)
248     {
249         INT ret;
250         TRACE(region, " %04x\n", hrgn );
251         rect->left = obj->rgn->extents.left;
252         rect->top = obj->rgn->extents.top;
253         rect->right = obj->rgn->extents.right;
254         rect->bottom = obj->rgn->extents.bottom;
255         ret = obj->rgn->type;
256         GDI_HEAP_UNLOCK(hrgn);
257         return ret;
258     }
259     return ERROR;
260 }
261
262
263 /***********************************************************************
264  *           CreateRectRgn16    (GDI.64)
265  *
266  * NOTE: Doesn't call CreateRectRgn32 because of differences in SetRectRgn16/32
267  */
268 HRGN16 WINAPI CreateRectRgn16(INT16 left, INT16 top, INT16 right, INT16 bottom)
269 {
270     HRGN16 hrgn;
271
272     if (!(hrgn = (HRGN16)REGION_CreateRegion(RGN_DEFAULT_RECTS)))
273         return 0;
274     TRACE(region, "\n");
275     SetRectRgn16(hrgn, left, top, right, bottom);
276     return hrgn;
277 }
278
279
280 /***********************************************************************
281  *           CreateRectRgn32   (GDI32.59)
282  */
283 HRGN WINAPI CreateRectRgn(INT left, INT top, INT right, INT bottom)
284 {
285     HRGN hrgn;
286
287     /* Allocate 2 rects by default to reduce the number of reallocs */
288
289     if (!(hrgn = REGION_CreateRegion(RGN_DEFAULT_RECTS)))
290         return 0;
291     TRACE(region, "\n");
292     SetRectRgn(hrgn, left, top, right, bottom);
293     return hrgn;
294 }
295
296 /***********************************************************************
297  *           CreateRectRgnIndirect16    (GDI.65)
298  */
299 HRGN16 WINAPI CreateRectRgnIndirect16( const RECT16* rect )
300 {
301     return CreateRectRgn16( rect->left, rect->top, rect->right, rect->bottom );
302 }
303
304
305 /***********************************************************************
306  *           CreateRectRgnIndirect32    (GDI32.60)
307  */
308 HRGN WINAPI CreateRectRgnIndirect( const RECT* rect )
309 {
310     return CreateRectRgn( rect->left, rect->top, rect->right, rect->bottom );
311 }
312
313
314 /***********************************************************************
315  *           SetRectRgn16    (GDI.172)
316  *
317  * NOTE: Win 3.1 sets region to empty if left > right
318  */
319 VOID WINAPI SetRectRgn16( HRGN16 hrgn, INT16 left, INT16 top,
320                           INT16 right, INT16 bottom )
321 {
322     if(left < right)
323         SetRectRgn( hrgn, left, top, right, bottom );
324     else
325         SetRectRgn( hrgn, 0, 0, 0, 0 );
326 }
327
328
329 /***********************************************************************
330  *           SetRectRgn32    (GDI32.332)
331  *
332  * Allows either or both left and top to be greater than right or bottom.
333  */
334 VOID WINAPI SetRectRgn( HRGN hrgn, INT left, INT top,
335                           INT right, INT bottom )
336 {
337     RGNOBJ * obj;
338
339     TRACE(region, " %04x %d,%d-%d,%d\n", 
340                    hrgn, left, top, right, bottom );
341     
342     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
343
344     if (left > right) { INT tmp = left; left = right; right = tmp; }
345     if (top > bottom) { INT tmp = top; top = bottom; bottom = tmp; }
346
347     if((left != right) && (top != bottom))
348     {
349         obj->rgn->rects->left = obj->rgn->extents.left = left;
350         obj->rgn->rects->top = obj->rgn->extents.top = top;
351         obj->rgn->rects->right = obj->rgn->extents.right = right;
352         obj->rgn->rects->bottom = obj->rgn->extents.bottom = bottom;
353         obj->rgn->numRects = 1;
354         obj->rgn->type = SIMPLEREGION;
355     }
356     else
357         EMPTY_REGION(obj->rgn);
358
359     GDI_HEAP_UNLOCK( hrgn );
360 }
361
362
363 /***********************************************************************
364  *           CreateRoundRectRgn16    (GDI.444)
365  *
366  * If either ellipse dimension is zero we call CreateRectRgn16 for its
367  * `special' behaviour. -ve ellipse dimensions can result in GPFs under win3.1
368  * we just let CreateRoundRectRgn32 convert them to +ve values. 
369  */
370
371 HRGN16 WINAPI CreateRoundRectRgn16( INT16 left, INT16 top,
372                                     INT16 right, INT16 bottom,
373                                     INT16 ellipse_width, INT16 ellipse_height )
374 {
375     if( ellipse_width == 0 || ellipse_height == 0 )
376         return CreateRectRgn16( left, top, right, bottom );
377     else
378         return (HRGN16)CreateRoundRectRgn( left, top, right, bottom,
379                                          ellipse_width, ellipse_height );
380 }
381
382 /***********************************************************************
383  *           CreateRoundRectRgn32    (GDI32.61)
384  */
385 HRGN WINAPI CreateRoundRectRgn( INT left, INT top,
386                                     INT right, INT bottom,
387                                     INT ellipse_width, INT ellipse_height )
388 {
389     RGNOBJ * obj;
390     HRGN hrgn;
391     int asq, bsq, d, xd, yd;
392     RECT rect;
393     
394       /* Check if we can do a normal rectangle instead */
395
396     if ((ellipse_width == 0) || (ellipse_height == 0))
397         return CreateRectRgn( left, top, right, bottom );
398
399       /* Make the dimensions sensible */
400
401     if (left > right) { INT tmp = left; left = right; right = tmp; }
402     if (top > bottom) { INT tmp = top; top = bottom; bottom = tmp; }
403
404     ellipse_width = abs(ellipse_width);
405     ellipse_height = abs(ellipse_height);
406
407       /* Create region */
408
409     d = (ellipse_height < 128) ? ((3 * ellipse_height) >> 2) : 64;
410     if (!(hrgn = REGION_CreateRegion(d))) return 0;
411     obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
412     TRACE(region,"(%d,%d-%d,%d %dx%d): ret=%04x\n",
413                left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
414
415       /* Check parameters */
416
417     if (ellipse_width > right-left) ellipse_width = right-left;
418     if (ellipse_height > bottom-top) ellipse_height = bottom-top;
419
420       /* Ellipse algorithm, based on an article by K. Porter */
421       /* in DDJ Graphics Programming Column, 8/89 */
422
423     asq = ellipse_width * ellipse_width / 4;        /* a^2 */
424     bsq = ellipse_height * ellipse_height / 4;      /* b^2 */
425     d = bsq - asq * ellipse_height / 2 + asq / 4;   /* b^2 - a^2b + a^2/4 */
426     xd = 0;
427     yd = asq * ellipse_height;                      /* 2a^2b */
428
429     rect.left   = left + ellipse_width / 2;
430     rect.right  = right - ellipse_width / 2;
431
432       /* Loop to draw first half of quadrant */
433
434     while (xd < yd)
435     {
436         if (d > 0)  /* if nearest pixel is toward the center */
437         {
438               /* move toward center */
439             rect.top = top++;
440             rect.bottom = rect.top + 1;
441             REGION_UnionRectWithRegion( &rect, obj->rgn );
442             rect.top = --bottom;
443             rect.bottom = rect.top + 1;
444             REGION_UnionRectWithRegion( &rect, obj->rgn );
445             yd -= 2*asq;
446             d  -= yd;
447         }
448         rect.left--;        /* next horiz point */
449         rect.right++;
450         xd += 2*bsq;
451         d  += bsq + xd;
452     }
453
454       /* Loop to draw second half of quadrant */
455
456     d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
457     while (yd >= 0)
458     {
459           /* next vertical point */
460         rect.top = top++;
461         rect.bottom = rect.top + 1;
462         REGION_UnionRectWithRegion( &rect, obj->rgn );
463         rect.top = --bottom;
464         rect.bottom = rect.top + 1;
465         REGION_UnionRectWithRegion( &rect, obj->rgn );
466         if (d < 0)   /* if nearest pixel is outside ellipse */
467         {
468             rect.left--;     /* move away from center */
469             rect.right++;
470             xd += 2*bsq;
471             d  += xd;
472         }
473         yd -= 2*asq;
474         d  += asq - yd;
475     }
476
477       /* Add the inside rectangle */
478
479     if (top <= bottom)
480     {
481         rect.top = top;
482         rect.bottom = bottom;
483         REGION_UnionRectWithRegion( &rect, obj->rgn );
484     }
485     obj->rgn->type = SIMPLEREGION; /* FIXME? */
486     GDI_HEAP_UNLOCK( hrgn );
487     return hrgn;
488 }
489
490
491 /***********************************************************************
492  *           CreateEllipticRgn16    (GDI.54)
493  */
494 HRGN16 WINAPI CreateEllipticRgn16( INT16 left, INT16 top,
495                                    INT16 right, INT16 bottom )
496 {
497     return (HRGN16)CreateRoundRectRgn( left, top, right, bottom,
498                                          right-left, bottom-top );
499 }
500
501
502 /***********************************************************************
503  *           CreateEllipticRgn32    (GDI32.39)
504  */
505 HRGN WINAPI CreateEllipticRgn( INT left, INT top,
506                                    INT right, INT bottom )
507 {
508     return CreateRoundRectRgn( left, top, right, bottom,
509                                  right-left, bottom-top );
510 }
511
512
513 /***********************************************************************
514  *           CreateEllipticRgnIndirect16    (GDI.55)
515  */
516 HRGN16 WINAPI CreateEllipticRgnIndirect16( const RECT16 *rect )
517 {
518     return CreateRoundRectRgn( rect->left, rect->top, rect->right,
519                                  rect->bottom, rect->right - rect->left,
520                                  rect->bottom - rect->top );
521 }
522
523
524 /***********************************************************************
525  *           CreateEllipticRgnIndirect32    (GDI32.40)
526  */
527 HRGN WINAPI CreateEllipticRgnIndirect( const RECT *rect )
528 {
529     return CreateRoundRectRgn( rect->left, rect->top, rect->right,
530                                  rect->bottom, rect->right - rect->left,
531                                  rect->bottom - rect->top );
532 }
533
534 /***********************************************************************
535  *           GetRegionData32   (GDI32.217)
536  * 
537  */
538 DWORD WINAPI GetRegionData(HRGN hrgn, DWORD count, LPRGNDATA rgndata)
539 {
540     DWORD size;
541     RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
542     
543     TRACE(region, " %04x count = %ld, rgndata = %p\n",
544                    hrgn, count, rgndata);
545
546     if(!obj) return 0;
547
548     size = obj->rgn->numRects * sizeof(RECT);
549     if(count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
550     {
551         GDI_HEAP_UNLOCK( hrgn );
552         return size + sizeof(RGNDATAHEADER);
553     }
554
555     rgndata->rdh.dwSize = sizeof(RGNDATAHEADER);
556     rgndata->rdh.iType = RDH_RECTANGLES;
557     rgndata->rdh.nCount = obj->rgn->numRects;
558     rgndata->rdh.nRgnSize = size;
559     rgndata->rdh.rcBound.left = obj->rgn->extents.left;
560     rgndata->rdh.rcBound.top = obj->rgn->extents.top;
561     rgndata->rdh.rcBound.right = obj->rgn->extents.right;
562     rgndata->rdh.rcBound.bottom = obj->rgn->extents.bottom;
563
564     memcpy( rgndata->Buffer, obj->rgn->rects, size );
565
566     GDI_HEAP_UNLOCK( hrgn );
567     return 1;
568 }
569
570 /***********************************************************************
571  *           GetRegionData16   (GDI.607)
572  * FIXME: is LPRGNDATA the same in Win16 and Win32 ?
573  */
574 DWORD WINAPI GetRegionData16(HRGN16 hrgn, DWORD count, LPRGNDATA rgndata)
575 {
576     return GetRegionData((HRGN)hrgn, count, rgndata);
577 }
578
579 /***********************************************************************
580  *           ExtCreateRegion   (GDI32.94)
581  * 
582  */
583 HRGN WINAPI ExtCreateRegion( const XFORM* lpXform, DWORD dwCount, const RGNDATA* rgndata)
584 {
585     HRGN hrgn;
586
587     TRACE(region, " %p %ld %p = ", lpXform, dwCount, rgndata );
588
589     if( lpXform )
590         WARN(region, "(Xform not implemented - ignored) ");
591     
592     if( rgndata->rdh.iType != RDH_RECTANGLES )
593     {
594         /* FIXME: We can use CreatePolyPolygonRgn() here
595          *        for trapezoidal data */
596
597         WARN(region, "(Unsupported region data) ");
598         goto fail;
599     }
600
601     if( (hrgn = REGION_CreateRegion( rgndata->rdh.nCount )) )
602     {
603         RECT *pCurRect, *pEndRect;
604         RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
605
606         pEndRect = (RECT *)rgndata->Buffer + rgndata->rdh.nCount;
607         for(pCurRect = (RECT *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
608             REGION_UnionRectWithRegion( pCurRect, obj->rgn );
609         GDI_HEAP_UNLOCK( hrgn );
610
611         TRACE(region,"%04x\n", hrgn );
612         return hrgn;
613     }
614 fail:
615     WARN(region, "Failed\n");
616     return 0;
617 }
618
619 /***********************************************************************
620  *           PtInRegion16    (GDI.161)
621  */
622 BOOL16 WINAPI PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
623 {
624     return PtInRegion( hrgn, x, y );
625 }
626
627
628 /***********************************************************************
629  *           PtInRegion32    (GDI32.278)
630  */
631 BOOL WINAPI PtInRegion( HRGN hrgn, INT x, INT y )
632 {
633     RGNOBJ * obj;
634     
635     if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
636     {
637         BOOL ret = FALSE;
638         int i;
639
640         if (obj->rgn->numRects > 0 && INRECT(obj->rgn->extents, x, y))
641             for (i = 0; i < obj->rgn->numRects; i++)
642                 if (INRECT (obj->rgn->rects[i], x, y))
643                     ret = TRUE;
644         GDI_HEAP_UNLOCK( hrgn );
645         return ret;
646     }
647     return FALSE;
648 }
649
650
651 /***********************************************************************
652  *           RectInRegion16    (GDI.181)
653  */
654 BOOL16 WINAPI RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
655 {
656     RECT r32;
657
658     CONV_RECT16TO32(rect, &r32);
659     return (BOOL16)RectInRegion(hrgn, &r32);
660 }
661
662
663 /***********************************************************************
664  *           RectInRegion32    (GDI32.281)
665  *
666  * Returns TRUE if rect is at least partly inside hrgn
667  */
668 BOOL WINAPI RectInRegion( HRGN hrgn, const RECT *rect )
669 {
670     RGNOBJ * obj;
671     
672     if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
673     {
674         RECT *pCurRect, *pRectEnd;
675         BOOL ret = FALSE;
676     
677     /* this is (just) a useful optimization */
678         if ((obj->rgn->numRects > 0) && EXTENTCHECK(&obj->rgn->extents,
679                                                       rect))
680         {
681             for (pCurRect = obj->rgn->rects, pRectEnd = pCurRect +
682              obj->rgn->numRects; pCurRect < pRectEnd; pCurRect++)
683             {
684                 if (pCurRect->bottom <= rect->top)
685                     continue;             /* not far enough down yet */
686
687                 if (pCurRect->top >= rect->bottom) {
688                     ret = FALSE;          /* too far down */
689                     break;
690                 }
691
692                 if (pCurRect->right <= rect->left)
693                     continue;              /* not far enough over yet */
694
695                 if (pCurRect->left >= rect->right) {
696                     continue;
697                 }
698
699                 ret = TRUE;
700                 break;
701             }
702         }
703         GDI_HEAP_UNLOCK(hrgn);
704         return ret;
705     }
706     return FALSE;
707 }
708
709 /***********************************************************************
710  *           EqualRgn16    (GDI.72)
711  */
712 BOOL16 WINAPI EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
713 {
714     return EqualRgn( rgn1, rgn2 );
715 }
716
717
718 /***********************************************************************
719  *           EqualRgn32    (GDI32.90)
720  */
721 BOOL WINAPI EqualRgn( HRGN hrgn1, HRGN hrgn2 )
722 {
723     RGNOBJ *obj1, *obj2;
724     BOOL ret = FALSE;
725
726     if ((obj1 = (RGNOBJ *) GDI_GetObjPtr( hrgn1, REGION_MAGIC ))) 
727     {
728         if ((obj2 = (RGNOBJ *) GDI_GetObjPtr( hrgn2, REGION_MAGIC ))) 
729         {
730             int i;
731
732             ret = TRUE;
733             if ( obj1->rgn->numRects != obj2->rgn->numRects ) ret = FALSE;
734             else if ( obj1->rgn->numRects == 0 ) ret = TRUE;
735             else if ( !EqualRect(&obj1->rgn->extents, &obj2->rgn->extents) )
736                 ret = FALSE;
737             else for( i = 0; i < obj1->rgn->numRects; i++ ) {
738                 if (!EqualRect(obj1->rgn->rects + i, obj2->rgn->rects + i)) {
739                     ret = FALSE;
740                     break;
741                 }
742             }
743             GDI_HEAP_UNLOCK(hrgn2);
744         }
745         GDI_HEAP_UNLOCK(hrgn1);
746     }
747     return ret;
748 }
749 /***********************************************************************
750  *           REGION_UnionRectWithRegion
751  *           Adds a rectangle to a WINEREGION
752  *           See below for REGION_UnionRectWithRgn
753  */
754 static void REGION_UnionRectWithRegion(const RECT *rect, WINEREGION *rgn)
755 {
756     WINEREGION region;
757
758     region.rects = &region.extents;
759     region.numRects = 1;
760     region.size = 1;
761     region.type = SIMPLEREGION;
762     CopyRect(&(region.extents), rect);
763     REGION_UnionRegion(rgn, rgn, &region);
764     return;
765 }
766
767 /***********************************************************************
768  *           REGION_UnionRectWithRgn
769  *           Adds a rectangle to a HRGN32
770  *           A helper used by scroll.c
771  */
772 BOOL REGION_UnionRectWithRgn( HRGN hrgn, const RECT *lpRect )
773 {
774     RGNOBJ *obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
775
776     if(!obj) return FALSE;
777     REGION_UnionRectWithRegion( lpRect, obj->rgn );
778     GDI_HEAP_UNLOCK(hrgn);
779     return TRUE;
780 }
781
782 /***********************************************************************
783  *           REGION_CreateFrameRgn
784  *
785  * Create a region that is a frame around another region.
786  * Expand all rectangles by +/- x and y, then subtract original region.
787  */
788 BOOL REGION_FrameRgn( HRGN hDest, HRGN hSrc, INT x, INT y )
789 {
790     BOOL bRet;
791     RGNOBJ *srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
792
793     if (srcObj->rgn->numRects != 0) 
794     {
795         RGNOBJ* destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
796         RECT *pRect, *pEndRect;
797         RECT tempRect;
798
799         EMPTY_REGION( destObj->rgn );
800         
801         pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
802         for(pRect = srcObj->rgn->rects; pRect < pEndRect; pRect++)
803         {
804             tempRect.left = pRect->left - x;        
805             tempRect.top = pRect->top - y;
806             tempRect.right = pRect->right + x;
807             tempRect.bottom = pRect->bottom + y;
808             REGION_UnionRectWithRegion( &tempRect, destObj->rgn );
809         }
810         REGION_SubtractRegion( destObj->rgn, destObj->rgn, srcObj->rgn );
811         GDI_HEAP_UNLOCK ( hDest );
812         bRet = TRUE;
813     }
814     else
815         bRet = FALSE;
816     GDI_HEAP_UNLOCK( hSrc );
817     return bRet;
818 }
819
820 /***********************************************************************
821  *           REGION_LPTODP
822  *
823  * Convert region to device co-ords for the supplied dc. 
824  */
825 BOOL REGION_LPTODP( HDC hdc, HRGN hDest, HRGN hSrc )
826 {
827     RECT *pCurRect, *pEndRect;
828     RGNOBJ *srcObj, *destObj;
829     DC * dc = DC_GetDCPtr( hdc );
830     RECT tmpRect;
831
832     TRACE(region, " hdc=%04x dest=%04x src=%04x\n",
833                     hdc, hDest, hSrc) ;
834     
835     if (dc->w.MapMode == MM_TEXT) /* Requires only a translation */
836     {
837         if( CombineRgn( hDest, hSrc, 0, RGN_COPY ) == ERROR ) return FALSE;
838         OffsetRgn( hDest, dc->vportOrgX - dc->wndOrgX, 
839                      dc->vportOrgY - dc->wndOrgY );
840         return TRUE;
841     }
842
843     if(!( srcObj = (RGNOBJ *) GDI_GetObjPtr( hSrc, REGION_MAGIC) ))
844         return FALSE;
845     if(!( destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC) ))
846     {
847         GDI_HEAP_UNLOCK( hSrc );
848         return FALSE;
849     }
850     EMPTY_REGION( destObj->rgn );
851
852     pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
853     for(pCurRect = srcObj->rgn->rects; pCurRect < pEndRect; pCurRect++)
854     {
855         tmpRect = *pCurRect;
856         tmpRect.left = XLPTODP( dc, tmpRect.left );
857         tmpRect.top = YLPTODP( dc, tmpRect.top );
858         tmpRect.right = XLPTODP( dc, tmpRect.right );
859         tmpRect.bottom = YLPTODP( dc, tmpRect.bottom );
860         REGION_UnionRectWithRegion( &tmpRect, destObj->rgn );
861     }
862     
863     GDI_HEAP_UNLOCK( hDest );
864     GDI_HEAP_UNLOCK( hSrc );
865     return TRUE;
866 }
867     
868 /***********************************************************************
869  *           CombineRgn16    (GDI.451)
870  */
871 INT16 WINAPI CombineRgn16(HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode)
872 {
873     return (INT16)CombineRgn( hDest, hSrc1, hSrc2, mode );
874 }
875
876
877 /***********************************************************************
878  *           CombineRgn32   (GDI32.19)
879  *
880  * Note: The behavior is correct even if src and dest regions are the same.
881  */
882 INT WINAPI CombineRgn(HRGN hDest, HRGN hSrc1, HRGN hSrc2, INT mode)
883 {
884     RGNOBJ *destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC);
885     INT result = ERROR;
886
887     TRACE(region, " %04x,%04x -> %04x mode=%x\n", 
888                  hSrc1, hSrc2, hDest, mode );
889     if (destObj)
890     {
891         RGNOBJ *src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC);
892
893         if (src1Obj)
894         {
895             TRACE(region, "dump:\n");
896             if(TRACE_ON(region)) 
897               REGION_DumpRegion(src1Obj->rgn);
898             if (mode == RGN_COPY)
899             {
900                 REGION_CopyRegion( destObj->rgn, src1Obj->rgn );
901                 result = destObj->rgn->type;
902             }
903             else
904             {
905                 RGNOBJ *src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC);
906
907                 if (src2Obj)
908                 {
909                     TRACE(region, "dump:\n");
910                     if(TRACE_ON(region)) 
911                       REGION_DumpRegion(src2Obj->rgn);
912                     switch (mode)
913                     {
914                     case RGN_AND:
915                         REGION_IntersectRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn);
916                         break;
917                     case RGN_OR:
918                         REGION_UnionRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
919                         break;
920                     case RGN_XOR:
921                         REGION_XorRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
922                         break;
923                     case RGN_DIFF:
924                         REGION_SubtractRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
925                         break;
926                     }
927                     result = destObj->rgn->type;
928                     GDI_HEAP_UNLOCK( hSrc2 );
929                 }
930             }
931             GDI_HEAP_UNLOCK( hSrc1 );
932         }
933         TRACE(region, "dump:\n");
934         if(TRACE_ON(region)) 
935           REGION_DumpRegion(destObj->rgn);
936
937         GDI_HEAP_UNLOCK( hDest );
938     }
939     return result;
940 }
941
942 /***********************************************************************
943  *           REGION_SetExtents
944  *           Re-calculate the extents of a region
945  */
946 static void REGION_SetExtents (WINEREGION *pReg)
947 {
948     RECT *pRect, *pRectEnd, *pExtents;
949
950     if (pReg->numRects == 0)
951     {
952         pReg->extents.left = 0;
953         pReg->extents.top = 0;
954         pReg->extents.right = 0;
955         pReg->extents.bottom = 0;
956         return;
957     }
958
959     pExtents = &pReg->extents;
960     pRect = pReg->rects;
961     pRectEnd = &pRect[pReg->numRects - 1];
962
963     /*
964      * Since pRect is the first rectangle in the region, it must have the
965      * smallest top and since pRectEnd is the last rectangle in the region,
966      * it must have the largest bottom, because of banding. Initialize left and
967      * right from pRect and pRectEnd, resp., as good things to initialize them
968      * to...
969      */
970     pExtents->left = pRect->left;
971     pExtents->top = pRect->top;
972     pExtents->right = pRectEnd->right;
973     pExtents->bottom = pRectEnd->bottom;
974
975     while (pRect <= pRectEnd)
976     {
977         if (pRect->left < pExtents->left)
978             pExtents->left = pRect->left;
979         if (pRect->right > pExtents->right)
980             pExtents->right = pRect->right;
981         pRect++;
982     }
983 }
984
985 /***********************************************************************
986  *           REGION_CopyRegion
987  */
988 static void REGION_CopyRegion(WINEREGION *dst, WINEREGION *src)
989 {
990     if (dst != src) /*  don't want to copy to itself */
991     {  
992         if (dst->size < src->numRects)
993         {
994             if (! (dst->rects = HeapReAlloc( SystemHeap, 0, dst->rects,
995                                 src->numRects * sizeof(RECT) )))
996                 return;
997             dst->size = src->numRects;
998         }
999         dst->numRects = src->numRects;
1000         dst->extents.left = src->extents.left;
1001         dst->extents.top = src->extents.top;
1002         dst->extents.right = src->extents.right;
1003         dst->extents.bottom = src->extents.bottom;
1004         dst->type = src->type;
1005
1006         memcpy((char *) dst->rects, (char *) src->rects,
1007                (int) (src->numRects * sizeof(RECT)));
1008     }
1009     return;
1010 }
1011
1012 /***********************************************************************
1013  *           REGION_Coalesce
1014  *
1015  *      Attempt to merge the rects in the current band with those in the
1016  *      previous one. Used only by REGION_RegionOp.
1017  *
1018  * Results:
1019  *      The new index for the previous band.
1020  *
1021  * Side Effects:
1022  *      If coalescing takes place:
1023  *          - rectangles in the previous band will have their bottom fields
1024  *            altered.
1025  *          - pReg->numRects will be decreased.
1026  *
1027  */
1028 static INT REGION_Coalesce (
1029              WINEREGION *pReg, /* Region to coalesce */
1030              INT prevStart,  /* Index of start of previous band */
1031              INT curStart    /* Index of start of current band */
1032 ) {
1033     RECT *pPrevRect;          /* Current rect in previous band */
1034     RECT *pCurRect;           /* Current rect in current band */
1035     RECT *pRegEnd;            /* End of region */
1036     INT curNumRects;          /* Number of rectangles in current band */
1037     INT prevNumRects;         /* Number of rectangles in previous band */
1038     INT bandtop;               /* top coordinate for current band */
1039
1040     pRegEnd = &pReg->rects[pReg->numRects];
1041
1042     pPrevRect = &pReg->rects[prevStart];
1043     prevNumRects = curStart - prevStart;
1044
1045     /*
1046      * Figure out how many rectangles are in the current band. Have to do
1047      * this because multiple bands could have been added in REGION_RegionOp
1048      * at the end when one region has been exhausted.
1049      */
1050     pCurRect = &pReg->rects[curStart];
1051     bandtop = pCurRect->top;
1052     for (curNumRects = 0;
1053          (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
1054          curNumRects++)
1055     {
1056         pCurRect++;
1057     }
1058     
1059     if (pCurRect != pRegEnd)
1060     {
1061         /*
1062          * If more than one band was added, we have to find the start
1063          * of the last band added so the next coalescing job can start
1064          * at the right place... (given when multiple bands are added,
1065          * this may be pointless -- see above).
1066          */
1067         pRegEnd--;
1068         while (pRegEnd[-1].top == pRegEnd->top)
1069         {
1070             pRegEnd--;
1071         }
1072         curStart = pRegEnd - pReg->rects;
1073         pRegEnd = pReg->rects + pReg->numRects;
1074     }
1075         
1076     if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
1077         pCurRect -= curNumRects;
1078         /*
1079          * The bands may only be coalesced if the bottom of the previous
1080          * matches the top scanline of the current.
1081          */
1082         if (pPrevRect->bottom == pCurRect->top)
1083         {
1084             /*
1085              * Make sure the bands have rects in the same places. This
1086              * assumes that rects have been added in such a way that they
1087              * cover the most area possible. I.e. two rects in a band must
1088              * have some horizontal space between them.
1089              */
1090             do
1091             {
1092                 if ((pPrevRect->left != pCurRect->left) ||
1093                     (pPrevRect->right != pCurRect->right))
1094                 {
1095                     /*
1096                      * The bands don't line up so they can't be coalesced.
1097                      */
1098                     return (curStart);
1099                 }
1100                 pPrevRect++;
1101                 pCurRect++;
1102                 prevNumRects -= 1;
1103             } while (prevNumRects != 0);
1104
1105             pReg->numRects -= curNumRects;
1106             pCurRect -= curNumRects;
1107             pPrevRect -= curNumRects;
1108
1109             /*
1110              * The bands may be merged, so set the bottom of each rect
1111              * in the previous band to that of the corresponding rect in
1112              * the current band.
1113              */
1114             do
1115             {
1116                 pPrevRect->bottom = pCurRect->bottom;
1117                 pPrevRect++;
1118                 pCurRect++;
1119                 curNumRects -= 1;
1120             } while (curNumRects != 0);
1121
1122             /*
1123              * If only one band was added to the region, we have to backup
1124              * curStart to the start of the previous band.
1125              *
1126              * If more than one band was added to the region, copy the
1127              * other bands down. The assumption here is that the other bands
1128              * came from the same region as the current one and no further
1129              * coalescing can be done on them since it's all been done
1130              * already... curStart is already in the right place.
1131              */
1132             if (pCurRect == pRegEnd)
1133             {
1134                 curStart = prevStart;
1135             }
1136             else
1137             {
1138                 do
1139                 {
1140                     *pPrevRect++ = *pCurRect++;
1141                 } while (pCurRect != pRegEnd);
1142             }
1143             
1144         }
1145     }
1146     return (curStart);
1147 }
1148
1149 /***********************************************************************
1150  *           REGION_RegionOp
1151  *
1152  *      Apply an operation to two regions. Called by REGION_Union,
1153  *      REGION_Inverse, REGION_Subtract, REGION_Intersect...
1154  *
1155  * Results:
1156  *      None.
1157  *
1158  * Side Effects:
1159  *      The new region is overwritten.
1160  *
1161  * Notes:
1162  *      The idea behind this function is to view the two regions as sets.
1163  *      Together they cover a rectangle of area that this function divides
1164  *      into horizontal bands where points are covered only by one region
1165  *      or by both. For the first case, the nonOverlapFunc is called with
1166  *      each the band and the band's upper and lower extents. For the
1167  *      second, the overlapFunc is called to process the entire band. It
1168  *      is responsible for clipping the rectangles in the band, though
1169  *      this function provides the boundaries.
1170  *      At the end of each band, the new region is coalesced, if possible,
1171  *      to reduce the number of rectangles in the region.
1172  *
1173  */
1174 static void REGION_RegionOp(
1175             WINEREGION *newReg, /* Place to store result */
1176             WINEREGION *reg1,   /* First region in operation */
1177             WINEREGION *reg2,   /* 2nd region in operation */
1178             void (*overlapFunc)(),     /* Function to call for over-lapping bands */
1179             void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
1180             void (*nonOverlap2Func)()  /* Function to call for non-overlapping bands in region 2 */
1181 ) {
1182     RECT *r1;                         /* Pointer into first region */
1183     RECT *r2;                         /* Pointer into 2d region */
1184     RECT *r1End;                      /* End of 1st region */
1185     RECT *r2End;                      /* End of 2d region */
1186     INT ybot;                         /* Bottom of intersection */
1187     INT ytop;                         /* Top of intersection */
1188     RECT *oldRects;                   /* Old rects for newReg */
1189     INT prevBand;                     /* Index of start of
1190                                                  * previous band in newReg */
1191     INT curBand;                      /* Index of start of current
1192                                                  * band in newReg */
1193     RECT *r1BandEnd;                  /* End of current band in r1 */
1194     RECT *r2BandEnd;                  /* End of current band in r2 */
1195     INT top;                          /* Top of non-overlapping band */
1196     INT bot;                          /* Bottom of non-overlapping band */
1197     
1198     /*
1199      * Initialization:
1200      *  set r1, r2, r1End and r2End appropriately, preserve the important
1201      * parts of the destination region until the end in case it's one of
1202      * the two source regions, then mark the "new" region empty, allocating
1203      * another array of rectangles for it to use.
1204      */
1205     r1 = reg1->rects;
1206     r2 = reg2->rects;
1207     r1End = r1 + reg1->numRects;
1208     r2End = r2 + reg2->numRects;
1209     
1210
1211     /*
1212      * newReg may be one of the src regions so we can't empty it. We keep a 
1213      * note of its rects pointer (so that we can free them later), preserve its
1214      * extents and simply set numRects to zero. 
1215      */
1216
1217     oldRects = newReg->rects;
1218     newReg->numRects = 0;
1219
1220     /*
1221      * Allocate a reasonable number of rectangles for the new region. The idea
1222      * is to allocate enough so the individual functions don't need to
1223      * reallocate and copy the array, which is time consuming, yet we don't
1224      * have to worry about using too much memory. I hope to be able to
1225      * nuke the Xrealloc() at the end of this function eventually.
1226      */
1227     newReg->size = MAX(reg1->numRects,reg2->numRects) * 2;
1228
1229     if (! (newReg->rects = HeapAlloc( SystemHeap, 0, 
1230                                   sizeof(RECT) * newReg->size )))
1231     {
1232         newReg->size = 0;
1233         return;
1234     }
1235     
1236     /*
1237      * Initialize ybot and ytop.
1238      * In the upcoming loop, ybot and ytop serve different functions depending
1239      * on whether the band being handled is an overlapping or non-overlapping
1240      * band.
1241      *  In the case of a non-overlapping band (only one of the regions
1242      * has points in the band), ybot is the bottom of the most recent
1243      * intersection and thus clips the top of the rectangles in that band.
1244      * ytop is the top of the next intersection between the two regions and
1245      * serves to clip the bottom of the rectangles in the current band.
1246      *  For an overlapping band (where the two regions intersect), ytop clips
1247      * the top of the rectangles of both regions and ybot clips the bottoms.
1248      */
1249     if (reg1->extents.top < reg2->extents.top)
1250         ybot = reg1->extents.top;
1251     else
1252         ybot = reg2->extents.top;
1253     
1254     /*
1255      * prevBand serves to mark the start of the previous band so rectangles
1256      * can be coalesced into larger rectangles. qv. miCoalesce, above.
1257      * In the beginning, there is no previous band, so prevBand == curBand
1258      * (curBand is set later on, of course, but the first band will always
1259      * start at index 0). prevBand and curBand must be indices because of
1260      * the possible expansion, and resultant moving, of the new region's
1261      * array of rectangles.
1262      */
1263     prevBand = 0;
1264     
1265     do
1266     {
1267         curBand = newReg->numRects;
1268
1269         /*
1270          * This algorithm proceeds one source-band (as opposed to a
1271          * destination band, which is determined by where the two regions
1272          * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1273          * rectangle after the last one in the current band for their
1274          * respective regions.
1275          */
1276         r1BandEnd = r1;
1277         while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
1278         {
1279             r1BandEnd++;
1280         }
1281         
1282         r2BandEnd = r2;
1283         while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
1284         {
1285             r2BandEnd++;
1286         }
1287         
1288         /*
1289          * First handle the band that doesn't intersect, if any.
1290          *
1291          * Note that attention is restricted to one band in the
1292          * non-intersecting region at once, so if a region has n
1293          * bands between the current position and the next place it overlaps
1294          * the other, this entire loop will be passed through n times.
1295          */
1296         if (r1->top < r2->top)
1297         {
1298             top = MAX(r1->top,ybot);
1299             bot = MIN(r1->bottom,r2->top);
1300
1301             if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
1302             {
1303                 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
1304             }
1305
1306             ytop = r2->top;
1307         }
1308         else if (r2->top < r1->top)
1309         {
1310             top = MAX(r2->top,ybot);
1311             bot = MIN(r2->bottom,r1->top);
1312
1313             if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
1314             {
1315                 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
1316             }
1317
1318             ytop = r1->top;
1319         }
1320         else
1321         {
1322             ytop = r1->top;
1323         }
1324
1325         /*
1326          * If any rectangles got added to the region, try and coalesce them
1327          * with rectangles from the previous band. Note we could just do
1328          * this test in miCoalesce, but some machines incur a not
1329          * inconsiderable cost for function calls, so...
1330          */
1331         if (newReg->numRects != curBand)
1332         {
1333             prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1334         }
1335
1336         /*
1337          * Now see if we've hit an intersecting band. The two bands only
1338          * intersect if ybot > ytop
1339          */
1340         ybot = MIN(r1->bottom, r2->bottom);
1341         curBand = newReg->numRects;
1342         if (ybot > ytop)
1343         {
1344             (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1345
1346         }
1347         
1348         if (newReg->numRects != curBand)
1349         {
1350             prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1351         }
1352
1353         /*
1354          * If we've finished with a band (bottom == ybot) we skip forward
1355          * in the region to the next band.
1356          */
1357         if (r1->bottom == ybot)
1358         {
1359             r1 = r1BandEnd;
1360         }
1361         if (r2->bottom == ybot)
1362         {
1363             r2 = r2BandEnd;
1364         }
1365     } while ((r1 != r1End) && (r2 != r2End));
1366
1367     /*
1368      * Deal with whichever region still has rectangles left.
1369      */
1370     curBand = newReg->numRects;
1371     if (r1 != r1End)
1372     {
1373         if (nonOverlap1Func != (void (*)())NULL)
1374         {
1375             do
1376             {
1377                 r1BandEnd = r1;
1378                 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
1379                 {
1380                     r1BandEnd++;
1381                 }
1382                 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
1383                                      MAX(r1->top,ybot), r1->bottom);
1384                 r1 = r1BandEnd;
1385             } while (r1 != r1End);
1386         }
1387     }
1388     else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
1389     {
1390         do
1391         {
1392             r2BandEnd = r2;
1393             while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
1394             {
1395                  r2BandEnd++;
1396             }
1397             (* nonOverlap2Func) (newReg, r2, r2BandEnd,
1398                                 MAX(r2->top,ybot), r2->bottom);
1399             r2 = r2BandEnd;
1400         } while (r2 != r2End);
1401     }
1402
1403     if (newReg->numRects != curBand)
1404     {
1405         (void) REGION_Coalesce (newReg, prevBand, curBand);
1406     }
1407
1408     /*
1409      * A bit of cleanup. To keep regions from growing without bound,
1410      * we shrink the array of rectangles to match the new number of
1411      * rectangles in the region. This never goes to 0, however...
1412      *
1413      * Only do this stuff if the number of rectangles allocated is more than
1414      * twice the number of rectangles in the region (a simple optimization...).
1415      */
1416     if ((newReg->numRects < (newReg->size >> 1)) && (newReg->numRects > 2))
1417     {
1418         if (REGION_NOT_EMPTY(newReg))
1419         {
1420             RECT *prev_rects = newReg->rects;
1421             newReg->size = newReg->numRects;
1422             newReg->rects = HeapReAlloc( SystemHeap, 0, newReg->rects,
1423                                    sizeof(RECT) * newReg->size );
1424             if (! newReg->rects)
1425                 newReg->rects = prev_rects;
1426         }
1427         else
1428         {
1429             /*
1430              * No point in doing the extra work involved in an Xrealloc if
1431              * the region is empty
1432              */
1433             newReg->size = 1;
1434             HeapFree( SystemHeap, 0, newReg->rects );
1435             newReg->rects = HeapAlloc( SystemHeap, 0, sizeof(RECT) );
1436         }
1437     }
1438     HeapFree( SystemHeap, 0, oldRects );
1439     return;
1440 }
1441
1442 /***********************************************************************
1443  *          Region Intersection
1444  ***********************************************************************/
1445
1446
1447 /***********************************************************************
1448  *           REGION_IntersectO
1449  *
1450  * Handle an overlapping band for REGION_Intersect.
1451  *
1452  * Results:
1453  *      None.
1454  *
1455  * Side Effects:
1456  *      Rectangles may be added to the region.
1457  *
1458  */
1459 static void REGION_IntersectO(WINEREGION *pReg,  RECT *r1, RECT *r1End,
1460                 RECT *r2, RECT *r2End, INT top, INT bottom)
1461
1462 {
1463     INT       left, right;
1464     RECT      *pNextRect;
1465
1466     pNextRect = &pReg->rects[pReg->numRects];
1467
1468     while ((r1 != r1End) && (r2 != r2End))
1469     {
1470         left = MAX(r1->left, r2->left);
1471         right = MIN(r1->right, r2->right);
1472
1473         /*
1474          * If there's any overlap between the two rectangles, add that
1475          * overlap to the new region.
1476          * There's no need to check for subsumption because the only way
1477          * such a need could arise is if some region has two rectangles
1478          * right next to each other. Since that should never happen...
1479          */
1480         if (left < right)
1481         {
1482             MEMCHECK(pReg, pNextRect, pReg->rects);
1483             pNextRect->left = left;
1484             pNextRect->top = top;
1485             pNextRect->right = right;
1486             pNextRect->bottom = bottom;
1487             pReg->numRects += 1;
1488             pNextRect++;
1489         }
1490
1491         /*
1492          * Need to advance the pointers. Shift the one that extends
1493          * to the right the least, since the other still has a chance to
1494          * overlap with that region's next rectangle, if you see what I mean.
1495          */
1496         if (r1->right < r2->right)
1497         {
1498             r1++;
1499         }
1500         else if (r2->right < r1->right)
1501         {
1502             r2++;
1503         }
1504         else
1505         {
1506             r1++;
1507             r2++;
1508         }
1509     }
1510     return;
1511 }
1512
1513 /***********************************************************************
1514  *           REGION_IntersectRegion
1515  */
1516 static void REGION_IntersectRegion(WINEREGION *newReg, WINEREGION *reg1,
1517                                    WINEREGION *reg2)
1518 {
1519    /* check for trivial reject */
1520     if ( (!(reg1->numRects)) || (!(reg2->numRects))  ||
1521         (!EXTENTCHECK(&reg1->extents, &reg2->extents)))
1522         newReg->numRects = 0;
1523     else
1524         REGION_RegionOp (newReg, reg1, reg2, 
1525          (voidProcp) REGION_IntersectO, (voidProcp) NULL, (voidProcp) NULL);
1526     
1527     /*
1528      * Can't alter newReg's extents before we call miRegionOp because
1529      * it might be one of the source regions and miRegionOp depends
1530      * on the extents of those regions being the same. Besides, this
1531      * way there's no checking against rectangles that will be nuked
1532      * due to coalescing, so we have to examine fewer rectangles.
1533      */
1534     REGION_SetExtents(newReg);
1535     newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1536     return;
1537 }
1538
1539 /***********************************************************************
1540  *           Region Union
1541  ***********************************************************************/
1542
1543 /***********************************************************************
1544  *           REGION_UnionNonO
1545  *
1546  *      Handle a non-overlapping band for the union operation. Just
1547  *      Adds the rectangles into the region. Doesn't have to check for
1548  *      subsumption or anything.
1549  *
1550  * Results:
1551  *      None.
1552  *
1553  * Side Effects:
1554  *      pReg->numRects is incremented and the final rectangles overwritten
1555  *      with the rectangles we're passed.
1556  *
1557  */
1558 static void REGION_UnionNonO (WINEREGION *pReg, RECT *r, RECT *rEnd,
1559                               INT top, INT bottom)
1560 {
1561     RECT *pNextRect;
1562
1563     pNextRect = &pReg->rects[pReg->numRects];
1564
1565     while (r != rEnd)
1566     {
1567         MEMCHECK(pReg, pNextRect, pReg->rects);
1568         pNextRect->left = r->left;
1569         pNextRect->top = top;
1570         pNextRect->right = r->right;
1571         pNextRect->bottom = bottom;
1572         pReg->numRects += 1;
1573         pNextRect++;
1574         r++;
1575     }
1576     return;
1577 }
1578
1579 /***********************************************************************
1580  *           REGION_UnionO
1581  *
1582  *      Handle an overlapping band for the union operation. Picks the
1583  *      left-most rectangle each time and merges it into the region.
1584  *
1585  * Results:
1586  *      None.
1587  *
1588  * Side Effects:
1589  *      Rectangles are overwritten in pReg->rects and pReg->numRects will
1590  *      be changed.
1591  *
1592  */
1593 static void REGION_UnionO (WINEREGION *pReg, RECT *r1, RECT *r1End,
1594                            RECT *r2, RECT *r2End, INT top, INT bottom)
1595 {
1596     RECT *pNextRect;
1597     
1598     pNextRect = &pReg->rects[pReg->numRects];
1599
1600 #define MERGERECT(r) \
1601     if ((pReg->numRects != 0) &&  \
1602         (pNextRect[-1].top == top) &&  \
1603         (pNextRect[-1].bottom == bottom) &&  \
1604         (pNextRect[-1].right >= r->left))  \
1605     {  \
1606         if (pNextRect[-1].right < r->right)  \
1607         {  \
1608             pNextRect[-1].right = r->right;  \
1609         }  \
1610     }  \
1611     else  \
1612     {  \
1613         MEMCHECK(pReg, pNextRect, pReg->rects);  \
1614         pNextRect->top = top;  \
1615         pNextRect->bottom = bottom;  \
1616         pNextRect->left = r->left;  \
1617         pNextRect->right = r->right;  \
1618         pReg->numRects += 1;  \
1619         pNextRect += 1;  \
1620     }  \
1621     r++;
1622     
1623     while ((r1 != r1End) && (r2 != r2End))
1624     {
1625         if (r1->left < r2->left)
1626         {
1627             MERGERECT(r1);
1628         }
1629         else
1630         {
1631             MERGERECT(r2);
1632         }
1633     }
1634     
1635     if (r1 != r1End)
1636     {
1637         do
1638         {
1639             MERGERECT(r1);
1640         } while (r1 != r1End);
1641     }
1642     else while (r2 != r2End)
1643     {
1644         MERGERECT(r2);
1645     }
1646     return;
1647 }
1648
1649 /***********************************************************************
1650  *           REGION_UnionRegion
1651  */
1652 static void REGION_UnionRegion(WINEREGION *newReg, WINEREGION *reg1,
1653                                WINEREGION *reg2)
1654 {
1655     /*  checks all the simple cases */
1656
1657     /*
1658      * Region 1 and 2 are the same or region 1 is empty
1659      */
1660     if ( (reg1 == reg2) || (!(reg1->numRects)) )
1661     {
1662         if (newReg != reg2)
1663             REGION_CopyRegion(newReg, reg2);
1664         return;
1665     }
1666
1667     /*
1668      * if nothing to union (region 2 empty)
1669      */
1670     if (!(reg2->numRects))
1671     {
1672         if (newReg != reg1)
1673             REGION_CopyRegion(newReg, reg1);
1674         return;
1675     }
1676
1677     /*
1678      * Region 1 completely subsumes region 2
1679      */
1680     if ((reg1->numRects == 1) && 
1681         (reg1->extents.left <= reg2->extents.left) &&
1682         (reg1->extents.top <= reg2->extents.top) &&
1683         (reg1->extents.right >= reg2->extents.right) &&
1684         (reg1->extents.bottom >= reg2->extents.bottom))
1685     {
1686         if (newReg != reg1)
1687             REGION_CopyRegion(newReg, reg1);
1688         return;
1689     }
1690
1691     /*
1692      * Region 2 completely subsumes region 1
1693      */
1694     if ((reg2->numRects == 1) && 
1695         (reg2->extents.left <= reg1->extents.left) &&
1696         (reg2->extents.top <= reg1->extents.top) &&
1697         (reg2->extents.right >= reg1->extents.right) &&
1698         (reg2->extents.bottom >= reg1->extents.bottom))
1699     {
1700         if (newReg != reg2)
1701             REGION_CopyRegion(newReg, reg2);
1702         return;
1703     }
1704
1705     REGION_RegionOp (newReg, reg1, reg2, (voidProcp) REGION_UnionO, 
1706                 (voidProcp) REGION_UnionNonO, (voidProcp) REGION_UnionNonO);
1707
1708     newReg->extents.left = MIN(reg1->extents.left, reg2->extents.left);
1709     newReg->extents.top = MIN(reg1->extents.top, reg2->extents.top);
1710     newReg->extents.right = MAX(reg1->extents.right, reg2->extents.right);
1711     newReg->extents.bottom = MAX(reg1->extents.bottom, reg2->extents.bottom);
1712     newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
1713     return;
1714 }
1715
1716 /***********************************************************************
1717  *           Region Subtraction
1718  ***********************************************************************/
1719
1720 /***********************************************************************
1721  *           REGION_SubtractNonO1
1722  *
1723  *      Deal with non-overlapping band for subtraction. Any parts from
1724  *      region 2 we discard. Anything from region 1 we add to the region.
1725  *
1726  * Results:
1727  *      None.
1728  *
1729  * Side Effects:
1730  *      pReg may be affected.
1731  *
1732  */
1733 static void REGION_SubtractNonO1 (WINEREGION *pReg, RECT *r, RECT *rEnd, 
1734                 INT top, INT bottom)
1735 {
1736     RECT *pNextRect;
1737         
1738     pNextRect = &pReg->rects[pReg->numRects];
1739         
1740     while (r != rEnd)
1741     {
1742         MEMCHECK(pReg, pNextRect, pReg->rects);
1743         pNextRect->left = r->left;
1744         pNextRect->top = top;
1745         pNextRect->right = r->right;
1746         pNextRect->bottom = bottom;
1747         pReg->numRects += 1;
1748         pNextRect++;
1749         r++;
1750     }
1751     return;
1752 }
1753
1754
1755 /***********************************************************************
1756  *           REGION_SubtractO
1757  *
1758  *      Overlapping band subtraction. x1 is the left-most point not yet
1759  *      checked.
1760  *
1761  * Results:
1762  *      None.
1763  *
1764  * Side Effects:
1765  *      pReg may have rectangles added to it.
1766  *
1767  */
1768 static void REGION_SubtractO (WINEREGION *pReg, RECT *r1, RECT *r1End, 
1769                 RECT *r2, RECT *r2End, INT top, INT bottom)
1770 {
1771     RECT *pNextRect;
1772     INT left;
1773     
1774     left = r1->left;
1775     pNextRect = &pReg->rects[pReg->numRects];
1776
1777     while ((r1 != r1End) && (r2 != r2End))
1778     {
1779         if (r2->right <= left)
1780         {
1781             /*
1782              * Subtrahend missed the boat: go to next subtrahend.
1783              */
1784             r2++;
1785         }
1786         else if (r2->left <= left)
1787         {
1788             /*
1789              * Subtrahend preceeds minuend: nuke left edge of minuend.
1790              */
1791             left = r2->right;
1792             if (left >= r1->right)
1793             {
1794                 /*
1795                  * Minuend completely covered: advance to next minuend and
1796                  * reset left fence to edge of new minuend.
1797                  */
1798                 r1++;
1799                 if (r1 != r1End)
1800                     left = r1->left;
1801             }
1802             else
1803             {
1804                 /*
1805                  * Subtrahend now used up since it doesn't extend beyond
1806                  * minuend
1807                  */
1808                 r2++;
1809             }
1810         }
1811         else if (r2->left < r1->right)
1812         {
1813             /*
1814              * Left part of subtrahend covers part of minuend: add uncovered
1815              * part of minuend to region and skip to next subtrahend.
1816              */
1817             MEMCHECK(pReg, pNextRect, pReg->rects);
1818             pNextRect->left = left;
1819             pNextRect->top = top;
1820             pNextRect->right = r2->left;
1821             pNextRect->bottom = bottom;
1822             pReg->numRects += 1;
1823             pNextRect++;
1824             left = r2->right;
1825             if (left >= r1->right)
1826             {
1827                 /*
1828                  * Minuend used up: advance to new...
1829                  */
1830                 r1++;
1831                 if (r1 != r1End)
1832                     left = r1->left;
1833             }
1834             else
1835             {
1836                 /*
1837                  * Subtrahend used up
1838                  */
1839                 r2++;
1840             }
1841         }
1842         else
1843         {
1844             /*
1845              * Minuend used up: add any remaining piece before advancing.
1846              */
1847             if (r1->right > left)
1848             {
1849                 MEMCHECK(pReg, pNextRect, pReg->rects);
1850                 pNextRect->left = left;
1851                 pNextRect->top = top;
1852                 pNextRect->right = r1->right;
1853                 pNextRect->bottom = bottom;
1854                 pReg->numRects += 1;
1855                 pNextRect++;
1856             }
1857             r1++;
1858             left = r1->left;
1859         }
1860     }
1861
1862     /*
1863      * Add remaining minuend rectangles to region.
1864      */
1865     while (r1 != r1End)
1866     {
1867         MEMCHECK(pReg, pNextRect, pReg->rects);
1868         pNextRect->left = left;
1869         pNextRect->top = top;
1870         pNextRect->right = r1->right;
1871         pNextRect->bottom = bottom;
1872         pReg->numRects += 1;
1873         pNextRect++;
1874         r1++;
1875         if (r1 != r1End)
1876         {
1877             left = r1->left;
1878         }
1879     }
1880     return;
1881 }
1882         
1883 /***********************************************************************
1884  *           REGION_SubtractRegion
1885  *
1886  *      Subtract regS from regM and leave the result in regD.
1887  *      S stands for subtrahend, M for minuend and D for difference.
1888  *
1889  * Results:
1890  *      TRUE.
1891  *
1892  * Side Effects:
1893  *      regD is overwritten.
1894  *
1895  */
1896 static void REGION_SubtractRegion(WINEREGION *regD, WINEREGION *regM,
1897                                                        WINEREGION *regS )
1898 {
1899    /* check for trivial reject */
1900     if ( (!(regM->numRects)) || (!(regS->numRects))  ||
1901         (!EXTENTCHECK(&regM->extents, &regS->extents)) )
1902     {
1903         REGION_CopyRegion(regD, regM);
1904         return;
1905     }
1906  
1907     REGION_RegionOp (regD, regM, regS, (voidProcp) REGION_SubtractO, 
1908                 (voidProcp) REGION_SubtractNonO1, (voidProcp) NULL);
1909
1910     /*
1911      * Can't alter newReg's extents before we call miRegionOp because
1912      * it might be one of the source regions and miRegionOp depends
1913      * on the extents of those regions being the unaltered. Besides, this
1914      * way there's no checking against rectangles that will be nuked
1915      * due to coalescing, so we have to examine fewer rectangles.
1916      */
1917     REGION_SetExtents (regD);
1918     regD->type = (regD->numRects) ? COMPLEXREGION : NULLREGION ;
1919     return;
1920 }
1921
1922 /***********************************************************************
1923  *           REGION_XorRegion
1924  */
1925 static void REGION_XorRegion(WINEREGION *dr, WINEREGION *sra,
1926                                                         WINEREGION *srb)
1927 {
1928     WINEREGION *tra, *trb;
1929
1930     if ((! (tra = REGION_AllocWineRegion(sra->numRects + 1))) || 
1931         (! (trb = REGION_AllocWineRegion(srb->numRects + 1))))
1932         return;
1933     REGION_SubtractRegion(tra,sra,srb);
1934     REGION_SubtractRegion(trb,srb,sra);
1935     REGION_UnionRegion(dr,tra,trb);
1936     REGION_DestroyWineRegion(tra);
1937     REGION_DestroyWineRegion(trb);
1938     return;
1939 }
1940
1941 /**************************************************************************
1942  *
1943  *    Poly Regions
1944  * 
1945  *************************************************************************/
1946
1947 #define LARGE_COORDINATE  0x7fffffff /* FIXME */
1948 #define SMALL_COORDINATE  0x80000000
1949
1950 /***********************************************************************
1951  *     REGION_InsertEdgeInET
1952  *
1953  *     Insert the given edge into the edge table.
1954  *     First we must find the correct bucket in the
1955  *     Edge table, then find the right slot in the
1956  *     bucket.  Finally, we can insert it.
1957  *
1958  */
1959 static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
1960                 INT scanline, ScanLineListBlock **SLLBlock, INT *iSLLBlock)
1961
1962 {
1963     EdgeTableEntry *start, *prev;
1964     ScanLineList *pSLL, *pPrevSLL;
1965     ScanLineListBlock *tmpSLLBlock;
1966
1967     /*
1968      * find the right bucket to put the edge into
1969      */
1970     pPrevSLL = &ET->scanlines;
1971     pSLL = pPrevSLL->next;
1972     while (pSLL && (pSLL->scanline < scanline)) 
1973     {
1974         pPrevSLL = pSLL;
1975         pSLL = pSLL->next;
1976     }
1977
1978     /*
1979      * reassign pSLL (pointer to ScanLineList) if necessary
1980      */
1981     if ((!pSLL) || (pSLL->scanline > scanline)) 
1982     {
1983         if (*iSLLBlock > SLLSPERBLOCK-1) 
1984         {
1985             tmpSLLBlock = HeapAlloc( SystemHeap, 0, sizeof(ScanLineListBlock));
1986             if(!tmpSLLBlock)
1987             {
1988                 WARN(region, "Can't alloc SLLB\n");
1989                 return;
1990             }
1991             (*SLLBlock)->next = tmpSLLBlock;
1992             tmpSLLBlock->next = (ScanLineListBlock *)NULL;
1993             *SLLBlock = tmpSLLBlock;
1994             *iSLLBlock = 0;
1995         }
1996         pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
1997
1998         pSLL->next = pPrevSLL->next;
1999         pSLL->edgelist = (EdgeTableEntry *)NULL;
2000         pPrevSLL->next = pSLL;
2001     }
2002     pSLL->scanline = scanline;
2003
2004     /*
2005      * now insert the edge in the right bucket
2006      */
2007     prev = (EdgeTableEntry *)NULL;
2008     start = pSLL->edgelist;
2009     while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) 
2010     {
2011         prev = start;
2012         start = start->next;
2013     }
2014     ETE->next = start;
2015
2016     if (prev)
2017         prev->next = ETE;
2018     else
2019         pSLL->edgelist = ETE;
2020 }
2021
2022 /***********************************************************************
2023  *     REGION_CreateEdgeTable
2024  *
2025  *     This routine creates the edge table for
2026  *     scan converting polygons. 
2027  *     The Edge Table (ET) looks like:
2028  *
2029  *    EdgeTable
2030  *     --------
2031  *    |  ymax  |        ScanLineLists
2032  *    |scanline|-->------------>-------------->...
2033  *     --------   |scanline|   |scanline|
2034  *                |edgelist|   |edgelist|
2035  *                ---------    ---------
2036  *                    |             |
2037  *                    |             |
2038  *                    V             V
2039  *              list of ETEs   list of ETEs
2040  *
2041  *     where ETE is an EdgeTableEntry data structure,
2042  *     and there is one ScanLineList per scanline at
2043  *     which an edge is initially entered.
2044  *
2045  */
2046 static void REGION_CreateETandAET(const INT *Count, INT nbpolygons, 
2047             const POINT *pts, EdgeTable *ET, EdgeTableEntry *AET,
2048             EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
2049 {
2050     const POINT *top, *bottom;
2051     const POINT *PrevPt, *CurrPt, *EndPt;
2052     INT poly, count;
2053     int iSLLBlock = 0;
2054     int dy;
2055
2056     
2057     /*
2058      *  initialize the Active Edge Table
2059      */
2060     AET->next = (EdgeTableEntry *)NULL;
2061     AET->back = (EdgeTableEntry *)NULL;
2062     AET->nextWETE = (EdgeTableEntry *)NULL;
2063     AET->bres.minor_axis = SMALL_COORDINATE;
2064
2065     /*
2066      *  initialize the Edge Table.
2067      */
2068     ET->scanlines.next = (ScanLineList *)NULL;
2069     ET->ymax = SMALL_COORDINATE;
2070     ET->ymin = LARGE_COORDINATE;
2071     pSLLBlock->next = (ScanLineListBlock *)NULL;
2072
2073     EndPt = pts - 1;
2074     for(poly = 0; poly < nbpolygons; poly++)
2075     {
2076         count = Count[poly];
2077         EndPt += count;
2078         if(count < 2)
2079             continue;
2080         
2081         PrevPt = EndPt;
2082
2083     /*
2084      *  for each vertex in the array of points.
2085      *  In this loop we are dealing with two vertices at
2086      *  a time -- these make up one edge of the polygon.
2087      */
2088         while (count--) 
2089         {
2090             CurrPt = pts++;
2091
2092         /*
2093          *  find out which point is above and which is below.
2094          */
2095             if (PrevPt->y > CurrPt->y) 
2096             {
2097                 bottom = PrevPt, top = CurrPt;
2098                 pETEs->ClockWise = 0;
2099             }
2100             else 
2101             {
2102                 bottom = CurrPt, top = PrevPt;
2103                 pETEs->ClockWise = 1;
2104             }
2105
2106         /*
2107          * don't add horizontal edges to the Edge table.
2108          */
2109             if (bottom->y != top->y) 
2110             {
2111                 pETEs->ymax = bottom->y-1;
2112                                 /* -1 so we don't get last scanline */
2113
2114             /*
2115              *  initialize integer edge algorithm
2116              */
2117                 dy = bottom->y - top->y;
2118                 BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
2119
2120                 REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, 
2121                                                                 &iSLLBlock);
2122
2123                 if (PrevPt->y > ET->ymax)
2124                   ET->ymax = PrevPt->y;
2125                 if (PrevPt->y < ET->ymin)
2126                   ET->ymin = PrevPt->y;
2127                 pETEs++;
2128             }
2129
2130             PrevPt = CurrPt;
2131         }
2132     }
2133 }
2134
2135 /***********************************************************************
2136  *     REGION_loadAET
2137  *
2138  *     This routine moves EdgeTableEntries from the
2139  *     EdgeTable into the Active Edge Table,
2140  *     leaving them sorted by smaller x coordinate.
2141  *
2142  */
2143 static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
2144 {
2145     EdgeTableEntry *pPrevAET;
2146     EdgeTableEntry *tmp;
2147
2148     pPrevAET = AET;
2149     AET = AET->next;
2150     while (ETEs) 
2151     {
2152         while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis)) 
2153         {
2154             pPrevAET = AET;
2155             AET = AET->next;
2156         }
2157         tmp = ETEs->next;
2158         ETEs->next = AET;
2159         if (AET)
2160             AET->back = ETEs;
2161         ETEs->back = pPrevAET;
2162         pPrevAET->next = ETEs;
2163         pPrevAET = ETEs;
2164
2165         ETEs = tmp;
2166     }
2167 }
2168
2169 /***********************************************************************
2170  *     REGION_computeWAET
2171  *
2172  *     This routine links the AET by the
2173  *     nextWETE (winding EdgeTableEntry) link for
2174  *     use by the winding number rule.  The final 
2175  *     Active Edge Table (AET) might look something
2176  *     like:
2177  *
2178  *     AET
2179  *     ----------  ---------   ---------
2180  *     |ymax    |  |ymax    |  |ymax    | 
2181  *     | ...    |  |...     |  |...     |
2182  *     |next    |->|next    |->|next    |->...
2183  *     |nextWETE|  |nextWETE|  |nextWETE|
2184  *     ---------   ---------   ^--------
2185  *         |                   |       |
2186  *         V------------------->       V---> ...
2187  *
2188  */
2189 static void REGION_computeWAET(EdgeTableEntry *AET)
2190 {
2191     register EdgeTableEntry *pWETE;
2192     register int inside = 1;
2193     register int isInside = 0;
2194
2195     AET->nextWETE = (EdgeTableEntry *)NULL;
2196     pWETE = AET;
2197     AET = AET->next;
2198     while (AET) 
2199     {
2200         if (AET->ClockWise)
2201             isInside++;
2202         else
2203             isInside--;
2204
2205         if ((!inside && !isInside) ||
2206             ( inside &&  isInside)) 
2207         {
2208             pWETE->nextWETE = AET;
2209             pWETE = AET;
2210             inside = !inside;
2211         }
2212         AET = AET->next;
2213     }
2214     pWETE->nextWETE = (EdgeTableEntry *)NULL;
2215 }
2216
2217 /***********************************************************************
2218  *     REGION_InsertionSort
2219  *
2220  *     Just a simple insertion sort using
2221  *     pointers and back pointers to sort the Active
2222  *     Edge Table.
2223  *
2224  */
2225 static BOOL REGION_InsertionSort(EdgeTableEntry *AET)
2226 {
2227     EdgeTableEntry *pETEchase;
2228     EdgeTableEntry *pETEinsert;
2229     EdgeTableEntry *pETEchaseBackTMP;
2230     BOOL changed = FALSE;
2231
2232     AET = AET->next;
2233     while (AET) 
2234     {
2235         pETEinsert = AET;
2236         pETEchase = AET;
2237         while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
2238             pETEchase = pETEchase->back;
2239
2240         AET = AET->next;
2241         if (pETEchase != pETEinsert) 
2242         {
2243             pETEchaseBackTMP = pETEchase->back;
2244             pETEinsert->back->next = AET;
2245             if (AET)
2246                 AET->back = pETEinsert->back;
2247             pETEinsert->next = pETEchase;
2248             pETEchase->back->next = pETEinsert;
2249             pETEchase->back = pETEinsert;
2250             pETEinsert->back = pETEchaseBackTMP;
2251             changed = TRUE;
2252         }
2253     }
2254     return changed;
2255 }
2256
2257 /***********************************************************************
2258  *     REGION_FreeStorage
2259  *
2260  *     Clean up our act.
2261  */
2262 static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
2263 {
2264     ScanLineListBlock   *tmpSLLBlock;
2265
2266     while (pSLLBlock) 
2267     {
2268         tmpSLLBlock = pSLLBlock->next;
2269         HeapFree( SystemHeap, 0, pSLLBlock );
2270         pSLLBlock = tmpSLLBlock;
2271     }
2272 }
2273
2274
2275 /***********************************************************************
2276  *     REGION_PtsToRegion
2277  *
2278  *     Create an array of rectangles from a list of points.
2279  */
2280 static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock, 
2281                        POINTBLOCK *FirstPtBlock, WINEREGION *reg)
2282 {
2283     RECT *rects;
2284     POINT *pts;
2285     POINTBLOCK *CurPtBlock;
2286     int i;
2287     RECT *extents;
2288     INT numRects;
2289  
2290     extents = &reg->extents;
2291  
2292     numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
2293  
2294     if (!(reg->rects = HeapReAlloc( SystemHeap, 0, reg->rects, 
2295                            sizeof(RECT) * numRects )))
2296         return(0);
2297  
2298     reg->size = numRects;
2299     CurPtBlock = FirstPtBlock;
2300     rects = reg->rects - 1;
2301     numRects = 0;
2302     extents->left = LARGE_COORDINATE,  extents->right = SMALL_COORDINATE;
2303  
2304     for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
2305         /* the loop uses 2 points per iteration */
2306         i = NUMPTSTOBUFFER >> 1;
2307         if (!numFullPtBlocks)
2308             i = iCurPtBlock >> 1;
2309         for (pts = CurPtBlock->pts; i--; pts += 2) {
2310             if (pts->x == pts[1].x)
2311                 continue;
2312             if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
2313                 pts[1].x == rects->right &&
2314                 (numRects == 1 || rects[-1].top != rects->top) &&
2315                 (i && pts[2].y > pts[1].y)) {
2316                 rects->bottom = pts[1].y + 1;
2317                 continue;
2318             }
2319             numRects++;
2320             rects++;
2321             rects->left = pts->x;  rects->top = pts->y;
2322             rects->right = pts[1].x;  rects->bottom = pts[1].y + 1;
2323             if (rects->left < extents->left)
2324                 extents->left = rects->left;
2325             if (rects->right > extents->right)
2326                 extents->right = rects->right;
2327         }
2328         CurPtBlock = CurPtBlock->next;
2329     }
2330
2331     if (numRects) {
2332         extents->top = reg->rects->top;
2333         extents->bottom = rects->bottom;
2334     } else {
2335         extents->left = 0;
2336         extents->top = 0;
2337         extents->right = 0;
2338         extents->bottom = 0;
2339     }
2340     reg->numRects = numRects;
2341  
2342     return(TRUE);
2343 }
2344
2345 /***********************************************************************
2346  *           CreatePolyPolygonRgn32    (GDI32.57)
2347  */
2348 HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count, 
2349                       INT nbpolygons, INT mode)
2350 {
2351     HRGN hrgn;
2352     RGNOBJ *obj;
2353     WINEREGION *region;
2354     register EdgeTableEntry *pAET;   /* Active Edge Table       */
2355     register INT y;                /* current scanline        */
2356     register int iPts = 0;           /* number of pts in buffer */
2357     register EdgeTableEntry *pWETE;  /* Winding Edge Table Entry*/
2358     register ScanLineList *pSLL;     /* current scanLineList    */
2359     register POINT *pts;           /* output buffer           */
2360     EdgeTableEntry *pPrevAET;        /* ptr to previous AET     */
2361     EdgeTable ET;                    /* header node for ET      */
2362     EdgeTableEntry AET;              /* header node for AET     */
2363     EdgeTableEntry *pETEs;           /* EdgeTableEntries pool   */
2364     ScanLineListBlock SLLBlock;      /* header for scanlinelist */
2365     int fixWAET = FALSE;
2366     POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers    */
2367     POINTBLOCK *tmpPtBlock;
2368     int numFullPtBlocks = 0;
2369     INT poly, total;
2370
2371     if(!(hrgn = REGION_CreateRegion(nbpolygons)))
2372         return 0;
2373     obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
2374     region = obj->rgn;
2375
2376     /* special case a rectangle */
2377
2378     if (((nbpolygons == 1) && ((*Count == 4) ||
2379        ((*Count == 5) && (Pts[4].x == Pts[0].x) && (Pts[4].y == Pts[0].y)))) &&
2380         (((Pts[0].y == Pts[1].y) &&
2381           (Pts[1].x == Pts[2].x) &&
2382           (Pts[2].y == Pts[3].y) &&
2383           (Pts[3].x == Pts[0].x)) ||
2384          ((Pts[0].x == Pts[1].x) &&
2385           (Pts[1].y == Pts[2].y) &&
2386           (Pts[2].x == Pts[3].x) &&
2387           (Pts[3].y == Pts[0].y))))
2388     {
2389         SetRectRgn( hrgn, MIN(Pts[0].x, Pts[2].x), MIN(Pts[0].y, Pts[2].y), 
2390                             MAX(Pts[0].x, Pts[2].x), MAX(Pts[0].y, Pts[2].y) );
2391         GDI_HEAP_UNLOCK( hrgn );
2392         return hrgn;
2393     }
2394     
2395     for(poly = total = 0; poly < nbpolygons; poly++)
2396         total += Count[poly];
2397     if (! (pETEs = HeapAlloc( SystemHeap, 0, sizeof(EdgeTableEntry) * total )))
2398     {
2399         REGION_DeleteObject( hrgn, obj );
2400         return 0;
2401     }
2402     pts = FirstPtBlock.pts;
2403     REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
2404     pSLL = ET.scanlines.next;
2405     curPtBlock = &FirstPtBlock;
2406  
2407     if (mode != WINDING) {
2408         /*
2409          *  for each scanline
2410          */
2411         for (y = ET.ymin; y < ET.ymax; y++) {
2412             /*
2413              *  Add a new edge to the active edge table when we
2414              *  get to the next edge.
2415              */
2416             if (pSLL != NULL && y == pSLL->scanline) {
2417                 REGION_loadAET(&AET, pSLL->edgelist);
2418                 pSLL = pSLL->next;
2419             }
2420             pPrevAET = &AET;
2421             pAET = AET.next;
2422  
2423             /*
2424              *  for each active edge
2425              */
2426             while (pAET) {
2427                 pts->x = pAET->bres.minor_axis,  pts->y = y;
2428                 pts++, iPts++;
2429  
2430                 /*
2431                  *  send out the buffer
2432                  */
2433                 if (iPts == NUMPTSTOBUFFER) {
2434                     tmpPtBlock = HeapAlloc( SystemHeap, 0, sizeof(POINTBLOCK));
2435                     if(!tmpPtBlock) {
2436                         WARN(region, "Can't alloc tPB\n");
2437                         return 0;
2438                     }
2439                     curPtBlock->next = tmpPtBlock;
2440                     curPtBlock = tmpPtBlock;
2441                     pts = curPtBlock->pts;
2442                     numFullPtBlocks++;
2443                     iPts = 0;
2444                 }
2445                 EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
2446             }
2447             REGION_InsertionSort(&AET);
2448         }
2449     }
2450     else {
2451         /*
2452          *  for each scanline
2453          */
2454         for (y = ET.ymin; y < ET.ymax; y++) {
2455             /*
2456              *  Add a new edge to the active edge table when we
2457              *  get to the next edge.
2458              */
2459             if (pSLL != NULL && y == pSLL->scanline) {
2460                 REGION_loadAET(&AET, pSLL->edgelist);
2461                 REGION_computeWAET(&AET);
2462                 pSLL = pSLL->next;
2463             }
2464             pPrevAET = &AET;
2465             pAET = AET.next;
2466             pWETE = pAET;
2467  
2468             /*
2469              *  for each active edge
2470              */
2471             while (pAET) {
2472                 /*
2473                  *  add to the buffer only those edges that
2474                  *  are in the Winding active edge table.
2475                  */
2476                 if (pWETE == pAET) {
2477                     pts->x = pAET->bres.minor_axis,  pts->y = y;
2478                     pts++, iPts++;
2479  
2480                     /*
2481                      *  send out the buffer
2482                      */
2483                     if (iPts == NUMPTSTOBUFFER) {
2484                         tmpPtBlock = HeapAlloc( SystemHeap, 0,
2485                                                sizeof(POINTBLOCK) );
2486                         if(!tmpPtBlock) {
2487                             WARN(region, "Can't alloc tPB\n");
2488                             return 0;
2489                         }
2490                         curPtBlock->next = tmpPtBlock;
2491                         curPtBlock = tmpPtBlock;
2492                         pts = curPtBlock->pts;
2493                         numFullPtBlocks++;    iPts = 0;
2494                     }
2495                     pWETE = pWETE->nextWETE;
2496                 }
2497                 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
2498             }
2499  
2500             /*
2501              *  recompute the winding active edge table if
2502              *  we just resorted or have exited an edge.
2503              */
2504             if (REGION_InsertionSort(&AET) || fixWAET) {
2505                 REGION_computeWAET(&AET);
2506                 fixWAET = FALSE;
2507             }
2508         }
2509     }
2510     REGION_FreeStorage(SLLBlock.next);  
2511     REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
2512     for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
2513         tmpPtBlock = curPtBlock->next;
2514         HeapFree( SystemHeap, 0, curPtBlock );
2515         curPtBlock = tmpPtBlock;
2516     }
2517     HeapFree( SystemHeap, 0, pETEs );
2518     GDI_HEAP_UNLOCK( hrgn );
2519     return hrgn;
2520 }
2521
2522
2523 /***********************************************************************
2524  *           CreatePolygonRgn16    (GDI.63)
2525  */
2526 HRGN16 WINAPI CreatePolygonRgn16( const POINT16 * points, INT16 count,
2527                                   INT16 mode )
2528 {
2529     return CreatePolyPolygonRgn16( points, &count, 1, mode );
2530 }
2531
2532 /***********************************************************************
2533  *           CreatePolyPolygonRgn16    (GDI.451)
2534  */
2535 HRGN16 WINAPI CreatePolyPolygonRgn16( const POINT16 *points,
2536                 const INT16 *count, INT16 nbpolygons, INT16 mode )
2537 {
2538     HRGN hrgn;
2539     int i, npts = 0;
2540     INT *count32;
2541     POINT *points32;
2542
2543     for (i = 0; i < nbpolygons; i++)
2544         npts += count[i];
2545     points32 = HeapAlloc( SystemHeap, 0, npts * sizeof(POINT) );
2546     for (i = 0; i < npts; i++)
2547         CONV_POINT16TO32( &(points[i]), &(points32[i]) );
2548
2549     count32 = HeapAlloc( SystemHeap, 0, nbpolygons * sizeof(INT) );
2550     for (i = 0; i < nbpolygons; i++)
2551         count32[i] = count[i];
2552     hrgn = CreatePolyPolygonRgn( points32, count32, nbpolygons, mode );
2553     HeapFree( SystemHeap, 0, count32 );
2554     HeapFree( SystemHeap, 0, points32 );
2555     return hrgn;
2556 }
2557
2558 /***********************************************************************
2559  *           CreatePolygonRgn32    (GDI32.58)
2560  */
2561 HRGN WINAPI CreatePolygonRgn( const POINT *points, INT count,
2562                                   INT mode )
2563 {
2564     return CreatePolyPolygonRgn( points, &count, 1, mode );
2565 }
2566
2567
2568 /***********************************************************************
2569  * GetRandomRgn [GDI32.215]
2570  *
2571  * NOTES
2572  *     This function is UNDOCUMENTED, it isn't even in the header file.
2573  *     I assume that it will return a HRGN32!??
2574  */
2575 HRGN WINAPI GetRandomRgn(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3)
2576 {
2577     FIXME (region, "(0x%08lx 0x%08lx 0x%08lx): empty stub!\n",
2578            dwArg1, dwArg2, dwArg3);
2579
2580     return 0;
2581 }
2582
2583 /***********************************************************************
2584  *           REGION_CropAndOffsetRegion
2585  */
2586 static BOOL REGION_CropAndOffsetRegion(const POINT* off, const RECT *rect, WINEREGION *rgnSrc, WINEREGION* rgnDst)
2587 {
2588     if( IsRectEmpty(rect) || !EXTENTCHECK(rect, &rgnSrc->extents) )
2589     {
2590 empty:
2591         if( !rgnDst->rects )
2592         {
2593             rgnDst->rects = HeapAlloc(SystemHeap, 0, sizeof( RECT ));
2594             if( rgnDst->rects )
2595                 rgnDst->size = 1;
2596             else
2597                 return FALSE;
2598         }
2599
2600         TRACE(region,"cropped to empty!\n");
2601         EMPTY_REGION(rgnDst);
2602     }
2603     else /* region box and clipping rect appear to intersect */
2604     {
2605         RECT *lpr;
2606         INT i, j, clipa, clipb;
2607         INT left = rgnSrc->extents.right + off->x;
2608         INT right = rgnSrc->extents.left + off->x;
2609
2610         for( clipa = 0; rgnSrc->rects[clipa].bottom <= rect->top; clipa++ )
2611              ; /* skip bands above the clipping rectangle */
2612
2613         for( clipb = clipa; clipb < rgnSrc->numRects; clipb++ )
2614              if( rgnSrc->rects[clipb].top >= rect->bottom )
2615                  break;    /* and below it */
2616
2617         /* clipa - index of the first rect in the first intersecting band
2618          * clipb - index of the last rect in the last intersecting band
2619          */
2620
2621         if((rgnDst != rgnSrc) && (rgnDst->size < (i = (clipb - clipa))))
2622         {
2623             rgnDst->rects = HeapReAlloc( SystemHeap, 0, 
2624                                 rgnDst->rects, i * sizeof(RECT));
2625             if( !rgnDst->rects ) return FALSE;
2626             rgnDst->size = i;
2627         }
2628
2629         if( TRACE_ON(region) )
2630         {
2631             REGION_DumpRegion( rgnSrc );
2632             TRACE(region,"\tclipa = %i, clipb = %i\n", clipa, clipb );
2633         }
2634
2635         for( i = clipa, j = 0; i < clipb ; i++ )
2636         {
2637              /* i - src index, j - dst index, j is always <= i for obvious reasons */
2638
2639              lpr = rgnSrc->rects + i;
2640              if( lpr->left < rect->right && lpr->right > rect->left )
2641              {
2642                  rgnDst->rects[j].top = lpr->top + off->y;
2643                  rgnDst->rects[j].bottom = lpr->bottom + off->y;
2644                  rgnDst->rects[j].left = ((lpr->left > rect->left) ? lpr->left : rect->left) + off->x;
2645                  rgnDst->rects[j].right = ((lpr->right < rect->right) ? lpr->right : rect->right) + off->x;
2646
2647                  if( rgnDst->rects[j].left < left ) left = rgnDst->rects[j].left;
2648                  if( rgnDst->rects[j].right > right ) right = rgnDst->rects[j].right;
2649
2650                  j++;
2651              }
2652         }
2653
2654         if( j == 0 ) goto empty;
2655
2656         rgnDst->extents.left = left;
2657         rgnDst->extents.right = right;
2658
2659         left = rect->top + off->y;
2660         right = rect->bottom + off->y;
2661
2662         rgnDst->numRects = j--;
2663         for( i = 0; i <= j; i++ )       /* fixup top band */
2664              if( rgnDst->rects[i].top < left )
2665                  rgnDst->rects[i].top = left;
2666              else
2667                  break;
2668
2669         for( i = j; i >= 0; i-- )       /* fixup bottom band */
2670              if( rgnDst->rects[i].bottom > right )
2671                  rgnDst->rects[i].bottom = right;
2672              else
2673                  break;
2674
2675         rgnDst->extents.top = rgnDst->rects[0].top;
2676         rgnDst->extents.bottom = rgnDst->rects[j].bottom;
2677
2678         rgnDst->type = (j >= 1) ? COMPLEXREGION : SIMPLEREGION;
2679
2680         if( TRACE_ON(region) )
2681         {
2682             TRACE(region,"result:\n");
2683             REGION_DumpRegion( rgnDst );
2684         }
2685     }
2686
2687     return TRUE;
2688 }
2689
2690 /***********************************************************************
2691  *           REGION_CropRgn
2692  *
2693  *
2694  * hSrc:        Region to crop and offset.
2695  * lpRect:      Clipping rectangle.
2696  * lpPt:        Points to offset the cropped region. Can be NULL.
2697  *
2698  * hDst: Region to hold the result (if 0 a new region is created).
2699  *       Allowed to be the same region as hSrc (in place, no extra memory needed).
2700  *
2701  * Returns: hDst if success, 0 otherwise.
2702  */
2703 HRGN REGION_CropRgn( HRGN hDst, HRGN hSrc, const RECT *lpRect, const POINT *lpPt )
2704 {
2705 /*  Optimization of the following generic code:
2706
2707     HRGN h = CreateRectRgn( lpRect->left, lpRect->top, lpRect->right, lpRect->bottom );
2708     if( hDst == 0 ) hDst = h;
2709     CombineRgn( hDst, hSrc, h, RGN_AND );
2710     if( lpPt )
2711         OffsetRgn( hDst, lpPt->x, lpPt->y );
2712     if( hDst != h )
2713         DeleteObject( h );
2714     return hDst;
2715
2716 */
2717
2718     RGNOBJ *objSrc = (RGNOBJ *) GDI_HEAP_LOCK( hSrc );
2719
2720     if(objSrc)
2721     {
2722         RGNOBJ *objDst;
2723         WINEREGION *rgnDst;
2724
2725         if( hDst )
2726         {
2727             objDst = (RGNOBJ *) GDI_HEAP_LOCK( hDst );
2728             rgnDst = objDst->rgn;
2729         }
2730         else
2731         {
2732             rgnDst = HeapAlloc(SystemHeap, 0, sizeof( WINEREGION ));
2733             if( rgnDst ) 
2734             {
2735                 rgnDst->size = rgnDst->numRects = 0;
2736                 rgnDst->rects = NULL;   /* back end will allocate exact number */
2737             }
2738         }
2739
2740         if( rgnDst )
2741         {
2742             POINT pt = { 0, 0 };
2743
2744             if( !lpPt ) lpPt = &pt;
2745
2746             TRACE(region, "src %p -> dst %p (%i,%i)-(%i,%i) by (%li,%li)\n", objSrc->rgn, rgnDst,
2747                            lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, lpPt->x, lpPt->y );
2748
2749             if( REGION_CropAndOffsetRegion( lpPt, lpRect, objSrc->rgn, rgnDst ) == FALSE )
2750             {
2751                 if( hDst ) /* existing rgn */
2752                 {
2753                     GDI_HEAP_UNLOCK(hDst);
2754                     hDst = 0;
2755                     goto done;
2756                 }
2757                 goto fail;
2758             }
2759             else if( hDst == 0 )
2760             {
2761                 if(!(hDst = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
2762                 {
2763 fail:
2764                     if( rgnDst->rects )
2765                         HeapFree( SystemHeap, 0, rgnDst->rects );
2766                     HeapFree( SystemHeap, 0, rgnDst );
2767                     goto done;
2768                 }
2769
2770                 objDst = (RGNOBJ *) GDI_HEAP_LOCK( hDst );
2771                 objDst->rgn = rgnDst;
2772             }
2773
2774             GDI_HEAP_UNLOCK(hDst);
2775         }
2776         else hDst = 0;
2777 done:
2778         GDI_HEAP_UNLOCK(hSrc);
2779         return hDst;
2780     }
2781     return 0;
2782 }
2783