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