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