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