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