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