Set selector 0000H base to 0xf0000 until the first 64K are
[wine] / objects / region.c
1 /*
2  * GDI region objects. Shamelessly ripped out from the X11 distribution
3  * Thanks for the nice licence.
4  *
5  * Copyright 1993, 1994, 1995 Alexandre Julliard
6  * Modifications and additions: Copyright 1998 Huw Davies
7  *                                        1999 Alex Korobka
8  *
9  */
10
11 /************************************************************************
12
13 Copyright (c) 1987, 1988  X Consortium
14
15 Permission is hereby granted, free of charge, to any person obtaining a copy
16 of this software and associated documentation files (the "Software"), to deal
17 in the Software without restriction, including without limitation the rights
18 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19 copies of the Software, and to permit persons to whom the Software is
20 furnished to do so, subject to the following conditions:
21
22 The above copyright notice and this permission notice shall be included in
23 all copies or substantial portions of the Software.
24
25 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
28 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
29 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
32 Except as contained in this notice, the name of the X Consortium shall not be
33 used in advertising or otherwise to promote the sale, use or other dealings
34 in this Software without prior written authorization from the X Consortium.
35
36
37 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
38
39                         All Rights Reserved
40
41 Permission to use, copy, modify, and distribute this software and its 
42 documentation for any purpose and without fee is hereby granted, 
43 provided that the above copyright notice appear in all copies and that
44 both that copyright notice and this permission notice appear in 
45 supporting documentation, and that the name of Digital not be
46 used in advertising or publicity pertaining to distribution of the
47 software without specific, written prior permission.  
48
49 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
50 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
51 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
52 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
53 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
54 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
55 SOFTWARE.
56
57 ************************************************************************/
58 /*
59  * The functions in this file implement the Region abstraction, similar to one
60  * used in the X11 sample server. A Region is simply an area, as the name
61  * implies, and is implemented as a "y-x-banded" array of rectangles. To
62  * explain: Each Region is made up of a certain number of rectangles sorted
63  * by y coordinate first, and then by x coordinate.
64  *
65  * Furthermore, the rectangles are banded such that every rectangle with a
66  * given upper-left y coordinate (y1) will have the same lower-right y
67  * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
68  * will span the entire vertical distance of the band. This means that some
69  * areas that could be merged into a taller rectangle will be represented as
70  * several shorter rectangles to account for shorter rectangles to its left
71  * or right but within its "vertical scope".
72  *
73  * An added constraint on the rectangles is that they must cover as much
74  * horizontal area as possible. E.g. no two rectangles in a band are allowed
75  * to touch.
76  *
77  * Whenever possible, bands will be merged together to cover a greater vertical
78  * distance (and thus reduce the number of rectangles). Two bands can be merged
79  * only if the bottom of one touches the top of the other and they have
80  * rectangles in the same places (of the same width, of course). This maintains
81  * the y-x-banding that's so nice to have...
82  */
83
84 #include <stdlib.h>
85 #include <string.h>
86 #include "windef.h"
87 #include "wingdi.h"
88 #include "debugtools.h"
89 #include "region.h"
90 #include "heap.h"
91 #include "dc.h"
92
93 DEFAULT_DEBUG_CHANNEL(region);
94
95 /*  1 if two RECTs overlap.
96  *  0 if two RECTs do not overlap.
97  */
98 #define EXTENTCHECK(r1, r2) \
99         ((r1)->right > (r2)->left && \
100          (r1)->left < (r2)->right && \
101          (r1)->bottom > (r2)->top && \
102          (r1)->top < (r2)->bottom)
103
104 /*
105  *   Check to see if there is enough memory in the present region.
106  */
107 #define MEMCHECK(reg, rect, firstrect){\
108         if ((reg)->numRects >= ((reg)->size - 1)){\
109           (firstrect) = HeapReAlloc( GetProcessHeap(), 0, \
110            (firstrect), (2 * (sizeof(RECT)) * ((reg)->size)));\
111           if ((firstrect) == 0)\
112             return;\
113           (reg)->size *= 2;\
114           (rect) = &(firstrect)[(reg)->numRects];\
115          }\
116        }
117
118 #define EMPTY_REGION(pReg) { \
119     (pReg)->numRects = 0; \
120     (pReg)->extents.left = (pReg)->extents.top = 0; \
121     (pReg)->extents.right = (pReg)->extents.bottom = 0; \
122     (pReg)->type = NULLREGION; \
123  }
124
125 #define REGION_NOT_EMPTY(pReg) pReg->numRects
126
127 #define INRECT(r, x, y) \
128       ( ( ((r).right >  x)) && \
129         ( ((r).left <= x)) && \
130         ( ((r).bottom >  y)) && \
131         ( ((r).top <= y)) )
132
133
134 /*
135  * number of points to buffer before sending them off
136  * to scanlines() :  Must be an even number
137  */
138 #define NUMPTSTOBUFFER 200
139
140 /*
141  * used to allocate buffers for points and link
142  * the buffers together
143  */
144
145 typedef struct _POINTBLOCK {
146     POINT pts[NUMPTSTOBUFFER];
147     struct _POINTBLOCK *next;
148 } POINTBLOCK;
149
150
151
152 /*
153  *     This file contains a few macros to help track
154  *     the edge of a filled object.  The object is assumed
155  *     to be filled in scanline order, and thus the
156  *     algorithm used is an extension of Bresenham's line
157  *     drawing algorithm which assumes that y is always the
158  *     major axis.
159  *     Since these pieces of code are the same for any filled shape,
160  *     it is more convenient to gather the library in one
161  *     place, but since these pieces of code are also in
162  *     the inner loops of output primitives, procedure call
163  *     overhead is out of the question.
164  *     See the author for a derivation if needed.
165  */
166
167
168 /*
169  *  In scan converting polygons, we want to choose those pixels
170  *  which are inside the polygon.  Thus, we add .5 to the starting
171  *  x coordinate for both left and right edges.  Now we choose the
172  *  first pixel which is inside the pgon for the left edge and the
173  *  first pixel which is outside the pgon for the right edge.
174  *  Draw the left pixel, but not the right.
175  *
176  *  How to add .5 to the starting x coordinate:
177  *      If the edge is moving to the right, then subtract dy from the
178  *  error term from the general form of the algorithm.
179  *      If the edge is moving to the left, then add dy to the error term.
180  *
181  *  The reason for the difference between edges moving to the left
182  *  and edges moving to the right is simple:  If an edge is moving
183  *  to the right, then we want the algorithm to flip immediately.
184  *  If it is moving to the left, then we don't want it to flip until
185  *  we traverse an entire pixel.
186  */
187 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
188     int dx;      /* local storage */ \
189 \
190     /* \
191      *  if the edge is horizontal, then it is ignored \
192      *  and assumed not to be processed.  Otherwise, do this stuff. \
193      */ \
194     if ((dy) != 0) { \
195         xStart = (x1); \
196         dx = (x2) - xStart; \
197         if (dx < 0) { \
198             m = dx / (dy); \
199             m1 = m - 1; \
200             incr1 = -2 * dx + 2 * (dy) * m1; \
201             incr2 = -2 * dx + 2 * (dy) * m; \
202             d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
203         } else { \
204             m = dx / (dy); \
205             m1 = m + 1; \
206             incr1 = 2 * dx - 2 * (dy) * m1; \
207             incr2 = 2 * dx - 2 * (dy) * m; \
208             d = -2 * m * (dy) + 2 * dx; \
209         } \
210     } \
211 }
212
213 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
214     if (m1 > 0) { \
215         if (d > 0) { \
216             minval += m1; \
217             d += incr1; \
218         } \
219         else { \
220             minval += m; \
221             d += incr2; \
222         } \
223     } else {\
224         if (d >= 0) { \
225             minval += m1; \
226             d += incr1; \
227         } \
228         else { \
229             minval += m; \
230             d += incr2; \
231         } \
232     } \
233 }
234
235 /*
236  *     This structure contains all of the information needed
237  *     to run the bresenham algorithm.
238  *     The variables may be hardcoded into the declarations
239  *     instead of using this structure to make use of
240  *     register declarations.
241  */
242 typedef struct {
243     INT minor_axis;     /* minor axis        */
244     INT d;              /* decision variable */
245     INT m, m1;          /* slope and slope+1 */
246     INT incr1, incr2;   /* error increments */
247 } BRESINFO;
248
249
250 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
251         BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
252                      bres.m, bres.m1, bres.incr1, bres.incr2)
253
254 #define BRESINCRPGONSTRUCT(bres) \
255         BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
256
257
258
259 /*
260  *     These are the data structures needed to scan
261  *     convert regions.  Two different scan conversion
262  *     methods are available -- the even-odd method, and
263  *     the winding number method.
264  *     The even-odd rule states that a point is inside
265  *     the polygon if a ray drawn from that point in any
266  *     direction will pass through an odd number of
267  *     path segments.
268  *     By the winding number rule, a point is decided
269  *     to be inside the polygon if a ray drawn from that
270  *     point in any direction passes through a different
271  *     number of clockwise and counter-clockwise path
272  *     segments.
273  *
274  *     These data structures are adapted somewhat from
275  *     the algorithm in (Foley/Van Dam) for scan converting
276  *     polygons.
277  *     The basic algorithm is to start at the top (smallest y)
278  *     of the polygon, stepping down to the bottom of
279  *     the polygon by incrementing the y coordinate.  We
280  *     keep a list of edges which the current scanline crosses,
281  *     sorted by x.  This list is called the Active Edge Table (AET)
282  *     As we change the y-coordinate, we update each entry in 
283  *     in the active edge table to reflect the edges new xcoord.
284  *     This list must be sorted at each scanline in case
285  *     two edges intersect.
286  *     We also keep a data structure known as the Edge Table (ET),
287  *     which keeps track of all the edges which the current
288  *     scanline has not yet reached.  The ET is basically a
289  *     list of ScanLineList structures containing a list of
290  *     edges which are entered at a given scanline.  There is one
291  *     ScanLineList per scanline at which an edge is entered.
292  *     When we enter a new edge, we move it from the ET to the AET.
293  *
294  *     From the AET, we can implement the even-odd rule as in
295  *     (Foley/Van Dam).
296  *     The winding number rule is a little trickier.  We also
297  *     keep the EdgeTableEntries in the AET linked by the
298  *     nextWETE (winding EdgeTableEntry) link.  This allows
299  *     the edges to be linked just as before for updating
300  *     purposes, but only uses the edges linked by the nextWETE
301  *     link as edges representing spans of the polygon to
302  *     drawn (as with the even-odd rule).
303  */
304
305 /*
306  * for the winding number rule
307  */
308 #define CLOCKWISE          1
309 #define COUNTERCLOCKWISE  -1 
310
311 typedef struct _EdgeTableEntry {
312      INT ymax;           /* ycoord at which we exit this edge. */
313      BRESINFO bres;        /* Bresenham info to run the edge     */
314      struct _EdgeTableEntry *next;       /* next in the list     */
315      struct _EdgeTableEntry *back;       /* for insertion sort   */
316      struct _EdgeTableEntry *nextWETE;   /* for winding num rule */
317      int ClockWise;        /* flag for winding number rule       */
318 } EdgeTableEntry;
319
320
321 typedef struct _ScanLineList{
322      INT scanline;            /* the scanline represented */
323      EdgeTableEntry *edgelist;  /* header node              */
324      struct _ScanLineList *next;  /* next in the list       */
325 } ScanLineList;
326
327
328 typedef struct {
329      INT ymax;               /* ymax for the polygon     */
330      INT ymin;               /* ymin for the polygon     */
331      ScanLineList scanlines;   /* header node              */
332 } EdgeTable;
333
334
335 /*
336  * Here is a struct to help with storage allocation
337  * so we can allocate a big chunk at a time, and then take
338  * pieces from this heap when we need to.
339  */
340 #define SLLSPERBLOCK 25
341
342 typedef struct _ScanLineListBlock {
343      ScanLineList SLLs[SLLSPERBLOCK];
344      struct _ScanLineListBlock *next;
345 } ScanLineListBlock;
346
347
348 /*
349  *
350  *     a few macros for the inner loops of the fill code where
351  *     performance considerations don't allow a procedure call.
352  *
353  *     Evaluate the given edge at the given scanline.
354  *     If the edge has expired, then we leave it and fix up
355  *     the active edge table; otherwise, we increment the
356  *     x value to be ready for the next scanline.
357  *     The winding number rule is in effect, so we must notify
358  *     the caller when the edge has been removed so he
359  *     can reorder the Winding Active Edge Table.
360  */
361 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
362    if (pAET->ymax == y) {          /* leaving this edge */ \
363       pPrevAET->next = pAET->next; \
364       pAET = pPrevAET->next; \
365       fixWAET = 1; \
366       if (pAET) \
367          pAET->back = pPrevAET; \
368    } \
369    else { \
370       BRESINCRPGONSTRUCT(pAET->bres); \
371       pPrevAET = pAET; \
372       pAET = pAET->next; \
373    } \
374 }
375
376
377 /*
378  *     Evaluate the given edge at the given scanline.
379  *     If the edge has expired, then we leave it and fix up
380  *     the active edge table; otherwise, we increment the
381  *     x value to be ready for the next scanline.
382  *     The even-odd rule is in effect.
383  */
384 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
385    if (pAET->ymax == y) {          /* leaving this edge */ \
386       pPrevAET->next = pAET->next; \
387       pAET = pPrevAET->next; \
388       if (pAET) \
389          pAET->back = pPrevAET; \
390    } \
391    else { \
392       BRESINCRPGONSTRUCT(pAET->bres); \
393       pPrevAET = pAET; \
394       pAET = pAET->next; \
395    } \
396 }
397
398 typedef void (*voidProcp)();
399
400 /* Note the parameter order is different from the X11 equivalents */
401
402 static void REGION_CopyRegion(WINEREGION *d, WINEREGION *s);
403 static void REGION_IntersectRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
404 static void REGION_UnionRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
405 static void REGION_SubtractRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
406 static void REGION_XorRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
407 static void REGION_UnionRectWithRegion(const RECT *rect, WINEREGION *rgn);
408
409 #define RGN_DEFAULT_RECTS       2
410
411 /***********************************************************************
412  *            REGION_DumpRegion
413  *            Outputs the contents of a WINEREGION
414  */
415 static void REGION_DumpRegion(WINEREGION *pReg)
416 {
417     RECT *pRect, *pRectEnd = pReg->rects + pReg->numRects;
418
419     TRACE("Region %p: %d,%d - %d,%d %d rects\n", pReg,
420             pReg->extents.left, pReg->extents.top,
421             pReg->extents.right, pReg->extents.bottom, pReg->numRects);
422     for(pRect = pReg->rects; pRect < pRectEnd; pRect++)
423         TRACE("\t%d,%d - %d,%d\n", pRect->left, pRect->top,
424                        pRect->right, pRect->bottom);
425     return;
426 }
427
428
429 /***********************************************************************
430  *            REGION_AllocWineRegion
431  *            Create a new empty WINEREGION.
432  */
433 static WINEREGION *REGION_AllocWineRegion( INT n )
434 {
435     WINEREGION *pReg;
436
437     if ((pReg = HeapAlloc(GetProcessHeap(), 0, sizeof( WINEREGION ))))
438     {
439         if ((pReg->rects = HeapAlloc(GetProcessHeap(), 0, n * sizeof( RECT ))))
440         {
441             pReg->size = n;
442             EMPTY_REGION(pReg);
443             return pReg;
444         }
445         HeapFree(GetProcessHeap(), 0, pReg);
446     }
447     return NULL;
448 }
449
450
451 /***********************************************************************
452  *          REGION_CreateRegion
453  *          Create a new empty region.
454  */
455 static HRGN REGION_CreateRegion( INT n )
456 {
457     HRGN hrgn;
458     RGNOBJ *obj;
459
460     if(!(obj = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC, &hrgn ))) return 0;
461     if(!(obj->rgn = REGION_AllocWineRegion(n))) {
462         GDI_FreeObject( hrgn, obj );
463         return 0;
464     }
465     GDI_ReleaseObj( hrgn );
466     return hrgn;
467 }
468
469
470 /***********************************************************************
471  *           REGION_DestroyWineRegion
472  */
473 static void REGION_DestroyWineRegion( WINEREGION* pReg )
474 {
475     HeapFree( GetProcessHeap(), 0, pReg->rects );
476     HeapFree( GetProcessHeap(), 0, pReg );
477     return;
478 }
479
480 /***********************************************************************
481  *           REGION_DeleteObject
482  */
483 BOOL REGION_DeleteObject( HRGN hrgn, RGNOBJ * obj )
484 {
485     TRACE(" %04x\n", hrgn );
486
487     REGION_DestroyWineRegion( obj->rgn );
488     return GDI_FreeObject( hrgn, obj );
489 }
490
491 /***********************************************************************
492  *           OffsetRgn16    (GDI.101)
493  */
494 INT16 WINAPI OffsetRgn16( HRGN16 hrgn, INT16 x, INT16 y )
495 {
496     return OffsetRgn( hrgn, x, y );
497 }
498
499 /***********************************************************************
500  *           OffsetRgn   (GDI32.256)
501  */
502 INT WINAPI OffsetRgn( HRGN hrgn, INT x, INT y )
503 {
504     RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
505     INT ret;
506
507     TRACE("%04x %d,%d\n", hrgn, x, y);
508
509     if (!obj)
510         return ERROR;
511
512     if(x || y) {
513         int nbox = obj->rgn->numRects;
514         RECT *pbox = obj->rgn->rects;
515         
516         if(nbox) {
517             while(nbox--) {
518                 pbox->left += x;
519                 pbox->right += x;
520                 pbox->top += y;
521                 pbox->bottom += y;
522                 pbox++;
523             }
524             obj->rgn->extents.left += x;
525             obj->rgn->extents.right += x;
526             obj->rgn->extents.top += y;
527             obj->rgn->extents.bottom += y;
528         }
529     }
530     ret = obj->rgn->type;
531     GDI_ReleaseObj( hrgn );
532     return ret;
533 }
534
535
536 /***********************************************************************
537  *           GetRgnBox16    (GDI.134)
538  */
539 INT16 WINAPI GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
540 {
541     RECT r;
542     INT16 ret = (INT16)GetRgnBox( hrgn, &r );
543     CONV_RECT32TO16( &r, rect );
544     return ret;
545 }
546
547 /***********************************************************************
548  *           GetRgnBox    (GDI32.219)
549  */
550 INT WINAPI GetRgnBox( HRGN hrgn, LPRECT rect )
551 {
552     RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
553     if (obj)
554     {
555         INT ret;
556         TRACE(" %04x\n", hrgn );
557         rect->left = obj->rgn->extents.left;
558         rect->top = obj->rgn->extents.top;
559         rect->right = obj->rgn->extents.right;
560         rect->bottom = obj->rgn->extents.bottom;
561         ret = obj->rgn->type;
562         GDI_ReleaseObj(hrgn);
563         return ret;
564     }
565     return ERROR;
566 }
567
568
569 /***********************************************************************
570  *           CreateRectRgn16    (GDI.64)
571  *
572  * NOTE: Doesn't call CreateRectRgn because of differences in SetRectRgn16/32
573  */
574 HRGN16 WINAPI CreateRectRgn16(INT16 left, INT16 top, INT16 right, INT16 bottom)
575 {
576     HRGN16 hrgn;
577
578     if (!(hrgn = (HRGN16)REGION_CreateRegion(RGN_DEFAULT_RECTS)))
579         return 0;
580     TRACE("\n");
581     SetRectRgn16(hrgn, left, top, right, bottom);
582     return hrgn;
583 }
584
585
586 /***********************************************************************
587  *           CreateRectRgn   (GDI32.59)
588  */
589 HRGN WINAPI CreateRectRgn(INT left, INT top, INT right, INT bottom)
590 {
591     HRGN hrgn;
592
593     /* Allocate 2 rects by default to reduce the number of reallocs */
594
595     if (!(hrgn = REGION_CreateRegion(RGN_DEFAULT_RECTS)))
596         return 0;
597     TRACE("\n");
598     SetRectRgn(hrgn, left, top, right, bottom);
599     return hrgn;
600 }
601
602 /***********************************************************************
603  *           CreateRectRgnIndirect16    (GDI.65)
604  */
605 HRGN16 WINAPI CreateRectRgnIndirect16( const RECT16* rect )
606 {
607     return CreateRectRgn16( rect->left, rect->top, rect->right, rect->bottom );
608 }
609
610
611 /***********************************************************************
612  *           CreateRectRgnIndirect    (GDI32.60)
613  */
614 HRGN WINAPI CreateRectRgnIndirect( const RECT* rect )
615 {
616     return CreateRectRgn( rect->left, rect->top, rect->right, rect->bottom );
617 }
618
619
620 /***********************************************************************
621  *           SetRectRgn16    (GDI.172)
622  *
623  * NOTE: Win 3.1 sets region to empty if left > right
624  */
625 VOID WINAPI SetRectRgn16( HRGN16 hrgn, INT16 left, INT16 top,
626                           INT16 right, INT16 bottom )
627 {
628     if(left < right)
629         SetRectRgn( hrgn, left, top, right, bottom );
630     else
631         SetRectRgn( hrgn, 0, 0, 0, 0 );
632 }
633
634
635 /***********************************************************************
636  *           SetRectRgn    (GDI32.332)
637  *
638  * Allows either or both left and top to be greater than right or bottom.
639  */
640 BOOL WINAPI SetRectRgn( HRGN hrgn, INT left, INT top,
641                           INT right, INT bottom )
642 {
643     RGNOBJ * obj;
644
645     TRACE(" %04x %d,%d-%d,%d\n", 
646           hrgn, left, top, right, bottom );
647     
648     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return FALSE;
649
650     if (left > right) { INT tmp = left; left = right; right = tmp; }
651     if (top > bottom) { INT tmp = top; top = bottom; bottom = tmp; }
652
653     if((left != right) && (top != bottom))
654     {
655         obj->rgn->rects->left = obj->rgn->extents.left = left;
656         obj->rgn->rects->top = obj->rgn->extents.top = top;
657         obj->rgn->rects->right = obj->rgn->extents.right = right;
658         obj->rgn->rects->bottom = obj->rgn->extents.bottom = bottom;
659         obj->rgn->numRects = 1;
660         obj->rgn->type = SIMPLEREGION;
661     }
662     else
663         EMPTY_REGION(obj->rgn);
664
665     GDI_ReleaseObj( hrgn );
666     return TRUE;
667 }
668
669
670 /***********************************************************************
671  *           CreateRoundRectRgn16    (GDI.444)
672  *
673  * If either ellipse dimension is zero we call CreateRectRgn16 for its
674  * `special' behaviour. -ve ellipse dimensions can result in GPFs under win3.1
675  * we just let CreateRoundRectRgn convert them to +ve values. 
676  */
677
678 HRGN16 WINAPI CreateRoundRectRgn16( INT16 left, INT16 top,
679                                     INT16 right, INT16 bottom,
680                                     INT16 ellipse_width, INT16 ellipse_height )
681 {
682     if( ellipse_width == 0 || ellipse_height == 0 )
683         return CreateRectRgn16( left, top, right, bottom );
684     else
685         return (HRGN16)CreateRoundRectRgn( left, top, right, bottom,
686                                          ellipse_width, ellipse_height );
687 }
688
689 /***********************************************************************
690  *           CreateRoundRectRgn    (GDI32.61)
691  */
692 HRGN WINAPI CreateRoundRectRgn( INT left, INT top,
693                                     INT right, INT bottom,
694                                     INT ellipse_width, INT ellipse_height )
695 {
696     RGNOBJ * obj;
697     HRGN hrgn;
698     int asq, bsq, d, xd, yd;
699     RECT rect;
700     
701       /* Check if we can do a normal rectangle instead */
702
703     if ((ellipse_width == 0) || (ellipse_height == 0))
704         return CreateRectRgn( left, top, right, bottom );
705
706       /* Make the dimensions sensible */
707
708     if (left > right) { INT tmp = left; left = right; right = tmp; }
709     if (top > bottom) { INT tmp = top; top = bottom; bottom = tmp; }
710
711     ellipse_width = abs(ellipse_width);
712     ellipse_height = abs(ellipse_height);
713
714       /* Create region */
715
716     d = (ellipse_height < 128) ? ((3 * ellipse_height) >> 2) : 64;
717     if (!(hrgn = REGION_CreateRegion(d))) return 0;
718     if (!(obj = GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return 0;
719     TRACE("(%d,%d-%d,%d %dx%d): ret=%04x\n",
720           left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
721
722       /* Check parameters */
723
724     if (ellipse_width > right-left) ellipse_width = right-left;
725     if (ellipse_height > bottom-top) ellipse_height = bottom-top;
726
727       /* Ellipse algorithm, based on an article by K. Porter */
728       /* in DDJ Graphics Programming Column, 8/89 */
729
730     asq = ellipse_width * ellipse_width / 4;        /* a^2 */
731     bsq = ellipse_height * ellipse_height / 4;      /* b^2 */
732     d = bsq - asq * ellipse_height / 2 + asq / 4;   /* b^2 - a^2b + a^2/4 */
733     xd = 0;
734     yd = asq * ellipse_height;                      /* 2a^2b */
735
736     rect.left   = left + ellipse_width / 2;
737     rect.right  = right - ellipse_width / 2;
738
739       /* Loop to draw first half of quadrant */
740
741     while (xd < yd)
742     {
743         if (d > 0)  /* if nearest pixel is toward the center */
744         {
745               /* move toward center */
746             rect.top = top++;
747             rect.bottom = rect.top + 1;
748             REGION_UnionRectWithRegion( &rect, obj->rgn );
749             rect.top = --bottom;
750             rect.bottom = rect.top + 1;
751             REGION_UnionRectWithRegion( &rect, obj->rgn );
752             yd -= 2*asq;
753             d  -= yd;
754         }
755         rect.left--;        /* next horiz point */
756         rect.right++;
757         xd += 2*bsq;
758         d  += bsq + xd;
759     }
760
761       /* Loop to draw second half of quadrant */
762
763     d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
764     while (yd >= 0)
765     {
766           /* next vertical point */
767         rect.top = top++;
768         rect.bottom = rect.top + 1;
769         REGION_UnionRectWithRegion( &rect, obj->rgn );
770         rect.top = --bottom;
771         rect.bottom = rect.top + 1;
772         REGION_UnionRectWithRegion( &rect, obj->rgn );
773         if (d < 0)   /* if nearest pixel is outside ellipse */
774         {
775             rect.left--;     /* move away from center */
776             rect.right++;
777             xd += 2*bsq;
778             d  += xd;
779         }
780         yd -= 2*asq;
781         d  += asq - yd;
782     }
783
784       /* Add the inside rectangle */
785
786     if (top <= bottom)
787     {
788         rect.top = top;
789         rect.bottom = bottom;
790         REGION_UnionRectWithRegion( &rect, obj->rgn );
791     }
792     obj->rgn->type = SIMPLEREGION; /* FIXME? */
793     GDI_ReleaseObj( hrgn );
794     return hrgn;
795 }
796
797
798 /***********************************************************************
799  *           CreateEllipticRgn16    (GDI.54)
800  */
801 HRGN16 WINAPI CreateEllipticRgn16( INT16 left, INT16 top,
802                                    INT16 right, INT16 bottom )
803 {
804     return (HRGN16)CreateRoundRectRgn( left, top, right, bottom,
805                                          right-left, bottom-top );
806 }
807
808
809 /***********************************************************************
810  *           CreateEllipticRgn    (GDI32.39)
811  */
812 HRGN WINAPI CreateEllipticRgn( INT left, INT top,
813                                    INT right, INT bottom )
814 {
815     return CreateRoundRectRgn( left, top, right, bottom,
816                                  right-left, bottom-top );
817 }
818
819
820 /***********************************************************************
821  *           CreateEllipticRgnIndirect16    (GDI.55)
822  */
823 HRGN16 WINAPI CreateEllipticRgnIndirect16( const RECT16 *rect )
824 {
825     return CreateRoundRectRgn( rect->left, rect->top, rect->right,
826                                  rect->bottom, rect->right - rect->left,
827                                  rect->bottom - rect->top );
828 }
829
830
831 /***********************************************************************
832  *           CreateEllipticRgnIndirect    (GDI32.40)
833  */
834 HRGN WINAPI CreateEllipticRgnIndirect( const RECT *rect )
835 {
836     return CreateRoundRectRgn( rect->left, rect->top, rect->right,
837                                  rect->bottom, rect->right - rect->left,
838                                  rect->bottom - rect->top );
839 }
840
841 /***********************************************************************
842  *           GetRegionData   (GDI32.217)
843  * 
844  * MSDN: GetRegionData, Return Values:
845  *
846  * "If the function succeeds and dwCount specifies an adequate number of bytes,
847  * the return value is always dwCount. If dwCount is too small or the function
848  * fails, the return value is 0. If lpRgnData is NULL, the return value is the
849  * required number of bytes.
850  *
851  * If the function fails, the return value is zero."
852  */
853 DWORD WINAPI GetRegionData(HRGN hrgn, DWORD count, LPRGNDATA rgndata)
854 {
855     DWORD size;
856     RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
857     
858     TRACE(" %04x count = %ld, rgndata = %p\n",
859                    hrgn, count, rgndata);
860
861     if(!obj) return 0;
862
863     size = obj->rgn->numRects * sizeof(RECT);
864     if(count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
865     {
866         GDI_ReleaseObj( hrgn );
867         if (rgndata) /* buffer is too small, signal it by return 0 */
868             return 0;
869         else            /* user requested buffer size with rgndata NULL */
870             return size + sizeof(RGNDATAHEADER);
871     }
872
873     rgndata->rdh.dwSize = sizeof(RGNDATAHEADER);
874     rgndata->rdh.iType = RDH_RECTANGLES;
875     rgndata->rdh.nCount = obj->rgn->numRects;
876     rgndata->rdh.nRgnSize = size;
877     rgndata->rdh.rcBound.left = obj->rgn->extents.left;
878     rgndata->rdh.rcBound.top = obj->rgn->extents.top;
879     rgndata->rdh.rcBound.right = obj->rgn->extents.right;
880     rgndata->rdh.rcBound.bottom = obj->rgn->extents.bottom;
881
882     memcpy( rgndata->Buffer, obj->rgn->rects, size );
883
884     GDI_ReleaseObj( hrgn );
885     return size + sizeof(RGNDATAHEADER);
886 }
887
888 /***********************************************************************
889  *           GetRegionData16   (GDI.607)
890  * FIXME: is LPRGNDATA the same in Win16 and Win32 ?
891  */
892 DWORD WINAPI GetRegionData16(HRGN16 hrgn, DWORD count, LPRGNDATA rgndata)
893 {
894     return GetRegionData((HRGN)hrgn, count, rgndata);
895 }
896
897 /***********************************************************************
898  *           ExtCreateRegion   (GDI32.94)
899  * 
900  */
901 HRGN WINAPI ExtCreateRegion( const XFORM* lpXform, DWORD dwCount, const RGNDATA* rgndata)
902 {
903     HRGN hrgn;
904
905     TRACE(" %p %ld %p = ", lpXform, dwCount, rgndata );
906
907     if( lpXform )
908         WARN("(Xform not implemented - ignored) ");
909     
910     if( rgndata->rdh.iType != RDH_RECTANGLES )
911     {
912         /* FIXME: We can use CreatePolyPolygonRgn() here
913          *        for trapezoidal data */
914
915         WARN("(Unsupported region data) ");
916         goto fail;
917     }
918
919     if( (hrgn = REGION_CreateRegion( rgndata->rdh.nCount )) )
920     {
921         RECT *pCurRect, *pEndRect;
922         RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
923
924         if (obj) {
925             pEndRect = (RECT *)rgndata->Buffer + rgndata->rdh.nCount;
926             for(pCurRect = (RECT *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
927                 REGION_UnionRectWithRegion( pCurRect, obj->rgn );
928             GDI_ReleaseObj( hrgn );
929
930             TRACE("%04x\n", hrgn );
931             return hrgn;
932         }
933         else ERR("Could not get pointer to newborn Region!");
934     }
935 fail:
936     WARN("Failed\n");
937     return 0;
938 }
939
940 /***********************************************************************
941  *           PtInRegion16    (GDI.161)
942  */
943 BOOL16 WINAPI PtInRegion16( HRGN16 hrgn, INT16 x, INT16 y )
944 {
945     return PtInRegion( hrgn, x, y );
946 }
947
948
949 /***********************************************************************
950  *           PtInRegion    (GDI32.278)
951  */
952 BOOL WINAPI PtInRegion( HRGN hrgn, INT x, INT y )
953 {
954     RGNOBJ * obj;
955     BOOL ret = FALSE;
956     
957     if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
958     {
959         int i;
960
961         if (obj->rgn->numRects > 0 && INRECT(obj->rgn->extents, x, y))
962             for (i = 0; i < obj->rgn->numRects; i++)
963                 if (INRECT (obj->rgn->rects[i], x, y))
964                 {
965                     ret = TRUE;
966                     break;
967                 }
968         GDI_ReleaseObj( hrgn );
969     }
970     return ret;
971 }
972
973
974 /***********************************************************************
975  *           RectInRegion16    (GDI.181)
976  */
977 BOOL16 WINAPI RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
978 {
979     RECT r32;
980
981     CONV_RECT16TO32(rect, &r32);
982     return (BOOL16)RectInRegion(hrgn, &r32);
983 }
984
985
986 /***********************************************************************
987  *           RectInRegion    (GDI32.281)
988  *
989  * Returns TRUE if rect is at least partly inside hrgn
990  */
991 BOOL WINAPI RectInRegion( HRGN hrgn, const RECT *rect )
992 {
993     RGNOBJ * obj;
994     BOOL ret = FALSE;
995     
996     if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
997     {
998         RECT *pCurRect, *pRectEnd;
999     
1000     /* this is (just) a useful optimization */
1001         if ((obj->rgn->numRects > 0) && EXTENTCHECK(&obj->rgn->extents,
1002                                                       rect))
1003         {
1004             for (pCurRect = obj->rgn->rects, pRectEnd = pCurRect +
1005              obj->rgn->numRects; pCurRect < pRectEnd; pCurRect++)
1006             {
1007                 if (pCurRect->bottom <= rect->top)
1008                     continue;             /* not far enough down yet */
1009
1010                 if (pCurRect->top >= rect->bottom)
1011                     break;                /* too far down */
1012
1013                 if (pCurRect->right <= rect->left)
1014                     continue;              /* not far enough over yet */
1015
1016                 if (pCurRect->left >= rect->right) {
1017                     continue;
1018                 }
1019
1020                 ret = TRUE;
1021                 break;
1022             }
1023         }
1024         GDI_ReleaseObj(hrgn);
1025     }
1026     return ret;
1027 }
1028
1029 /***********************************************************************
1030  *           EqualRgn16    (GDI.72)
1031  */
1032 BOOL16 WINAPI EqualRgn16( HRGN16 rgn1, HRGN16 rgn2 )
1033 {
1034     return EqualRgn( rgn1, rgn2 );
1035 }
1036
1037
1038 /***********************************************************************
1039  *           EqualRgn    (GDI32.90)
1040  */
1041 BOOL WINAPI EqualRgn( HRGN hrgn1, HRGN hrgn2 )
1042 {
1043     RGNOBJ *obj1, *obj2;
1044     BOOL ret = FALSE;
1045
1046     if ((obj1 = (RGNOBJ *) GDI_GetObjPtr( hrgn1, REGION_MAGIC ))) 
1047     {
1048         if ((obj2 = (RGNOBJ *) GDI_GetObjPtr( hrgn2, REGION_MAGIC ))) 
1049         {
1050             int i;
1051
1052             if ( obj1->rgn->numRects != obj2->rgn->numRects ) goto done;
1053             if ( obj1->rgn->numRects == 0 )
1054             {
1055                 ret = TRUE;
1056                 goto done;
1057             
1058             }
1059             if (obj1->rgn->extents.left   != obj2->rgn->extents.left) goto done;
1060             if (obj1->rgn->extents.right  != obj2->rgn->extents.right) goto done;
1061             if (obj1->rgn->extents.top    != obj2->rgn->extents.top) goto done;
1062             if (obj1->rgn->extents.bottom != obj2->rgn->extents.bottom) goto done;
1063             for( i = 0; i < obj1->rgn->numRects; i++ )
1064             {
1065                 if (obj1->rgn->rects[i].left   != obj2->rgn->rects[i].left) goto done;
1066                 if (obj1->rgn->rects[i].right  != obj2->rgn->rects[i].right) goto done;
1067                 if (obj1->rgn->rects[i].top    != obj2->rgn->rects[i].top) goto done;
1068                 if (obj1->rgn->rects[i].bottom != obj2->rgn->rects[i].bottom) goto done;
1069             }
1070             ret = TRUE;
1071         done:
1072             GDI_ReleaseObj(hrgn2);
1073         }
1074         GDI_ReleaseObj(hrgn1);
1075     }
1076     return ret;
1077 }
1078 /***********************************************************************
1079  *           REGION_UnionRectWithRegion
1080  *           Adds a rectangle to a WINEREGION
1081  *           See below for REGION_UnionRectWithRgn
1082  */
1083 static void REGION_UnionRectWithRegion(const RECT *rect, WINEREGION *rgn)
1084 {
1085     WINEREGION region;
1086
1087     region.rects = &region.extents;
1088     region.numRects = 1;
1089     region.size = 1;
1090     region.type = SIMPLEREGION;
1091     region.extents = *rect;
1092     REGION_UnionRegion(rgn, rgn, &region);
1093     return;
1094 }
1095
1096 /***********************************************************************
1097  *           REGION_UnionRectWithRgn
1098  *           Adds a rectangle to a HRGN
1099  *           A helper used by scroll.c
1100  */
1101 BOOL REGION_UnionRectWithRgn( HRGN hrgn, const RECT *lpRect )
1102 {
1103     RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
1104
1105     if(!obj) return FALSE;
1106     REGION_UnionRectWithRegion( lpRect, obj->rgn );
1107     GDI_ReleaseObj(hrgn);
1108     return TRUE;
1109 }
1110
1111 /***********************************************************************
1112  *           REGION_CreateFrameRgn
1113  *
1114  * Create a region that is a frame around another region.
1115  * Expand all rectangles by +/- x and y, then subtract original region.
1116  */
1117 BOOL REGION_FrameRgn( HRGN hDest, HRGN hSrc, INT x, INT y )
1118 {
1119     BOOL bRet;
1120     RGNOBJ *srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
1121
1122     if (!srcObj) return FALSE;
1123     if (srcObj->rgn->numRects != 0) 
1124     {
1125         RGNOBJ* destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
1126         RECT *pRect, *pEndRect;
1127         RECT tempRect;
1128
1129         EMPTY_REGION( destObj->rgn );
1130         
1131         pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
1132         for(pRect = srcObj->rgn->rects; pRect < pEndRect; pRect++)
1133         {
1134             tempRect.left = pRect->left - x;        
1135             tempRect.top = pRect->top - y;
1136             tempRect.right = pRect->right + x;
1137             tempRect.bottom = pRect->bottom + y;
1138             REGION_UnionRectWithRegion( &tempRect, destObj->rgn );
1139         }
1140         REGION_SubtractRegion( destObj->rgn, destObj->rgn, srcObj->rgn );
1141         GDI_ReleaseObj ( hDest );
1142         bRet = TRUE;
1143     }
1144     else
1145         bRet = FALSE;
1146     GDI_ReleaseObj( hSrc );
1147     return bRet;
1148 }
1149
1150 /***********************************************************************
1151  *           REGION_LPTODP
1152  *
1153  * Convert region to device co-ords for the supplied dc. 
1154  */
1155 BOOL REGION_LPTODP( HDC hdc, HRGN hDest, HRGN hSrc )
1156 {
1157     RECT *pCurRect, *pEndRect;
1158     RGNOBJ *srcObj, *destObj;
1159     DC * dc = DC_GetDCPtr( hdc );
1160     RECT tmpRect;
1161     BOOL ret = FALSE;
1162
1163     TRACE(" hdc=%04x dest=%04x src=%04x\n",
1164           hdc, hDest, hSrc) ;
1165     if (!dc) return ret;
1166     
1167     if (dc->w.MapMode == MM_TEXT) /* Requires only a translation */
1168     {
1169         if( CombineRgn( hDest, hSrc, 0, RGN_COPY ) == ERROR ) goto done;
1170         OffsetRgn( hDest, dc->vportOrgX - dc->wndOrgX, 
1171                      dc->vportOrgY - dc->wndOrgY );
1172         ret = TRUE;
1173         goto done;
1174     }
1175
1176     if(!( srcObj = (RGNOBJ *) GDI_GetObjPtr( hSrc, REGION_MAGIC) ))
1177         goto done;
1178     if(!( destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC) ))
1179     {
1180         GDI_ReleaseObj( hSrc );
1181         goto done;
1182     }
1183     EMPTY_REGION( destObj->rgn );
1184
1185     pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
1186     for(pCurRect = srcObj->rgn->rects; pCurRect < pEndRect; pCurRect++)
1187     {
1188         tmpRect = *pCurRect;
1189         tmpRect.left = XLPTODP( dc, tmpRect.left );
1190         tmpRect.top = YLPTODP( dc, tmpRect.top );
1191         tmpRect.right = XLPTODP( dc, tmpRect.right );
1192         tmpRect.bottom = YLPTODP( dc, tmpRect.bottom );
1193         REGION_UnionRectWithRegion( &tmpRect, destObj->rgn );
1194     }
1195     
1196     GDI_ReleaseObj( hDest );
1197     GDI_ReleaseObj( hSrc );
1198  done:
1199     GDI_ReleaseObj( hdc );
1200     return ret;
1201 }
1202     
1203 /***********************************************************************
1204  *           CombineRgn16    (GDI.451)
1205  */
1206 INT16 WINAPI CombineRgn16(HRGN16 hDest, HRGN16 hSrc1, HRGN16 hSrc2, INT16 mode)
1207 {
1208     return (INT16)CombineRgn( hDest, hSrc1, hSrc2, mode );
1209 }
1210
1211
1212 /***********************************************************************
1213  *           CombineRgn   (GDI32.19)
1214  *
1215  * Note: The behavior is correct even if src and dest regions are the same.
1216  */
1217 INT WINAPI CombineRgn(HRGN hDest, HRGN hSrc1, HRGN hSrc2, INT mode)
1218 {
1219     RGNOBJ *destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC);
1220     INT result = ERROR;
1221
1222     TRACE(" %04x,%04x -> %04x mode=%x\n", 
1223           hSrc1, hSrc2, hDest, mode );
1224     if (destObj)
1225     {
1226         RGNOBJ *src1Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc1, REGION_MAGIC);
1227
1228         if (src1Obj)
1229         {
1230             TRACE("dump:\n");
1231             if(TRACE_ON(region)) 
1232               REGION_DumpRegion(src1Obj->rgn);
1233             if (mode == RGN_COPY)
1234             {
1235                 REGION_CopyRegion( destObj->rgn, src1Obj->rgn );
1236                 result = destObj->rgn->type;
1237             }
1238             else
1239             {
1240                 RGNOBJ *src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC);
1241
1242                 if (src2Obj)
1243                 {
1244                     TRACE("dump:\n");
1245                     if(TRACE_ON(region)) 
1246                         REGION_DumpRegion(src2Obj->rgn);
1247                     switch (mode)
1248                     {
1249                     case RGN_AND:
1250                         REGION_IntersectRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn);
1251                         break;
1252                     case RGN_OR:
1253                         REGION_UnionRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
1254                         break;
1255                     case RGN_XOR:
1256                         REGION_XorRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
1257                         break;
1258                     case RGN_DIFF:
1259                         REGION_SubtractRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
1260                         break;
1261                     }
1262                     result = destObj->rgn->type;
1263                     GDI_ReleaseObj( hSrc2 );
1264                 }
1265             }
1266             GDI_ReleaseObj( hSrc1 );
1267         }
1268         TRACE("dump:\n");
1269         if(TRACE_ON(region)) 
1270           REGION_DumpRegion(destObj->rgn);
1271
1272         GDI_ReleaseObj( hDest );
1273     } else {
1274        ERR("Invalid rgn=%04x\n", hDest);
1275     }
1276     return result;
1277 }
1278
1279 /***********************************************************************
1280  *           REGION_SetExtents
1281  *           Re-calculate the extents of a region
1282  */
1283 static void REGION_SetExtents (WINEREGION *pReg)
1284 {
1285     RECT *pRect, *pRectEnd, *pExtents;
1286
1287     if (pReg->numRects == 0)
1288     {
1289         pReg->extents.left = 0;
1290         pReg->extents.top = 0;
1291         pReg->extents.right = 0;
1292         pReg->extents.bottom = 0;
1293         return;
1294     }
1295
1296     pExtents = &pReg->extents;
1297     pRect = pReg->rects;
1298     pRectEnd = &pRect[pReg->numRects - 1];
1299
1300     /*
1301      * Since pRect is the first rectangle in the region, it must have the
1302      * smallest top and since pRectEnd is the last rectangle in the region,
1303      * it must have the largest bottom, because of banding. Initialize left and
1304      * right from pRect and pRectEnd, resp., as good things to initialize them
1305      * to...
1306      */
1307     pExtents->left = pRect->left;
1308     pExtents->top = pRect->top;
1309     pExtents->right = pRectEnd->right;
1310     pExtents->bottom = pRectEnd->bottom;
1311
1312     while (pRect <= pRectEnd)
1313     {
1314         if (pRect->left < pExtents->left)
1315             pExtents->left = pRect->left;
1316         if (pRect->right > pExtents->right)
1317             pExtents->right = pRect->right;
1318         pRect++;
1319     }
1320 }
1321
1322 /***********************************************************************
1323  *           REGION_CopyRegion
1324  */
1325 static void REGION_CopyRegion(WINEREGION *dst, WINEREGION *src)
1326 {
1327     if (dst != src) /*  don't want to copy to itself */
1328     {  
1329         if (dst->size < src->numRects)
1330         {
1331             if (! (dst->rects = HeapReAlloc( GetProcessHeap(), 0, dst->rects,
1332                                 src->numRects * sizeof(RECT) )))
1333                 return;
1334             dst->size = src->numRects;
1335         }
1336         dst->numRects = src->numRects;
1337         dst->extents.left = src->extents.left;
1338         dst->extents.top = src->extents.top;
1339         dst->extents.right = src->extents.right;
1340         dst->extents.bottom = src->extents.bottom;
1341         dst->type = src->type;
1342
1343         memcpy((char *) dst->rects, (char *) src->rects,
1344                (int) (src->numRects * sizeof(RECT)));
1345     }
1346     return;
1347 }
1348
1349 /***********************************************************************
1350  *           REGION_Coalesce
1351  *
1352  *      Attempt to merge the rects in the current band with those in the
1353  *      previous one. Used only by REGION_RegionOp.
1354  *
1355  * Results:
1356  *      The new index for the previous band.
1357  *
1358  * Side Effects:
1359  *      If coalescing takes place:
1360  *          - rectangles in the previous band will have their bottom fields
1361  *            altered.
1362  *          - pReg->numRects will be decreased.
1363  *
1364  */
1365 static INT REGION_Coalesce (
1366              WINEREGION *pReg, /* Region to coalesce */
1367              INT prevStart,  /* Index of start of previous band */
1368              INT curStart    /* Index of start of current band */
1369 ) {
1370     RECT *pPrevRect;          /* Current rect in previous band */
1371     RECT *pCurRect;           /* Current rect in current band */
1372     RECT *pRegEnd;            /* End of region */
1373     INT curNumRects;          /* Number of rectangles in current band */
1374     INT prevNumRects;         /* Number of rectangles in previous band */
1375     INT bandtop;               /* top coordinate for current band */
1376
1377     pRegEnd = &pReg->rects[pReg->numRects];
1378
1379     pPrevRect = &pReg->rects[prevStart];
1380     prevNumRects = curStart - prevStart;
1381
1382     /*
1383      * Figure out how many rectangles are in the current band. Have to do
1384      * this because multiple bands could have been added in REGION_RegionOp
1385      * at the end when one region has been exhausted.
1386      */
1387     pCurRect = &pReg->rects[curStart];
1388     bandtop = pCurRect->top;
1389     for (curNumRects = 0;
1390          (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
1391          curNumRects++)
1392     {
1393         pCurRect++;
1394     }
1395     
1396     if (pCurRect != pRegEnd)
1397     {
1398         /*
1399          * If more than one band was added, we have to find the start
1400          * of the last band added so the next coalescing job can start
1401          * at the right place... (given when multiple bands are added,
1402          * this may be pointless -- see above).
1403          */
1404         pRegEnd--;
1405         while (pRegEnd[-1].top == pRegEnd->top)
1406         {
1407             pRegEnd--;
1408         }
1409         curStart = pRegEnd - pReg->rects;
1410         pRegEnd = pReg->rects + pReg->numRects;
1411     }
1412         
1413     if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
1414         pCurRect -= curNumRects;
1415         /*
1416          * The bands may only be coalesced if the bottom of the previous
1417          * matches the top scanline of the current.
1418          */
1419         if (pPrevRect->bottom == pCurRect->top)
1420         {
1421             /*
1422              * Make sure the bands have rects in the same places. This
1423              * assumes that rects have been added in such a way that they
1424              * cover the most area possible. I.e. two rects in a band must
1425              * have some horizontal space between them.
1426              */
1427             do
1428             {
1429                 if ((pPrevRect->left != pCurRect->left) ||
1430                     (pPrevRect->right != pCurRect->right))
1431                 {
1432                     /*
1433                      * The bands don't line up so they can't be coalesced.
1434                      */
1435                     return (curStart);
1436                 }
1437                 pPrevRect++;
1438                 pCurRect++;
1439                 prevNumRects -= 1;
1440             } while (prevNumRects != 0);
1441
1442             pReg->numRects -= curNumRects;
1443             pCurRect -= curNumRects;
1444             pPrevRect -= curNumRects;
1445
1446             /*
1447              * The bands may be merged, so set the bottom of each rect
1448              * in the previous band to that of the corresponding rect in
1449              * the current band.
1450              */
1451             do
1452             {
1453                 pPrevRect->bottom = pCurRect->bottom;
1454                 pPrevRect++;
1455                 pCurRect++;
1456                 curNumRects -= 1;
1457             } while (curNumRects != 0);
1458
1459             /*
1460              * If only one band was added to the region, we have to backup
1461              * curStart to the start of the previous band.
1462              *
1463              * If more than one band was added to the region, copy the
1464              * other bands down. The assumption here is that the other bands
1465              * came from the same region as the current one and no further
1466              * coalescing can be done on them since it's all been done
1467              * already... curStart is already in the right place.
1468              */
1469             if (pCurRect == pRegEnd)
1470             {
1471                 curStart = prevStart;
1472             }
1473             else
1474             {
1475                 do
1476                 {
1477                     *pPrevRect++ = *pCurRect++;
1478                 } while (pCurRect != pRegEnd);
1479             }
1480             
1481         }
1482     }
1483     return (curStart);
1484 }
1485
1486 /***********************************************************************
1487  *           REGION_RegionOp
1488  *
1489  *      Apply an operation to two regions. Called by REGION_Union,
1490  *      REGION_Inverse, REGION_Subtract, REGION_Intersect...
1491  *
1492  * Results:
1493  *      None.
1494  *
1495  * Side Effects:
1496  *      The new region is overwritten.
1497  *
1498  * Notes:
1499  *      The idea behind this function is to view the two regions as sets.
1500  *      Together they cover a rectangle of area that this function divides
1501  *      into horizontal bands where points are covered only by one region
1502  *      or by both. For the first case, the nonOverlapFunc is called with
1503  *      each the band and the band's upper and lower extents. For the
1504  *      second, the overlapFunc is called to process the entire band. It
1505  *      is responsible for clipping the rectangles in the band, though
1506  *      this function provides the boundaries.
1507  *      At the end of each band, the new region is coalesced, if possible,
1508  *      to reduce the number of rectangles in the region.
1509  *
1510  */
1511 static void REGION_RegionOp(
1512             WINEREGION *newReg, /* Place to store result */
1513             WINEREGION *reg1,   /* First region in operation */
1514             WINEREGION *reg2,   /* 2nd region in operation */
1515             void (*overlapFunc)(),     /* Function to call for over-lapping bands */
1516             void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
1517             void (*nonOverlap2Func)()  /* Function to call for non-overlapping bands in region 2 */
1518 ) {
1519     RECT *r1;                         /* Pointer into first region */
1520     RECT *r2;                         /* Pointer into 2d region */
1521     RECT *r1End;                      /* End of 1st region */
1522     RECT *r2End;                      /* End of 2d region */
1523     INT ybot;                         /* Bottom of intersection */
1524     INT ytop;                         /* Top of intersection */
1525     RECT *oldRects;                   /* Old rects for newReg */
1526     INT prevBand;                     /* Index of start of
1527                                                  * previous band in newReg */
1528     INT curBand;                      /* Index of start of current
1529                                                  * band in newReg */
1530     RECT *r1BandEnd;                  /* End of current band in r1 */
1531     RECT *r2BandEnd;                  /* End of current band in r2 */
1532     INT top;                          /* Top of non-overlapping band */
1533     INT bot;                          /* Bottom of non-overlapping band */
1534     
1535     /*
1536      * Initialization:
1537      *  set r1, r2, r1End and r2End appropriately, preserve the important
1538      * parts of the destination region until the end in case it's one of
1539      * the two source regions, then mark the "new" region empty, allocating
1540      * another array of rectangles for it to use.
1541      */
1542     r1 = reg1->rects;
1543     r2 = reg2->rects;
1544     r1End = r1 + reg1->numRects;
1545     r2End = r2 + reg2->numRects;
1546     
1547
1548     /*
1549      * newReg may be one of the src regions so we can't empty it. We keep a 
1550      * note of its rects pointer (so that we can free them later), preserve its
1551      * extents and simply set numRects to zero. 
1552      */
1553
1554     oldRects = newReg->rects;
1555     newReg->numRects = 0;
1556
1557     /*
1558      * Allocate a reasonable number of rectangles for the new region. The idea
1559      * is to allocate enough so the individual functions don't need to
1560      * reallocate and copy the array, which is time consuming, yet we don't
1561      * have to worry about using too much memory. I hope to be able to
1562      * nuke the Xrealloc() at the end of this function eventually.
1563      */
1564     newReg->size = max(reg1->numRects,reg2->numRects) * 2;
1565
1566     if (! (newReg->rects = HeapAlloc( GetProcessHeap(), 0, 
1567                                   sizeof(RECT) * newReg->size )))
1568     {
1569         newReg->size = 0;
1570         return;
1571     }
1572     
1573     /*
1574      * Initialize ybot and ytop.
1575      * In the upcoming loop, ybot and ytop serve different functions depending
1576      * on whether the band being handled is an overlapping or non-overlapping
1577      * band.
1578      *  In the case of a non-overlapping band (only one of the regions
1579      * has points in the band), ybot is the bottom of the most recent
1580      * intersection and thus clips the top of the rectangles in that band.
1581      * ytop is the top of the next intersection between the two regions and
1582      * serves to clip the bottom of the rectangles in the current band.
1583      *  For an overlapping band (where the two regions intersect), ytop clips
1584      * the top of the rectangles of both regions and ybot clips the bottoms.
1585      */
1586     if (reg1->extents.top < reg2->extents.top)
1587         ybot = reg1->extents.top;
1588     else
1589         ybot = reg2->extents.top;
1590     
1591     /*
1592      * prevBand serves to mark the start of the previous band so rectangles
1593      * can be coalesced into larger rectangles. qv. miCoalesce, above.
1594      * In the beginning, there is no previous band, so prevBand == curBand
1595      * (curBand is set later on, of course, but the first band will always
1596      * start at index 0). prevBand and curBand must be indices because of
1597      * the possible expansion, and resultant moving, of the new region's
1598      * array of rectangles.
1599      */
1600     prevBand = 0;
1601     
1602     do
1603     {
1604         curBand = newReg->numRects;
1605
1606         /*
1607          * This algorithm proceeds one source-band (as opposed to a
1608          * destination band, which is determined by where the two regions
1609          * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1610          * rectangle after the last one in the current band for their
1611          * respective regions.
1612          */
1613         r1BandEnd = r1;
1614         while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
1615         {
1616             r1BandEnd++;
1617         }
1618         
1619         r2BandEnd = r2;
1620         while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
1621         {
1622             r2BandEnd++;
1623         }
1624         
1625         /*
1626          * First handle the band that doesn't intersect, if any.
1627          *
1628          * Note that attention is restricted to one band in the
1629          * non-intersecting region at once, so if a region has n
1630          * bands between the current position and the next place it overlaps
1631          * the other, this entire loop will be passed through n times.
1632          */
1633         if (r1->top < r2->top)
1634         {
1635             top = max(r1->top,ybot);
1636             bot = min(r1->bottom,r2->top);
1637
1638             if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
1639             {
1640                 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
1641             }
1642
1643             ytop = r2->top;
1644         }
1645         else if (r2->top < r1->top)
1646         {
1647             top = max(r2->top,ybot);
1648             bot = min(r2->bottom,r1->top);
1649
1650             if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
1651             {
1652                 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
1653             }
1654
1655             ytop = r1->top;
1656         }
1657         else
1658         {
1659             ytop = r1->top;
1660         }
1661
1662         /*
1663          * If any rectangles got added to the region, try and coalesce them
1664          * with rectangles from the previous band. Note we could just do
1665          * this test in miCoalesce, but some machines incur a not
1666          * inconsiderable cost for function calls, so...
1667          */
1668         if (newReg->numRects != curBand)
1669         {
1670             prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1671         }
1672
1673         /*
1674          * Now see if we've hit an intersecting band. The two bands only
1675          * intersect if ybot > ytop
1676          */
1677         ybot = min(r1->bottom, r2->bottom);
1678         curBand = newReg->numRects;
1679         if (ybot > ytop)
1680         {
1681             (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
1682
1683         }
1684         
1685         if (newReg->numRects != curBand)
1686         {
1687             prevBand = REGION_Coalesce (newReg, prevBand, curBand);
1688         }
1689
1690         /*
1691          * If we've finished with a band (bottom == ybot) we skip forward
1692          * in the region to the next band.
1693          */
1694         if (r1->bottom == ybot)
1695         {
1696             r1 = r1BandEnd;
1697         }
1698         if (r2->bottom == ybot)
1699         {
1700             r2 = r2BandEnd;
1701         }
1702     } while ((r1 != r1End) && (r2 != r2End));
1703
1704     /*
1705      * Deal with whichever region still has rectangles left.
1706      */
1707     curBand = newReg->numRects;
1708     if (r1 != r1End)
1709     {
1710         if (nonOverlap1Func != (void (*)())NULL)
1711         {
1712             do
1713             {
1714                 r1BandEnd = r1;
1715                 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
1716                 {
1717                     r1BandEnd++;
1718                 }
1719                 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
1720                                      max(r1->top,ybot), r1->bottom);
1721                 r1 = r1BandEnd;
1722             } while (r1 != r1End);
1723         }
1724     }
1725     else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
1726     {
1727         do
1728         {
1729             r2BandEnd = r2;
1730             while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
1731             {
1732                  r2BandEnd++;
1733             }
1734             (* nonOverlap2Func) (newReg, r2, r2BandEnd,
1735                                 max(r2->top,ybot), r2->bottom);
1736             r2 = r2BandEnd;
1737         } while (r2 != r2End);
1738     }
1739
1740     if (newReg->numRects != curBand)
1741     {
1742         (void) REGION_Coalesce (newReg, prevBand, curBand);
1743     }
1744
1745     /*
1746      * A bit of cleanup. To keep regions from growing without bound,
1747      * we shrink the array of rectangles to match the new number of
1748      * rectangles in the region. This never goes to 0, however...
1749      *
1750      * Only do this stuff if the number of rectangles allocated is more than
1751      * twice the number of rectangles in the region (a simple optimization...).
1752      */
1753     if ((newReg->numRects < (newReg->size >> 1)) && (newReg->numRects > 2))
1754     {
1755         if (REGION_NOT_EMPTY(newReg))
1756         {
1757             RECT *prev_rects = newReg->rects;
1758             newReg->size = newReg->numRects;
1759             newReg->rects = HeapReAlloc( GetProcessHeap(), 0, newReg->rects,
1760                                    sizeof(RECT) * newReg->size );
1761             if (! newReg->rects)
1762                 newReg->rects = prev_rects;
1763         }
1764         else
1765         {
1766             /*
1767              * No point in doing the extra work involved in an Xrealloc if
1768              * the region is empty
1769              */
1770             newReg->size = 1;
1771             HeapFree( GetProcessHeap(), 0, newReg->rects );
1772             newReg->rects = HeapAlloc( GetProcessHeap(), 0, sizeof(RECT) );
1773         }
1774     }
1775     HeapFree( GetProcessHeap(), 0, oldRects );
1776     return;
1777 }
1778
1779 /***********************************************************************
1780  *          Region Intersection
1781  ***********************************************************************/
1782
1783
1784 /***********************************************************************
1785  *           REGION_IntersectO
1786  *
1787  * Handle an overlapping band for REGION_Intersect.
1788  *
1789  * Results:
1790  *      None.
1791  *
1792  * Side Effects:
1793  *      Rectangles may be added to the region.
1794  *
1795  */
1796 static void REGION_IntersectO(WINEREGION *pReg,  RECT *r1, RECT *r1End,
1797                 RECT *r2, RECT *r2End, INT top, INT bottom)
1798
1799 {
1800     INT       left, right;
1801     RECT      *pNextRect;
1802
1803     pNextRect = &pReg->rects[pReg->numRects];
1804
1805     while ((r1 != r1End) && (r2 != r2End))
1806     {
1807         left = max(r1->left, r2->left);
1808         right = min(r1->right, r2->right);
1809
1810         /*
1811          * If there's any overlap between the two rectangles, add that
1812          * overlap to the new region.
1813          * There's no need to check for subsumption because the only way
1814          * such a need could arise is if some region has two rectangles
1815          * right next to each other. Since that should never happen...
1816          */
1817         if (left < right)
1818         {
1819             MEMCHECK(pReg, pNextRect, pReg->rects);
1820             pNextRect->left = left;
1821             pNextRect->top = top;
1822             pNextRect->right = right;
1823             pNextRect->bottom = bottom;
1824             pReg->numRects += 1;
1825             pNextRect++;
1826         }
1827
1828         /*
1829          * Need to advance the pointers. Shift the one that extends
1830          * to the right the least, since the other still has a chance to
1831          * overlap with that region's next rectangle, if you see what I mean.
1832          */
1833         if (r1->right < r2->right)
1834         {
1835             r1++;
1836         }
1837         else if (r2->right < r1->right)
1838         {
1839             r2++;
1840         }
1841         else
1842         {
1843             r1++;
1844             r2++;
1845         }
1846     }
1847     return;
1848 }
1849
1850 /***********************************************************************
1851  *           REGION_IntersectRegion
1852  */
1853 static void REGION_IntersectRegion(WINEREGION *newReg, WINEREGION *reg1,
1854                                    WINEREGION *reg2)
1855 {
1856    /* check for trivial reject */
1857     if ( (!(reg1->numRects)) || (!(reg2->numRects))  ||
1858         (!EXTENTCHECK(&reg1->extents, &reg2->extents)))
1859         newReg->numRects = 0;
1860     else
1861         REGION_RegionOp (newReg, reg1, reg2, 
1862          (voidProcp) REGION_IntersectO, (voidProcp) NULL, (voidProcp) NULL);
1863     
1864     /*
1865      * Can't alter newReg's extents before we call miRegionOp because
1866      * it might be one of the source regions and miRegionOp depends
1867      * on the extents of those regions being the same. Besides, this
1868      * way there's no checking against rectangles that will be nuked
1869      * due to coalescing, so we have to examine fewer rectangles.
1870      */
1871     REGION_SetExtents(newReg);
1872     newReg->type = (newReg->numRects) ?
1873                        ((newReg->numRects > 1) ? COMPLEXREGION : SIMPLEREGION)
1874                        : NULLREGION ;
1875     return;
1876 }
1877
1878 /***********************************************************************
1879  *           Region Union
1880  ***********************************************************************/
1881
1882 /***********************************************************************
1883  *           REGION_UnionNonO
1884  *
1885  *      Handle a non-overlapping band for the union operation. Just
1886  *      Adds the rectangles into the region. Doesn't have to check for
1887  *      subsumption or anything.
1888  *
1889  * Results:
1890  *      None.
1891  *
1892  * Side Effects:
1893  *      pReg->numRects is incremented and the final rectangles overwritten
1894  *      with the rectangles we're passed.
1895  *
1896  */
1897 static void REGION_UnionNonO (WINEREGION *pReg, RECT *r, RECT *rEnd,
1898                               INT top, INT bottom)
1899 {
1900     RECT *pNextRect;
1901
1902     pNextRect = &pReg->rects[pReg->numRects];
1903
1904     while (r != rEnd)
1905     {
1906         MEMCHECK(pReg, pNextRect, pReg->rects);
1907         pNextRect->left = r->left;
1908         pNextRect->top = top;
1909         pNextRect->right = r->right;
1910         pNextRect->bottom = bottom;
1911         pReg->numRects += 1;
1912         pNextRect++;
1913         r++;
1914     }
1915     return;
1916 }
1917
1918 /***********************************************************************
1919  *           REGION_UnionO
1920  *
1921  *      Handle an overlapping band for the union operation. Picks the
1922  *      left-most rectangle each time and merges it into the region.
1923  *
1924  * Results:
1925  *      None.
1926  *
1927  * Side Effects:
1928  *      Rectangles are overwritten in pReg->rects and pReg->numRects will
1929  *      be changed.
1930  *
1931  */
1932 static void REGION_UnionO (WINEREGION *pReg, RECT *r1, RECT *r1End,
1933                            RECT *r2, RECT *r2End, INT top, INT bottom)
1934 {
1935     RECT *pNextRect;
1936     
1937     pNextRect = &pReg->rects[pReg->numRects];
1938
1939 #define MERGERECT(r) \
1940     if ((pReg->numRects != 0) &&  \
1941         (pNextRect[-1].top == top) &&  \
1942         (pNextRect[-1].bottom == bottom) &&  \
1943         (pNextRect[-1].right >= r->left))  \
1944     {  \
1945         if (pNextRect[-1].right < r->right)  \
1946         {  \
1947             pNextRect[-1].right = r->right;  \
1948         }  \
1949     }  \
1950     else  \
1951     {  \
1952         MEMCHECK(pReg, pNextRect, pReg->rects);  \
1953         pNextRect->top = top;  \
1954         pNextRect->bottom = bottom;  \
1955         pNextRect->left = r->left;  \
1956         pNextRect->right = r->right;  \
1957         pReg->numRects += 1;  \
1958         pNextRect += 1;  \
1959     }  \
1960     r++;
1961     
1962     while ((r1 != r1End) && (r2 != r2End))
1963     {
1964         if (r1->left < r2->left)
1965         {
1966             MERGERECT(r1);
1967         }
1968         else
1969         {
1970             MERGERECT(r2);
1971         }
1972     }
1973     
1974     if (r1 != r1End)
1975     {
1976         do
1977         {
1978             MERGERECT(r1);
1979         } while (r1 != r1End);
1980     }
1981     else while (r2 != r2End)
1982     {
1983         MERGERECT(r2);
1984     }
1985     return;
1986 }
1987
1988 /***********************************************************************
1989  *           REGION_UnionRegion
1990  */
1991 static void REGION_UnionRegion(WINEREGION *newReg, WINEREGION *reg1,
1992                                WINEREGION *reg2)
1993 {
1994     /*  checks all the simple cases */
1995
1996     /*
1997      * Region 1 and 2 are the same or region 1 is empty
1998      */
1999     if ( (reg1 == reg2) || (!(reg1->numRects)) )
2000     {
2001         if (newReg != reg2)
2002             REGION_CopyRegion(newReg, reg2);
2003         return;
2004     }
2005
2006     /*
2007      * if nothing to union (region 2 empty)
2008      */
2009     if (!(reg2->numRects))
2010     {
2011         if (newReg != reg1)
2012             REGION_CopyRegion(newReg, reg1);
2013         return;
2014     }
2015
2016     /*
2017      * Region 1 completely subsumes region 2
2018      */
2019     if ((reg1->numRects == 1) && 
2020         (reg1->extents.left <= reg2->extents.left) &&
2021         (reg1->extents.top <= reg2->extents.top) &&
2022         (reg1->extents.right >= reg2->extents.right) &&
2023         (reg1->extents.bottom >= reg2->extents.bottom))
2024     {
2025         if (newReg != reg1)
2026             REGION_CopyRegion(newReg, reg1);
2027         return;
2028     }
2029
2030     /*
2031      * Region 2 completely subsumes region 1
2032      */
2033     if ((reg2->numRects == 1) && 
2034         (reg2->extents.left <= reg1->extents.left) &&
2035         (reg2->extents.top <= reg1->extents.top) &&
2036         (reg2->extents.right >= reg1->extents.right) &&
2037         (reg2->extents.bottom >= reg1->extents.bottom))
2038     {
2039         if (newReg != reg2)
2040             REGION_CopyRegion(newReg, reg2);
2041         return;
2042     }
2043
2044     REGION_RegionOp (newReg, reg1, reg2, (voidProcp) REGION_UnionO, 
2045                 (voidProcp) REGION_UnionNonO, (voidProcp) REGION_UnionNonO);
2046
2047     newReg->extents.left = min(reg1->extents.left, reg2->extents.left);
2048     newReg->extents.top = min(reg1->extents.top, reg2->extents.top);
2049     newReg->extents.right = max(reg1->extents.right, reg2->extents.right);
2050     newReg->extents.bottom = max(reg1->extents.bottom, reg2->extents.bottom);
2051     newReg->type = (newReg->numRects) ?
2052                         ((newReg->numRects > 1) ? COMPLEXREGION : SIMPLEREGION)
2053                         : NULLREGION ;
2054     return;
2055 }
2056
2057 /***********************************************************************
2058  *           Region Subtraction
2059  ***********************************************************************/
2060
2061 /***********************************************************************
2062  *           REGION_SubtractNonO1
2063  *
2064  *      Deal with non-overlapping band for subtraction. Any parts from
2065  *      region 2 we discard. Anything from region 1 we add to the region.
2066  *
2067  * Results:
2068  *      None.
2069  *
2070  * Side Effects:
2071  *      pReg may be affected.
2072  *
2073  */
2074 static void REGION_SubtractNonO1 (WINEREGION *pReg, RECT *r, RECT *rEnd, 
2075                 INT top, INT bottom)
2076 {
2077     RECT *pNextRect;
2078         
2079     pNextRect = &pReg->rects[pReg->numRects];
2080         
2081     while (r != rEnd)
2082     {
2083         MEMCHECK(pReg, pNextRect, pReg->rects);
2084         pNextRect->left = r->left;
2085         pNextRect->top = top;
2086         pNextRect->right = r->right;
2087         pNextRect->bottom = bottom;
2088         pReg->numRects += 1;
2089         pNextRect++;
2090         r++;
2091     }
2092     return;
2093 }
2094
2095
2096 /***********************************************************************
2097  *           REGION_SubtractO
2098  *
2099  *      Overlapping band subtraction. x1 is the left-most point not yet
2100  *      checked.
2101  *
2102  * Results:
2103  *      None.
2104  *
2105  * Side Effects:
2106  *      pReg may have rectangles added to it.
2107  *
2108  */
2109 static void REGION_SubtractO (WINEREGION *pReg, RECT *r1, RECT *r1End, 
2110                 RECT *r2, RECT *r2End, INT top, INT bottom)
2111 {
2112     RECT *pNextRect;
2113     INT left;
2114     
2115     left = r1->left;
2116     pNextRect = &pReg->rects[pReg->numRects];
2117
2118     while ((r1 != r1End) && (r2 != r2End))
2119     {
2120         if (r2->right <= left)
2121         {
2122             /*
2123              * Subtrahend missed the boat: go to next subtrahend.
2124              */
2125             r2++;
2126         }
2127         else if (r2->left <= left)
2128         {
2129             /*
2130              * Subtrahend preceeds minuend: nuke left edge of minuend.
2131              */
2132             left = r2->right;
2133             if (left >= r1->right)
2134             {
2135                 /*
2136                  * Minuend completely covered: advance to next minuend and
2137                  * reset left fence to edge of new minuend.
2138                  */
2139                 r1++;
2140                 if (r1 != r1End)
2141                     left = r1->left;
2142             }
2143             else
2144             {
2145                 /*
2146                  * Subtrahend now used up since it doesn't extend beyond
2147                  * minuend
2148                  */
2149                 r2++;
2150             }
2151         }
2152         else if (r2->left < r1->right)
2153         {
2154             /*
2155              * Left part of subtrahend covers part of minuend: add uncovered
2156              * part of minuend to region and skip to next subtrahend.
2157              */
2158             MEMCHECK(pReg, pNextRect, pReg->rects);
2159             pNextRect->left = left;
2160             pNextRect->top = top;
2161             pNextRect->right = r2->left;
2162             pNextRect->bottom = bottom;
2163             pReg->numRects += 1;
2164             pNextRect++;
2165             left = r2->right;
2166             if (left >= r1->right)
2167             {
2168                 /*
2169                  * Minuend used up: advance to new...
2170                  */
2171                 r1++;
2172                 if (r1 != r1End)
2173                     left = r1->left;
2174             }
2175             else
2176             {
2177                 /*
2178                  * Subtrahend used up
2179                  */
2180                 r2++;
2181             }
2182         }
2183         else
2184         {
2185             /*
2186              * Minuend used up: add any remaining piece before advancing.
2187              */
2188             if (r1->right > left)
2189             {
2190                 MEMCHECK(pReg, pNextRect, pReg->rects);
2191                 pNextRect->left = left;
2192                 pNextRect->top = top;
2193                 pNextRect->right = r1->right;
2194                 pNextRect->bottom = bottom;
2195                 pReg->numRects += 1;
2196                 pNextRect++;
2197             }
2198             r1++;
2199             left = r1->left;
2200         }
2201     }
2202
2203     /*
2204      * Add remaining minuend rectangles to region.
2205      */
2206     while (r1 != r1End)
2207     {
2208         MEMCHECK(pReg, pNextRect, pReg->rects);
2209         pNextRect->left = left;
2210         pNextRect->top = top;
2211         pNextRect->right = r1->right;
2212         pNextRect->bottom = bottom;
2213         pReg->numRects += 1;
2214         pNextRect++;
2215         r1++;
2216         if (r1 != r1End)
2217         {
2218             left = r1->left;
2219         }
2220     }
2221     return;
2222 }
2223         
2224 /***********************************************************************
2225  *           REGION_SubtractRegion
2226  *
2227  *      Subtract regS from regM and leave the result in regD.
2228  *      S stands for subtrahend, M for minuend and D for difference.
2229  *
2230  * Results:
2231  *      TRUE.
2232  *
2233  * Side Effects:
2234  *      regD is overwritten.
2235  *
2236  */
2237 static void REGION_SubtractRegion(WINEREGION *regD, WINEREGION *regM,
2238                                                        WINEREGION *regS )
2239 {
2240    /* check for trivial reject */
2241     if ( (!(regM->numRects)) || (!(regS->numRects))  ||
2242         (!EXTENTCHECK(&regM->extents, &regS->extents)) )
2243     {
2244         REGION_CopyRegion(regD, regM);
2245         return;
2246     }
2247  
2248     REGION_RegionOp (regD, regM, regS, (voidProcp) REGION_SubtractO, 
2249                 (voidProcp) REGION_SubtractNonO1, (voidProcp) NULL);
2250
2251     /*
2252      * Can't alter newReg's extents before we call miRegionOp because
2253      * it might be one of the source regions and miRegionOp depends
2254      * on the extents of those regions being the unaltered. Besides, this
2255      * way there's no checking against rectangles that will be nuked
2256      * due to coalescing, so we have to examine fewer rectangles.
2257      */
2258     REGION_SetExtents (regD);
2259     regD->type = (regD->numRects) ?
2260                        ((regD->numRects > 1) ? COMPLEXREGION : SIMPLEREGION)
2261                        : NULLREGION ;
2262     return;
2263 }
2264
2265 /***********************************************************************
2266  *           REGION_XorRegion
2267  */
2268 static void REGION_XorRegion(WINEREGION *dr, WINEREGION *sra,
2269                                                         WINEREGION *srb)
2270 {
2271     WINEREGION *tra, *trb;
2272
2273     if ((! (tra = REGION_AllocWineRegion(sra->numRects + 1))) || 
2274         (! (trb = REGION_AllocWineRegion(srb->numRects + 1))))
2275         return;
2276     REGION_SubtractRegion(tra,sra,srb);
2277     REGION_SubtractRegion(trb,srb,sra);
2278     REGION_UnionRegion(dr,tra,trb);
2279     REGION_DestroyWineRegion(tra);
2280     REGION_DestroyWineRegion(trb);
2281     return;
2282 }
2283
2284 /**************************************************************************
2285  *
2286  *    Poly Regions
2287  * 
2288  *************************************************************************/
2289
2290 #define LARGE_COORDINATE  0x7fffffff /* FIXME */
2291 #define SMALL_COORDINATE  0x80000000
2292
2293 /***********************************************************************
2294  *     REGION_InsertEdgeInET
2295  *
2296  *     Insert the given edge into the edge table.
2297  *     First we must find the correct bucket in the
2298  *     Edge table, then find the right slot in the
2299  *     bucket.  Finally, we can insert it.
2300  *
2301  */
2302 static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
2303                 INT scanline, ScanLineListBlock **SLLBlock, INT *iSLLBlock)
2304
2305 {
2306     EdgeTableEntry *start, *prev;
2307     ScanLineList *pSLL, *pPrevSLL;
2308     ScanLineListBlock *tmpSLLBlock;
2309
2310     /*
2311      * find the right bucket to put the edge into
2312      */
2313     pPrevSLL = &ET->scanlines;
2314     pSLL = pPrevSLL->next;
2315     while (pSLL && (pSLL->scanline < scanline)) 
2316     {
2317         pPrevSLL = pSLL;
2318         pSLL = pSLL->next;
2319     }
2320
2321     /*
2322      * reassign pSLL (pointer to ScanLineList) if necessary
2323      */
2324     if ((!pSLL) || (pSLL->scanline > scanline)) 
2325     {
2326         if (*iSLLBlock > SLLSPERBLOCK-1) 
2327         {
2328             tmpSLLBlock = HeapAlloc( GetProcessHeap(), 0, sizeof(ScanLineListBlock));
2329             if(!tmpSLLBlock)
2330             {
2331                 WARN("Can't alloc SLLB\n");
2332                 return;
2333             }
2334             (*SLLBlock)->next = tmpSLLBlock;
2335             tmpSLLBlock->next = (ScanLineListBlock *)NULL;
2336             *SLLBlock = tmpSLLBlock;
2337             *iSLLBlock = 0;
2338         }
2339         pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
2340
2341         pSLL->next = pPrevSLL->next;
2342         pSLL->edgelist = (EdgeTableEntry *)NULL;
2343         pPrevSLL->next = pSLL;
2344     }
2345     pSLL->scanline = scanline;
2346
2347     /*
2348      * now insert the edge in the right bucket
2349      */
2350     prev = (EdgeTableEntry *)NULL;
2351     start = pSLL->edgelist;
2352     while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) 
2353     {
2354         prev = start;
2355         start = start->next;
2356     }
2357     ETE->next = start;
2358
2359     if (prev)
2360         prev->next = ETE;
2361     else
2362         pSLL->edgelist = ETE;
2363 }
2364
2365 /***********************************************************************
2366  *     REGION_CreateEdgeTable
2367  *
2368  *     This routine creates the edge table for
2369  *     scan converting polygons. 
2370  *     The Edge Table (ET) looks like:
2371  *
2372  *    EdgeTable
2373  *     --------
2374  *    |  ymax  |        ScanLineLists
2375  *    |scanline|-->------------>-------------->...
2376  *     --------   |scanline|   |scanline|
2377  *                |edgelist|   |edgelist|
2378  *                ---------    ---------
2379  *                    |             |
2380  *                    |             |
2381  *                    V             V
2382  *              list of ETEs   list of ETEs
2383  *
2384  *     where ETE is an EdgeTableEntry data structure,
2385  *     and there is one ScanLineList per scanline at
2386  *     which an edge is initially entered.
2387  *
2388  */
2389 static void REGION_CreateETandAET(const INT *Count, INT nbpolygons, 
2390             const POINT *pts, EdgeTable *ET, EdgeTableEntry *AET,
2391             EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
2392 {
2393     const POINT *top, *bottom;
2394     const POINT *PrevPt, *CurrPt, *EndPt;
2395     INT poly, count;
2396     int iSLLBlock = 0;
2397     int dy;
2398
2399     
2400     /*
2401      *  initialize the Active Edge Table
2402      */
2403     AET->next = (EdgeTableEntry *)NULL;
2404     AET->back = (EdgeTableEntry *)NULL;
2405     AET->nextWETE = (EdgeTableEntry *)NULL;
2406     AET->bres.minor_axis = SMALL_COORDINATE;
2407
2408     /*
2409      *  initialize the Edge Table.
2410      */
2411     ET->scanlines.next = (ScanLineList *)NULL;
2412     ET->ymax = SMALL_COORDINATE;
2413     ET->ymin = LARGE_COORDINATE;
2414     pSLLBlock->next = (ScanLineListBlock *)NULL;
2415
2416     EndPt = pts - 1;
2417     for(poly = 0; poly < nbpolygons; poly++)
2418     {
2419         count = Count[poly];
2420         EndPt += count;
2421         if(count < 2)
2422             continue;
2423         
2424         PrevPt = EndPt;
2425
2426     /*
2427      *  for each vertex in the array of points.
2428      *  In this loop we are dealing with two vertices at
2429      *  a time -- these make up one edge of the polygon.
2430      */
2431         while (count--) 
2432         {
2433             CurrPt = pts++;
2434
2435         /*
2436          *  find out which point is above and which is below.
2437          */
2438             if (PrevPt->y > CurrPt->y) 
2439             {
2440                 bottom = PrevPt, top = CurrPt;
2441                 pETEs->ClockWise = 0;
2442             }
2443             else 
2444             {
2445                 bottom = CurrPt, top = PrevPt;
2446                 pETEs->ClockWise = 1;
2447             }
2448
2449         /*
2450          * don't add horizontal edges to the Edge table.
2451          */
2452             if (bottom->y != top->y) 
2453             {
2454                 pETEs->ymax = bottom->y-1;
2455                                 /* -1 so we don't get last scanline */
2456
2457             /*
2458              *  initialize integer edge algorithm
2459              */
2460                 dy = bottom->y - top->y;
2461                 BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
2462
2463                 REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, 
2464                                                                 &iSLLBlock);
2465
2466                 if (PrevPt->y > ET->ymax)
2467                   ET->ymax = PrevPt->y;
2468                 if (PrevPt->y < ET->ymin)
2469                   ET->ymin = PrevPt->y;
2470                 pETEs++;
2471             }
2472
2473             PrevPt = CurrPt;
2474         }
2475     }
2476 }
2477
2478 /***********************************************************************
2479  *     REGION_loadAET
2480  *
2481  *     This routine moves EdgeTableEntries from the
2482  *     EdgeTable into the Active Edge Table,
2483  *     leaving them sorted by smaller x coordinate.
2484  *
2485  */
2486 static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
2487 {
2488     EdgeTableEntry *pPrevAET;
2489     EdgeTableEntry *tmp;
2490
2491     pPrevAET = AET;
2492     AET = AET->next;
2493     while (ETEs) 
2494     {
2495         while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis)) 
2496         {
2497             pPrevAET = AET;
2498             AET = AET->next;
2499         }
2500         tmp = ETEs->next;
2501         ETEs->next = AET;
2502         if (AET)
2503             AET->back = ETEs;
2504         ETEs->back = pPrevAET;
2505         pPrevAET->next = ETEs;
2506         pPrevAET = ETEs;
2507
2508         ETEs = tmp;
2509     }
2510 }
2511
2512 /***********************************************************************
2513  *     REGION_computeWAET
2514  *
2515  *     This routine links the AET by the
2516  *     nextWETE (winding EdgeTableEntry) link for
2517  *     use by the winding number rule.  The final 
2518  *     Active Edge Table (AET) might look something
2519  *     like:
2520  *
2521  *     AET
2522  *     ----------  ---------   ---------
2523  *     |ymax    |  |ymax    |  |ymax    | 
2524  *     | ...    |  |...     |  |...     |
2525  *     |next    |->|next    |->|next    |->...
2526  *     |nextWETE|  |nextWETE|  |nextWETE|
2527  *     ---------   ---------   ^--------
2528  *         |                   |       |
2529  *         V------------------->       V---> ...
2530  *
2531  */
2532 static void REGION_computeWAET(EdgeTableEntry *AET)
2533 {
2534     register EdgeTableEntry *pWETE;
2535     register int inside = 1;
2536     register int isInside = 0;
2537
2538     AET->nextWETE = (EdgeTableEntry *)NULL;
2539     pWETE = AET;
2540     AET = AET->next;
2541     while (AET) 
2542     {
2543         if (AET->ClockWise)
2544             isInside++;
2545         else
2546             isInside--;
2547
2548         if ((!inside && !isInside) ||
2549             ( inside &&  isInside)) 
2550         {
2551             pWETE->nextWETE = AET;
2552             pWETE = AET;
2553             inside = !inside;
2554         }
2555         AET = AET->next;
2556     }
2557     pWETE->nextWETE = (EdgeTableEntry *)NULL;
2558 }
2559
2560 /***********************************************************************
2561  *     REGION_InsertionSort
2562  *
2563  *     Just a simple insertion sort using
2564  *     pointers and back pointers to sort the Active
2565  *     Edge Table.
2566  *
2567  */
2568 static BOOL REGION_InsertionSort(EdgeTableEntry *AET)
2569 {
2570     EdgeTableEntry *pETEchase;
2571     EdgeTableEntry *pETEinsert;
2572     EdgeTableEntry *pETEchaseBackTMP;
2573     BOOL changed = FALSE;
2574
2575     AET = AET->next;
2576     while (AET) 
2577     {
2578         pETEinsert = AET;
2579         pETEchase = AET;
2580         while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
2581             pETEchase = pETEchase->back;
2582
2583         AET = AET->next;
2584         if (pETEchase != pETEinsert) 
2585         {
2586             pETEchaseBackTMP = pETEchase->back;
2587             pETEinsert->back->next = AET;
2588             if (AET)
2589                 AET->back = pETEinsert->back;
2590             pETEinsert->next = pETEchase;
2591             pETEchase->back->next = pETEinsert;
2592             pETEchase->back = pETEinsert;
2593             pETEinsert->back = pETEchaseBackTMP;
2594             changed = TRUE;
2595         }
2596     }
2597     return changed;
2598 }
2599
2600 /***********************************************************************
2601  *     REGION_FreeStorage
2602  *
2603  *     Clean up our act.
2604  */
2605 static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
2606 {
2607     ScanLineListBlock   *tmpSLLBlock;
2608
2609     while (pSLLBlock) 
2610     {
2611         tmpSLLBlock = pSLLBlock->next;
2612         HeapFree( GetProcessHeap(), 0, pSLLBlock );
2613         pSLLBlock = tmpSLLBlock;
2614     }
2615 }
2616
2617
2618 /***********************************************************************
2619  *     REGION_PtsToRegion
2620  *
2621  *     Create an array of rectangles from a list of points.
2622  */
2623 static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock, 
2624                        POINTBLOCK *FirstPtBlock, WINEREGION *reg)
2625 {
2626     RECT *rects;
2627     POINT *pts;
2628     POINTBLOCK *CurPtBlock;
2629     int i;
2630     RECT *extents;
2631     INT numRects;
2632  
2633     extents = &reg->extents;
2634  
2635     numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
2636  
2637     if (!(reg->rects = HeapReAlloc( GetProcessHeap(), 0, reg->rects, 
2638                            sizeof(RECT) * numRects )))
2639         return(0);
2640  
2641     reg->size = numRects;
2642     CurPtBlock = FirstPtBlock;
2643     rects = reg->rects - 1;
2644     numRects = 0;
2645     extents->left = LARGE_COORDINATE,  extents->right = SMALL_COORDINATE;
2646  
2647     for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
2648         /* the loop uses 2 points per iteration */
2649         i = NUMPTSTOBUFFER >> 1;
2650         if (!numFullPtBlocks)
2651             i = iCurPtBlock >> 1;
2652         for (pts = CurPtBlock->pts; i--; pts += 2) {
2653             if (pts->x == pts[1].x)
2654                 continue;
2655             if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
2656                 pts[1].x == rects->right &&
2657                 (numRects == 1 || rects[-1].top != rects->top) &&
2658                 (i && pts[2].y > pts[1].y)) {
2659                 rects->bottom = pts[1].y + 1;
2660                 continue;
2661             }
2662             numRects++;
2663             rects++;
2664             rects->left = pts->x;  rects->top = pts->y;
2665             rects->right = pts[1].x;  rects->bottom = pts[1].y + 1;
2666             if (rects->left < extents->left)
2667                 extents->left = rects->left;
2668             if (rects->right > extents->right)
2669                 extents->right = rects->right;
2670         }
2671         CurPtBlock = CurPtBlock->next;
2672     }
2673
2674     if (numRects) {
2675         extents->top = reg->rects->top;
2676         extents->bottom = rects->bottom;
2677     } else {
2678         extents->left = 0;
2679         extents->top = 0;
2680         extents->right = 0;
2681         extents->bottom = 0;
2682     }
2683     reg->numRects = numRects;
2684  
2685     return(TRUE);
2686 }
2687
2688 /***********************************************************************
2689  *           CreatePolyPolygonRgn    (GDI32.57)
2690  */
2691 HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count, 
2692                       INT nbpolygons, INT mode)
2693 {
2694     HRGN hrgn;
2695     RGNOBJ *obj;
2696     WINEREGION *region;
2697     register EdgeTableEntry *pAET;   /* Active Edge Table       */
2698     register INT y;                /* current scanline        */
2699     register int iPts = 0;           /* number of pts in buffer */
2700     register EdgeTableEntry *pWETE;  /* Winding Edge Table Entry*/
2701     register ScanLineList *pSLL;     /* current scanLineList    */
2702     register POINT *pts;           /* output buffer           */
2703     EdgeTableEntry *pPrevAET;        /* ptr to previous AET     */
2704     EdgeTable ET;                    /* header node for ET      */
2705     EdgeTableEntry AET;              /* header node for AET     */
2706     EdgeTableEntry *pETEs;           /* EdgeTableEntries pool   */
2707     ScanLineListBlock SLLBlock;      /* header for scanlinelist */
2708     int fixWAET = FALSE;
2709     POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers    */
2710     POINTBLOCK *tmpPtBlock;
2711     int numFullPtBlocks = 0;
2712     INT poly, total;
2713
2714     if(!(hrgn = REGION_CreateRegion(nbpolygons)))
2715         return 0;
2716     obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
2717     region = obj->rgn;
2718
2719     /* special case a rectangle */
2720
2721     if (((nbpolygons == 1) && ((*Count == 4) ||
2722        ((*Count == 5) && (Pts[4].x == Pts[0].x) && (Pts[4].y == Pts[0].y)))) &&
2723         (((Pts[0].y == Pts[1].y) &&
2724           (Pts[1].x == Pts[2].x) &&
2725           (Pts[2].y == Pts[3].y) &&
2726           (Pts[3].x == Pts[0].x)) ||
2727          ((Pts[0].x == Pts[1].x) &&
2728           (Pts[1].y == Pts[2].y) &&
2729           (Pts[2].x == Pts[3].x) &&
2730           (Pts[3].y == Pts[0].y))))
2731     {
2732         SetRectRgn( hrgn, min(Pts[0].x, Pts[2].x), min(Pts[0].y, Pts[2].y), 
2733                             max(Pts[0].x, Pts[2].x), max(Pts[0].y, Pts[2].y) );
2734         GDI_ReleaseObj( hrgn );
2735         return hrgn;
2736     }
2737     
2738     for(poly = total = 0; poly < nbpolygons; poly++)
2739         total += Count[poly];
2740     if (! (pETEs = HeapAlloc( GetProcessHeap(), 0, sizeof(EdgeTableEntry) * total )))
2741     {
2742         REGION_DeleteObject( hrgn, obj );
2743         return 0;
2744     }
2745     pts = FirstPtBlock.pts;
2746     REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
2747     pSLL = ET.scanlines.next;
2748     curPtBlock = &FirstPtBlock;
2749  
2750     if (mode != WINDING) {
2751         /*
2752          *  for each scanline
2753          */
2754         for (y = ET.ymin; y < ET.ymax; y++) {
2755             /*
2756              *  Add a new edge to the active edge table when we
2757              *  get to the next edge.
2758              */
2759             if (pSLL != NULL && y == pSLL->scanline) {
2760                 REGION_loadAET(&AET, pSLL->edgelist);
2761                 pSLL = pSLL->next;
2762             }
2763             pPrevAET = &AET;
2764             pAET = AET.next;
2765  
2766             /*
2767              *  for each active edge
2768              */
2769             while (pAET) {
2770                 pts->x = pAET->bres.minor_axis,  pts->y = y;
2771                 pts++, iPts++;
2772  
2773                 /*
2774                  *  send out the buffer
2775                  */
2776                 if (iPts == NUMPTSTOBUFFER) {
2777                     tmpPtBlock = HeapAlloc( GetProcessHeap(), 0, sizeof(POINTBLOCK));
2778                     if(!tmpPtBlock) {
2779                         WARN("Can't alloc tPB\n");
2780                         return 0;
2781                     }
2782                     curPtBlock->next = tmpPtBlock;
2783                     curPtBlock = tmpPtBlock;
2784                     pts = curPtBlock->pts;
2785                     numFullPtBlocks++;
2786                     iPts = 0;
2787                 }
2788                 EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
2789             }
2790             REGION_InsertionSort(&AET);
2791         }
2792     }
2793     else {
2794         /*
2795          *  for each scanline
2796          */
2797         for (y = ET.ymin; y < ET.ymax; y++) {
2798             /*
2799              *  Add a new edge to the active edge table when we
2800              *  get to the next edge.
2801              */
2802             if (pSLL != NULL && y == pSLL->scanline) {
2803                 REGION_loadAET(&AET, pSLL->edgelist);
2804                 REGION_computeWAET(&AET);
2805                 pSLL = pSLL->next;
2806             }
2807             pPrevAET = &AET;
2808             pAET = AET.next;
2809             pWETE = pAET;
2810  
2811             /*
2812              *  for each active edge
2813              */
2814             while (pAET) {
2815                 /*
2816                  *  add to the buffer only those edges that
2817                  *  are in the Winding active edge table.
2818                  */
2819                 if (pWETE == pAET) {
2820                     pts->x = pAET->bres.minor_axis,  pts->y = y;
2821                     pts++, iPts++;
2822  
2823                     /*
2824                      *  send out the buffer
2825                      */
2826                     if (iPts == NUMPTSTOBUFFER) {
2827                         tmpPtBlock = HeapAlloc( GetProcessHeap(), 0,
2828                                                sizeof(POINTBLOCK) );
2829                         if(!tmpPtBlock) {
2830                             WARN("Can't alloc tPB\n");
2831                             REGION_DeleteObject( hrgn, obj );
2832                             return 0;
2833                         }
2834                         curPtBlock->next = tmpPtBlock;
2835                         curPtBlock = tmpPtBlock;
2836                         pts = curPtBlock->pts;
2837                         numFullPtBlocks++;    iPts = 0;
2838                     }
2839                     pWETE = pWETE->nextWETE;
2840                 }
2841                 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
2842             }
2843  
2844             /*
2845              *  recompute the winding active edge table if
2846              *  we just resorted or have exited an edge.
2847              */
2848             if (REGION_InsertionSort(&AET) || fixWAET) {
2849                 REGION_computeWAET(&AET);
2850                 fixWAET = FALSE;
2851             }
2852         }
2853     }
2854     REGION_FreeStorage(SLLBlock.next);  
2855     REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
2856     region->type = (region->numRects) ?
2857                         ((region->numRects > 1) ? COMPLEXREGION : SIMPLEREGION)
2858                         : NULLREGION;
2859
2860     for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
2861         tmpPtBlock = curPtBlock->next;
2862         HeapFree( GetProcessHeap(), 0, curPtBlock );
2863         curPtBlock = tmpPtBlock;
2864     }
2865     HeapFree( GetProcessHeap(), 0, pETEs );
2866     GDI_ReleaseObj( hrgn );
2867     return hrgn;
2868 }
2869
2870
2871 /***********************************************************************
2872  *           CreatePolygonRgn16    (GDI.63)
2873  */
2874 HRGN16 WINAPI CreatePolygonRgn16( const POINT16 * points, INT16 count,
2875                                   INT16 mode )
2876 {
2877     return CreatePolyPolygonRgn16( points, &count, 1, mode );
2878 }
2879
2880 /***********************************************************************
2881  *           CreatePolyPolygonRgn16    (GDI.451)
2882  */
2883 HRGN16 WINAPI CreatePolyPolygonRgn16( const POINT16 *points,
2884                 const INT16 *count, INT16 nbpolygons, INT16 mode )
2885 {
2886     HRGN hrgn;
2887     int i, npts = 0;
2888     INT *count32;
2889     POINT *points32;
2890
2891     for (i = 0; i < nbpolygons; i++)
2892         npts += count[i];
2893     points32 = HeapAlloc( GetProcessHeap(), 0, npts * sizeof(POINT) );
2894     for (i = 0; i < npts; i++)
2895         CONV_POINT16TO32( &(points[i]), &(points32[i]) );
2896
2897     count32 = HeapAlloc( GetProcessHeap(), 0, nbpolygons * sizeof(INT) );
2898     for (i = 0; i < nbpolygons; i++)
2899         count32[i] = count[i];
2900     hrgn = CreatePolyPolygonRgn( points32, count32, nbpolygons, mode );
2901     HeapFree( GetProcessHeap(), 0, count32 );
2902     HeapFree( GetProcessHeap(), 0, points32 );
2903     return hrgn;
2904 }
2905
2906 /***********************************************************************
2907  *           CreatePolygonRgn    (GDI32.58)
2908  */
2909 HRGN WINAPI CreatePolygonRgn( const POINT *points, INT count,
2910                                   INT mode )
2911 {
2912     return CreatePolyPolygonRgn( points, &count, 1, mode );
2913 }
2914
2915
2916 /***********************************************************************
2917  * GetRandomRgn [GDI32.215]
2918  *
2919  * NOTES
2920  *     This function is documented in MSDN online
2921  */
2922 INT WINAPI GetRandomRgn(HDC hDC, HRGN hRgn, DWORD dwCode)
2923 {
2924     switch (dwCode)
2925     {
2926         case 4: /* == SYSRGN ? */
2927         {
2928             DC *dc = DC_GetDCPtr (hDC);
2929             OSVERSIONINFOA vi;
2930             POINT org;
2931
2932             if (!dc) return -1;
2933             CombineRgn (hRgn, dc->w.hVisRgn, 0, RGN_COPY);
2934             /*
2935              *     On Windows NT/2000,
2936              *           the region returned is in screen coordinates.
2937              *     On Windows 95/98, 
2938              *           the region returned is in window coordinates
2939              */
2940             vi.dwOSVersionInfoSize = sizeof(vi);
2941             if (GetVersionExA( &vi ) && vi.dwPlatformId == VER_PLATFORM_WIN32_NT)
2942                 GetDCOrgEx(hDC, &org);
2943             else
2944                 org.x = org.y = 0;
2945             org.x -= dc->w.DCOrgX;
2946             org.y -= dc->w.DCOrgY;
2947             OffsetRgn (hRgn, org.x, org.y);
2948             GDI_ReleaseObj( hDC );
2949             return 1;
2950         }
2951 /*      case 1:
2952             return GetClipRgn (hDC, hRgn);
2953 */
2954         default:
2955             WARN("Unknown dwCode %ld\n", dwCode);
2956             return -1;
2957     }
2958
2959     return -1;
2960 }
2961
2962 /***********************************************************************
2963  *           REGION_CropAndOffsetRegion
2964  */
2965 static BOOL REGION_CropAndOffsetRegion(const POINT* off, const RECT *rect, WINEREGION *rgnSrc, WINEREGION* rgnDst)
2966 {
2967
2968     if( !rect ) /* just copy and offset */
2969     {
2970         RECT *xrect;
2971         if( rgnDst == rgnSrc )
2972         {
2973             if( off->x || off->y )
2974                 xrect = rgnDst->rects;
2975             else 
2976                 return TRUE;
2977         }
2978         else
2979             xrect = HeapReAlloc( GetProcessHeap(), 0, rgnDst->rects,
2980                                 rgnSrc->size * sizeof( RECT ));
2981         if( xrect )
2982         {
2983             INT i;
2984
2985             if( rgnDst != rgnSrc )
2986                 memcpy( rgnDst, rgnSrc, sizeof( WINEREGION ));
2987
2988             if( off->x || off->y )
2989             {
2990                 for( i = 0; i < rgnDst->numRects; i++ )
2991                 {
2992                     xrect[i].left = rgnSrc->rects[i].left + off->x;
2993                     xrect[i].right = rgnSrc->rects[i].right + off->x;
2994                     xrect[i].top = rgnSrc->rects[i].top + off->y;
2995                     xrect[i].bottom = rgnSrc->rects[i].bottom + off->y;
2996                 }
2997                 rgnDst->extents.left   += off->x;
2998                 rgnDst->extents.right  += off->x;
2999                 rgnDst->extents.top    += off->y;
3000                 rgnDst->extents.bottom += off->y;
3001             }
3002             else
3003                 memcpy( xrect, rgnSrc->rects, rgnDst->numRects * sizeof(RECT));
3004             rgnDst->rects = xrect;
3005         } else
3006             return FALSE;
3007     }
3008     else if ((rect->left >= rect->right) ||
3009              (rect->top >= rect->bottom) ||
3010              !EXTENTCHECK(rect, &rgnSrc->extents))
3011     {
3012 empty:
3013         if( !rgnDst->rects )
3014         {
3015             rgnDst->rects = HeapAlloc(GetProcessHeap(), 0, RGN_DEFAULT_RECTS * sizeof( RECT ));
3016             if( rgnDst->rects )
3017                 rgnDst->size = RGN_DEFAULT_RECTS;
3018             else
3019                 return FALSE;
3020         }
3021
3022         TRACE("cropped to empty!\n");
3023         EMPTY_REGION(rgnDst);
3024     }
3025     else /* region box and clipping rect appear to intersect */
3026     {
3027         RECT *lpr;
3028         INT i, j, clipa, clipb;
3029         INT left = rgnSrc->extents.right + off->x;
3030         INT right = rgnSrc->extents.left + off->x;
3031
3032         for( clipa = 0; rgnSrc->rects[clipa].bottom <= rect->top; clipa++ )
3033              ; /* skip bands above the clipping rectangle */
3034
3035         for( clipb = clipa; clipb < rgnSrc->numRects; clipb++ )
3036              if( rgnSrc->rects[clipb].top >= rect->bottom )
3037                  break;    /* and below it */
3038
3039         /* clipa - index of the first rect in the first intersecting band
3040          * clipb - index of the last rect in the last intersecting band
3041          */
3042
3043         if((rgnDst != rgnSrc) && (rgnDst->size < (i = (clipb - clipa))))
3044         {
3045             rgnDst->rects = HeapReAlloc( GetProcessHeap(), 0, 
3046                                 rgnDst->rects, i * sizeof(RECT));
3047             if( !rgnDst->rects ) return FALSE;
3048             rgnDst->size = i;
3049         }
3050
3051         if( TRACE_ON(region) )
3052         {
3053             REGION_DumpRegion( rgnSrc );
3054             TRACE("\tclipa = %i, clipb = %i\n", clipa, clipb );
3055         }
3056
3057         for( i = clipa, j = 0; i < clipb ; i++ )
3058         {
3059              /* i - src index, j - dst index, j is always <= i for obvious reasons */
3060
3061              lpr = rgnSrc->rects + i;
3062              if( lpr->left < rect->right && lpr->right > rect->left )
3063              {
3064                  rgnDst->rects[j].top = lpr->top + off->y;
3065                  rgnDst->rects[j].bottom = lpr->bottom + off->y;
3066                  rgnDst->rects[j].left = ((lpr->left > rect->left) ? lpr->left : rect->left) + off->x;
3067                  rgnDst->rects[j].right = ((lpr->right < rect->right) ? lpr->right : rect->right) + off->x;
3068
3069                  if( rgnDst->rects[j].left < left ) left = rgnDst->rects[j].left;
3070                  if( rgnDst->rects[j].right > right ) right = rgnDst->rects[j].right;
3071
3072                  j++;
3073              }
3074         }
3075
3076         if( j == 0 ) goto empty;
3077
3078         rgnDst->extents.left = left;
3079         rgnDst->extents.right = right;
3080
3081         left = rect->top + off->y;
3082         right = rect->bottom + off->y;
3083
3084         rgnDst->numRects = j--;
3085         for( i = 0; i <= j; i++ )       /* fixup top band */
3086              if( rgnDst->rects[i].top < left )
3087                  rgnDst->rects[i].top = left;
3088              else
3089                  break;
3090
3091         for( i = j; i >= 0; i-- )       /* fixup bottom band */
3092              if( rgnDst->rects[i].bottom > right )
3093                  rgnDst->rects[i].bottom = right;
3094              else
3095                  break;
3096
3097         rgnDst->extents.top = rgnDst->rects[0].top;
3098         rgnDst->extents.bottom = rgnDst->rects[j].bottom;
3099
3100         rgnDst->type = (j >= 1) ? COMPLEXREGION : SIMPLEREGION;
3101
3102         if( TRACE_ON(region) )
3103         {
3104             TRACE("result:\n");
3105             REGION_DumpRegion( rgnDst );
3106         }
3107     }
3108
3109     return TRUE;
3110 }
3111
3112 /***********************************************************************
3113  *           REGION_CropRgn
3114  *
3115  *
3116  * hSrc:        Region to crop and offset.
3117  * lpRect:      Clipping rectangle. Can be NULL (no clipping).
3118  * lpPt:        Points to offset the cropped region. Can be NULL (no offset).
3119  *
3120  * hDst: Region to hold the result (a new region is created if it's 0).
3121  *       Allowed to be the same region as hSrc in which case everything
3122  *       will be done in place, with no memory reallocations.
3123  *
3124  * Returns: hDst if success, 0 otherwise.
3125  */
3126 HRGN REGION_CropRgn( HRGN hDst, HRGN hSrc, const RECT *lpRect, const POINT *lpPt )
3127 {
3128 /*  Optimization of the following generic code:
3129
3130     HRGN h; 
3131
3132     if( lpRect ) 
3133         h = CreateRectRgn( lpRect->left, lpRect->top, lpRect->right, lpRect->bottom );
3134     else
3135         h = CreateRectRgn( 0, 0, 0, 0 );
3136     if( hDst == 0 ) hDst = h;
3137     if( lpRect )
3138         CombineRgn( hDst, hSrc, h, RGN_AND );
3139     else
3140         CombineRgn( hDst, hSrc, 0, RGN_COPY );
3141     if( lpPt )
3142         OffsetRgn( hDst, lpPt->x, lpPt->y );
3143     if( hDst != h )
3144         DeleteObject( h );
3145     return hDst;
3146
3147 */
3148
3149     RGNOBJ *objSrc = (RGNOBJ *) GDI_GetObjPtr( hSrc, REGION_MAGIC );
3150
3151     if(objSrc)
3152     {
3153         RGNOBJ *objDst;
3154         WINEREGION *rgnDst;
3155
3156         if( hDst )
3157         {
3158             if (!(objDst = (RGNOBJ *) GDI_GetObjPtr( hDst, REGION_MAGIC )))
3159             {
3160                hDst = 0;
3161                goto done;
3162             }
3163             rgnDst = objDst->rgn;
3164         }
3165         else
3166         {
3167             if ((rgnDst = HeapAlloc(GetProcessHeap(), 0, sizeof( WINEREGION ))))
3168             {
3169                 rgnDst->size = rgnDst->numRects = 0;
3170                 rgnDst->rects = NULL;   /* back end will allocate exact number */
3171             }
3172         }
3173
3174         if( rgnDst )
3175         {
3176             POINT pt = { 0, 0 };
3177
3178             if( !lpPt ) lpPt = &pt;
3179
3180             if( lpRect )
3181                 TRACE("src %p -> dst %p (%i,%i)-(%i,%i) by (%li,%li)\n", objSrc->rgn, rgnDst,
3182                       lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, lpPt->x, lpPt->y );
3183             else
3184                 TRACE("src %p -> dst %p by (%li,%li)\n", objSrc->rgn, rgnDst, lpPt->x, lpPt->y ); 
3185
3186             if( REGION_CropAndOffsetRegion( lpPt, lpRect, objSrc->rgn, rgnDst ) == FALSE )
3187             {
3188                 if( hDst ) /* existing rgn */
3189                 {
3190                     GDI_ReleaseObj(hDst);
3191                     hDst = 0;
3192                     goto done;
3193                 }
3194                 goto fail;
3195             }
3196             else if( hDst == 0 )
3197             {
3198                 if (!(objDst = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC, &hDst )))
3199                 {
3200 fail:
3201                     if( rgnDst->rects )
3202                         HeapFree( GetProcessHeap(), 0, rgnDst->rects );
3203                     HeapFree( GetProcessHeap(), 0, rgnDst );
3204                     goto done;
3205                 }
3206                 objDst->rgn = rgnDst;
3207             }
3208
3209             GDI_ReleaseObj(hDst);
3210         }
3211         else hDst = 0;
3212 done:
3213         GDI_ReleaseObj(hSrc);
3214         return hDst;
3215     }
3216     return 0;
3217 }
3218
3219 /***********************************************************************
3220  *           GetMetaRgn    (GDI.328)
3221  */
3222 INT WINAPI GetMetaRgn( HDC hdc, HRGN hRgn )
3223 {
3224   FIXME( "stub\n" );
3225
3226   return 0;
3227 }
3228
3229
3230 /***********************************************************************
3231  *           SetMetaRgn    (GDI.455)
3232  */
3233 INT WINAPI SetMetaRgn( HDC hdc )
3234 {
3235   FIXME( "stub\n" );
3236
3237   return ERROR;
3238 }