1 #undef WIN32_LEAN_AND_MEAN
4 #include <internal/safe.h>
5 #include <win32k/float.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>
15 #include <win32k/debug1.h>
18 IntEngPaint(IN SURFOBJ
*Surface
,IN CLIPOBJ
*ClipRegion
,IN BRUSHOBJ
*Brush
,IN POINTL
*BrushOrigin
,
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; \
30 #define REGION_NOT_EMPTY(pReg) pReg->rdh.nCount
32 #define INRECT(r, x, y) \
33 ( ( ((r).right > x)) && \
34 ( ((r).left <= x)) && \
35 ( ((r).bottom > y)) && \
38 /* 1 if two RECTs overlap.
39 * 0 if two RECTs do not overlap.
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)
48 * Check to see if there is enough memory in the present region.
50 static inline int xmemcheck(ROSRGNDATA
*reg
, LPRECT
*rect
, LPRECT
*firstrect
) {
51 if ( (reg
->rdh
.nCount
+1)*sizeof( RECT
) >= reg
->rdh
.nRgnSize
) {
53 temp
= ExAllocatePool( PagedPool
, (2 * (reg
->rdh
.nRgnSize
)));
57 RtlCopyMemory( temp
, *firstrect
, reg
->rdh
.nRgnSize
);
58 reg
->rdh
.nRgnSize
*= 2;
59 ExFreePool( *firstrect
);
61 *rect
= (*firstrect
)+reg
->rdh
.nCount
;
66 #define MEMCHECK(reg, rect, firstrect) xmemcheck(reg,&(rect),&(firstrect))
68 typedef void (*voidProcp
)();
70 // Number of points to buffer before sending them off to scanlines() : Must be an even number
71 #define NUMPTSTOBUFFER 200
73 #define RGN_DEFAULT_RECTS 2
75 // used to allocate buffers for points and link the buffers together
77 typedef struct _POINTBLOCK
{
78 POINT pts
[NUMPTSTOBUFFER
];
79 struct _POINTBLOCK
*next
;
82 static BOOL
REGION_CopyRegion(PROSRGNDATA dst
, PROSRGNDATA src
)
84 if(dst
!= src
) // don't want to copy to itself
86 if (dst
->rdh
.nRgnSize
< src
->rdh
.nCount
* sizeof(RECT
))
90 temp
= ExAllocatePool(PagedPool
, src
->rdh
.nCount
* sizeof(RECT
) );
95 ExFreePool( dst
->Buffer
); //free the old buffer
97 dst
->rdh
.nRgnSize
= src
->rdh
.nCount
* sizeof(RECT
); //size of region buffer
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
)));
110 static void REGION_SetExtents (ROSRGNDATA
*pReg
)
112 RECT
*pRect
, *pRectEnd
, *pExtents
;
114 if (pReg
->rdh
.nCount
== 0)
116 pReg
->rdh
.rcBound
.left
= 0;
117 pReg
->rdh
.rcBound
.top
= 0;
118 pReg
->rdh
.rcBound
.right
= 0;
119 pReg
->rdh
.rcBound
.bottom
= 0;
123 pExtents
= &pReg
->rdh
.rcBound
;
124 pRect
= (PRECT
)pReg
->Buffer
;
125 pRectEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
- 1;
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
134 pExtents
->left
= pRect
->left
;
135 pExtents
->top
= pRect
->top
;
136 pExtents
->right
= pRectEnd
->right
;
137 pExtents
->bottom
= pRectEnd
->bottom
;
139 while (pRect
<= pRectEnd
)
141 if (pRect
->left
< pExtents
->left
)
142 pExtents
->left
= pRect
->left
;
143 if (pRect
->right
> pExtents
->right
)
144 pExtents
->right
= pRect
->right
;
150 /***********************************************************************
151 * REGION_CropAndOffsetRegion
153 static BOOL
REGION_CropAndOffsetRegion(const PPOINT off
, const PRECT rect
, PROSRGNDATA rgnSrc
, PROSRGNDATA rgnDst
)
155 if(!rect
) // just copy and offset
161 xrect
= (PRECT
)rgnDst
->Buffer
;
166 xrect
= ExAllocatePool(PagedPool
, rgnSrc
->rdh
.nCount
* sizeof(RECT
));
168 ExFreePool( rgnDst
->Buffer
); //free the old buffer. will be assigned to xrect below.
176 RtlCopyMemory(rgnDst
, rgnSrc
, sizeof(ROSRGNDATA
));
180 for(i
= 0; i
< rgnDst
->rdh
.nCount
; i
++)
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
;
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
;
193 RtlCopyMemory(xrect
, rgnSrc
->Buffer
, rgnDst
->rdh
.nCount
* sizeof(RECT
));
195 rgnDst
->Buffer
= (char*)xrect
;
199 else if ((rect
->left
>= rect
->right
) ||
200 (rect
->top
>= rect
->bottom
) ||
201 !EXTENTCHECK(rect
, &rgnSrc
->rdh
.rcBound
))
205 else // region box and clipping rect appear to intersect
208 INT i
, j
, clipa
, clipb
;
209 INT left
= rgnSrc
->rdh
.rcBound
.right
+ off
->x
;
210 INT right
= rgnSrc
->rdh
.rcBound
.left
+ off
->x
;
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
216 for(clipb
= clipa
; clipb
< rgnSrc
->rdh
.nCount
; clipb
++)
217 if(((PRECT
)rgnSrc
->Buffer
+ clipb
)->top
>= rect
->bottom
)
218 break; // and below it
220 // clipa - index of the first rect in the first intersecting band
221 // clipb - index of the last rect in the last intersecting band
223 if((rgnDst
!= rgnSrc
) && (rgnDst
->rdh
.nCount
< (i
= (clipb
- clipa
))))
226 temp
= ExAllocatePool( PagedPool
, i
* sizeof(RECT
) );
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
);
237 for(i
= clipa
, j
= 0; i
< clipb
; i
++)
239 // i - src index, j - dst index, j is always <= i for obvious reasons
241 lpr
= (PRECT
)rgnSrc
->Buffer
+ i
;
243 if(lpr
->left
< rect
->right
&& lpr
->right
> rect
->left
)
245 rpr
= (PRECT
)rgnDst
->Buffer
+ j
;
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
;
252 if(rpr
->left
< left
) left
= rpr
->left
;
253 if(rpr
->right
> right
) right
= rpr
->right
;
259 if(j
== 0) goto empty
;
261 rgnDst
->rdh
.rcBound
.left
= left
;
262 rgnDst
->rdh
.rcBound
.right
= right
;
264 left
= rect
->top
+ off
->y
;
265 right
= rect
->bottom
+ off
->y
;
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
;
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
;
280 rgnDst
->rdh
.rcBound
.top
= ((PRECT
)rgnDst
->Buffer
)->top
;
281 rgnDst
->rdh
.rcBound
.bottom
= ((PRECT
)rgnDst
->Buffer
+ j
)->bottom
;
283 rgnDst
->rdh
.iType
= (j
>= 1) ? COMPLEXREGION
: SIMPLEREGION
;
291 rgnDst
->Buffer
= (char*)ExAllocatePool(PagedPool
, RGN_DEFAULT_RECTS
* sizeof(RECT
));
293 rgnDst
->rdh
.nCount
= RGN_DEFAULT_RECTS
;
294 rgnDst
->rdh
.nRgnSize
= RGN_DEFAULT_RECTS
* sizeof(RECT
);
299 EMPTY_REGION(rgnDst
);
303 /***********************************************************************
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).
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.
315 * Returns: hDst if success, 0 otherwise.
317 HRGN
REGION_CropRgn(HRGN hDst
, HRGN hSrc
, const PRECT lpRect
, PPOINT lpPt
)
319 PROSRGNDATA objSrc
= RGNDATA_LockRgn(hSrc
);
328 if(!(rgnDst
= RGNDATA_LockRgn(hDst
)))
335 if( !( hNewDst
= RGNDATA_AllocRgn(1) ) ){
336 RGNDATA_UnlockRgn( hSrc
);
340 if(!(rgnDst
= RGNDATA_LockRgn(hNewDst
)))
342 RGNDATA_FreeRgn( hNewDst
);
343 RGNDATA_UnlockRgn( hSrc
);
355 if(REGION_CropAndOffsetRegion(lpPt
, lpRect
, objSrc
, rgnDst
) == FALSE
)
356 { // ve failed cleanup and return
357 RGNDATA_UnlockRgn( hSrc
);
359 if(hDst
) // unlock new region if allocated
360 RGNDATA_UnlockRgn( hDst
);
362 RGNDATA_UnlockRgn( hNewDst
);
366 else{ // ve are fine. unlock the correct pointer and return correct handle
367 RGNDATA_UnlockRgn( hSrc
);
370 RGNDATA_UnlockRgn( hNewDst
);
374 RGNDATA_UnlockRgn( hDst
);
380 RGNDATA_UnlockRgn( hSrc
);
385 /***********************************************************************
388 * Attempt to merge the rects in the current band with those in the
389 * previous one. Used only by REGION_RegionOp.
392 * The new index for the previous band.
395 * If coalescing takes place:
396 * - rectangles in the previous band will have their bottom fields
398 * - pReg->numRects will be decreased.
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 */
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 */
413 pRegEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
414 pPrevRect
= (PRECT
)pReg
->Buffer
+ prevStart
;
415 prevNumRects
= curStart
- prevStart
;
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.
422 pCurRect
= (PRECT
)pReg
->Buffer
+ curStart
;
423 bandtop
= pCurRect
->top
;
424 for (curNumRects
= 0;
425 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
431 if (pCurRect
!= pRegEnd
)
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).
440 while ((pRegEnd
-1)->top
== pRegEnd
->top
)
444 curStart
= pRegEnd
- (PRECT
)pReg
->Buffer
;
445 pRegEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
448 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0)) {
449 pCurRect
-= curNumRects
;
451 * The bands may only be coalesced if the bottom of the previous
452 * matches the top scanline of the current.
454 if (pPrevRect
->bottom
== pCurRect
->top
)
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.
464 if ((pPrevRect
->left
!= pCurRect
->left
) ||
465 (pPrevRect
->right
!= pCurRect
->right
))
468 * The bands don't line up so they can't be coalesced.
475 } while (prevNumRects
!= 0);
477 pReg
->rdh
.nCount
-= curNumRects
;
478 pCurRect
-= curNumRects
;
479 pPrevRect
-= curNumRects
;
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
488 pPrevRect
->bottom
= pCurRect
->bottom
;
492 } while (curNumRects
!= 0);
495 * If only one band was added to the region, we have to backup
496 * curStart to the start of the previous band.
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.
504 if (pCurRect
== pRegEnd
)
506 curStart
= prevStart
;
512 *pPrevRect
++ = *pCurRect
++;
513 } while (pCurRect
!= pRegEnd
);
520 /***********************************************************************
523 * Apply an operation to two regions. Called by REGION_Union,
524 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
530 * The new region is overwritten.
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.
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 */
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
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 */
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.
576 r1
= (PRECT
)reg1
->Buffer
;
577 r2
= (PRECT
)reg2
->Buffer
;
578 r1End
= r1
+ reg1
->rdh
.nCount
;
579 r2End
= r2
+ reg2
->rdh
.nCount
;
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.
588 oldRects
= (PRECT
)newReg
->Buffer
;
589 newReg
->rdh
.nCount
= 0;
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.
598 newReg
->rdh
.nRgnSize
= max(reg1
->rdh
.nCount
,reg2
->rdh
.nCount
) * 2 * sizeof(RECT
);
600 if (! (newReg
->Buffer
= ExAllocatePool( PagedPool
, newReg
->rdh
.nRgnSize
)))
602 newReg
->rdh
.nRgnSize
= 0;
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
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.
619 if (reg1
->rdh
.rcBound
.top
< reg2
->rdh
.rcBound
.top
)
620 ybot
= reg1
->rdh
.rcBound
.top
;
622 ybot
= reg2
->rdh
.rcBound
.top
;
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.
637 curBand
= newReg
->rdh
.nCount
;
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.
647 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
653 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
659 * First handle the band that doesn't intersect, if any.
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.
666 if (r1
->top
< r2
->top
)
668 top
= max(r1
->top
,ybot
);
669 bot
= min(r1
->bottom
,r2
->top
);
671 if ((top
!= bot
) && (nonOverlap1Func
!= (void (*)())NULL
))
673 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
, top
, bot
);
678 else if (r2
->top
< r1
->top
)
680 top
= max(r2
->top
,ybot
);
681 bot
= min(r2
->bottom
,r1
->top
);
683 if ((top
!= bot
) && (nonOverlap2Func
!= (void (*)())NULL
))
685 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
, top
, bot
);
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...
701 if (newReg
->rdh
.nCount
!= curBand
)
703 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
707 * Now see if we've hit an intersecting band. The two bands only
708 * intersect if ybot > ytop
710 ybot
= min(r1
->bottom
, r2
->bottom
);
711 curBand
= newReg
->rdh
.nCount
;
714 (* overlapFunc
) (newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
717 if (newReg
->rdh
.nCount
!= curBand
)
719 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
723 * If we've finished with a band (bottom == ybot) we skip forward
724 * in the region to the next band.
726 if (r1
->bottom
== ybot
)
730 if (r2
->bottom
== ybot
)
734 } while ((r1
!= r1End
) && (r2
!= r2End
));
737 * Deal with whichever region still has rectangles left.
739 curBand
= newReg
->rdh
.nCount
;
742 if (nonOverlap1Func
!= (void (*)())NULL
)
747 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
751 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
,
752 max(r1
->top
,ybot
), r1
->bottom
);
754 } while (r1
!= r1End
);
757 else if ((r2
!= r2End
) && (nonOverlap2Func
!= (void (*)())NULL
))
762 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
766 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
,
767 max(r2
->top
,ybot
), r2
->bottom
);
769 } while (r2
!= r2End
);
772 if (newReg
->rdh
.nCount
!= curBand
)
774 (void) REGION_Coalesce (newReg
, prevBand
, curBand
);
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...
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...).
785 if ((newReg
->rdh
.nCount
*sizeof(RECT
) < 2*newReg
->rdh
.nRgnSize
&& (newReg
->rdh
.nCount
> 2)))
787 if (REGION_NOT_EMPTY(newReg
))
789 RECT
*prev_rects
= (PRECT
)newReg
->Buffer
;
790 newReg
->Buffer
= ExAllocatePool( PagedPool
, newReg
->rdh
.nCount
*sizeof(RECT
) );
792 if (! newReg
->Buffer
)
793 newReg
->Buffer
= (char*)prev_rects
;
795 newReg
->rdh
.nRgnSize
= newReg
->rdh
.nCount
*sizeof(RECT
);
796 RtlCopyMemory( newReg
->Buffer
, prev_rects
, newReg
->rdh
.nRgnSize
);
797 ExFreePool( prev_rects
);
803 * No point in doing the extra work involved in an Xrealloc if
804 * the region is empty
806 newReg
->rdh
.nRgnSize
= sizeof(RECT
);
807 ExFreePool( newReg
->Buffer
);
808 newReg
->Buffer
= ExAllocatePool( PagedPool
, sizeof(RECT
) );
809 ASSERT( newReg
->Buffer
);
813 if( newReg
->rdh
.nCount
== 0 )
814 newReg
->rdh
.iType
= NULLREGION
;
816 newReg
->rdh
.iType
= (newReg
->rdh
.nCount
> 1)? COMPLEXREGION
: SIMPLEREGION
;
818 ExFreePool( oldRects
);
822 /***********************************************************************
823 * Region Intersection
824 ***********************************************************************/
827 /***********************************************************************
830 * Handle an overlapping band for REGION_Intersect.
836 * Rectangles may be added to the region.
839 static void REGION_IntersectO(ROSRGNDATA
*pReg
, RECT
*r1
, RECT
*r1End
,
840 RECT
*r2
, RECT
*r2End
, INT top
, INT bottom
)
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 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 (voidProcp
) REGION_IntersectO
, (voidProcp
) NULL
, (voidProcp
) 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 ***********************************************************************/
922 /***********************************************************************
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.
933 * pReg->numRects is incremented and the final rectangles overwritten
934 * with the rectangles we're passed.
937 static void REGION_UnionNonO (ROSRGNDATA
*pReg
, RECT
*r
, RECT
*rEnd
,
942 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
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;
958 /***********************************************************************
961 * Handle an overlapping band for the union operation. Picks the
962 * left-most rectangle each time and merges it into the region.
968 * Rectangles are overwritten in pReg->rects and pReg->numRects will
972 static void REGION_UnionO (ROSRGNDATA
*pReg
, RECT
*r1
, RECT
*r1End
,
973 RECT
*r2
, RECT
*r2End
, INT top
, INT bottom
)
977 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
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)) \
985 if ((pNextRect-1)->right < r->right) \
987 (pNextRect-1)->right = r->right; \
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; \
1002 while ((r1
!= r1End
) && (r2
!= r2End
))
1004 if (r1
->left
< r2
->left
)
1019 } while (r1
!= r1End
);
1021 else while (r2
!= r2End
)
1028 /***********************************************************************
1029 * REGION_UnionRegion
1031 static void REGION_UnionRegion(ROSRGNDATA
*newReg
, ROSRGNDATA
*reg1
,
1034 /* checks all the simple cases */
1037 * Region 1 and 2 are the same or region 1 is empty
1039 if ( (reg1
== reg2
) || (!(reg1
->rdh
.nCount
)) )
1042 REGION_CopyRegion(newReg
, reg2
);
1047 * if nothing to union (region 2 empty)
1049 if (!(reg2
->rdh
.nCount
))
1052 REGION_CopyRegion(newReg
, reg1
);
1057 * Region 1 completely subsumes region 2
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
))
1066 REGION_CopyRegion(newReg
, reg1
);
1071 * Region 2 completely subsumes region 1
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
))
1080 REGION_CopyRegion(newReg
, reg2
);
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
);
1092 /***********************************************************************
1093 * Region Subtraction
1094 ***********************************************************************/
1096 /***********************************************************************
1097 * REGION_SubtractNonO1
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.
1106 * pReg may be affected.
1109 static void REGION_SubtractNonO1 (ROSRGNDATA
*pReg
, RECT
*r
, RECT
*rEnd
,
1110 INT top
, INT bottom
)
1114 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
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;
1131 /***********************************************************************
1134 * Overlapping band subtraction. x1 is the left-most point not yet
1141 * pReg may have rectangles added to it.
1144 static void REGION_SubtractO (ROSRGNDATA
*pReg
, RECT
*r1
, RECT
*r1End
,
1145 RECT
*r2
, RECT
*r2End
, INT top
, INT bottom
)
1151 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1153 while ((r1
!= r1End
) && (r2
!= r2End
))
1155 if (r2
->right
<= left
)
1158 * Subtrahend missed the boat: go to next subtrahend.
1162 else if (r2
->left
<= left
)
1165 * Subtrahend preceeds minuend: nuke left edge of minuend.
1168 if (left
>= r1
->right
)
1171 * Minuend completely covered: advance to next minuend and
1172 * reset left fence to edge of new minuend.
1181 * Subtrahend now used up since it doesn't extend beyond
1187 else if (r2
->left
< r1
->right
)
1190 * Left part of subtrahend covers part of minuend: add uncovered
1191 * part of minuend to region and skip to next subtrahend.
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;
1201 if (left
>= r1
->right
)
1204 * Minuend used up: advance to new...
1213 * Subtrahend used up
1221 * Minuend used up: add any remaining piece before advancing.
1223 if (r1
->right
> left
)
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;
1239 * Add remaining minuend rectangles to region.
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;
1259 /***********************************************************************
1260 * REGION_SubtractRegion
1262 * Subtract regS from regM and leave the result in regD.
1263 * S stands for subtrahend, M for minuend and D for difference.
1269 * regD is overwritten.
1272 static void REGION_SubtractRegion(ROSRGNDATA
*regD
, ROSRGNDATA
*regM
,
1275 /* check for trivial reject */
1276 if ( (!(regM
->rdh
.nCount
)) || (!(regS
->rdh
.nCount
)) ||
1277 (!EXTENTCHECK(®M
->rdh
.rcBound
, ®S
->rdh
.rcBound
)) )
1279 REGION_CopyRegion(regD
, regM
);
1283 REGION_RegionOp (regD
, regM
, regS
, (voidProcp
) REGION_SubtractO
,
1284 (voidProcp
) REGION_SubtractNonO1
, (voidProcp
) NULL
);
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.
1293 REGION_SetExtents (regD
);
1296 /***********************************************************************
1299 static void REGION_XorRegion(ROSRGNDATA
*dr
, ROSRGNDATA
*sra
,
1303 ROSRGNDATA
*tra
, *trb
;
1305 if ((! (htra
= RGNDATA_AllocRgn(sra
->rdh
.nCount
+ 1))) ||
1306 (! (htrb
= RGNDATA_AllocRgn(srb
->rdh
.nCount
+ 1))))
1308 tra
= RGNDATA_LockRgn( htra
);
1310 W32kDeleteObject( htra
);
1311 W32kDeleteObject( htrb
);
1315 trb
= RGNDATA_LockRgn( htrb
);
1317 RGNDATA_UnlockRgn( htra
);
1318 W32kDeleteObject( htra
);
1319 W32kDeleteObject( htrb
);
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
);
1329 W32kDeleteObject( htra
);
1330 W32kDeleteObject( htrb
);
1335 /***********************************************************************
1336 * REGION_UnionRectWithRegion
1337 * Adds a rectangle to a WINEREGION
1339 static void REGION_UnionRectWithRegion(const RECT
*rect
, ROSRGNDATA
*rgn
)
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
, ®ion
);
1351 BOOL
REGION_LPTODP(HDC hdc
, HRGN hDest
, HRGN hSrc
)
1353 RECT
*pCurRect
, *pEndRect
;
1354 PROSRGNDATA srcObj
= NULL
;
1355 PROSRGNDATA destObj
= NULL
;
1357 DC
* dc
= DC_HandleToPtr(hdc
);
1364 if(dc
->w
.MapMode
== MM_TEXT
) // Requires only a translation
1366 if(W32kCombineRgn(hDest
, hSrc
, 0, RGN_COPY
) == ERROR
)
1369 W32kOffsetRgn(hDest
, dc
->vportOrgX
- dc
->wndOrgX
, dc
->vportOrgY
- dc
->wndOrgY
);
1374 if(!( srcObj
= (PROSRGNDATA
) RGNDATA_LockRgn( hSrc
) ))
1376 if(!( destObj
= (PROSRGNDATA
) RGNDATA_LockRgn( hDest
) ))
1378 RGNDATA_UnlockRgn( hSrc
);
1381 EMPTY_REGION(destObj
);
1383 pEndRect
= (PRECT
)srcObj
->Buffer
+ srcObj
->rdh
.nCount
;
1384 for(pCurRect
= (PRECT
)srcObj
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
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
);
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
; }
1397 REGION_UnionRectWithRegion(&tmpRect
, destObj
);
1401 RGNDATA_UnlockRgn( hSrc
);
1402 RGNDATA_UnlockRgn( hDest
);
1405 DC_ReleasePtr( hdc
);
1409 HRGN
RGNDATA_AllocRgn(INT n
)
1415 if((hReg
= (HRGN
)GDIOBJ_AllocObj(sizeof(ROSRGNDATA
), GO_REGION_MAGIC
))){
1416 if( (pReg
= GDIOBJ_LockObj( hReg
, GO_REGION_MAGIC
)) ){
1418 if ((pReg
->Buffer
= ExAllocatePool(PagedPool
, n
* sizeof(RECT
)))){
1420 pReg
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
1421 pReg
->rdh
.nCount
= n
;
1422 pReg
->rdh
.nRgnSize
= n
*sizeof(RECT
);
1424 bRet
= GDIOBJ_UnlockObj( hReg
, GO_REGION_MAGIC
);
1432 GDIOBJ_FreeObj( hReg
, GO_REGION_MAGIC
);
1437 BOOL
RGNDATA_InternalDelete( PROSRGNDATA pRgn
)
1441 ExFreePool(pRgn
->Buffer
);
1445 // W32k Exported Functions
1448 W32kCombineRgn(HRGN hDest
,
1454 PROSRGNDATA destRgn
= RGNDATA_LockRgn(hDest
);
1457 PROSRGNDATA src1Rgn
= RGNDATA_LockRgn(hSrc1
);
1460 if (CombineMode
== RGN_COPY
)
1462 if( !REGION_CopyRegion(destRgn
, src1Rgn
) )
1464 result
= destRgn
->rdh
.iType
;
1468 PROSRGNDATA src2Rgn
= RGNDATA_LockRgn(hSrc2
);
1470 switch (CombineMode
)
1473 REGION_IntersectRegion(destRgn
, src1Rgn
, src2Rgn
);
1476 REGION_UnionRegion(destRgn
, src1Rgn
, src2Rgn
);
1479 REGION_XorRegion(destRgn
, src1Rgn
, src2Rgn
);
1482 REGION_SubtractRegion(destRgn
, src1Rgn
, src2Rgn
);
1485 result
= destRgn
->rdh
.iType
;
1486 RGNDATA_UnlockRgn( hSrc2
);
1488 RGNDATA_UnlockRgn( hSrc1
);
1490 RGNDATA_UnlockRgn( hDest
);
1493 DPRINT("W32kCombineRgn: hDest unavailable\n");
1502 W32kCreateEllipticRgn(INT LeftRect
,
1512 W32kCreateEllipticRgnIndirect(CONST PRECT rc
)
1519 W32kCreatePolygonRgn(CONST PPOINT pt
,
1528 W32kCreatePolyPolygonRgn(CONST PPOINT pt
,
1529 CONST PINT PolyCounts
,
1538 W32kCreateRectRgn(INT LeftRect
,
1544 PROSRGNDATA pRgnData
;
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
;
1553 // Fill in the region data header
1554 pRgnData
->rdh
.iType
= SIMPLEREGION
;
1555 W32kSetRect(&(pRgnData
->rdh
.rcBound
), LeftRect
, TopRect
, RightRect
, BottomRect
);
1557 // use W32kCopyRect when implemented
1558 W32kSetRect(pRect
, LeftRect
, TopRect
, RightRect
, BottomRect
);
1559 RGNDATA_UnlockRgn( hRgn
);
1563 W32kDeleteObject( hRgn
);
1565 DPRINT("W32kCreateRectRgn: can't allocate region\n");
1570 W32kCreateRectRgnIndirect(CONST PRECT rc
)
1575 Status
= MmCopyFromCaller(&SafeRc
, rc
, sizeof(RECT
));
1576 if (!NT_SUCCESS(Status
))
1580 return(UnsafeW32kCreateRectRgnIndirect(&SafeRc
));
1584 UnsafeW32kCreateRectRgnIndirect(CONST PRECT rc
)
1586 return(W32kCreateRectRgn(rc
->left
, rc
->top
, rc
->right
, rc
->bottom
));
1591 W32kCreateRoundRectRgn(INT LeftRect
,
1603 W32kEqualRgn(HRGN hSrcRgn1
,
1606 PROSRGNDATA rgn1
, rgn2
;
1607 PRECT tRect1
, tRect2
;
1611 if( !(rgn1
= RGNDATA_LockRgn(hSrcRgn1
)))
1614 if( !(rgn2
= RGNDATA_LockRgn(hSrcRgn2
))){
1615 RGNDATA_UnlockRgn( hSrcRgn1
);
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
)
1627 tRect1
= (PRECT
)rgn1
->Buffer
;
1628 tRect2
= (PRECT
)rgn2
->Buffer
;
1630 if( !tRect1
|| !tRect2
)
1633 for(i
=0; i
< rgn1
->rdh
.nCount
; i
++)
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
)
1644 RGNDATA_UnlockRgn( hSrcRgn1
);
1645 RGNDATA_UnlockRgn( hSrcRgn2
);
1651 W32kExtCreateRegion(CONST PXFORM Xform
,
1653 CONST PROSRGNDATA RgnData
)
1657 // FIXME: Apply Xform transformation to the regional data
1667 W32kFillRgn(HDC hDC
,
1676 W32kFrameRgn(HDC hDC
,
1688 W32kGetRgnBox(HRGN hRgn
,
1691 PROSRGNDATA rgn
= RGNDATA_LockRgn(hRgn
);
1696 SafeRect
.left
= rgn
->rdh
.rcBound
.left
;
1697 SafeRect
.top
= rgn
->rdh
.rcBound
.top
;
1698 SafeRect
.right
= rgn
->rdh
.rcBound
.right
;
1699 SafeRect
.bottom
= rgn
->rdh
.rcBound
.bottom
;
1700 ret
= rgn
->rdh
.iType
;
1701 RGNDATA_UnlockRgn( hRgn
);
1703 if(!NT_SUCCESS(MmCopyToCaller(pRect
, &SafeRect
, sizeof(RECT
))))
1708 return 0; //if invalid region return zero
1713 W32kInvertRgn(HDC hDC
,
1721 W32kOffsetRgn(HRGN hRgn
,
1725 PROSRGNDATA rgn
= RGNDATA_LockRgn(hRgn
);
1728 DPRINT("W32kOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn
, XOffset
, YOffset
, rgn
);
1731 DPRINT("W32kOffsetRgn: hRgn error\n");
1735 if(XOffset
|| YOffset
) {
1736 int nbox
= rgn
->rdh
.nCount
;
1737 PRECT pbox
= (PRECT
)rgn
->Buffer
;
1741 pbox
->left
+= XOffset
;
1742 pbox
->right
+= XOffset
;
1743 pbox
->top
+= YOffset
;
1744 pbox
->bottom
+= YOffset
;
1747 rgn
->rdh
.rcBound
.left
+= XOffset
;
1748 rgn
->rdh
.rcBound
.right
+= XOffset
;
1749 rgn
->rdh
.rcBound
.top
+= YOffset
;
1750 rgn
->rdh
.rcBound
.bottom
+= YOffset
;
1753 ret
= rgn
->rdh
.iType
;
1754 RGNDATA_UnlockRgn( hRgn
);
1760 W32kPaintRgn(HDC hDC
,
1764 HRGN tmpVisRgn
, prevVisRgn
;
1765 DC
*dc
= DC_HandleToPtr(hDC
);
1767 CLIPOBJ
* ClipRegion
;
1776 if(!(tmpVisRgn
= W32kCreateRectRgn(0, 0, 0, 0))){
1777 DC_ReleasePtr( hDC
);
1782 // Transform region into device co-ords
1783 if(!REGION_LPTODP(hDC, tmpVisRgn, hRgn) || W32kOffsetRgn(tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY) == ERROR) {
1784 W32kDeleteObject( tmpVisRgn );
1785 DC_ReleasePtr( hDC );
1789 /* enable when clipping is implemented
1790 W32kCombineRgn(tmpVisRgn, tmpVisRgn, dc->w.hGCClipRgn, RGN_AND);
1793 //visrgn = RGNDATA_LockRgn(tmpVisRgn);
1794 visrgn
= RGNDATA_LockRgn(hRgn
);
1796 ClipRegion
= IntEngCreateClipRegion( visrgn
->rdh
.nCount
, visrgn
->Buffer
, visrgn
->rdh
.rcBound
);
1797 ASSERT( ClipRegion
);
1798 pBrush
= BRUSHOBJ_LockBrush(dc
->w
.hBrush
);
1800 BrushOrigin
.x
= dc
->w
.brushOrgX
;
1801 BrushOrigin
.y
= dc
->w
.brushOrgY
;
1802 SurfObj
= (SURFOBJ
*)AccessUserObject(dc
->Surface
);
1804 bRet
= IntEngPaint(SurfObj
,
1808 0xFFFF);//don't know what to put here
1810 RGNDATA_UnlockRgn( tmpVisRgn
);
1813 DC_ReleasePtr( hDC
);
1819 W32kPtInRegion(HRGN hRgn
,
1826 if( (rgn
= RGNDATA_LockRgn(hRgn
) ) )
1829 if(rgn
->rdh
.nCount
> 0 && INRECT(rgn
->rdh
.rcBound
, X
, Y
)){
1830 for(i
= 0; i
< rgn
->rdh
.nCount
; i
++) {
1831 if(INRECT(*(PRECT
)&rgn
->Buffer
[i
], X
, Y
)){
1832 RGNDATA_UnlockRgn(hRgn
);
1837 RGNDATA_UnlockRgn(hRgn
);
1843 W32kRectInRegion(HRGN hRgn
,
1844 CONST LPRECT unsaferc
)
1847 PRECT pCurRect
, pRectEnd
;
1851 if( !NT_SUCCESS( MmCopyFromCaller( rc
, unsaferc
, sizeof( RECT
) ) ) ){
1852 DPRINT("W32kRectInRegion: bogus rc\n");
1856 if( !( rgn
= RGNDATA_LockRgn(hRgn
) ) )
1859 // this is (just) a useful optimization
1860 if((rgn
->rdh
.nCount
> 0) && EXTENTCHECK(&rgn
->rdh
.rcBound
, rc
))
1862 for (pCurRect
= (PRECT
)rgn
->Buffer
, pRectEnd
= pCurRect
+ rgn
->rdh
.nCount
; pCurRect
< pRectEnd
; pCurRect
++)
1864 if (pCurRect
->bottom
<= rc
->top
) continue; // not far enough down yet
1865 if (pCurRect
->top
>= rc
->bottom
) break; // too far down
1866 if (pCurRect
->right
<= rc
->left
) continue; // not far enough over yet
1867 if (pCurRect
->left
>= rc
->right
) continue;
1872 RGNDATA_UnlockRgn(hRgn
);
1878 W32kSetRectRgn(HRGN hRgn
,
1889 if( !( rgn
= RGNDATA_LockRgn(hRgn
) ) )
1890 return 0; //per documentation
1892 if (LeftRect
> RightRect
) { INT tmp
= LeftRect
; LeftRect
= RightRect
; RightRect
= tmp
; }
1893 if (TopRect
> BottomRect
) { INT tmp
= TopRect
; TopRect
= BottomRect
; BottomRect
= tmp
; }
1895 if((LeftRect
!= RightRect
) && (TopRect
!= BottomRect
))
1897 firstRect
= (PRECT
)rgn
->Buffer
;
1898 ASSERT( firstRect
);
1899 firstRect
->left
= rgn
->rdh
.rcBound
.left
= LeftRect
;
1900 firstRect
->top
= rgn
->rdh
.rcBound
.top
= TopRect
;
1901 firstRect
->right
= rgn
->rdh
.rcBound
.right
= RightRect
;
1902 firstRect
->bottom
= rgn
->rdh
.rcBound
.bottom
= BottomRect
;
1903 rgn
->rdh
.nCount
= 1;
1904 rgn
->rdh
.iType
= SIMPLEREGION
;
1908 RGNDATA_UnlockRgn( hRgn
);
1913 W32kUnionRectWithRgn(HRGN hDest
, const RECT
* unsafeRect
)
1918 if( !NT_SUCCESS( MmCopyFromCaller( pRect
, unsafeRect
, sizeof( RECT
) ) ) )
1921 if( !(pRgn
= RGNDATA_LockRgn( hDest
) ) )
1924 REGION_UnionRectWithRegion( pRect
, pRgn
);
1925 RGNDATA_UnlockRgn( hDest
);
1929 /***********************************************************************
1930 * GetRegionData (GDI32.@)
1932 * MSDN: GetRegionData, Return Values:
1934 * "If the function succeeds and dwCount specifies an adequate number of bytes,
1935 * the return value is always dwCount. If dwCount is too small or the function
1936 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
1937 * required number of bytes.
1939 * If the function fails, the return value is zero."
1941 DWORD STDCALL
W32kGetRegionData(HRGN hrgn
, DWORD count
, LPRGNDATA rgndata
)
1944 PROSRGNDATA obj
= RGNDATA_LockRgn( hrgn
);
1949 size
= obj
->rdh
.nCount
* sizeof(RECT
);
1950 if(count
< (size
+ sizeof(RGNDATAHEADER
)) || rgndata
== NULL
)
1952 RGNDATA_UnlockRgn( hrgn
);
1953 if (rgndata
) /* buffer is too small, signal it by return 0 */
1955 else /* user requested buffer size with rgndata NULL */
1956 return size
+ sizeof(RGNDATAHEADER
);
1959 //first we copy the header then we copy buffer
1960 if( !NT_SUCCESS( MmCopyToCaller( rgndata
, obj
, sizeof( RGNDATAHEADER
)))){
1961 RGNDATA_UnlockRgn( hrgn
);
1964 if( !NT_SUCCESS( MmCopyToCaller( (char*)rgndata
+sizeof( RGNDATAHEADER
), obj
->Buffer
, size
))){
1965 RGNDATA_UnlockRgn( hrgn
);
1969 RGNDATA_UnlockRgn( hrgn
);
1970 return size
+ sizeof(RGNDATAHEADER
);