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