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