2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #undef WIN32_LEAN_AND_MEAN
22 #include <ddk/ntddk.h>
23 #include <internal/safe.h>
24 #include <win32k/float.h>
25 #include <win32k/dc.h>
26 #include <win32k/bitmaps.h>
27 #include <win32k/region.h>
28 #include <win32k/cliprgn.h>
29 #include <win32k/brush.h>
30 #include <include/rect.h>
31 #include <include/object.h>
32 #include <include/inteng.h>
33 #include <include/error.h>
36 #include <win32k/debug1.h>
39 IntEngPaint(IN SURFOBJ *Surface,IN CLIPOBJ *ClipRegion,IN BRUSHOBJ *Brush,IN POINTL *BrushOrigin,
44 #define EMPTY_REGION(pReg) { \
45 (pReg)->rdh.nCount = 0; \
46 (pReg)->rdh.rcBound.left = (pReg)->rdh.rcBound.top = 0; \
47 (pReg)->rdh.rcBound.right = (pReg)->rdh.rcBound.bottom = 0; \
48 (pReg)->rdh.iType = NULLREGION; \
51 #define REGION_NOT_EMPTY(pReg) pReg->rdh.nCount
53 #define INRECT(r, x, y) \
54 ( ( ((r).right > x)) && \
55 ( ((r).left <= x)) && \
56 ( ((r).bottom > y)) && \
59 /* 1 if two RECTs overlap.
60 * 0 if two RECTs do not overlap.
62 #define EXTENTCHECK(r1, r2) \
63 ((r1)->right > (r2)->left && \
64 (r1)->left < (r2)->right && \
65 (r1)->bottom > (r2)->top && \
66 (r1)->top < (r2)->bottom)
69 * Check to see if there is enough memory in the present region.
71 static inline int xmemcheck(ROSRGNDATA *reg, LPRECT *rect, LPRECT *firstrect ) {
72 if ( (reg->rdh.nCount+1)*sizeof( RECT ) >= reg->rdh.nRgnSize ) {
74 temp = ExAllocatePool( PagedPool, (2 * (reg->rdh.nRgnSize)));
78 RtlCopyMemory( temp, *firstrect, reg->rdh.nRgnSize );
79 reg->rdh.nRgnSize *= 2;
80 ExFreePool( *firstrect );
82 *rect = (*firstrect)+reg->rdh.nCount;
87 #define MEMCHECK(reg, rect, firstrect) xmemcheck(reg,&(rect),(LPRECT *)&(firstrect))
89 typedef void FASTCALL (*overlapProcp)(PROSRGNDATA, PRECT, PRECT, PRECT, PRECT, INT, INT);
90 typedef void FASTCALL (*nonOverlapProcp)(PROSRGNDATA, PRECT, PRECT, INT, INT);
92 // Number of points to buffer before sending them off to scanlines() : Must be an even number
93 #define NUMPTSTOBUFFER 200
95 #define RGN_DEFAULT_RECTS 2
97 // used to allocate buffers for points and link the buffers together
99 typedef struct _POINTBLOCK {
100 POINT pts[NUMPTSTOBUFFER];
101 struct _POINTBLOCK *next;
104 static BOOL FASTCALL REGION_CopyRegion(PROSRGNDATA dst, PROSRGNDATA src)
106 if(dst != src) // don't want to copy to itself
108 if (dst->rdh.nRgnSize < src->rdh.nCount * sizeof(RECT))
112 temp = ExAllocatePool(PagedPool, src->rdh.nCount * sizeof(RECT) );
117 ExFreePool( dst->Buffer ); //free the old buffer
119 dst->rdh.nRgnSize = src->rdh.nCount * sizeof(RECT); //size of region buffer
121 dst->rdh.nCount = src->rdh.nCount; //number of rectangles present in Buffer
122 dst->rdh.rcBound.left = src->rdh.rcBound.left;
123 dst->rdh.rcBound.top = src->rdh.rcBound.top;
124 dst->rdh.rcBound.right = src->rdh.rcBound.right;
125 dst->rdh.rcBound.bottom = src->rdh.rcBound.bottom;
126 dst->rdh.iType = src->rdh.iType;
127 RtlCopyMemory(dst->Buffer, src->Buffer, (int)(src->rdh.nCount * sizeof(RECT)));
132 static void FASTCALL REGION_SetExtents (ROSRGNDATA *pReg)
134 RECT *pRect, *pRectEnd, *pExtents;
136 if (pReg->rdh.nCount == 0)
138 pReg->rdh.rcBound.left = 0;
139 pReg->rdh.rcBound.top = 0;
140 pReg->rdh.rcBound.right = 0;
141 pReg->rdh.rcBound.bottom = 0;
142 pReg->rdh.iType = NULLREGION;
146 pExtents = &pReg->rdh.rcBound;
147 pRect = (PRECT)pReg->Buffer;
148 pRectEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount - 1;
151 * Since pRect is the first rectangle in the region, it must have the
152 * smallest top and since pRectEnd is the last rectangle in the region,
153 * it must have the largest bottom, because of banding. Initialize left and
154 * right from pRect and pRectEnd, resp., as good things to initialize them
157 pExtents->left = pRect->left;
158 pExtents->top = pRect->top;
159 pExtents->right = pRectEnd->right;
160 pExtents->bottom = pRectEnd->bottom;
162 while (pRect <= pRectEnd)
164 if (pRect->left < pExtents->left)
165 pExtents->left = pRect->left;
166 if (pRect->right > pExtents->right)
167 pExtents->right = pRect->right;
170 pReg->rdh.iType = (1 == pReg->rdh.nCount ? SIMPLEREGION : COMPLEXREGION);
174 /***********************************************************************
175 * REGION_CropAndOffsetRegion
177 static BOOL FASTCALL REGION_CropAndOffsetRegion(const PPOINT off, const PRECT rect, PROSRGNDATA rgnSrc, PROSRGNDATA rgnDst)
179 if(!rect) // just copy and offset
185 xrect = (PRECT)rgnDst->Buffer;
190 xrect = ExAllocatePool(PagedPool, rgnSrc->rdh.nCount * sizeof(RECT));
192 ExFreePool( rgnDst->Buffer ); //free the old buffer. will be assigned to xrect below.
200 RtlCopyMemory(rgnDst, rgnSrc, sizeof(ROSRGNDATA));
204 for(i = 0; i < rgnDst->rdh.nCount; i++)
206 xrect[i].left = ((PRECT)rgnSrc->Buffer + i)->left + off->x;
207 xrect[i].right = ((PRECT)rgnSrc->Buffer + i)->right + off->x;
208 xrect[i].top = ((PRECT)rgnSrc->Buffer + i)->top + off->y;
209 xrect[i].bottom = ((PRECT)rgnSrc->Buffer + i)->bottom + off->y;
211 rgnDst->rdh.rcBound.left += off->x;
212 rgnDst->rdh.rcBound.right += off->x;
213 rgnDst->rdh.rcBound.top += off->y;
214 rgnDst->rdh.rcBound.bottom += off->y;
217 RtlCopyMemory(xrect, rgnSrc->Buffer, rgnDst->rdh.nCount * sizeof(RECT));
219 rgnDst->Buffer = (char*)xrect;
223 else if ((rect->left >= rect->right) ||
224 (rect->top >= rect->bottom) ||
225 !EXTENTCHECK(rect, &rgnSrc->rdh.rcBound))
229 else // region box and clipping rect appear to intersect
232 ULONG i, j, clipa, clipb;
233 INT left = rgnSrc->rdh.rcBound.right + off->x;
234 INT right = rgnSrc->rdh.rcBound.left + off->x;
236 for(clipa = 0; ((PRECT)rgnSrc->Buffer + clipa)->bottom <= rect->top; clipa++)
237 //region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount
238 ; // skip bands above the clipping rectangle
240 for(clipb = clipa; clipb < rgnSrc->rdh.nCount; clipb++)
241 if(((PRECT)rgnSrc->Buffer + clipb)->top >= rect->bottom)
242 break; // and below it
244 // clipa - index of the first rect in the first intersecting band
245 // clipb - index of the last rect in the last intersecting band
247 if((rgnDst != rgnSrc) && (rgnDst->rdh.nCount < (i = (clipb - clipa))))
250 temp = ExAllocatePool( PagedPool, i * sizeof(RECT) );
255 ExFreePool( rgnDst->Buffer ); //free the old buffer
256 (PRECT)rgnDst->Buffer = temp;
257 rgnDst->rdh.nCount = i;
258 rgnDst->rdh.nRgnSize = i * sizeof(RECT);
261 for(i = clipa, j = 0; i < clipb ; i++)
263 // i - src index, j - dst index, j is always <= i for obvious reasons
265 lpr = (PRECT)rgnSrc->Buffer + i;
267 if(lpr->left < rect->right && lpr->right > rect->left)
269 rpr = (PRECT)rgnDst->Buffer + j;
271 rpr->top = lpr->top + off->y;
272 rpr->bottom = lpr->bottom + off->y;
273 rpr->left = ((lpr->left > rect->left) ? lpr->left : rect->left) + off->x;
274 rpr->right = ((lpr->right < rect->right) ? lpr->right : rect->right) + off->x;
276 if(rpr->left < left) left = rpr->left;
277 if(rpr->right > right) right = rpr->right;
283 if(j == 0) goto empty;
285 rgnDst->rdh.rcBound.left = left;
286 rgnDst->rdh.rcBound.right = right;
288 left = rect->top + off->y;
289 right = rect->bottom + off->y;
291 rgnDst->rdh.nCount = j--;
292 for(i = 0; i <= j; i++) // fixup top band
293 if(((PRECT)rgnDst->Buffer + i)->top < left)
294 ((PRECT)rgnDst->Buffer + i)->top = left;
298 for(i = j; i >= 0; i--) // fixup bottom band
299 if(((PRECT)rgnDst->Buffer + i)->bottom > right)
300 ((PRECT)rgnDst->Buffer + i)->bottom = right;
304 rgnDst->rdh.rcBound.top = ((PRECT)rgnDst->Buffer)->top;
305 rgnDst->rdh.rcBound.bottom = ((PRECT)rgnDst->Buffer + j)->bottom;
307 rgnDst->rdh.iType = (j >= 1) ? COMPLEXREGION : SIMPLEREGION;
315 rgnDst->Buffer = (char*)ExAllocatePool(PagedPool, RGN_DEFAULT_RECTS * sizeof(RECT));
317 rgnDst->rdh.nCount = RGN_DEFAULT_RECTS;
318 rgnDst->rdh.nRgnSize = RGN_DEFAULT_RECTS * sizeof(RECT);
323 EMPTY_REGION(rgnDst);
329 * hSrc: Region to crop and offset.
330 * lpRect: Clipping rectangle. Can be NULL (no clipping).
331 * lpPt: Points to offset the cropped region. Can be NULL (no offset).
333 * hDst: Region to hold the result (a new region is created if it's 0).
334 * Allowed to be the same region as hSrc in which case everything
335 * will be done in place, with no memory reallocations.
337 * \return hDst if success, 0 otherwise.
339 HRGN STDCALL REGION_CropRgn(HRGN hDst, HRGN hSrc, const PRECT lpRect, PPOINT lpPt)
341 PROSRGNDATA objSrc, rgnDst;
342 HRGN hNewDst, hRet = NULL;
343 GDIMULTILOCK Lock[2] = {{hDst, 0, GDI_OBJECT_TYPE_REGION}, {hSrc, 0, GDI_OBJECT_TYPE_REGION}};
347 if( !( hNewDst = RGNDATA_AllocRgn(1) ) )
351 Lock[0].hObj = hNewDst;
354 if ( !GDIOBJ_LockMultipleObj(Lock, sizeof(Lock)/sizeof(Lock[0])) )
356 DPRINT1("GDIOBJ_LockMultipleObj() failed\n" );
359 rgnDst = Lock[0].pObj;
360 objSrc = Lock[1].pObj;
362 if( objSrc && rgnDst )
371 if(REGION_CropAndOffsetRegion(lpPt, lpRect, objSrc, rgnDst) == FALSE)
372 { // ve failed cleanup and return
375 else{ // ve are fine. unlock the correct pointer and return correct handle
380 GDIOBJ_UnlockMultipleObj(Lock, sizeof(Lock)/sizeof(Lock[0]));
385 * Attempt to merge the rects in the current band with those in the
386 * previous one. Used only by REGION_RegionOp.
389 * The new index for the previous band.
391 * \note Side Effects:
392 * If coalescing takes place:
393 * - rectangles in the previous band will have their bottom fields
395 * - pReg->numRects will be decreased.
398 static INT FASTCALL REGION_Coalesce (
399 PROSRGNDATA pReg, /* Region to coalesce */
400 INT prevStart, /* Index of start of previous band */
401 INT curStart /* Index of start of current band */
403 RECT *pPrevRect; /* Current rect in previous band */
404 RECT *pCurRect; /* Current rect in current band */
405 RECT *pRegEnd; /* End of region */
406 INT curNumRects; /* Number of rectangles in current band */
407 INT prevNumRects; /* Number of rectangles in previous band */
408 INT bandtop; /* top coordinate for current band */
410 pRegEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount;
411 pPrevRect = (PRECT)pReg->Buffer + prevStart;
412 prevNumRects = curStart - prevStart;
415 * Figure out how many rectangles are in the current band. Have to do
416 * this because multiple bands could have been added in REGION_RegionOp
417 * at the end when one region has been exhausted.
419 pCurRect = (PRECT)pReg->Buffer + curStart;
420 bandtop = pCurRect->top;
421 for (curNumRects = 0;
422 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
428 if (pCurRect != pRegEnd)
431 * If more than one band was added, we have to find the start
432 * of the last band added so the next coalescing job can start
433 * at the right place... (given when multiple bands are added,
434 * this may be pointless -- see above).
437 while ((pRegEnd-1)->top == pRegEnd->top)
441 curStart = pRegEnd - (PRECT)pReg->Buffer;
442 pRegEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount;
445 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
446 pCurRect -= curNumRects;
448 * The bands may only be coalesced if the bottom of the previous
449 * matches the top scanline of the current.
451 if (pPrevRect->bottom == pCurRect->top)
454 * Make sure the bands have rects in the same places. This
455 * assumes that rects have been added in such a way that they
456 * cover the most area possible. I.e. two rects in a band must
457 * have some horizontal space between them.
461 if ((pPrevRect->left != pCurRect->left) ||
462 (pPrevRect->right != pCurRect->right))
465 * The bands don't line up so they can't be coalesced.
472 } while (prevNumRects != 0);
474 pReg->rdh.nCount -= curNumRects;
475 pCurRect -= curNumRects;
476 pPrevRect -= curNumRects;
479 * The bands may be merged, so set the bottom of each rect
480 * in the previous band to that of the corresponding rect in
485 pPrevRect->bottom = pCurRect->bottom;
489 } while (curNumRects != 0);
492 * If only one band was added to the region, we have to backup
493 * curStart to the start of the previous band.
495 * If more than one band was added to the region, copy the
496 * other bands down. The assumption here is that the other bands
497 * came from the same region as the current one and no further
498 * coalescing can be done on them since it's all been done
499 * already... curStart is already in the right place.
501 if (pCurRect == pRegEnd)
503 curStart = prevStart;
509 *pPrevRect++ = *pCurRect++;
510 } while (pCurRect != pRegEnd);
518 * Apply an operation to two regions. Called by REGION_Union,
519 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
525 * The new region is overwritten.
527 *\note The idea behind this function is to view the two regions as sets.
528 * Together they cover a rectangle of area that this function divides
529 * into horizontal bands where points are covered only by one region
530 * or by both. For the first case, the nonOverlapFunc is called with
531 * each the band and the band's upper and lower extents. For the
532 * second, the overlapFunc is called to process the entire band. It
533 * is responsible for clipping the rectangles in the band, though
534 * this function provides the boundaries.
535 * At the end of each band, the new region is coalesced, if possible,
536 * to reduce the number of rectangles in the region.
541 ROSRGNDATA *newReg, /* Place to store result */
542 ROSRGNDATA *reg1, /* First region in operation */
543 ROSRGNDATA *reg2, /* 2nd region in operation */
544 overlapProcp overlapFunc, /* Function to call for over-lapping bands */
545 nonOverlapProcp nonOverlap1Func, /* Function to call for non-overlapping bands in region 1 */
546 nonOverlapProcp nonOverlap2Func /* Function to call for non-overlapping bands in region 2 */
549 RECT *r1; /* Pointer into first region */
550 RECT *r2; /* Pointer into 2d region */
551 RECT *r1End; /* End of 1st region */
552 RECT *r2End; /* End of 2d region */
553 INT ybot; /* Bottom of intersection */
554 INT ytop; /* Top of intersection */
555 RECT *oldRects; /* Old rects for newReg */
556 ULONG prevBand; /* Index of start of
557 * previous band in newReg */
558 ULONG curBand; /* Index of start of current band in newReg */
559 RECT *r1BandEnd; /* End of current band in r1 */
560 RECT *r2BandEnd; /* End of current band in r2 */
561 ULONG top; /* Top of non-overlapping band */
562 ULONG bot; /* Bottom of non-overlapping band */
566 * set r1, r2, r1End and r2End appropriately, preserve the important
567 * parts of the destination region until the end in case it's one of
568 * the two source regions, then mark the "new" region empty, allocating
569 * another array of rectangles for it to use.
571 r1 = (PRECT)reg1->Buffer;
572 r2 = (PRECT)reg2->Buffer;
573 r1End = r1 + reg1->rdh.nCount;
574 r2End = r2 + reg2->rdh.nCount;
578 * newReg may be one of the src regions so we can't empty it. We keep a
579 * note of its rects pointer (so that we can free them later), preserve its
580 * extents and simply set numRects to zero.
583 oldRects = (PRECT)newReg->Buffer;
584 newReg->rdh.nCount = 0;
587 * Allocate a reasonable number of rectangles for the new region. The idea
588 * is to allocate enough so the individual functions don't need to
589 * reallocate and copy the array, which is time consuming, yet we don't
590 * have to worry about using too much memory. I hope to be able to
591 * nuke the Xrealloc() at the end of this function eventually.
593 newReg->rdh.nRgnSize = max(reg1->rdh.nCount,reg2->rdh.nCount) * 2 * sizeof(RECT);
595 if (! (newReg->Buffer = ExAllocatePool( PagedPool, newReg->rdh.nRgnSize )))
597 newReg->rdh.nRgnSize = 0;
602 * Initialize ybot and ytop.
603 * In the upcoming loop, ybot and ytop serve different functions depending
604 * on whether the band being handled is an overlapping or non-overlapping
606 * In the case of a non-overlapping band (only one of the regions
607 * has points in the band), ybot is the bottom of the most recent
608 * intersection and thus clips the top of the rectangles in that band.
609 * ytop is the top of the next intersection between the two regions and
610 * serves to clip the bottom of the rectangles in the current band.
611 * For an overlapping band (where the two regions intersect), ytop clips
612 * the top of the rectangles of both regions and ybot clips the bottoms.
614 if (reg1->rdh.rcBound.top < reg2->rdh.rcBound.top)
615 ybot = reg1->rdh.rcBound.top;
617 ybot = reg2->rdh.rcBound.top;
620 * prevBand serves to mark the start of the previous band so rectangles
621 * can be coalesced into larger rectangles. qv. miCoalesce, above.
622 * In the beginning, there is no previous band, so prevBand == curBand
623 * (curBand is set later on, of course, but the first band will always
624 * start at index 0). prevBand and curBand must be indices because of
625 * the possible expansion, and resultant moving, of the new region's
626 * array of rectangles.
632 curBand = newReg->rdh.nCount;
635 * This algorithm proceeds one source-band (as opposed to a
636 * destination band, which is determined by where the two regions
637 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
638 * rectangle after the last one in the current band for their
639 * respective regions.
642 while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
648 while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
654 * First handle the band that doesn't intersect, if any.
656 * Note that attention is restricted to one band in the
657 * non-intersecting region at once, so if a region has n
658 * bands between the current position and the next place it overlaps
659 * the other, this entire loop will be passed through n times.
661 if (r1->top < r2->top)
663 top = max(r1->top,ybot);
664 bot = min(r1->bottom,r2->top);
666 if ((top != bot) && (nonOverlap1Func != NULL))
668 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
673 else if (r2->top < r1->top)
675 top = max(r2->top,ybot);
676 bot = min(r2->bottom,r1->top);
678 if ((top != bot) && (nonOverlap2Func != NULL))
680 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
691 * If any rectangles got added to the region, try and coalesce them
692 * with rectangles from the previous band. Note we could just do
693 * this test in miCoalesce, but some machines incur a not
694 * inconsiderable cost for function calls, so...
696 if (newReg->rdh.nCount != curBand)
698 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
702 * Now see if we've hit an intersecting band. The two bands only
703 * intersect if ybot > ytop
705 ybot = min(r1->bottom, r2->bottom);
706 curBand = newReg->rdh.nCount;
709 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
712 if (newReg->rdh.nCount != curBand)
714 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
718 * If we've finished with a band (bottom == ybot) we skip forward
719 * in the region to the next band.
721 if (r1->bottom == ybot)
725 if (r2->bottom == ybot)
729 } while ((r1 != r1End) && (r2 != r2End));
732 * Deal with whichever region still has rectangles left.
734 curBand = newReg->rdh.nCount;
737 if (nonOverlap1Func != NULL)
742 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
746 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
747 max(r1->top,ybot), r1->bottom);
749 } while (r1 != r1End);
752 else if ((r2 != r2End) && (nonOverlap2Func != NULL))
757 while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
761 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
762 max(r2->top,ybot), r2->bottom);
764 } while (r2 != r2End);
767 if (newReg->rdh.nCount != curBand)
769 (void) REGION_Coalesce (newReg, prevBand, curBand);
773 * A bit of cleanup. To keep regions from growing without bound,
774 * we shrink the array of rectangles to match the new number of
775 * rectangles in the region. This never goes to 0, however...
777 * Only do this stuff if the number of rectangles allocated is more than
778 * twice the number of rectangles in the region (a simple optimization...).
780 if ((2 * newReg->rdh.nCount*sizeof(RECT) < newReg->rdh.nRgnSize && (newReg->rdh.nCount > 2)))
782 if (REGION_NOT_EMPTY(newReg))
784 RECT *prev_rects = (PRECT)newReg->Buffer;
785 newReg->Buffer = ExAllocatePool( PagedPool, newReg->rdh.nCount*sizeof(RECT) );
787 if (! newReg->Buffer)
788 newReg->Buffer = (char*)prev_rects;
790 newReg->rdh.nRgnSize = newReg->rdh.nCount*sizeof(RECT);
791 RtlCopyMemory( newReg->Buffer, prev_rects, newReg->rdh.nRgnSize );
792 ExFreePool( prev_rects );
798 * No point in doing the extra work involved in an Xrealloc if
799 * the region is empty
801 newReg->rdh.nRgnSize = sizeof(RECT);
802 ExFreePool( newReg->Buffer );
803 newReg->Buffer = ExAllocatePool( PagedPool, sizeof(RECT) );
804 ASSERT( newReg->Buffer );
808 if( newReg->rdh.nCount == 0 )
809 newReg->rdh.iType = NULLREGION;
811 newReg->rdh.iType = (newReg->rdh.nCount > 1)? COMPLEXREGION : SIMPLEREGION;
813 ExFreePool( oldRects );
817 /***********************************************************************
818 * Region Intersection
819 ***********************************************************************/
823 * Handle an overlapping band for REGION_Intersect.
828 * \note Side Effects:
829 * Rectangles may be added to the region.
846 pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
848 while ((r1 != r1End) && (r2 != r2End))
850 left = max(r1->left, r2->left);
851 right = min(r1->right, r2->right);
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...
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;
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.
876 if (r1->right < r2->right)
880 else if (r2->right < r1->right)
893 /***********************************************************************
894 * REGION_IntersectRegion
896 static void FASTCALL REGION_IntersectRegion(ROSRGNDATA *newReg, ROSRGNDATA *reg1,
899 /* check for trivial reject */
900 if ( (!(reg1->rdh.nCount)) || (!(reg2->rdh.nCount)) ||
901 (!EXTENTCHECK(®1->rdh.rcBound, ®2->rdh.rcBound)))
902 newReg->rdh.nCount = 0;
904 REGION_RegionOp (newReg, reg1, reg2,
905 REGION_IntersectO, NULL, NULL);
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.
915 REGION_SetExtents(newReg);
918 /***********************************************************************
920 ***********************************************************************/
923 * Handle a non-overlapping band for the union operation. Just
924 * Adds the rectangles into the region. Doesn't have to check for
925 * subsumption or anything.
930 * \note Side Effects:
931 * pReg->numRects is incremented and the final rectangles overwritten
932 * with the rectangles we're passed.
946 pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
950 MEMCHECK(pReg, pNextRect, pReg->Buffer);
951 pNextRect->left = r->left;
952 pNextRect->top = top;
953 pNextRect->right = r->right;
954 pNextRect->bottom = bottom;
955 pReg->rdh.nCount += 1;
963 * Handle an overlapping band for the union operation. Picks the
964 * left-most rectangle each time and merges it into the region.
969 * \note Side Effects:
970 * Rectangles are overwritten in pReg->rects and pReg->numRects will
987 pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
989 #define MERGERECT(r) \
990 if ((pReg->rdh.nCount != 0) && \
991 ((pNextRect-1)->top == top) && \
992 ((pNextRect-1)->bottom == bottom) && \
993 ((pNextRect-1)->right >= r->left)) \
995 if ((pNextRect-1)->right < r->right) \
997 (pNextRect-1)->right = r->right; \
1002 MEMCHECK(pReg, pNextRect, pReg->Buffer); \
1003 pNextRect->top = top; \
1004 pNextRect->bottom = bottom; \
1005 pNextRect->left = r->left; \
1006 pNextRect->right = r->right; \
1007 pReg->rdh.nCount += 1; \
1012 while ((r1 != r1End) && (r2 != r2End))
1014 if (r1->left < r2->left)
1029 } while (r1 != r1End);
1031 else while (r2 != r2End)
1038 /***********************************************************************
1039 * REGION_UnionRegion
1041 static void FASTCALL REGION_UnionRegion(ROSRGNDATA *newReg, ROSRGNDATA *reg1,
1044 /* checks all the simple cases */
1047 * Region 1 and 2 are the same or region 1 is empty
1049 if (reg1 == reg2 || 0 == reg1->rdh.nCount ||
1050 reg1->rdh.rcBound.right <= reg1->rdh.rcBound.left ||
1051 reg1->rdh.rcBound.bottom <= reg1->rdh.rcBound.top)
1055 REGION_CopyRegion(newReg, reg2);
1061 * if nothing to union (region 2 empty)
1063 if (0 == reg2->rdh.nCount ||
1064 reg2->rdh.rcBound.right <= reg2->rdh.rcBound.left ||
1065 reg2->rdh.rcBound.bottom <= reg2->rdh.rcBound.top)
1069 REGION_CopyRegion(newReg, reg1);
1075 * Region 1 completely subsumes region 2
1077 if (1 == reg1->rdh.nCount &&
1078 reg1->rdh.rcBound.left <= reg2->rdh.rcBound.left &&
1079 reg1->rdh.rcBound.top <= reg2->rdh.rcBound.top &&
1080 reg2->rdh.rcBound.right <= reg1->rdh.rcBound.right &&
1081 reg2->rdh.rcBound.bottom <= reg1->rdh.rcBound.bottom)
1085 REGION_CopyRegion(newReg, reg1);
1091 * Region 2 completely subsumes region 1
1093 if (1 == reg2->rdh.nCount &&
1094 reg2->rdh.rcBound.left <= reg1->rdh.rcBound.left &&
1095 reg2->rdh.rcBound.top <= reg1->rdh.rcBound.top &&
1096 reg1->rdh.rcBound.right <= reg2->rdh.rcBound.right &&
1097 reg1->rdh.rcBound.bottom <= reg2->rdh.rcBound.bottom)
1101 REGION_CopyRegion(newReg, reg2);
1106 REGION_RegionOp ( newReg, reg1, reg2, REGION_UnionO,
1107 REGION_UnionNonO, REGION_UnionNonO );
1108 newReg->rdh.rcBound.left = min(reg1->rdh.rcBound.left, reg2->rdh.rcBound.left);
1109 newReg->rdh.rcBound.top = min(reg1->rdh.rcBound.top, reg2->rdh.rcBound.top);
1110 newReg->rdh.rcBound.right = max(reg1->rdh.rcBound.right, reg2->rdh.rcBound.right);
1111 newReg->rdh.rcBound.bottom = max(reg1->rdh.rcBound.bottom, reg2->rdh.rcBound.bottom);
1114 /***********************************************************************
1115 * Region Subtraction
1116 ***********************************************************************/
1119 * Deal with non-overlapping band for subtraction. Any parts from
1120 * region 2 we discard. Anything from region 1 we add to the region.
1125 * \note Side Effects:
1126 * pReg may be affected.
1129 static void FASTCALL
1130 REGION_SubtractNonO1 (
1140 pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
1144 MEMCHECK(pReg, pNextRect, pReg->Buffer);
1145 pNextRect->left = r->left;
1146 pNextRect->top = top;
1147 pNextRect->right = r->right;
1148 pNextRect->bottom = bottom;
1149 pReg->rdh.nCount += 1;
1158 * Overlapping band subtraction. x1 is the left-most point not yet
1164 * \note Side Effects:
1165 * pReg may have rectangles added to it.
1168 static void FASTCALL
1183 pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
1185 while ((r1 != r1End) && (r2 != r2End))
1187 if (r2->right <= left)
1190 * Subtrahend missed the boat: go to next subtrahend.
1194 else if (r2->left <= left)
1197 * Subtrahend preceeds minuend: nuke left edge of minuend.
1200 if (left >= r1->right)
1203 * Minuend completely covered: advance to next minuend and
1204 * reset left fence to edge of new minuend.
1213 * Subtrahend now used up since it doesn't extend beyond
1219 else if (r2->left < r1->right)
1222 * Left part of subtrahend covers part of minuend: add uncovered
1223 * part of minuend to region and skip to next subtrahend.
1225 MEMCHECK(pReg, pNextRect, pReg->Buffer);
1226 pNextRect->left = left;
1227 pNextRect->top = top;
1228 pNextRect->right = r2->left;
1229 pNextRect->bottom = bottom;
1230 pReg->rdh.nCount += 1;
1233 if (left >= r1->right)
1236 * Minuend used up: advance to new...
1245 * Subtrahend used up
1253 * Minuend used up: add any remaining piece before advancing.
1255 if (r1->right > left)
1257 MEMCHECK(pReg, pNextRect, pReg->Buffer);
1258 pNextRect->left = left;
1259 pNextRect->top = top;
1260 pNextRect->right = r1->right;
1261 pNextRect->bottom = bottom;
1262 pReg->rdh.nCount += 1;
1271 * Add remaining minuend rectangles to region.
1275 MEMCHECK(pReg, pNextRect, pReg->Buffer);
1276 pNextRect->left = left;
1277 pNextRect->top = top;
1278 pNextRect->right = r1->right;
1279 pNextRect->bottom = bottom;
1280 pReg->rdh.nCount += 1;
1292 * Subtract regS from regM and leave the result in regD.
1293 * S stands for subtrahend, M for minuend and D for difference.
1298 * \note Side Effects:
1299 * regD is overwritten.
1302 static void FASTCALL REGION_SubtractRegion(ROSRGNDATA *regD, ROSRGNDATA *regM,
1305 /* check for trivial reject */
1306 if ( (!(regM->rdh.nCount)) || (!(regS->rdh.nCount)) ||
1307 (!EXTENTCHECK(®M->rdh.rcBound, ®S->rdh.rcBound)) )
1309 REGION_CopyRegion(regD, regM);
1313 REGION_RegionOp (regD, regM, regS, REGION_SubtractO,
1314 REGION_SubtractNonO1, NULL);
1317 * Can't alter newReg's extents before we call miRegionOp because
1318 * it might be one of the source regions and miRegionOp depends
1319 * on the extents of those regions being the unaltered. Besides, this
1320 * way there's no checking against rectangles that will be nuked
1321 * due to coalescing, so we have to examine fewer rectangles.
1323 REGION_SetExtents (regD);
1326 /***********************************************************************
1329 static void FASTCALL REGION_XorRegion(ROSRGNDATA *dr, ROSRGNDATA *sra,
1333 ROSRGNDATA *tra, *trb;
1335 if ((! (htra = RGNDATA_AllocRgn(sra->rdh.nCount + 1))) ||
1336 (! (htrb = RGNDATA_AllocRgn(srb->rdh.nCount + 1))))
1338 tra = RGNDATA_LockRgn( htra );
1340 NtGdiDeleteObject( htra );
1341 NtGdiDeleteObject( htrb );
1345 trb = RGNDATA_LockRgn( htrb );
1347 RGNDATA_UnlockRgn( htra );
1348 NtGdiDeleteObject( htra );
1349 NtGdiDeleteObject( htrb );
1353 REGION_SubtractRegion(tra,sra,srb);
1354 REGION_SubtractRegion(trb,srb,sra);
1355 REGION_UnionRegion(dr,tra,trb);
1356 RGNDATA_UnlockRgn( htra );
1357 RGNDATA_UnlockRgn( htrb );
1359 NtGdiDeleteObject( htra );
1360 NtGdiDeleteObject( htrb );
1366 * Adds a rectangle to a REGION
1368 static void FASTCALL REGION_UnionRectWithRegion(const RECT *rect, ROSRGNDATA *rgn)
1372 region.Buffer = (char*)(&(region.rdh.rcBound));
1373 region.rdh.nCount = 1;
1374 region.rdh.nRgnSize = sizeof( RECT );
1375 region.rdh.rcBound = *rect;
1376 REGION_UnionRegion(rgn, rgn, ®ion);
1380 BOOL STDCALL REGION_LPTODP(HDC hdc, HRGN hDest, HRGN hSrc)
1382 RECT *pCurRect, *pEndRect;
1383 PROSRGNDATA srcObj = NULL;
1384 PROSRGNDATA destObj = NULL;
1386 DC * dc = DC_LockDc(hdc);
1393 if(dc->w.MapMode == MM_TEXT) // Requires only a translation
1395 if(NtGdiCombineRgn(hDest, hSrc, 0, RGN_COPY) == ERROR)
1398 NtGdiOffsetRgn(hDest, dc->vportOrgX - dc->wndOrgX, dc->vportOrgY - dc->wndOrgY);
1403 if(!( srcObj = (PROSRGNDATA) RGNDATA_LockRgn( hSrc ) ))
1405 if(!( destObj = (PROSRGNDATA) RGNDATA_LockRgn( hDest ) ))
1407 RGNDATA_UnlockRgn( hSrc );
1410 EMPTY_REGION(destObj);
1412 pEndRect = (PRECT)srcObj->Buffer + srcObj->rdh.nCount;
1413 for(pCurRect = (PRECT)srcObj->Buffer; pCurRect < pEndRect; pCurRect++)
1415 tmpRect = *pCurRect;
1416 tmpRect.left = XLPTODP(dc, tmpRect.left);
1417 tmpRect.top = YLPTODP(dc, tmpRect.top);
1418 tmpRect.right = XLPTODP(dc, tmpRect.right);
1419 tmpRect.bottom = YLPTODP(dc, tmpRect.bottom);
1421 if(tmpRect.left > tmpRect.right)
1422 { INT tmp = tmpRect.left; tmpRect.left = tmpRect.right; tmpRect.right = tmp; }
1423 if(tmpRect.top > tmpRect.bottom)
1424 { INT tmp = tmpRect.top; tmpRect.top = tmpRect.bottom; tmpRect.bottom = tmp; }
1426 REGION_UnionRectWithRegion(&tmpRect, destObj);
1430 RGNDATA_UnlockRgn( hSrc );
1431 RGNDATA_UnlockRgn( hDest );
1438 HRGN FASTCALL RGNDATA_AllocRgn(INT n)
1444 if((hReg = (HRGN)GDIOBJ_AllocObj(sizeof(ROSRGNDATA), GDI_OBJECT_TYPE_REGION,
1445 (GDICLEANUPPROC) RGNDATA_InternalDelete))){
1446 if( (pReg = RGNDATA_LockRgn(hReg)) ){
1448 if ((pReg->Buffer = ExAllocatePool(PagedPool, n * sizeof(RECT)))){
1450 pReg->rdh.dwSize = sizeof(RGNDATAHEADER);
1451 pReg->rdh.nCount = n;
1452 pReg->rdh.nRgnSize = n*sizeof(RECT);
1454 bRet = RGNDATA_UnlockRgn(hReg);
1462 RGNDATA_FreeRgn(hReg);
1467 BOOL FASTCALL RGNDATA_InternalDelete( PROSRGNDATA pRgn )
1471 ExFreePool(pRgn->Buffer);
1475 // NtGdi Exported Functions
1478 NtGdiCombineRgn(HRGN hDest,
1484 GDIMULTILOCK Lock[3] = {{hDest, 0, GDI_OBJECT_TYPE_REGION}, {hSrc1, 0, GDI_OBJECT_TYPE_REGION}, {hSrc2, 0, GDI_OBJECT_TYPE_REGION}};
1485 PROSRGNDATA destRgn, src1Rgn, src2Rgn;
1487 if ( !GDIOBJ_LockMultipleObj(Lock, sizeof(Lock)/sizeof(Lock[0])) )
1489 DPRINT1("GDIOBJ_LockMultipleObj() failed\n" );
1493 destRgn = (PROSRGNDATA) Lock[0].pObj;
1494 src1Rgn = (PROSRGNDATA) Lock[1].pObj;
1495 src2Rgn = (PROSRGNDATA) Lock[2].pObj;
1501 if (CombineMode == RGN_COPY)
1503 if( !REGION_CopyRegion(destRgn, src1Rgn) )
1505 result = destRgn->rdh.iType;
1511 switch (CombineMode)
1514 REGION_IntersectRegion(destRgn, src1Rgn, src2Rgn);
1517 REGION_UnionRegion(destRgn, src1Rgn, src2Rgn);
1520 REGION_XorRegion(destRgn, src1Rgn, src2Rgn);
1523 REGION_SubtractRegion(destRgn, src1Rgn, src2Rgn);
1526 result = destRgn->rdh.iType;
1533 DPRINT("NtGdiCombineRgn: hDest unavailable\n");
1536 GDIOBJ_UnlockMultipleObj(Lock, sizeof(Lock)/sizeof(Lock[0]));
1542 NtGdiCreateEllipticRgn(INT LeftRect,
1552 NtGdiCreateEllipticRgnIndirect(CONST PRECT rc)
1559 NtGdiCreatePolygonRgn(CONST PPOINT pt,
1568 NtGdiCreatePolyPolygonRgn(CONST PPOINT pt,
1569 CONST PINT PolyCounts,
1578 NtGdiCreateRectRgn(INT LeftRect,
1584 PROSRGNDATA pRgnData;
1587 if (RightRect < LeftRect || BottomRect < TopRect)
1589 DPRINT1("Invalid parameters (%d, %d) - (%d, %d)\n", LeftRect, TopRect, RightRect, BottomRect);
1590 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1594 /* Allocate region data structure with space for 1 RECT */
1595 if ((hRgn = RGNDATA_AllocRgn(1)))
1597 if ((pRgnData = RGNDATA_LockRgn(hRgn)))
1599 pRect = (PRECT)pRgnData->Buffer;
1602 /* Fill in the region data header */
1603 pRgnData->rdh.iType = (LeftRect == RightRect || TopRect == BottomRect) ? NULLREGION : SIMPLEREGION;
1604 NtGdiSetRect(&(pRgnData->rdh.rcBound), LeftRect, TopRect, RightRect, BottomRect);
1606 /* use NtGdiCopyRect when implemented */
1607 NtGdiSetRect(pRect, LeftRect, TopRect, RightRect, BottomRect);
1608 RGNDATA_UnlockRgn(hRgn);
1612 NtGdiDeleteObject( hRgn );
1615 DPRINT1("NtGdiCreateRectRgn: can't allocate region\n");
1620 NtGdiCreateRectRgnIndirect(CONST PRECT rc)
1625 Status = MmCopyFromCaller(&SafeRc, rc, sizeof(RECT));
1626 if (!NT_SUCCESS(Status))
1630 return(UnsafeIntCreateRectRgnIndirect(&SafeRc));
1634 UnsafeIntCreateRectRgnIndirect(CONST PRECT rc)
1636 return(NtGdiCreateRectRgn(rc->left, rc->top, rc->right, rc->bottom));
1641 NtGdiCreateRoundRectRgn(INT LeftRect,
1653 NtGdiEqualRgn(HRGN hSrcRgn1,
1656 PROSRGNDATA rgn1, rgn2;
1657 PRECT tRect1, tRect2;
1661 if( !(rgn1 = RGNDATA_LockRgn(hSrcRgn1)))
1664 if( !(rgn2 = RGNDATA_LockRgn(hSrcRgn2))){
1665 RGNDATA_UnlockRgn( hSrcRgn1 );
1669 if(rgn1->rdh.nCount != rgn2->rdh.nCount ||
1670 rgn1->rdh.nCount == 0 ||
1671 rgn1->rdh.rcBound.left != rgn2->rdh.rcBound.left ||
1672 rgn1->rdh.rcBound.right != rgn2->rdh.rcBound.right ||
1673 rgn1->rdh.rcBound.top != rgn2->rdh.rcBound.top ||
1674 rgn1->rdh.rcBound.bottom != rgn2->rdh.rcBound.bottom)
1677 tRect1 = (PRECT)rgn1->Buffer;
1678 tRect2 = (PRECT)rgn2->Buffer;
1680 if( !tRect1 || !tRect2 )
1683 for(i=0; i < rgn1->rdh.nCount; i++)
1685 if(tRect1[i].left != tRect2[i].left ||
1686 tRect1[i].right != tRect2[i].right ||
1687 tRect1[i].top != tRect2[i].top ||
1688 tRect1[i].bottom != tRect2[i].bottom)
1694 RGNDATA_UnlockRgn( hSrcRgn1 );
1695 RGNDATA_UnlockRgn( hSrcRgn2 );
1701 NtGdiExtCreateRegion(CONST PXFORM Xform,
1703 CONST PROSRGNDATA RgnData)
1707 // FIXME: Apply Xform transformation to the regional data
1717 NtGdiFillRgn(HDC hDC, HRGN hRgn, HBRUSH hBrush)
1723 if (NULL == (rgn = RGNDATA_LockRgn(hRgn)))
1728 if (NULL == (oldhBrush = NtGdiSelectObject(hDC, hBrush)))
1730 RGNDATA_UnlockRgn(hRgn);
1734 for (r = (PRECT) rgn->Buffer; r < ((PRECT) rgn->Buffer) + rgn->rdh.nCount; r++)
1736 NtGdiPatBlt(hDC, r->left, r->top, r->right - r->left, r->bottom - r->top, PATCOPY);
1739 NtGdiSelectObject(hDC, oldhBrush);
1740 RGNDATA_UnlockRgn( hRgn );
1747 NtGdiFrameRgn(HDC hDC,
1757 UnsafeIntGetRgnBox(HRGN hRgn,
1760 PROSRGNDATA rgn = RGNDATA_LockRgn(hRgn);
1765 *pRect = rgn->rdh.rcBound;
1766 ret = rgn->rdh.iType;
1767 RGNDATA_UnlockRgn( hRgn );
1771 return 0; //if invalid region return zero
1776 NtGdiGetRgnBox(HRGN hRgn,
1782 ret = UnsafeIntGetRgnBox(hRgn, &SafeRect);
1788 if (!NT_SUCCESS(MmCopyToCaller(pRect, &SafeRect, sizeof(RECT))))
1798 NtGdiInvertRgn(HDC hDC,
1806 NtGdiOffsetRgn(HRGN hRgn,
1810 PROSRGNDATA rgn = RGNDATA_LockRgn(hRgn);
1813 DPRINT("NtGdiOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn, XOffset, YOffset, rgn );
1816 DPRINT("NtGdiOffsetRgn: hRgn error\n");
1820 if(XOffset || YOffset) {
1821 int nbox = rgn->rdh.nCount;
1822 PRECT pbox = (PRECT)rgn->Buffer;
1826 pbox->left += XOffset;
1827 pbox->right += XOffset;
1828 pbox->top += YOffset;
1829 pbox->bottom += YOffset;
1832 rgn->rdh.rcBound.left += XOffset;
1833 rgn->rdh.rcBound.right += XOffset;
1834 rgn->rdh.rcBound.top += YOffset;
1835 rgn->rdh.rcBound.bottom += YOffset;
1838 ret = rgn->rdh.iType;
1839 RGNDATA_UnlockRgn( hRgn );
1845 NtGdiPaintRgn(HDC hDC,
1849 HRGN tmpVisRgn; //, prevVisRgn;
1850 DC *dc = DC_LockDc(hDC);
1852 CLIPOBJ* ClipRegion;
1861 if(!(tmpVisRgn = NtGdiCreateRectRgn(0, 0, 0, 0))){
1867 // Transform region into device co-ords
1868 if(!REGION_LPTODP(hDC, tmpVisRgn, hRgn) || NtGdiOffsetRgn(tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY) == ERROR) {
1869 NtGdiDeleteObject( tmpVisRgn );
1874 /* enable when clipping is implemented
1875 NtGdiCombineRgn(tmpVisRgn, tmpVisRgn, dc->w.hGCClipRgn, RGN_AND);
1878 //visrgn = RGNDATA_LockRgn(tmpVisRgn);
1879 visrgn = RGNDATA_LockRgn(hRgn);
1881 ClipRegion = IntEngCreateClipRegion (
1882 visrgn->rdh.nCount, (PRECTL)visrgn->Buffer, visrgn->rdh.rcBound );
1883 ASSERT( ClipRegion );
1884 pBrush = BRUSHOBJ_LockBrush(dc->w.hBrush);
1886 BrushOrigin.x = dc->w.brushOrgX;
1887 BrushOrigin.y = dc->w.brushOrgY;
1888 SurfObj = (SURFOBJ*)AccessUserObject((ULONG)dc->Surface);
1890 bRet = IntEngPaint(SurfObj,
1894 0xFFFF);//FIXME:don't know what to put here
1896 RGNDATA_UnlockRgn( tmpVisRgn );
1905 NtGdiPtInRegion(HRGN hRgn,
1912 if( (rgn = RGNDATA_LockRgn(hRgn) ) )
1915 if(rgn->rdh.nCount > 0 && INRECT(rgn->rdh.rcBound, X, Y)){
1916 for(i = 0; i < rgn->rdh.nCount; i++) {
1917 if(INRECT(*(PRECT)&rgn->Buffer[i], X, Y)){
1918 RGNDATA_UnlockRgn(hRgn);
1923 RGNDATA_UnlockRgn(hRgn);
1929 UnsafeIntRectInRegion(HRGN hRgn,
1933 PRECT pCurRect, pRectEnd;
1936 if( !( rgn = RGNDATA_LockRgn(hRgn) ) )
1939 // this is (just) a useful optimization
1940 if((rgn->rdh.nCount > 0) && EXTENTCHECK(&rgn->rdh.rcBound, rc))
1942 for (pCurRect = (PRECT)rgn->Buffer, pRectEnd = pCurRect + rgn->rdh.nCount; pCurRect < pRectEnd; pCurRect++)
1944 if (pCurRect->bottom <= rc->top) continue; // not far enough down yet
1945 if (pCurRect->top >= rc->bottom) break; // too far down
1946 if (pCurRect->right <= rc->left) continue; // not far enough over yet
1947 if (pCurRect->left >= rc->right) continue;
1952 RGNDATA_UnlockRgn(hRgn);
1958 NtGdiRectInRegion(HRGN hRgn,
1959 CONST LPRECT unsaferc)
1963 if (!NT_SUCCESS(MmCopyFromCaller(&rc, unsaferc, sizeof(RECT))))
1965 DPRINT1("NtGdiRectInRegion: bogus rc\n");
1969 return UnsafeIntRectInRegion(hRgn, &rc);
1974 NtGdiSetRectRgn(HRGN hRgn,
1985 if( !( rgn = RGNDATA_LockRgn(hRgn) ) )
1986 return 0; //per documentation
1988 if (LeftRect > RightRect) { INT tmp = LeftRect; LeftRect = RightRect; RightRect = tmp; }
1989 if (TopRect > BottomRect) { INT tmp = TopRect; TopRect = BottomRect; BottomRect = tmp; }
1991 if((LeftRect != RightRect) && (TopRect != BottomRect))
1993 firstRect = (PRECT)rgn->Buffer;
1994 ASSERT( firstRect );
1995 firstRect->left = rgn->rdh.rcBound.left = LeftRect;
1996 firstRect->top = rgn->rdh.rcBound.top = TopRect;
1997 firstRect->right = rgn->rdh.rcBound.right = RightRect;
1998 firstRect->bottom = rgn->rdh.rcBound.bottom = BottomRect;
1999 rgn->rdh.nCount = 1;
2000 rgn->rdh.iType = SIMPLEREGION;
2004 RGNDATA_UnlockRgn( hRgn );
2009 UnsafeIntUnionRectWithRgn(HRGN hDest, CONST PRECT Rect)
2013 pRgn = RGNDATA_LockRgn(hDest);
2016 SetLastWin32Error(ERROR_INVALID_HANDLE);
2020 REGION_UnionRectWithRegion(Rect, pRgn);
2021 RGNDATA_UnlockRgn(hDest);
2027 NtGdiUnionRectWithRgn(HRGN hDest, CONST PRECT UnsafeRect)
2031 if (! NT_SUCCESS(MmCopyFromCaller(&SafeRect, UnsafeRect, sizeof(RECT))))
2033 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2037 return UnsafeIntUnionRectWithRgn(hDest, &SafeRect);
2041 * MSDN: GetRegionData, Return Values:
2043 * "If the function succeeds and dwCount specifies an adequate number of bytes,
2044 * the return value is always dwCount. If dwCount is too small or the function
2045 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
2046 * required number of bytes.
2048 * If the function fails, the return value is zero."
2050 DWORD STDCALL NtGdiGetRegionData(HRGN hrgn, DWORD count, LPRGNDATA rgndata)
2053 PROSRGNDATA obj = RGNDATA_LockRgn( hrgn );
2058 size = obj->rdh.nCount * sizeof(RECT);
2059 if(count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
2061 RGNDATA_UnlockRgn( hrgn );
2062 if (rgndata) /* buffer is too small, signal it by return 0 */
2064 else /* user requested buffer size with rgndata NULL */
2065 return size + sizeof(RGNDATAHEADER);
2068 //first we copy the header then we copy buffer
2069 if( !NT_SUCCESS( MmCopyToCaller( rgndata, obj, sizeof( RGNDATAHEADER )))){
2070 RGNDATA_UnlockRgn( hrgn );
2073 if( !NT_SUCCESS( MmCopyToCaller( (char*)rgndata+sizeof( RGNDATAHEADER ), obj->Buffer, size ))){
2074 RGNDATA_UnlockRgn( hrgn );
2078 RGNDATA_UnlockRgn( hrgn );
2079 return size + sizeof(RGNDATAHEADER);