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