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