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