:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / subsys / win32k / objects / region.c
1 #undef WIN32_LEAN_AND_MEAN
2 #include <windows.h>
3 #include <ddk/ntddk.h>
4 #include <internal/safe.h>
5 #include <win32k/float.h>
6 #include <win32k/dc.h>
7 #include <win32k/bitmaps.h>
8 #include <win32k/region.h>
9 #include <win32k/cliprgn.h>
10 #include <win32k/brush.h>
11 #include <include/rect.h>
12
13
14 // #define NDEBUG
15 #include <win32k/debug1.h>
16
17 BOOL STDCALL
18 IntEngPaint(IN SURFOBJ *Surface,IN CLIPOBJ *ClipRegion,IN BRUSHOBJ *Brush,IN POINTL *BrushOrigin,
19          IN MIX  Mix);
20
21 // Internal Functions
22
23 #define EMPTY_REGION(pReg) { \
24   (pReg)->rdh.nCount = 0; \
25   (pReg)->rdh.rcBound.left = (pReg)->rdh.rcBound.top = 0; \
26   (pReg)->rdh.rcBound.right = (pReg)->rdh.rcBound.bottom = 0; \
27   (pReg)->rdh.iType = NULLREGION; \
28 }
29
30 #define REGION_NOT_EMPTY(pReg) pReg->rdh.nCount
31
32 #define INRECT(r, x, y) \
33       ( ( ((r).right >  x)) && \
34         ( ((r).left <= x)) && \
35         ( ((r).bottom >  y)) && \
36         ( ((r).top <= y)) )
37
38 /*  1 if two RECTs overlap.
39  *  0 if two RECTs do not overlap.
40  */
41 #define EXTENTCHECK(r1, r2) \
42         ((r1)->right > (r2)->left && \
43          (r1)->left < (r2)->right && \
44          (r1)->bottom > (r2)->top && \
45          (r1)->top < (r2)->bottom)
46
47 /*
48  *   Check to see if there is enough memory in the present region.
49  */
50 static inline int xmemcheck(ROSRGNDATA *reg, LPRECT *rect, LPRECT *firstrect ) {
51         if ( (reg->rdh.nCount+1)*sizeof( RECT ) >= reg->rdh.nRgnSize ) {
52                 PRECT temp;
53                 temp = ExAllocatePool( PagedPool, (2 * (reg->rdh.nRgnSize)));
54
55                 if (temp == 0)
56                     return 0;
57                 RtlCopyMemory( temp, *firstrect, reg->rdh.nRgnSize );
58                 reg->rdh.nRgnSize *= 2;
59                 ExFreePool( *firstrect );
60                 *firstrect = temp;
61                 *rect = (*firstrect)+reg->rdh.nCount;
62     }
63     return 1;
64 }
65
66 #define MEMCHECK(reg, rect, firstrect) xmemcheck(reg,&(rect),&(firstrect))
67
68 typedef void (*voidProcp)();
69
70 // Number of points to buffer before sending them off to scanlines() :  Must be an even number
71 #define NUMPTSTOBUFFER 200
72
73 #define RGN_DEFAULT_RECTS       2
74
75 // used to allocate buffers for points and link the buffers together
76
77 typedef struct _POINTBLOCK {
78   POINT pts[NUMPTSTOBUFFER];
79   struct _POINTBLOCK *next;
80 } POINTBLOCK;
81
82 static BOOL REGION_CopyRegion(PROSRGNDATA dst, PROSRGNDATA src)
83 {
84   if(dst != src) //  don't want to copy to itself
85   {
86     if (dst->rdh.nRgnSize < src->rdh.nCount * sizeof(RECT))
87     {
88           PCHAR temp;
89
90           temp = ExAllocatePool(PagedPool, src->rdh.nCount * sizeof(RECT) );
91           if( !temp )
92                 return FALSE;
93
94           if( dst->Buffer )
95                 ExFreePool( dst->Buffer );      //free the old buffer
96           dst->Buffer = temp;
97       dst->rdh.nRgnSize = src->rdh.nCount * sizeof(RECT);  //size of region buffer
98     }
99     dst->rdh.nCount = src->rdh.nCount;                 //number of rectangles present in Buffer
100     dst->rdh.rcBound.left = src->rdh.rcBound.left;
101     dst->rdh.rcBound.top = src->rdh.rcBound.top;
102     dst->rdh.rcBound.right = src->rdh.rcBound.right;
103     dst->rdh.rcBound.bottom = src->rdh.rcBound.bottom;
104     dst->rdh.iType = src->rdh.iType;
105     RtlCopyMemory(dst->Buffer, src->Buffer, (int)(src->rdh.nCount * sizeof(RECT)));
106   }
107   return TRUE;
108 }
109
110 static void REGION_SetExtents (ROSRGNDATA *pReg)
111 {
112     RECT *pRect, *pRectEnd, *pExtents;
113
114     if (pReg->rdh.nCount == 0)
115     {
116                 pReg->rdh.rcBound.left = 0;
117                 pReg->rdh.rcBound.top = 0;
118                 pReg->rdh.rcBound.right = 0;
119                 pReg->rdh.rcBound.bottom = 0;
120                 return;
121     }
122
123     pExtents = &pReg->rdh.rcBound;
124     pRect = (PRECT)pReg->Buffer;
125     pRectEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount - 1;
126
127     /*
128      * Since pRect is the first rectangle in the region, it must have the
129      * smallest top and since pRectEnd is the last rectangle in the region,
130      * it must have the largest bottom, because of banding. Initialize left and
131      * right from pRect and pRectEnd, resp., as good things to initialize them
132      * to...
133      */
134     pExtents->left = pRect->left;
135     pExtents->top = pRect->top;
136     pExtents->right = pRectEnd->right;
137     pExtents->bottom = pRectEnd->bottom;
138
139     while (pRect <= pRectEnd)
140     {
141                 if (pRect->left < pExtents->left)
142                     pExtents->left = pRect->left;
143                 if (pRect->right > pExtents->right)
144                     pExtents->right = pRect->right;
145                 pRect++;
146     }
147 }
148
149
150 /***********************************************************************
151  *           REGION_CropAndOffsetRegion
152  */
153 static BOOL REGION_CropAndOffsetRegion(const PPOINT off, const PRECT rect, PROSRGNDATA rgnSrc, PROSRGNDATA rgnDst)
154 {
155   if(!rect) // just copy and offset
156   {
157     PRECT xrect;
158     if(rgnDst == rgnSrc)
159     {
160       if(off->x || off->y)
161         xrect = (PRECT)rgnDst->Buffer;
162       else
163         return TRUE;
164     }
165     else{
166       xrect = ExAllocatePool(PagedPool, rgnSrc->rdh.nCount * sizeof(RECT));
167           if( rgnDst->Buffer )
168                 ExFreePool( rgnDst->Buffer ); //free the old buffer. will be assigned to xrect below.
169         }
170
171     if(xrect)
172     {
173       INT i;
174
175       if(rgnDst != rgnSrc)
176                 RtlCopyMemory(rgnDst, rgnSrc, sizeof(ROSRGNDATA));
177
178       if(off->x || off->y)
179       {
180         for(i = 0; i < rgnDst->rdh.nCount; i++)
181         {
182           xrect[i].left = ((PRECT)rgnSrc->Buffer + i)->left + off->x;
183           xrect[i].right = ((PRECT)rgnSrc->Buffer + i)->right + off->x;
184           xrect[i].top = ((PRECT)rgnSrc->Buffer + i)->top + off->y;
185           xrect[i].bottom = ((PRECT)rgnSrc->Buffer + i)->bottom + off->y;
186         }
187         rgnDst->rdh.rcBound.left   += off->x;
188         rgnDst->rdh.rcBound.right  += off->x;
189         rgnDst->rdh.rcBound.top    += off->y;
190         rgnDst->rdh.rcBound.bottom += off->y;
191       }
192       else
193         RtlCopyMemory(xrect, rgnSrc->Buffer, rgnDst->rdh.nCount * sizeof(RECT));
194
195           rgnDst->Buffer = (char*)xrect;
196     } else
197       return FALSE;
198   }
199   else if ((rect->left >= rect->right) ||
200            (rect->top >= rect->bottom) ||
201             !EXTENTCHECK(rect, &rgnSrc->rdh.rcBound))
202   {
203         goto empty;
204   }
205   else // region box and clipping rect appear to intersect
206   {
207     PRECT lpr, rpr;
208     INT i, j, clipa, clipb;
209     INT left = rgnSrc->rdh.rcBound.right + off->x;
210     INT right = rgnSrc->rdh.rcBound.left + off->x;
211
212     for(clipa = 0; ((PRECT)rgnSrc->Buffer + clipa)->bottom <= rect->top; clipa++)
213         //region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount
214       ; // skip bands above the clipping rectangle
215
216     for(clipb = clipa; clipb < rgnSrc->rdh.nCount; clipb++)
217       if(((PRECT)rgnSrc->Buffer + clipb)->top >= rect->bottom)
218         break;    // and below it
219
220     // clipa - index of the first rect in the first intersecting band
221     // clipb - index of the last rect in the last intersecting band
222
223     if((rgnDst != rgnSrc) && (rgnDst->rdh.nCount < (i = (clipb - clipa))))
224     {
225           PCHAR temp;
226           temp = ExAllocatePool( PagedPool, i * sizeof(RECT) );
227       if(!temp)
228               return FALSE;
229
230           if( rgnDst->Buffer )
231                 ExFreePool( rgnDst->Buffer ); //free the old buffer
232       (PRECT)rgnDst->Buffer = temp;
233       rgnDst->rdh.nCount = i;
234           rgnDst->rdh.nRgnSize = i * sizeof(RECT);
235     }
236
237     for(i = clipa, j = 0; i < clipb ; i++)
238     {
239       // i - src index, j - dst index, j is always <= i for obvious reasons
240
241       lpr = (PRECT)rgnSrc->Buffer + i;
242
243       if(lpr->left < rect->right && lpr->right > rect->left)
244       {
245             rpr = (PRECT)rgnDst->Buffer + j;
246
247         rpr->top = lpr->top + off->y;
248         rpr->bottom = lpr->bottom + off->y;
249         rpr->left = ((lpr->left > rect->left) ? lpr->left : rect->left) + off->x;
250         rpr->right = ((lpr->right < rect->right) ? lpr->right : rect->right) + off->x;
251
252         if(rpr->left < left) left = rpr->left;
253         if(rpr->right > right) right = rpr->right;
254
255         j++;
256       }
257     }
258
259     if(j == 0) goto empty;
260
261     rgnDst->rdh.rcBound.left = left;
262     rgnDst->rdh.rcBound.right = right;
263
264     left = rect->top + off->y;
265     right = rect->bottom + off->y;
266
267     rgnDst->rdh.nCount = j--;
268     for(i = 0; i <= j; i++) // fixup top band
269       if(((PRECT)rgnDst->Buffer + i)->top < left)
270         ((PRECT)rgnDst->Buffer + i)->top = left;
271       else
272         break;
273
274     for(i = j; i >= 0; i--) // fixup bottom band
275       if(((PRECT)rgnDst->Buffer + i)->bottom > right)
276         ((PRECT)rgnDst->Buffer + i)->bottom = right;
277       else
278         break;
279
280     rgnDst->rdh.rcBound.top = ((PRECT)rgnDst->Buffer)->top;
281     rgnDst->rdh.rcBound.bottom = ((PRECT)rgnDst->Buffer + j)->bottom;
282
283     rgnDst->rdh.iType = (j >= 1) ? COMPLEXREGION : SIMPLEREGION;
284   }
285
286   return TRUE;
287
288 empty:
289         if(!rgnDst->Buffer)
290         {
291           rgnDst->Buffer = (char*)ExAllocatePool(PagedPool, RGN_DEFAULT_RECTS * sizeof(RECT));
292           if(rgnDst->Buffer){
293             rgnDst->rdh.nCount = RGN_DEFAULT_RECTS;
294                 rgnDst->rdh.nRgnSize = RGN_DEFAULT_RECTS * sizeof(RECT);
295           }
296           else
297             return FALSE;
298         }
299         EMPTY_REGION(rgnDst);
300         return TRUE;
301 }
302
303 /***********************************************************************
304  *           REGION_CropRgn
305  *
306  *
307  * hSrc:        Region to crop and offset.
308  * lpRect:      Clipping rectangle. Can be NULL (no clipping).
309  * lpPt:        Points to offset the cropped region. Can be NULL (no offset).
310  *
311  * hDst: Region to hold the result (a new region is created if it's 0).
312  *       Allowed to be the same region as hSrc in which case everything
313  *       will be done in place, with no memory reallocations.
314  *
315  * Returns: hDst if success, 0 otherwise.
316  */
317 HRGN REGION_CropRgn(HRGN hDst, HRGN hSrc, const PRECT lpRect, PPOINT lpPt)
318 {
319   PROSRGNDATA objSrc = RGNDATA_LockRgn(hSrc);
320   HRGN hNewDst;
321
322   if(objSrc)
323   {
324         PROSRGNDATA rgnDst;
325
326     if(hDst)
327     {
328       if(!(rgnDst = RGNDATA_LockRgn(hDst)))
329       {
330         hDst = 0;
331         goto done;
332       }
333     }
334         else{
335           if( !( hNewDst = RGNDATA_AllocRgn(1) ) ){
336                 RGNDATA_UnlockRgn( hSrc );
337                 return 0;
338           }
339
340       if(!(rgnDst = RGNDATA_LockRgn(hNewDst)))
341       {
342         RGNDATA_FreeRgn( hNewDst );
343                 RGNDATA_UnlockRgn( hSrc );
344         return 0;
345       }
346         }
347
348     if(rgnDst)
349     {
350       POINT pt = { 0, 0 };
351
352           if(!lpPt)
353                 lpPt = &pt;
354
355       if(REGION_CropAndOffsetRegion(lpPt, lpRect, objSrc, rgnDst) == FALSE)
356           { // ve failed cleanup and return
357                 RGNDATA_UnlockRgn( hSrc );
358
359                 if(hDst) // unlock new region if allocated
360                   RGNDATA_UnlockRgn( hDst );
361                 else
362                   RGNDATA_UnlockRgn( hNewDst );
363
364                 return 0;
365       }
366       else{ // ve are fine. unlock the correct pointer and return correct handle
367                 RGNDATA_UnlockRgn( hSrc );
368
369                 if(hDst == 0){
370                         RGNDATA_UnlockRgn( hNewDst );
371                         return hNewDst;
372                 }
373                 else {
374                         RGNDATA_UnlockRgn( hDst );
375                         return hDst;
376                 }
377           }
378     }
379 done:
380         RGNDATA_UnlockRgn( hSrc );
381   }
382   return 0;
383 }
384
385 /***********************************************************************
386  *           REGION_Coalesce
387  *
388  *      Attempt to merge the rects in the current band with those in the
389  *      previous one. Used only by REGION_RegionOp.
390  *
391  * Results:
392  *      The new index for the previous band.
393  *
394  * Side Effects:
395  *      If coalescing takes place:
396  *          - rectangles in the previous band will have their bottom fields
397  *            altered.
398  *          - pReg->numRects will be decreased.
399  *
400  */
401 static INT REGION_Coalesce (
402              PROSRGNDATA pReg, /* Region to coalesce */
403              INT prevStart,  /* Index of start of previous band */
404              INT curStart    /* Index of start of current band */
405 ) {
406     RECT *pPrevRect;          /* Current rect in previous band */
407     RECT *pCurRect;           /* Current rect in current band */
408     RECT *pRegEnd;            /* End of region */
409     INT curNumRects;          /* Number of rectangles in current band */
410     INT prevNumRects;         /* Number of rectangles in previous band */
411     INT bandtop;               /* top coordinate for current band */
412
413     pRegEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount;
414     pPrevRect = (PRECT)pReg->Buffer + prevStart;
415     prevNumRects = curStart - prevStart;
416
417     /*
418      * Figure out how many rectangles are in the current band. Have to do
419      * this because multiple bands could have been added in REGION_RegionOp
420      * at the end when one region has been exhausted.
421      */
422     pCurRect = (PRECT)pReg->Buffer + curStart;
423     bandtop = pCurRect->top;
424     for (curNumRects = 0;
425          (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
426          curNumRects++)
427     {
428                 pCurRect++;
429     }
430
431     if (pCurRect != pRegEnd)
432     {
433                 /*
434                  * If more than one band was added, we have to find the start
435                  * of the last band added so the next coalescing job can start
436                  * at the right place... (given when multiple bands are added,
437                  * this may be pointless -- see above).
438                  */
439                 pRegEnd--;
440                 while ((pRegEnd-1)->top == pRegEnd->top)
441                 {
442                     pRegEnd--;
443                 }
444                 curStart = pRegEnd - (PRECT)pReg->Buffer;
445                 pRegEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount;
446     }
447
448     if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
449                 pCurRect -= curNumRects;
450                 /*
451                  * The bands may only be coalesced if the bottom of the previous
452                  * matches the top scanline of the current.
453                  */
454                 if (pPrevRect->bottom == pCurRect->top)
455                 {
456                     /*
457                      * Make sure the bands have rects in the same places. This
458                      * assumes that rects have been added in such a way that they
459                      * cover the most area possible. I.e. two rects in a band must
460                      * have some horizontal space between them.
461                      */
462                     do
463                     {
464                                 if ((pPrevRect->left != pCurRect->left) ||
465                                     (pPrevRect->right != pCurRect->right))
466                                 {
467                                     /*
468                                      * The bands don't line up so they can't be coalesced.
469                                      */
470                                     return (curStart);
471                                 }
472                                 pPrevRect++;
473                                 pCurRect++;
474                                 prevNumRects -= 1;
475                     } while (prevNumRects != 0);
476
477                     pReg->rdh.nCount -= curNumRects;
478                     pCurRect -= curNumRects;
479                     pPrevRect -= curNumRects;
480
481                     /*
482                      * The bands may be merged, so set the bottom of each rect
483                      * in the previous band to that of the corresponding rect in
484                      * the current band.
485                      */
486                     do
487                     {
488                                 pPrevRect->bottom = pCurRect->bottom;
489                                 pPrevRect++;
490                                 pCurRect++;
491                                 curNumRects -= 1;
492                     } while (curNumRects != 0);
493
494                     /*
495                      * If only one band was added to the region, we have to backup
496                      * curStart to the start of the previous band.
497                      *
498                      * If more than one band was added to the region, copy the
499                      * other bands down. The assumption here is that the other bands
500                      * came from the same region as the current one and no further
501                      * coalescing can be done on them since it's all been done
502                      * already... curStart is already in the right place.
503                      */
504                     if (pCurRect == pRegEnd)
505                     {
506                                 curStart = prevStart;
507                     }
508                     else
509                     {
510                                 do
511                                 {
512                                     *pPrevRect++ = *pCurRect++;
513                                 } while (pCurRect != pRegEnd);
514                     }
515                 }
516     }
517     return (curStart);
518 }
519
520 /***********************************************************************
521  *           REGION_RegionOp
522  *
523  *      Apply an operation to two regions. Called by REGION_Union,
524  *      REGION_Inverse, REGION_Subtract, REGION_Intersect...
525  *
526  * Results:
527  *      None.
528  *
529  * Side Effects:
530  *      The new region is overwritten.
531  *
532  * Notes:
533  *      The idea behind this function is to view the two regions as sets.
534  *      Together they cover a rectangle of area that this function divides
535  *      into horizontal bands where points are covered only by one region
536  *      or by both. For the first case, the nonOverlapFunc is called with
537  *      each the band and the band's upper and lower extents. For the
538  *      second, the overlapFunc is called to process the entire band. It
539  *      is responsible for clipping the rectangles in the band, though
540  *      this function provides the boundaries.
541  *      At the end of each band, the new region is coalesced, if possible,
542  *      to reduce the number of rectangles in the region.
543  *
544  */
545 static void REGION_RegionOp(
546             ROSRGNDATA *newReg, /* Place to store result */
547             ROSRGNDATA *reg1,   /* First region in operation */
548         ROSRGNDATA *reg2,   /* 2nd region in operation */
549             void (*overlapFunc)(),     /* Function to call for over-lapping bands */
550             void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
551             void (*nonOverlap2Func)()  /* Function to call for non-overlapping bands in region 2 */
552 ) {
553     RECT *r1;                         /* Pointer into first region */
554     RECT *r2;                         /* Pointer into 2d region */
555     RECT *r1End;                      /* End of 1st region */
556     RECT *r2End;                      /* End of 2d region */
557     INT ybot;                         /* Bottom of intersection */
558     INT ytop;                         /* Top of intersection */
559     RECT *oldRects;                   /* Old rects for newReg */
560     INT prevBand;                     /* Index of start of
561                                                  * previous band in newReg */
562     INT curBand;                      /* Index of start of current
563                                                  * band in newReg */
564     RECT *r1BandEnd;                  /* End of current band in r1 */
565     RECT *r2BandEnd;                  /* End of current band in r2 */
566     INT top;                          /* Top of non-overlapping band */
567     INT bot;                          /* Bottom of non-overlapping band */
568
569     /*
570      * Initialization:
571      *  set r1, r2, r1End and r2End appropriately, preserve the important
572      * parts of the destination region until the end in case it's one of
573      * the two source regions, then mark the "new" region empty, allocating
574      * another array of rectangles for it to use.
575      */
576     r1 = (PRECT)reg1->Buffer;
577     r2 = (PRECT)reg2->Buffer;
578     r1End = r1 + reg1->rdh.nCount;
579     r2End = r2 + reg2->rdh.nCount;
580
581
582     /*
583      * newReg may be one of the src regions so we can't empty it. We keep a
584      * note of its rects pointer (so that we can free them later), preserve its
585      * extents and simply set numRects to zero.
586      */
587
588     oldRects = (PRECT)newReg->Buffer;
589     newReg->rdh.nCount = 0;
590
591     /*
592      * Allocate a reasonable number of rectangles for the new region. The idea
593      * is to allocate enough so the individual functions don't need to
594      * reallocate and copy the array, which is time consuming, yet we don't
595      * have to worry about using too much memory. I hope to be able to
596      * nuke the Xrealloc() at the end of this function eventually.
597      */
598     newReg->rdh.nRgnSize = max(reg1->rdh.nCount,reg2->rdh.nCount) * 2 * sizeof(RECT);
599
600     if (! (newReg->Buffer = ExAllocatePool( PagedPool, newReg->rdh.nRgnSize )))
601     {
602                 newReg->rdh.nRgnSize = 0;
603                 return;
604     }
605
606     /*
607      * Initialize ybot and ytop.
608      * In the upcoming loop, ybot and ytop serve different functions depending
609      * on whether the band being handled is an overlapping or non-overlapping
610      * band.
611      *  In the case of a non-overlapping band (only one of the regions
612      * has points in the band), ybot is the bottom of the most recent
613      * intersection and thus clips the top of the rectangles in that band.
614      * ytop is the top of the next intersection between the two regions and
615      * serves to clip the bottom of the rectangles in the current band.
616      *  For an overlapping band (where the two regions intersect), ytop clips
617      * the top of the rectangles of both regions and ybot clips the bottoms.
618      */
619     if (reg1->rdh.rcBound.top < reg2->rdh.rcBound.top)
620                 ybot = reg1->rdh.rcBound.top;
621     else
622                 ybot = reg2->rdh.rcBound.top;
623
624     /*
625      * prevBand serves to mark the start of the previous band so rectangles
626      * can be coalesced into larger rectangles. qv. miCoalesce, above.
627      * In the beginning, there is no previous band, so prevBand == curBand
628      * (curBand is set later on, of course, but the first band will always
629      * start at index 0). prevBand and curBand must be indices because of
630      * the possible expansion, and resultant moving, of the new region's
631      * array of rectangles.
632      */
633     prevBand = 0;
634
635     do
636     {
637                 curBand = newReg->rdh.nCount;
638
639                 /*
640                  * This algorithm proceeds one source-band (as opposed to a
641                  * destination band, which is determined by where the two regions
642                  * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
643                  * rectangle after the last one in the current band for their
644                  * respective regions.
645                  */
646                 r1BandEnd = r1;
647                 while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
648                 {
649                     r1BandEnd++;
650                 }
651
652                 r2BandEnd = r2;
653                 while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
654                 {
655                     r2BandEnd++;
656                 }
657
658                 /*
659                  * First handle the band that doesn't intersect, if any.
660                  *
661                  * Note that attention is restricted to one band in the
662                  * non-intersecting region at once, so if a region has n
663                  * bands between the current position and the next place it overlaps
664                  * the other, this entire loop will be passed through n times.
665                  */
666                 if (r1->top < r2->top)
667                 {
668                     top = max(r1->top,ybot);
669                     bot = min(r1->bottom,r2->top);
670
671                     if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
672                     {
673                                 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
674                     }
675
676                     ytop = r2->top;
677                 }
678                 else if (r2->top < r1->top)
679                 {
680                     top = max(r2->top,ybot);
681                     bot = min(r2->bottom,r1->top);
682
683                     if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
684                     {
685                                 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
686                     }
687
688                     ytop = r1->top;
689                 }
690                 else
691                 {
692                     ytop = r1->top;
693                 }
694
695                 /*
696                  * If any rectangles got added to the region, try and coalesce them
697                  * with rectangles from the previous band. Note we could just do
698                  * this test in miCoalesce, but some machines incur a not
699                  * inconsiderable cost for function calls, so...
700                  */
701                 if (newReg->rdh.nCount != curBand)
702                 {
703                     prevBand = REGION_Coalesce (newReg, prevBand, curBand);
704                 }
705
706                 /*
707                  * Now see if we've hit an intersecting band. The two bands only
708                  * intersect if ybot > ytop
709                  */
710                 ybot = min(r1->bottom, r2->bottom);
711                 curBand = newReg->rdh.nCount;
712                 if (ybot > ytop)
713                 {
714                     (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
715                 }
716
717                 if (newReg->rdh.nCount != curBand)
718                 {
719                     prevBand = REGION_Coalesce (newReg, prevBand, curBand);
720                 }
721
722                 /*
723                  * If we've finished with a band (bottom == ybot) we skip forward
724                  * in the region to the next band.
725                  */
726                 if (r1->bottom == ybot)
727                 {
728                     r1 = r1BandEnd;
729                 }
730                 if (r2->bottom == ybot)
731                 {
732                     r2 = r2BandEnd;
733                 }
734     } while ((r1 != r1End) && (r2 != r2End));
735
736     /*
737      * Deal with whichever region still has rectangles left.
738      */
739     curBand = newReg->rdh.nCount;
740     if (r1 != r1End)
741     {
742                 if (nonOverlap1Func != (void (*)())NULL)
743                 {
744                     do
745                     {
746                                 r1BandEnd = r1;
747                                 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
748                                 {
749                                     r1BandEnd++;
750                                 }
751                                 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
752                                                      max(r1->top,ybot), r1->bottom);
753                                 r1 = r1BandEnd;
754                     } while (r1 != r1End);
755                 }
756     }
757     else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
758     {
759                 do
760                 {
761                     r2BandEnd = r2;
762                     while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
763                     {
764                          r2BandEnd++;
765                     }
766                     (* nonOverlap2Func) (newReg, r2, r2BandEnd,
767                                         max(r2->top,ybot), r2->bottom);
768                     r2 = r2BandEnd;
769                 } while (r2 != r2End);
770     }
771
772     if (newReg->rdh.nCount != curBand)
773     {
774                 (void) REGION_Coalesce (newReg, prevBand, curBand);
775     }
776
777     /*
778      * A bit of cleanup. To keep regions from growing without bound,
779      * we shrink the array of rectangles to match the new number of
780      * rectangles in the region. This never goes to 0, however...
781      *
782      * Only do this stuff if the number of rectangles allocated is more than
783      * twice the number of rectangles in the region (a simple optimization...).
784      */
785     if ((newReg->rdh.nCount*sizeof(RECT) < 2*newReg->rdh.nRgnSize && (newReg->rdh.nCount > 2)))
786     {
787                 if (REGION_NOT_EMPTY(newReg))
788                 {
789                     RECT *prev_rects = (PRECT)newReg->Buffer;
790                     newReg->Buffer = ExAllocatePool( PagedPool, newReg->rdh.nCount*sizeof(RECT) );
791
792                     if (! newReg->Buffer)
793                                 newReg->Buffer = (char*)prev_rects;
794                         else{
795                                 newReg->rdh.nRgnSize = newReg->rdh.nCount*sizeof(RECT);
796                                 RtlCopyMemory( newReg->Buffer, prev_rects, newReg->rdh.nRgnSize );
797                                 ExFreePool( prev_rects );
798                         }
799                 }
800                 else
801                 {
802                     /*
803                      * No point in doing the extra work involved in an Xrealloc if
804                      * the region is empty
805                      */
806                     newReg->rdh.nRgnSize = sizeof(RECT);
807                     ExFreePool( newReg->Buffer );
808                     newReg->Buffer = ExAllocatePool( PagedPool, sizeof(RECT) );
809                         ASSERT( newReg->Buffer );
810                 }
811     }
812
813         if( newReg->rdh.nCount == 0 )
814                 newReg->rdh.iType = NULLREGION;
815         else
816                 newReg->rdh.iType = (newReg->rdh.nCount > 1)? COMPLEXREGION : SIMPLEREGION;
817
818         ExFreePool( oldRects );
819     return;
820 }
821
822 /***********************************************************************
823  *          Region Intersection
824  ***********************************************************************/
825
826
827 /***********************************************************************
828  *           REGION_IntersectO
829  *
830  * Handle an overlapping band for REGION_Intersect.
831  *
832  * Results:
833  *      None.
834  *
835  * Side Effects:
836  *      Rectangles may be added to the region.
837  *
838  */
839 static void REGION_IntersectO(ROSRGNDATA *pReg,  RECT *r1, RECT *r1End,
840                 RECT *r2, RECT *r2End, INT top, INT bottom)
841
842 {
843     INT       left, right;
844     RECT      *pNextRect;
845
846     pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
847
848     while ((r1 != r1End) && (r2 != r2End))
849     {
850                 left = max(r1->left, r2->left);
851                 right = min(r1->right, r2->right);
852
853                 /*
854                  * If there's any overlap between the two rectangles, add that
855                  * overlap to the new region.
856                  * There's no need to check for subsumption because the only way
857                  * such a need could arise is if some region has two rectangles
858                  * right next to each other. Since that should never happen...
859                  */
860                 if (left < right)
861                 {
862                     MEMCHECK(pReg, pNextRect, pReg->Buffer);
863                     pNextRect->left = left;
864                     pNextRect->top = top;
865                     pNextRect->right = right;
866                     pNextRect->bottom = bottom;
867                     pReg->rdh.nCount += 1;
868                     pNextRect++;
869                 }
870
871                 /*
872                  * Need to advance the pointers. Shift the one that extends
873                  * to the right the least, since the other still has a chance to
874                  * overlap with that region's next rectangle, if you see what I mean.
875                  */
876                 if (r1->right < r2->right)
877                 {
878                     r1++;
879                 }
880                 else if (r2->right < r1->right)
881                 {
882                     r2++;
883                 }
884                 else
885                 {
886                     r1++;
887                     r2++;
888                 }
889     }
890     return;
891 }
892
893 /***********************************************************************
894  *           REGION_IntersectRegion
895  */
896 static void REGION_IntersectRegion(ROSRGNDATA *newReg, ROSRGNDATA *reg1,
897                                    ROSRGNDATA *reg2)
898 {
899    /* check for trivial reject */
900     if ( (!(reg1->rdh.nCount)) || (!(reg2->rdh.nCount))  ||
901                 (!EXTENTCHECK(&reg1->rdh.rcBound, &reg2->rdh.rcBound)))
902                 newReg->rdh.nCount = 0;
903     else
904                 REGION_RegionOp (newReg, reg1, reg2,
905                         (voidProcp) REGION_IntersectO, (voidProcp) NULL, (voidProcp) NULL);
906
907     /*
908      * Can't alter newReg's extents before we call miRegionOp because
909      * it might be one of the source regions and miRegionOp depends
910      * on the extents of those regions being the same. Besides, this
911      * way there's no checking against rectangles that will be nuked
912      * due to coalescing, so we have to examine fewer rectangles.
913      */
914
915     REGION_SetExtents(newReg);
916 }
917
918 /***********************************************************************
919  *           Region Union
920  ***********************************************************************/
921
922 /***********************************************************************
923  *           REGION_UnionNonO
924  *
925  *      Handle a non-overlapping band for the union operation. Just
926  *      Adds the rectangles into the region. Doesn't have to check for
927  *      subsumption or anything.
928  *
929  * Results:
930  *      None.
931  *
932  * Side Effects:
933  *      pReg->numRects is incremented and the final rectangles overwritten
934  *      with the rectangles we're passed.
935  *
936  */
937 static void REGION_UnionNonO (ROSRGNDATA *pReg, RECT *r, RECT *rEnd,
938                               INT top, INT bottom)
939 {
940     RECT *pNextRect;
941
942     pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
943
944     while (r != rEnd)
945     {
946                 MEMCHECK(pReg, pNextRect, pReg->Buffer);
947                 pNextRect->left = r->left;
948                 pNextRect->top = top;
949                 pNextRect->right = r->right;
950                 pNextRect->bottom = bottom;
951                 pReg->rdh.nCount += 1;
952                 pNextRect++;
953                 r++;
954     }
955     return;
956 }
957
958 /***********************************************************************
959  *           REGION_UnionO
960  *
961  *      Handle an overlapping band for the union operation. Picks the
962  *      left-most rectangle each time and merges it into the region.
963  *
964  * Results:
965  *      None.
966  *
967  * Side Effects:
968  *      Rectangles are overwritten in pReg->rects and pReg->numRects will
969  *      be changed.
970  *
971  */
972 static void REGION_UnionO (ROSRGNDATA *pReg, RECT *r1, RECT *r1End,
973                            RECT *r2, RECT *r2End, INT top, INT bottom)
974 {
975     RECT *pNextRect;
976
977     pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
978
979 #define MERGERECT(r) \
980     if ((pReg->rdh.nCount != 0) &&  \
981                 ((pNextRect-1)->top == top) &&  \
982                 ((pNextRect-1)->bottom == bottom) &&  \
983                 ((pNextRect-1)->right >= r->left))  \
984     {  \
985                 if ((pNextRect-1)->right < r->right)  \
986                 {  \
987                     (pNextRect-1)->right = r->right;  \
988                 }  \
989     }  \
990     else  \
991     {  \
992                 MEMCHECK(pReg, pNextRect, pReg->Buffer);  \
993                 pNextRect->top = top;  \
994                 pNextRect->bottom = bottom;  \
995                 pNextRect->left = r->left;  \
996                 pNextRect->right = r->right;  \
997                 pReg->rdh.nCount += 1;  \
998                 pNextRect += 1;  \
999     }  \
1000     r++;
1001
1002     while ((r1 != r1End) && (r2 != r2End))
1003     {
1004                 if (r1->left < r2->left)
1005                 {
1006                     MERGERECT(r1);
1007                 }
1008                 else
1009                 {
1010                     MERGERECT(r2);
1011                 }
1012     }
1013
1014     if (r1 != r1End)
1015     {
1016                 do
1017                 {
1018                     MERGERECT(r1);
1019                 } while (r1 != r1End);
1020     }
1021     else while (r2 != r2End)
1022     {
1023                 MERGERECT(r2);
1024     }
1025     return;
1026 }
1027
1028 /***********************************************************************
1029  *           REGION_UnionRegion
1030  */
1031 static void REGION_UnionRegion(ROSRGNDATA *newReg, ROSRGNDATA *reg1,
1032                                ROSRGNDATA *reg2)
1033 {
1034     /*  checks all the simple cases */
1035
1036     /*
1037      * Region 1 and 2 are the same or region 1 is empty
1038      */
1039     if ( (reg1 == reg2) || (!(reg1->rdh.nCount)) )
1040     {
1041                 if (newReg != reg2)
1042                     REGION_CopyRegion(newReg, reg2);
1043                 return;
1044     }
1045
1046     /*
1047      * if nothing to union (region 2 empty)
1048      */
1049     if (!(reg2->rdh.nCount))
1050     {
1051                 if (newReg != reg1)
1052                     REGION_CopyRegion(newReg, reg1);
1053                 return;
1054     }
1055
1056     /*
1057      * Region 1 completely subsumes region 2
1058      */
1059     if ((reg1->rdh.nCount == 1) &&
1060                 (reg1->rdh.rcBound.left <= reg2->rdh.rcBound.left) &&
1061                 (reg1->rdh.rcBound.top <= reg2->rdh.rcBound.top) &&
1062                 (reg1->rdh.rcBound.right >= reg2->rdh.rcBound.right) &&
1063                 (reg1->rdh.rcBound.bottom >= reg2->rdh.rcBound.bottom))
1064     {
1065                 if (newReg != reg1)
1066                     REGION_CopyRegion(newReg, reg1);
1067                 return;
1068     }
1069
1070     /*
1071      * Region 2 completely subsumes region 1
1072      */
1073     if ((reg2->rdh.nCount == 1) &&
1074                 (reg2->rdh.rcBound.left <= reg1->rdh.rcBound.left) &&
1075                 (reg2->rdh.rcBound.top <= reg1->rdh.rcBound.top) &&
1076                 (reg2->rdh.rcBound.right >= reg1->rdh.rcBound.right) &&
1077                 (reg2->rdh.rcBound.bottom >= reg1->rdh.rcBound.bottom))
1078     {
1079                 if (newReg != reg2)
1080                     REGION_CopyRegion(newReg, reg2);
1081                 return;
1082     }
1083
1084     REGION_RegionOp (newReg, reg1, reg2, (voidProcp) REGION_UnionO,
1085                 (voidProcp) REGION_UnionNonO, (voidProcp) REGION_UnionNonO);
1086     newReg->rdh.rcBound.left = min(reg1->rdh.rcBound.left, reg2->rdh.rcBound.left);
1087     newReg->rdh.rcBound.top = min(reg1->rdh.rcBound.top, reg2->rdh.rcBound.top);
1088     newReg->rdh.rcBound.right = max(reg1->rdh.rcBound.right, reg2->rdh.rcBound.right);
1089     newReg->rdh.rcBound.bottom = max(reg1->rdh.rcBound.bottom, reg2->rdh.rcBound.bottom);
1090 }
1091
1092 /***********************************************************************
1093  *           Region Subtraction
1094  ***********************************************************************/
1095
1096 /***********************************************************************
1097  *           REGION_SubtractNonO1
1098  *
1099  *      Deal with non-overlapping band for subtraction. Any parts from
1100  *      region 2 we discard. Anything from region 1 we add to the region.
1101  *
1102  * Results:
1103  *      None.
1104  *
1105  * Side Effects:
1106  *      pReg may be affected.
1107  *
1108  */
1109 static void REGION_SubtractNonO1 (ROSRGNDATA *pReg, RECT *r, RECT *rEnd,
1110                 INT top, INT bottom)
1111 {
1112     RECT *pNextRect;
1113
1114     pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
1115
1116     while (r != rEnd)
1117     {
1118                 MEMCHECK(pReg, pNextRect, pReg->Buffer);
1119                 pNextRect->left = r->left;
1120                 pNextRect->top = top;
1121                 pNextRect->right = r->right;
1122                 pNextRect->bottom = bottom;
1123                 pReg->rdh.nCount += 1;
1124                 pNextRect++;
1125                 r++;
1126     }
1127     return;
1128 }
1129
1130
1131 /***********************************************************************
1132  *           REGION_SubtractO
1133  *
1134  *      Overlapping band subtraction. x1 is the left-most point not yet
1135  *      checked.
1136  *
1137  * Results:
1138  *      None.
1139  *
1140  * Side Effects:
1141  *      pReg may have rectangles added to it.
1142  *
1143  */
1144 static void REGION_SubtractO (ROSRGNDATA *pReg, RECT *r1, RECT *r1End,
1145                 RECT *r2, RECT *r2End, INT top, INT bottom)
1146 {
1147     RECT *pNextRect;
1148     INT left;
1149
1150     left = r1->left;
1151     pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
1152
1153     while ((r1 != r1End) && (r2 != r2End))
1154     {
1155                 if (r2->right <= left)
1156                 {
1157                     /*
1158                      * Subtrahend missed the boat: go to next subtrahend.
1159                      */
1160                     r2++;
1161                 }
1162                 else if (r2->left <= left)
1163                 {
1164                     /*
1165                      * Subtrahend preceeds minuend: nuke left edge of minuend.
1166                      */
1167                     left = r2->right;
1168                     if (left >= r1->right)
1169                     {
1170                         /*
1171                          * Minuend completely covered: advance to next minuend and
1172                          * reset left fence to edge of new minuend.
1173                          */
1174                         r1++;
1175                         if (r1 != r1End)
1176                             left = r1->left;
1177                     }
1178                     else
1179                     {
1180                         /*
1181                          * Subtrahend now used up since it doesn't extend beyond
1182                          * minuend
1183                          */
1184                         r2++;
1185                     }
1186                 }
1187                 else if (r2->left < r1->right)
1188                 {
1189                     /*
1190                      * Left part of subtrahend covers part of minuend: add uncovered
1191                      * part of minuend to region and skip to next subtrahend.
1192                      */
1193                     MEMCHECK(pReg, pNextRect, pReg->Buffer);
1194                     pNextRect->left = left;
1195                     pNextRect->top = top;
1196                     pNextRect->right = r2->left;
1197                     pNextRect->bottom = bottom;
1198                     pReg->rdh.nCount += 1;
1199                     pNextRect++;
1200                     left = r2->right;
1201                     if (left >= r1->right)
1202                     {
1203                         /*
1204                          * Minuend used up: advance to new...
1205                          */
1206                         r1++;
1207                         if (r1 != r1End)
1208                             left = r1->left;
1209                     }
1210                     else
1211                     {
1212                         /*
1213                          * Subtrahend used up
1214                          */
1215                         r2++;
1216                     }
1217                 }
1218                 else
1219                 {
1220                     /*
1221                      * Minuend used up: add any remaining piece before advancing.
1222                      */
1223                     if (r1->right > left)
1224                     {
1225                                 MEMCHECK(pReg, pNextRect, pReg->Buffer);
1226                                 pNextRect->left = left;
1227                                 pNextRect->top = top;
1228                                 pNextRect->right = r1->right;
1229                                 pNextRect->bottom = bottom;
1230                                 pReg->rdh.nCount += 1;
1231                                 pNextRect++;
1232                     }
1233                     r1++;
1234                     left = r1->left;
1235                 }
1236     }
1237
1238     /*
1239      * Add remaining minuend rectangles to region.
1240      */
1241     while (r1 != r1End)
1242     {
1243                 MEMCHECK(pReg, pNextRect, pReg->Buffer);
1244                 pNextRect->left = left;
1245                 pNextRect->top = top;
1246                 pNextRect->right = r1->right;
1247                 pNextRect->bottom = bottom;
1248                 pReg->rdh.nCount += 1;
1249                 pNextRect++;
1250                 r1++;
1251                 if (r1 != r1End)
1252                 {
1253                     left = r1->left;
1254                 }
1255     }
1256     return;
1257 }
1258
1259 /***********************************************************************
1260  *           REGION_SubtractRegion
1261  *
1262  *      Subtract regS from regM and leave the result in regD.
1263  *      S stands for subtrahend, M for minuend and D for difference.
1264  *
1265  * Results:
1266  *      TRUE.
1267  *
1268  * Side Effects:
1269  *      regD is overwritten.
1270  *
1271  */
1272 static void REGION_SubtractRegion(ROSRGNDATA *regD, ROSRGNDATA *regM,
1273                                                        ROSRGNDATA *regS )
1274 {
1275    /* check for trivial reject */
1276     if ( (!(regM->rdh.nCount)) || (!(regS->rdh.nCount))  ||
1277                 (!EXTENTCHECK(&regM->rdh.rcBound, &regS->rdh.rcBound)) )
1278     {
1279                 REGION_CopyRegion(regD, regM);
1280                 return;
1281     }
1282
1283     REGION_RegionOp (regD, regM, regS, (voidProcp) REGION_SubtractO,
1284                 (voidProcp) REGION_SubtractNonO1, (voidProcp) NULL);
1285
1286     /*
1287      * Can't alter newReg's extents before we call miRegionOp because
1288      * it might be one of the source regions and miRegionOp depends
1289      * on the extents of those regions being the unaltered. Besides, this
1290      * way there's no checking against rectangles that will be nuked
1291      * due to coalescing, so we have to examine fewer rectangles.
1292      */
1293     REGION_SetExtents (regD);
1294 }
1295
1296 /***********************************************************************
1297  *           REGION_XorRegion
1298  */
1299 static void REGION_XorRegion(ROSRGNDATA *dr, ROSRGNDATA *sra,
1300                                                         ROSRGNDATA *srb)
1301 {
1302         HRGN htra, htrb;
1303     ROSRGNDATA *tra, *trb;
1304
1305     if ((! (htra = RGNDATA_AllocRgn(sra->rdh.nCount + 1))) ||
1306                 (! (htrb = RGNDATA_AllocRgn(srb->rdh.nCount + 1))))
1307         return;
1308         tra = RGNDATA_LockRgn( htra );
1309         if( !tra ){
1310                 W32kDeleteObject( htra );
1311                 W32kDeleteObject( htrb );
1312                 return;
1313         }
1314
1315         trb = RGNDATA_LockRgn( htrb );
1316         if( !trb ){
1317                 RGNDATA_UnlockRgn( htra );
1318                 W32kDeleteObject( htra );
1319                 W32kDeleteObject( htrb );
1320                 return;
1321         }
1322
1323     REGION_SubtractRegion(tra,sra,srb);
1324     REGION_SubtractRegion(trb,srb,sra);
1325     REGION_UnionRegion(dr,tra,trb);
1326         RGNDATA_UnlockRgn( htra );
1327         RGNDATA_UnlockRgn( htrb );
1328
1329     W32kDeleteObject( htra );
1330     W32kDeleteObject( htrb );
1331     return;
1332 }
1333
1334
1335 /***********************************************************************
1336  *           REGION_UnionRectWithRegion
1337  *           Adds a rectangle to a WINEREGION
1338  */
1339 static void REGION_UnionRectWithRegion(const RECT *rect, ROSRGNDATA *rgn)
1340 {
1341     ROSRGNDATA region;
1342
1343     region.Buffer = (char*)(&(region.rdh.rcBound));
1344     region.rdh.nCount = 1;
1345     region.rdh.nRgnSize = sizeof( RECT );
1346     region.rdh.rcBound = *rect;
1347     REGION_UnionRegion(rgn, rgn, &region);
1348 }
1349
1350
1351 BOOL REGION_LPTODP(HDC hdc, HRGN hDest, HRGN hSrc)
1352 {
1353   RECT *pCurRect, *pEndRect;
1354   PROSRGNDATA srcObj = NULL;
1355   PROSRGNDATA destObj = NULL;
1356
1357   DC * dc = DC_HandleToPtr(hdc);
1358   RECT tmpRect;
1359   BOOL ret = FALSE;
1360
1361   if(!dc)
1362     return ret;
1363
1364   if(dc->w.MapMode == MM_TEXT) // Requires only a translation
1365   {
1366     if(W32kCombineRgn(hDest, hSrc, 0, RGN_COPY) == ERROR)
1367           goto done;
1368
1369     W32kOffsetRgn(hDest, dc->vportOrgX - dc->wndOrgX, dc->vportOrgY - dc->wndOrgY);
1370     ret = TRUE;
1371     goto done;
1372   }
1373
1374   if(!( srcObj = (PROSRGNDATA) RGNDATA_LockRgn( hSrc ) ))
1375         goto done;
1376   if(!( destObj = (PROSRGNDATA) RGNDATA_LockRgn( hDest ) ))
1377   {
1378     RGNDATA_UnlockRgn( hSrc );
1379     goto done;
1380   }
1381   EMPTY_REGION(destObj);
1382
1383   pEndRect = (PRECT)srcObj->Buffer + srcObj->rdh.nCount;
1384   for(pCurRect = (PRECT)srcObj->Buffer; pCurRect < pEndRect; pCurRect++)
1385   {
1386     tmpRect = *pCurRect;
1387     tmpRect.left = XLPTODP(dc, tmpRect.left);
1388     tmpRect.top = YLPTODP(dc, tmpRect.top);
1389     tmpRect.right = XLPTODP(dc, tmpRect.right);
1390     tmpRect.bottom = YLPTODP(dc, tmpRect.bottom);
1391
1392     if(tmpRect.left > tmpRect.right)
1393       { INT tmp = tmpRect.left; tmpRect.left = tmpRect.right; tmpRect.right = tmp; }
1394     if(tmpRect.top > tmpRect.bottom)
1395       { INT tmp = tmpRect.top; tmpRect.top = tmpRect.bottom; tmpRect.bottom = tmp; }
1396
1397     REGION_UnionRectWithRegion(&tmpRect, destObj);
1398   }
1399   ret = TRUE;
1400
1401   RGNDATA_UnlockRgn( hSrc );
1402   RGNDATA_UnlockRgn( hDest );
1403
1404 done:
1405   DC_ReleasePtr( hdc );
1406   return ret;
1407 }
1408
1409 HRGN RGNDATA_AllocRgn(INT n)
1410 {
1411   HRGN hReg;
1412   PROSRGNDATA pReg;
1413   BOOL bRet;
1414
1415   if((hReg = (HRGN)GDIOBJ_AllocObj(sizeof(ROSRGNDATA), GO_REGION_MAGIC))){
1416         if( (pReg = GDIOBJ_LockObj( hReg, GO_REGION_MAGIC )) ){
1417
1418       if ((pReg->Buffer = ExAllocatePool(PagedPool, n * sizeof(RECT)))){
1419         EMPTY_REGION(pReg);
1420         pReg->rdh.dwSize = sizeof(RGNDATAHEADER);
1421         pReg->rdh.nCount = n;
1422         pReg->rdh.nRgnSize = n*sizeof(RECT);
1423
1424         bRet = GDIOBJ_UnlockObj( hReg, GO_REGION_MAGIC );
1425         ASSERT(bRet);
1426
1427         return hReg;
1428           }
1429
1430         }
1431         else
1432                 GDIOBJ_FreeObj( hReg, GO_REGION_MAGIC, GDIOBJFLAG_DEFAULT );
1433   }
1434   return NULL;
1435 }
1436
1437 BOOL RGNDATA_InternalDelete( PROSRGNDATA pRgn )
1438 {
1439   ASSERT(pRgn);
1440   if(pRgn->Buffer)
1441     ExFreePool(pRgn->Buffer);
1442   return TRUE;
1443 }
1444
1445 // W32k Exported Functions
1446 INT
1447 STDCALL
1448 W32kCombineRgn(HRGN  hDest,
1449                     HRGN  hSrc1,
1450                     HRGN  hSrc2,
1451                     INT  CombineMode)
1452 {
1453   INT result = ERROR;
1454   PROSRGNDATA destRgn = RGNDATA_LockRgn(hDest);
1455
1456   if( destRgn ){
1457         PROSRGNDATA src1Rgn = RGNDATA_LockRgn(hSrc1);
1458
1459         if( src1Rgn ){
1460                 if (CombineMode == RGN_COPY)
1461                 {
1462                   if( !REGION_CopyRegion(destRgn, src1Rgn) )
1463                                 return ERROR;
1464                   result = destRgn->rdh.iType;
1465                 }
1466                 else
1467                 {
1468                   PROSRGNDATA src2Rgn = RGNDATA_LockRgn(hSrc2);
1469                   if( src2Rgn ){
1470                           switch (CombineMode)
1471                           {
1472                             case RGN_AND:
1473                               REGION_IntersectRegion(destRgn, src1Rgn, src2Rgn);
1474                               break;
1475                             case RGN_OR:
1476                               REGION_UnionRegion(destRgn, src1Rgn, src2Rgn);
1477                               break;
1478                             case RGN_XOR:
1479                               REGION_XorRegion(destRgn, src1Rgn, src2Rgn);
1480                               break;
1481                             case RGN_DIFF:
1482                               REGION_SubtractRegion(destRgn, src1Rgn, src2Rgn);
1483                               break;
1484                           }
1485                           result = destRgn->rdh.iType;
1486                           RGNDATA_UnlockRgn( hSrc2 );
1487                   }
1488                   RGNDATA_UnlockRgn( hSrc1 );
1489                 }
1490                 RGNDATA_UnlockRgn( hDest );
1491         }
1492         else{
1493                 DPRINT("W32kCombineRgn: hDest unavailable\n");
1494                 return ERROR;
1495         }
1496   }
1497   return result;
1498 }
1499
1500 HRGN
1501 STDCALL
1502 W32kCreateEllipticRgn(INT  LeftRect,
1503                             INT  TopRect,
1504                             INT  RightRect,
1505                             INT  BottomRect)
1506 {
1507   UNIMPLEMENTED;
1508 }
1509
1510 HRGN
1511 STDCALL
1512 W32kCreateEllipticRgnIndirect(CONST PRECT  rc)
1513 {
1514   UNIMPLEMENTED;
1515 }
1516
1517 HRGN
1518 STDCALL
1519 W32kCreatePolygonRgn(CONST PPOINT  pt,
1520                            INT  Count,
1521                            INT  PolyFillMode)
1522 {
1523   UNIMPLEMENTED;
1524 }
1525
1526 HRGN
1527 STDCALL
1528 W32kCreatePolyPolygonRgn(CONST PPOINT  pt,
1529                                CONST PINT  PolyCounts,
1530                                INT  Count,
1531                                INT  PolyFillMode)
1532 {
1533   UNIMPLEMENTED;
1534 }
1535
1536 HRGN
1537 STDCALL
1538 W32kCreateRectRgn(INT  LeftRect,
1539                         INT  TopRect,
1540                         INT  RightRect,
1541                         INT  BottomRect)
1542 {
1543   HRGN hRgn;
1544   PROSRGNDATA pRgnData;
1545   PRECT pRect;
1546
1547   // Allocate region data structure with space for 1 RECT
1548   if( ( hRgn = RGNDATA_AllocRgn(1) ) ){
1549         if( ( pRgnData = RGNDATA_LockRgn( hRgn ) ) ){
1550         pRect = (PRECT)pRgnData->Buffer;
1551         ASSERT(pRect);
1552
1553         // Fill in the region data header
1554         pRgnData->rdh.iType = SIMPLEREGION;
1555         W32kSetRect(&(pRgnData->rdh.rcBound), LeftRect, TopRect, RightRect, BottomRect);
1556
1557         // use W32kCopyRect when implemented
1558         W32kSetRect(pRect, LeftRect, TopRect, RightRect, BottomRect);
1559                 RGNDATA_UnlockRgn( hRgn );
1560
1561         return hRgn;
1562         }
1563         W32kDeleteObject( hRgn );
1564   }
1565   DPRINT("W32kCreateRectRgn: can't allocate region\n");
1566   return NULL;
1567 }
1568
1569 HRGN STDCALL
1570 W32kCreateRectRgnIndirect(CONST PRECT rc)
1571 {
1572   RECT SafeRc;
1573   NTSTATUS Status;
1574
1575   Status = MmCopyFromCaller(&SafeRc, rc, sizeof(RECT));
1576   if (!NT_SUCCESS(Status))
1577     {
1578       return(NULL);
1579     }
1580   return(UnsafeW32kCreateRectRgnIndirect(&SafeRc));
1581 }
1582
1583 HRGN STDCALL
1584 UnsafeW32kCreateRectRgnIndirect(CONST PRECT  rc)
1585 {
1586   return(W32kCreateRectRgn(rc->left, rc->top, rc->right, rc->bottom));
1587 }
1588
1589 HRGN
1590 STDCALL
1591 W32kCreateRoundRectRgn(INT  LeftRect,
1592                              INT  TopRect,
1593                              INT  RightRect,
1594                              INT  BottomRect,
1595                              INT  WidthEllipse,
1596                              INT  HeightEllipse)
1597 {
1598   UNIMPLEMENTED;
1599 }
1600
1601 BOOL
1602 STDCALL
1603 W32kEqualRgn(HRGN  hSrcRgn1,
1604                    HRGN  hSrcRgn2)
1605 {
1606   PROSRGNDATA rgn1, rgn2;
1607   PRECT tRect1, tRect2;
1608   int i;
1609   BOOL bRet = FALSE;
1610
1611   if( !(rgn1 = RGNDATA_LockRgn(hSrcRgn1)))
1612         return ERROR;
1613
1614   if( !(rgn2 = RGNDATA_LockRgn(hSrcRgn2))){
1615         RGNDATA_UnlockRgn( hSrcRgn1 );
1616         return ERROR;
1617   }
1618
1619   if(rgn1->rdh.nCount != rgn2->rdh.nCount ||
1620         rgn1->rdh.nCount == 0 ||
1621         rgn1->rdh.rcBound.left   != rgn2->rdh.rcBound.left ||
1622         rgn1->rdh.rcBound.right  != rgn2->rdh.rcBound.right ||
1623         rgn1->rdh.rcBound.top    != rgn2->rdh.rcBound.top ||
1624         rgn1->rdh.rcBound.bottom != rgn2->rdh.rcBound.bottom)
1625         goto exit;
1626
1627   tRect1 = (PRECT)rgn1->Buffer;
1628   tRect2 = (PRECT)rgn2->Buffer;
1629
1630   if( !tRect1 || !tRect2 )
1631         goto exit;
1632
1633   for(i=0; i < rgn1->rdh.nCount; i++)
1634   {
1635     if(tRect1[i].left   != tRect2[i].left ||
1636         tRect1[i].right  != tRect2[i].right ||
1637         tRect1[i].top    != tRect2[i].top ||
1638         tRect1[i].bottom != tRect2[i].bottom)
1639            goto exit;;
1640   }
1641   bRet = TRUE;
1642
1643 exit:
1644   RGNDATA_UnlockRgn( hSrcRgn1 );
1645   RGNDATA_UnlockRgn( hSrcRgn2 );
1646   return bRet;
1647 }
1648
1649 HRGN
1650 STDCALL
1651 W32kExtCreateRegion(CONST PXFORM  Xform,
1652                           DWORD  Count,
1653                           CONST PROSRGNDATA  RgnData)
1654 {
1655   HRGN hRgn;
1656
1657   // FIXME: Apply Xform transformation to the regional data
1658   if(Xform != NULL) {
1659
1660   }
1661
1662   return hRgn;
1663 }
1664
1665 BOOL
1666 STDCALL
1667 W32kFillRgn(HDC  hDC,
1668                   HRGN  hRgn,
1669                   HBRUSH  hBrush)
1670 {
1671   UNIMPLEMENTED;
1672 }
1673
1674 BOOL
1675 STDCALL
1676 W32kFrameRgn(HDC  hDC,
1677                    HRGN  hRgn,
1678                    HBRUSH  hBrush,
1679                    INT  Width,
1680                    INT  Height)
1681 {
1682   UNIMPLEMENTED;
1683 }
1684
1685 INT STDCALL
1686 UnsafeW32kGetRgnBox(HRGN  hRgn,
1687                     LPRECT  pRect)
1688 {
1689   PROSRGNDATA rgn = RGNDATA_LockRgn(hRgn);
1690   DWORD ret;
1691
1692   if (rgn)
1693     {
1694       *pRect = rgn->rdh.rcBound;
1695       ret = rgn->rdh.iType;
1696       RGNDATA_UnlockRgn( hRgn );
1697
1698       return ret;
1699     }
1700   return 0; //if invalid region return zero
1701 }
1702
1703
1704 INT STDCALL
1705 W32kGetRgnBox(HRGN  hRgn,
1706               LPRECT  pRect)
1707 {
1708   PROSRGNDATA rgn = RGNDATA_LockRgn(hRgn);
1709   DWORD ret;
1710
1711   if (rgn)
1712     {
1713       RECT SafeRect;
1714       SafeRect.left = rgn->rdh.rcBound.left;
1715       SafeRect.top = rgn->rdh.rcBound.top;
1716       SafeRect.right = rgn->rdh.rcBound.right;
1717       SafeRect.bottom = rgn->rdh.rcBound.bottom;
1718       ret = rgn->rdh.iType;
1719       RGNDATA_UnlockRgn( hRgn );
1720
1721       if(!NT_SUCCESS(MmCopyToCaller(pRect, &SafeRect, sizeof(RECT))))
1722         return 0;
1723
1724       return ret;
1725     }
1726   return 0; //if invalid region return zero
1727 }
1728
1729 BOOL
1730 STDCALL
1731 W32kInvertRgn(HDC  hDC,
1732                     HRGN  hRgn)
1733 {
1734   UNIMPLEMENTED;
1735 }
1736
1737 INT
1738 STDCALL
1739 W32kOffsetRgn(HRGN  hRgn,
1740                    INT  XOffset,
1741                    INT  YOffset)
1742 {
1743   PROSRGNDATA rgn = RGNDATA_LockRgn(hRgn);
1744   INT ret;
1745
1746   DPRINT("W32kOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn, XOffset, YOffset, rgn );
1747
1748   if( !rgn ){
1749           DPRINT("W32kOffsetRgn: hRgn error\n");
1750           return ERROR;
1751   }
1752
1753   if(XOffset || YOffset) {
1754     int nbox = rgn->rdh.nCount;
1755         PRECT pbox = (PRECT)rgn->Buffer;
1756
1757     if(nbox && pbox) {
1758       while(nbox--) {
1759         pbox->left += XOffset;
1760         pbox->right += XOffset;
1761         pbox->top += YOffset;
1762         pbox->bottom += YOffset;
1763         pbox++;
1764       }
1765       rgn->rdh.rcBound.left += XOffset;
1766       rgn->rdh.rcBound.right += XOffset;
1767       rgn->rdh.rcBound.top += YOffset;
1768       rgn->rdh.rcBound.bottom += YOffset;
1769     }
1770   }
1771   ret = rgn->rdh.iType;
1772   RGNDATA_UnlockRgn( hRgn );
1773   return ret;
1774 }
1775
1776 BOOL
1777 STDCALL
1778 W32kPaintRgn(HDC  hDC,
1779                    HRGN  hRgn)
1780 {
1781   RECT box;
1782   HRGN tmpVisRgn, prevVisRgn;
1783   DC *dc = DC_HandleToPtr(hDC);
1784   PROSRGNDATA visrgn;
1785   CLIPOBJ* ClipRegion;
1786   BOOL bRet = FALSE;
1787   PBRUSHOBJ pBrush;
1788   POINTL BrushOrigin;
1789   SURFOBJ       *SurfObj;
1790
1791   if( !dc )
1792         return FALSE;
1793
1794   if(!(tmpVisRgn = W32kCreateRectRgn(0, 0, 0, 0))){
1795         DC_ReleasePtr( hDC );
1796         return FALSE;
1797   }
1798
1799 /* ei enable later
1800   // Transform region into device co-ords
1801   if(!REGION_LPTODP(hDC, tmpVisRgn, hRgn) || W32kOffsetRgn(tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY) == ERROR) {
1802     W32kDeleteObject( tmpVisRgn );
1803         DC_ReleasePtr( hDC );
1804     return FALSE;
1805   }
1806 */
1807   /* enable when clipping is implemented
1808   W32kCombineRgn(tmpVisRgn, tmpVisRgn, dc->w.hGCClipRgn, RGN_AND);
1809   */
1810
1811   //visrgn = RGNDATA_LockRgn(tmpVisRgn);
1812   visrgn = RGNDATA_LockRgn(hRgn);
1813
1814   ClipRegion = IntEngCreateClipRegion( visrgn->rdh.nCount, visrgn->Buffer, visrgn->rdh.rcBound );
1815   ASSERT( ClipRegion );
1816   pBrush = BRUSHOBJ_LockBrush(dc->w.hBrush);
1817   ASSERT(pBrush);
1818   BrushOrigin.x = dc->w.brushOrgX;
1819   BrushOrigin.y = dc->w.brushOrgY;
1820   SurfObj = (SURFOBJ*)AccessUserObject(dc->Surface);
1821
1822   bRet = IntEngPaint(SurfObj,
1823          ClipRegion,
1824          pBrush,
1825          &BrushOrigin,
1826          0xFFFF);//don't know what to put here
1827
1828   RGNDATA_UnlockRgn( tmpVisRgn );
1829
1830   // Fill the region
1831   DC_ReleasePtr( hDC );
1832   return TRUE;
1833 }
1834
1835 BOOL
1836 STDCALL
1837 W32kPtInRegion(HRGN  hRgn,
1838                      INT  X,
1839                      INT  Y)
1840 {
1841   PROSRGNDATA rgn;
1842   int i;
1843
1844   if( (rgn = RGNDATA_LockRgn(hRgn) ) )
1845           return FALSE;
1846
1847   if(rgn->rdh.nCount > 0 && INRECT(rgn->rdh.rcBound, X, Y)){
1848     for(i = 0; i < rgn->rdh.nCount; i++) {
1849       if(INRECT(*(PRECT)&rgn->Buffer[i], X, Y)){
1850                 RGNDATA_UnlockRgn(hRgn);
1851                 return TRUE;
1852           }
1853     }
1854   }
1855   RGNDATA_UnlockRgn(hRgn);
1856   return FALSE;
1857 }
1858
1859 BOOL
1860 STDCALL
1861 W32kRectInRegion(HRGN  hRgn,
1862                        CONST LPRECT  unsaferc)
1863 {
1864   PROSRGNDATA rgn;
1865   PRECT pCurRect, pRectEnd;
1866   PRECT rc;
1867   BOOL bRet = FALSE;
1868
1869   if( !NT_SUCCESS( MmCopyFromCaller( rc, unsaferc, sizeof( RECT ) ) ) ){
1870         DPRINT("W32kRectInRegion: bogus rc\n");
1871         return ERROR;
1872   }
1873
1874   if( !( rgn  = RGNDATA_LockRgn(hRgn) ) )
1875         return ERROR;
1876
1877   // this is (just) a useful optimization
1878   if((rgn->rdh.nCount > 0) && EXTENTCHECK(&rgn->rdh.rcBound, rc))
1879   {
1880     for (pCurRect = (PRECT)rgn->Buffer, pRectEnd = pCurRect + rgn->rdh.nCount; pCurRect < pRectEnd; pCurRect++)
1881     {
1882       if (pCurRect->bottom <= rc->top) continue; // not far enough down yet
1883       if (pCurRect->top >= rc->bottom) break;    // too far down
1884       if (pCurRect->right <= rc->left) continue; // not far enough over yet
1885       if (pCurRect->left >= rc->right) continue;
1886       bRet = TRUE;
1887       break;
1888     }
1889   }
1890   RGNDATA_UnlockRgn(hRgn);
1891   return bRet;
1892 }
1893
1894 BOOL
1895 STDCALL
1896 W32kSetRectRgn(HRGN  hRgn,
1897                      INT  LeftRect,
1898                      INT  TopRect,
1899                      INT  RightRect,
1900                      INT  BottomRect)
1901 {
1902   PROSRGNDATA rgn;
1903   PRECT firstRect;
1904
1905
1906
1907   if( !( rgn = RGNDATA_LockRgn(hRgn) ) )
1908           return 0; //per documentation
1909
1910   if (LeftRect > RightRect) { INT tmp = LeftRect; LeftRect = RightRect; RightRect = tmp; }
1911   if (TopRect > BottomRect) { INT tmp = TopRect; TopRect = BottomRect; BottomRect = tmp; }
1912
1913   if((LeftRect != RightRect) && (TopRect != BottomRect))
1914   {
1915     firstRect = (PRECT)rgn->Buffer;
1916         ASSERT( firstRect );
1917         firstRect->left = rgn->rdh.rcBound.left = LeftRect;
1918     firstRect->top = rgn->rdh.rcBound.top = TopRect;
1919     firstRect->right = rgn->rdh.rcBound.right = RightRect;
1920     firstRect->bottom = rgn->rdh.rcBound.bottom = BottomRect;
1921     rgn->rdh.nCount = 1;
1922     rgn->rdh.iType = SIMPLEREGION;
1923   } else
1924     EMPTY_REGION(rgn);
1925
1926   RGNDATA_UnlockRgn( hRgn );
1927   return TRUE;
1928 }
1929
1930 HRGN STDCALL
1931 W32kUnionRectWithRgn(HRGN hDest, const RECT* unsafeRect)
1932 {
1933         PRECT pRect;
1934         PROSRGNDATA pRgn;
1935
1936         if( !NT_SUCCESS( MmCopyFromCaller( pRect, unsafeRect, sizeof( RECT ) ) ) )
1937                 return NULL;
1938
1939         if( !(pRgn = RGNDATA_LockRgn( hDest ) ) )
1940                 return NULL;
1941
1942         REGION_UnionRectWithRegion( pRect, pRgn );
1943         RGNDATA_UnlockRgn( hDest );
1944         return hDest;
1945 }
1946
1947 /***********************************************************************
1948  *           GetRegionData   (GDI32.@)
1949  *
1950  * MSDN: GetRegionData, Return Values:
1951  *
1952  * "If the function succeeds and dwCount specifies an adequate number of bytes,
1953  * the return value is always dwCount. If dwCount is too small or the function
1954  * fails, the return value is 0. If lpRgnData is NULL, the return value is the
1955  * required number of bytes.
1956  *
1957  * If the function fails, the return value is zero."
1958  */
1959 DWORD STDCALL W32kGetRegionData(HRGN hrgn, DWORD count, LPRGNDATA rgndata)
1960 {
1961     DWORD size;
1962     PROSRGNDATA obj = RGNDATA_LockRgn( hrgn );
1963
1964     if(!obj)
1965                 return 0;
1966
1967     size = obj->rdh.nCount * sizeof(RECT);
1968     if(count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
1969     {
1970         RGNDATA_UnlockRgn( hrgn );
1971                 if (rgndata) /* buffer is too small, signal it by return 0 */
1972                     return 0;
1973                 else            /* user requested buffer size with rgndata NULL */
1974                     return size + sizeof(RGNDATAHEADER);
1975     }
1976
1977         //first we copy the header then we copy buffer
1978         if( !NT_SUCCESS( MmCopyToCaller( rgndata, obj, sizeof( RGNDATAHEADER )))){
1979                 RGNDATA_UnlockRgn( hrgn );
1980                 return 0;
1981         }
1982         if( !NT_SUCCESS( MmCopyToCaller( (char*)rgndata+sizeof( RGNDATAHEADER ), obj->Buffer, size ))){
1983                 RGNDATA_UnlockRgn( hrgn );
1984                 return 0;
1985         }
1986
1987     RGNDATA_UnlockRgn( hrgn );
1988     return size + sizeof(RGNDATAHEADER);
1989 }
1990