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.
19 /* $Id: region.c,v 1.29 2003/07/17 07:49:15 gvg Exp $ */
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;
145 pExtents
= &pReg
->rdh
.rcBound
;
146 pRect
= (PRECT
)pReg
->Buffer
;
147 pRectEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
- 1;
150 * Since pRect is the first rectangle in the region, it must have the
151 * smallest top and since pRectEnd is the last rectangle in the region,
152 * it must have the largest bottom, because of banding. Initialize left and
153 * right from pRect and pRectEnd, resp., as good things to initialize them
156 pExtents
->left
= pRect
->left
;
157 pExtents
->top
= pRect
->top
;
158 pExtents
->right
= pRectEnd
->right
;
159 pExtents
->bottom
= pRectEnd
->bottom
;
161 while (pRect
<= pRectEnd
)
163 if (pRect
->left
< pExtents
->left
)
164 pExtents
->left
= pRect
->left
;
165 if (pRect
->right
> pExtents
->right
)
166 pExtents
->right
= pRect
->right
;
172 /***********************************************************************
173 * REGION_CropAndOffsetRegion
175 static BOOL FASTCALL
REGION_CropAndOffsetRegion(const PPOINT off
, const PRECT rect
, PROSRGNDATA rgnSrc
, PROSRGNDATA rgnDst
)
177 if(!rect
) // just copy and offset
183 xrect
= (PRECT
)rgnDst
->Buffer
;
188 xrect
= ExAllocatePool(PagedPool
, rgnSrc
->rdh
.nCount
* sizeof(RECT
));
190 ExFreePool( rgnDst
->Buffer
); //free the old buffer. will be assigned to xrect below.
198 RtlCopyMemory(rgnDst
, rgnSrc
, sizeof(ROSRGNDATA
));
202 for(i
= 0; i
< rgnDst
->rdh
.nCount
; i
++)
204 xrect
[i
].left
= ((PRECT
)rgnSrc
->Buffer
+ i
)->left
+ off
->x
;
205 xrect
[i
].right
= ((PRECT
)rgnSrc
->Buffer
+ i
)->right
+ off
->x
;
206 xrect
[i
].top
= ((PRECT
)rgnSrc
->Buffer
+ i
)->top
+ off
->y
;
207 xrect
[i
].bottom
= ((PRECT
)rgnSrc
->Buffer
+ i
)->bottom
+ off
->y
;
209 rgnDst
->rdh
.rcBound
.left
+= off
->x
;
210 rgnDst
->rdh
.rcBound
.right
+= off
->x
;
211 rgnDst
->rdh
.rcBound
.top
+= off
->y
;
212 rgnDst
->rdh
.rcBound
.bottom
+= off
->y
;
215 RtlCopyMemory(xrect
, rgnSrc
->Buffer
, rgnDst
->rdh
.nCount
* sizeof(RECT
));
217 rgnDst
->Buffer
= (char*)xrect
;
221 else if ((rect
->left
>= rect
->right
) ||
222 (rect
->top
>= rect
->bottom
) ||
223 !EXTENTCHECK(rect
, &rgnSrc
->rdh
.rcBound
))
227 else // region box and clipping rect appear to intersect
230 INT i
, j
, clipa
, clipb
;
231 INT left
= rgnSrc
->rdh
.rcBound
.right
+ off
->x
;
232 INT right
= rgnSrc
->rdh
.rcBound
.left
+ off
->x
;
234 for(clipa
= 0; ((PRECT
)rgnSrc
->Buffer
+ clipa
)->bottom
<= rect
->top
; clipa
++)
235 //region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount
236 ; // skip bands above the clipping rectangle
238 for(clipb
= clipa
; clipb
< rgnSrc
->rdh
.nCount
; clipb
++)
239 if(((PRECT
)rgnSrc
->Buffer
+ clipb
)->top
>= rect
->bottom
)
240 break; // and below it
242 // clipa - index of the first rect in the first intersecting band
243 // clipb - index of the last rect in the last intersecting band
245 if((rgnDst
!= rgnSrc
) && (rgnDst
->rdh
.nCount
< (i
= (clipb
- clipa
))))
248 temp
= ExAllocatePool( PagedPool
, i
* sizeof(RECT
) );
253 ExFreePool( rgnDst
->Buffer
); //free the old buffer
254 (PRECT
)rgnDst
->Buffer
= temp
;
255 rgnDst
->rdh
.nCount
= i
;
256 rgnDst
->rdh
.nRgnSize
= i
* sizeof(RECT
);
259 for(i
= clipa
, j
= 0; i
< clipb
; i
++)
261 // i - src index, j - dst index, j is always <= i for obvious reasons
263 lpr
= (PRECT
)rgnSrc
->Buffer
+ i
;
265 if(lpr
->left
< rect
->right
&& lpr
->right
> rect
->left
)
267 rpr
= (PRECT
)rgnDst
->Buffer
+ j
;
269 rpr
->top
= lpr
->top
+ off
->y
;
270 rpr
->bottom
= lpr
->bottom
+ off
->y
;
271 rpr
->left
= ((lpr
->left
> rect
->left
) ? lpr
->left
: rect
->left
) + off
->x
;
272 rpr
->right
= ((lpr
->right
< rect
->right
) ? lpr
->right
: rect
->right
) + off
->x
;
274 if(rpr
->left
< left
) left
= rpr
->left
;
275 if(rpr
->right
> right
) right
= rpr
->right
;
281 if(j
== 0) goto empty
;
283 rgnDst
->rdh
.rcBound
.left
= left
;
284 rgnDst
->rdh
.rcBound
.right
= right
;
286 left
= rect
->top
+ off
->y
;
287 right
= rect
->bottom
+ off
->y
;
289 rgnDst
->rdh
.nCount
= j
--;
290 for(i
= 0; i
<= j
; i
++) // fixup top band
291 if(((PRECT
)rgnDst
->Buffer
+ i
)->top
< left
)
292 ((PRECT
)rgnDst
->Buffer
+ i
)->top
= left
;
296 for(i
= j
; i
>= 0; i
--) // fixup bottom band
297 if(((PRECT
)rgnDst
->Buffer
+ i
)->bottom
> right
)
298 ((PRECT
)rgnDst
->Buffer
+ i
)->bottom
= right
;
302 rgnDst
->rdh
.rcBound
.top
= ((PRECT
)rgnDst
->Buffer
)->top
;
303 rgnDst
->rdh
.rcBound
.bottom
= ((PRECT
)rgnDst
->Buffer
+ j
)->bottom
;
305 rgnDst
->rdh
.iType
= (j
>= 1) ? COMPLEXREGION
: SIMPLEREGION
;
313 rgnDst
->Buffer
= (char*)ExAllocatePool(PagedPool
, RGN_DEFAULT_RECTS
* sizeof(RECT
));
315 rgnDst
->rdh
.nCount
= RGN_DEFAULT_RECTS
;
316 rgnDst
->rdh
.nRgnSize
= RGN_DEFAULT_RECTS
* sizeof(RECT
);
321 EMPTY_REGION(rgnDst
);
327 * hSrc: Region to crop and offset.
328 * lpRect: Clipping rectangle. Can be NULL (no clipping).
329 * lpPt: Points to offset the cropped region. Can be NULL (no offset).
331 * hDst: Region to hold the result (a new region is created if it's 0).
332 * Allowed to be the same region as hSrc in which case everything
333 * will be done in place, with no memory reallocations.
335 * \return hDst if success, 0 otherwise.
337 HRGN STDCALL
REGION_CropRgn(HRGN hDst
, HRGN hSrc
, const PRECT lpRect
, PPOINT lpPt
)
339 PROSRGNDATA objSrc
, rgnDst
;
340 HRGN hNewDst
, hRet
= NULL
;
341 GDIMULTILOCK Lock
[2] = {{hDst
, 0, GO_REGION_MAGIC
}, {hSrc
, 0, GO_REGION_MAGIC
}};
344 if( !( hNewDst
= RGNDATA_AllocRgn(1) ) ){
347 Lock
[0].hObj
= hNewDst
;
350 GDIOBJ_LockMultipleObj(Lock
, 2);
351 rgnDst
= Lock
[0].pObj
;
352 objSrc
= Lock
[1].pObj
;
354 if( objSrc
&& rgnDst
)
363 if(REGION_CropAndOffsetRegion(lpPt
, lpRect
, objSrc
, rgnDst
) == FALSE
)
364 { // ve failed cleanup and return
367 else{ // ve are fine. unlock the correct pointer and return correct handle
372 GDIOBJ_UnlockMultipleObj(Lock
, 2);
377 * Attempt to merge the rects in the current band with those in the
378 * previous one. Used only by REGION_RegionOp.
381 * The new index for the previous band.
383 * \note Side Effects:
384 * If coalescing takes place:
385 * - rectangles in the previous band will have their bottom fields
387 * - pReg->numRects will be decreased.
390 static INT FASTCALL
REGION_Coalesce (
391 PROSRGNDATA pReg
, /* Region to coalesce */
392 INT prevStart
, /* Index of start of previous band */
393 INT curStart
/* Index of start of current band */
395 RECT
*pPrevRect
; /* Current rect in previous band */
396 RECT
*pCurRect
; /* Current rect in current band */
397 RECT
*pRegEnd
; /* End of region */
398 INT curNumRects
; /* Number of rectangles in current band */
399 INT prevNumRects
; /* Number of rectangles in previous band */
400 INT bandtop
; /* top coordinate for current band */
402 pRegEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
403 pPrevRect
= (PRECT
)pReg
->Buffer
+ prevStart
;
404 prevNumRects
= curStart
- prevStart
;
407 * Figure out how many rectangles are in the current band. Have to do
408 * this because multiple bands could have been added in REGION_RegionOp
409 * at the end when one region has been exhausted.
411 pCurRect
= (PRECT
)pReg
->Buffer
+ curStart
;
412 bandtop
= pCurRect
->top
;
413 for (curNumRects
= 0;
414 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
420 if (pCurRect
!= pRegEnd
)
423 * If more than one band was added, we have to find the start
424 * of the last band added so the next coalescing job can start
425 * at the right place... (given when multiple bands are added,
426 * this may be pointless -- see above).
429 while ((pRegEnd
-1)->top
== pRegEnd
->top
)
433 curStart
= pRegEnd
- (PRECT
)pReg
->Buffer
;
434 pRegEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
437 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0)) {
438 pCurRect
-= curNumRects
;
440 * The bands may only be coalesced if the bottom of the previous
441 * matches the top scanline of the current.
443 if (pPrevRect
->bottom
== pCurRect
->top
)
446 * Make sure the bands have rects in the same places. This
447 * assumes that rects have been added in such a way that they
448 * cover the most area possible. I.e. two rects in a band must
449 * have some horizontal space between them.
453 if ((pPrevRect
->left
!= pCurRect
->left
) ||
454 (pPrevRect
->right
!= pCurRect
->right
))
457 * The bands don't line up so they can't be coalesced.
464 } while (prevNumRects
!= 0);
466 pReg
->rdh
.nCount
-= curNumRects
;
467 pCurRect
-= curNumRects
;
468 pPrevRect
-= curNumRects
;
471 * The bands may be merged, so set the bottom of each rect
472 * in the previous band to that of the corresponding rect in
477 pPrevRect
->bottom
= pCurRect
->bottom
;
481 } while (curNumRects
!= 0);
484 * If only one band was added to the region, we have to backup
485 * curStart to the start of the previous band.
487 * If more than one band was added to the region, copy the
488 * other bands down. The assumption here is that the other bands
489 * came from the same region as the current one and no further
490 * coalescing can be done on them since it's all been done
491 * already... curStart is already in the right place.
493 if (pCurRect
== pRegEnd
)
495 curStart
= prevStart
;
501 *pPrevRect
++ = *pCurRect
++;
502 } while (pCurRect
!= pRegEnd
);
510 * Apply an operation to two regions. Called by REGION_Union,
511 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
517 * The new region is overwritten.
519 *\note The idea behind this function is to view the two regions as sets.
520 * Together they cover a rectangle of area that this function divides
521 * into horizontal bands where points are covered only by one region
522 * or by both. For the first case, the nonOverlapFunc is called with
523 * each the band and the band's upper and lower extents. For the
524 * second, the overlapFunc is called to process the entire band. It
525 * is responsible for clipping the rectangles in the band, though
526 * this function provides the boundaries.
527 * At the end of each band, the new region is coalesced, if possible,
528 * to reduce the number of rectangles in the region.
531 static void FASTCALL
REGION_RegionOp(
532 ROSRGNDATA
*newReg
, /* Place to store result */
533 ROSRGNDATA
*reg1
, /* First region in operation */
534 ROSRGNDATA
*reg2
, /* 2nd region in operation */
535 overlapProcp overlapFunc
, /* Function to call for over-lapping bands */
536 nonOverlapProcp nonOverlap1Func
, /* Function to call for non-overlapping bands in region 1 */
537 nonOverlapProcp nonOverlap2Func
/* Function to call for non-overlapping bands in region 2 */
539 RECT
*r1
; /* Pointer into first region */
540 RECT
*r2
; /* Pointer into 2d region */
541 RECT
*r1End
; /* End of 1st region */
542 RECT
*r2End
; /* End of 2d region */
543 INT ybot
; /* Bottom of intersection */
544 INT ytop
; /* Top of intersection */
545 RECT
*oldRects
; /* Old rects for newReg */
546 INT prevBand
; /* Index of start of
547 * previous band in newReg */
548 INT curBand
; /* Index of start of current
550 RECT
*r1BandEnd
; /* End of current band in r1 */
551 RECT
*r2BandEnd
; /* End of current band in r2 */
552 INT top
; /* Top of non-overlapping band */
553 INT bot
; /* Bottom of non-overlapping band */
557 * set r1, r2, r1End and r2End appropriately, preserve the important
558 * parts of the destination region until the end in case it's one of
559 * the two source regions, then mark the "new" region empty, allocating
560 * another array of rectangles for it to use.
562 r1
= (PRECT
)reg1
->Buffer
;
563 r2
= (PRECT
)reg2
->Buffer
;
564 r1End
= r1
+ reg1
->rdh
.nCount
;
565 r2End
= r2
+ reg2
->rdh
.nCount
;
569 * newReg may be one of the src regions so we can't empty it. We keep a
570 * note of its rects pointer (so that we can free them later), preserve its
571 * extents and simply set numRects to zero.
574 oldRects
= (PRECT
)newReg
->Buffer
;
575 newReg
->rdh
.nCount
= 0;
578 * Allocate a reasonable number of rectangles for the new region. The idea
579 * is to allocate enough so the individual functions don't need to
580 * reallocate and copy the array, which is time consuming, yet we don't
581 * have to worry about using too much memory. I hope to be able to
582 * nuke the Xrealloc() at the end of this function eventually.
584 newReg
->rdh
.nRgnSize
= max(reg1
->rdh
.nCount
,reg2
->rdh
.nCount
) * 2 * sizeof(RECT
);
586 if (! (newReg
->Buffer
= ExAllocatePool( PagedPool
, newReg
->rdh
.nRgnSize
)))
588 newReg
->rdh
.nRgnSize
= 0;
593 * Initialize ybot and ytop.
594 * In the upcoming loop, ybot and ytop serve different functions depending
595 * on whether the band being handled is an overlapping or non-overlapping
597 * In the case of a non-overlapping band (only one of the regions
598 * has points in the band), ybot is the bottom of the most recent
599 * intersection and thus clips the top of the rectangles in that band.
600 * ytop is the top of the next intersection between the two regions and
601 * serves to clip the bottom of the rectangles in the current band.
602 * For an overlapping band (where the two regions intersect), ytop clips
603 * the top of the rectangles of both regions and ybot clips the bottoms.
605 if (reg1
->rdh
.rcBound
.top
< reg2
->rdh
.rcBound
.top
)
606 ybot
= reg1
->rdh
.rcBound
.top
;
608 ybot
= reg2
->rdh
.rcBound
.top
;
611 * prevBand serves to mark the start of the previous band so rectangles
612 * can be coalesced into larger rectangles. qv. miCoalesce, above.
613 * In the beginning, there is no previous band, so prevBand == curBand
614 * (curBand is set later on, of course, but the first band will always
615 * start at index 0). prevBand and curBand must be indices because of
616 * the possible expansion, and resultant moving, of the new region's
617 * array of rectangles.
623 curBand
= newReg
->rdh
.nCount
;
626 * This algorithm proceeds one source-band (as opposed to a
627 * destination band, which is determined by where the two regions
628 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
629 * rectangle after the last one in the current band for their
630 * respective regions.
633 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
639 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
645 * First handle the band that doesn't intersect, if any.
647 * Note that attention is restricted to one band in the
648 * non-intersecting region at once, so if a region has n
649 * bands between the current position and the next place it overlaps
650 * the other, this entire loop will be passed through n times.
652 if (r1
->top
< r2
->top
)
654 top
= max(r1
->top
,ybot
);
655 bot
= min(r1
->bottom
,r2
->top
);
657 if ((top
!= bot
) && (nonOverlap1Func
!= NULL
))
659 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
, top
, bot
);
664 else if (r2
->top
< r1
->top
)
666 top
= max(r2
->top
,ybot
);
667 bot
= min(r2
->bottom
,r1
->top
);
669 if ((top
!= bot
) && (nonOverlap2Func
!= NULL
))
671 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
, top
, bot
);
682 * If any rectangles got added to the region, try and coalesce them
683 * with rectangles from the previous band. Note we could just do
684 * this test in miCoalesce, but some machines incur a not
685 * inconsiderable cost for function calls, so...
687 if (newReg
->rdh
.nCount
!= curBand
)
689 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
693 * Now see if we've hit an intersecting band. The two bands only
694 * intersect if ybot > ytop
696 ybot
= min(r1
->bottom
, r2
->bottom
);
697 curBand
= newReg
->rdh
.nCount
;
700 (* overlapFunc
) (newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
703 if (newReg
->rdh
.nCount
!= curBand
)
705 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
709 * If we've finished with a band (bottom == ybot) we skip forward
710 * in the region to the next band.
712 if (r1
->bottom
== ybot
)
716 if (r2
->bottom
== ybot
)
720 } while ((r1
!= r1End
) && (r2
!= r2End
));
723 * Deal with whichever region still has rectangles left.
725 curBand
= newReg
->rdh
.nCount
;
728 if (nonOverlap1Func
!= NULL
)
733 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
737 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
,
738 max(r1
->top
,ybot
), r1
->bottom
);
740 } while (r1
!= r1End
);
743 else if ((r2
!= r2End
) && (nonOverlap2Func
!= NULL
))
748 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
752 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
,
753 max(r2
->top
,ybot
), r2
->bottom
);
755 } while (r2
!= r2End
);
758 if (newReg
->rdh
.nCount
!= curBand
)
760 (void) REGION_Coalesce (newReg
, prevBand
, curBand
);
764 * A bit of cleanup. To keep regions from growing without bound,
765 * we shrink the array of rectangles to match the new number of
766 * rectangles in the region. This never goes to 0, however...
768 * Only do this stuff if the number of rectangles allocated is more than
769 * twice the number of rectangles in the region (a simple optimization...).
771 if ((2 * newReg
->rdh
.nCount
*sizeof(RECT
) < newReg
->rdh
.nRgnSize
&& (newReg
->rdh
.nCount
> 2)))
773 if (REGION_NOT_EMPTY(newReg
))
775 RECT
*prev_rects
= (PRECT
)newReg
->Buffer
;
776 newReg
->Buffer
= ExAllocatePool( PagedPool
, newReg
->rdh
.nCount
*sizeof(RECT
) );
778 if (! newReg
->Buffer
)
779 newReg
->Buffer
= (char*)prev_rects
;
781 newReg
->rdh
.nRgnSize
= newReg
->rdh
.nCount
*sizeof(RECT
);
782 RtlCopyMemory( newReg
->Buffer
, prev_rects
, newReg
->rdh
.nRgnSize
);
783 ExFreePool( prev_rects
);
789 * No point in doing the extra work involved in an Xrealloc if
790 * the region is empty
792 newReg
->rdh
.nRgnSize
= sizeof(RECT
);
793 ExFreePool( newReg
->Buffer
);
794 newReg
->Buffer
= ExAllocatePool( PagedPool
, sizeof(RECT
) );
795 ASSERT( newReg
->Buffer
);
799 if( newReg
->rdh
.nCount
== 0 )
800 newReg
->rdh
.iType
= NULLREGION
;
802 newReg
->rdh
.iType
= (newReg
->rdh
.nCount
> 1)? COMPLEXREGION
: SIMPLEREGION
;
804 ExFreePool( oldRects
);
808 /***********************************************************************
809 * Region Intersection
810 ***********************************************************************/
814 * Handle an overlapping band for REGION_Intersect.
819 * \note Side Effects:
820 * Rectangles may be added to the region.
823 static void FASTCALL
REGION_IntersectO(ROSRGNDATA
*pReg
, RECT
*r1
, RECT
*r1End
,
824 RECT
*r2
, RECT
*r2End
, INT top
, INT bottom
)
830 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
832 while ((r1
!= r1End
) && (r2
!= r2End
))
834 left
= max(r1
->left
, r2
->left
);
835 right
= min(r1
->right
, r2
->right
);
838 * If there's any overlap between the two rectangles, add that
839 * overlap to the new region.
840 * There's no need to check for subsumption because the only way
841 * such a need could arise is if some region has two rectangles
842 * right next to each other. Since that should never happen...
846 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
847 pNextRect
->left
= left
;
848 pNextRect
->top
= top
;
849 pNextRect
->right
= right
;
850 pNextRect
->bottom
= bottom
;
851 pReg
->rdh
.nCount
+= 1;
856 * Need to advance the pointers. Shift the one that extends
857 * to the right the least, since the other still has a chance to
858 * overlap with that region's next rectangle, if you see what I mean.
860 if (r1
->right
< r2
->right
)
864 else if (r2
->right
< r1
->right
)
877 /***********************************************************************
878 * REGION_IntersectRegion
880 static void FASTCALL
REGION_IntersectRegion(ROSRGNDATA
*newReg
, ROSRGNDATA
*reg1
,
883 /* check for trivial reject */
884 if ( (!(reg1
->rdh
.nCount
)) || (!(reg2
->rdh
.nCount
)) ||
885 (!EXTENTCHECK(®1
->rdh
.rcBound
, ®2
->rdh
.rcBound
)))
886 newReg
->rdh
.nCount
= 0;
888 REGION_RegionOp (newReg
, reg1
, reg2
,
889 REGION_IntersectO
, NULL
, NULL
);
892 * Can't alter newReg's extents before we call miRegionOp because
893 * it might be one of the source regions and miRegionOp depends
894 * on the extents of those regions being the same. Besides, this
895 * way there's no checking against rectangles that will be nuked
896 * due to coalescing, so we have to examine fewer rectangles.
899 REGION_SetExtents(newReg
);
902 /***********************************************************************
904 ***********************************************************************/
907 * Handle a non-overlapping band for the union operation. Just
908 * Adds the rectangles into the region. Doesn't have to check for
909 * subsumption or anything.
914 * \note Side Effects:
915 * pReg->numRects is incremented and the final rectangles overwritten
916 * with the rectangles we're passed.
919 static void FASTCALL
REGION_UnionNonO (ROSRGNDATA
*pReg
, RECT
*r
, RECT
*rEnd
,
924 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
928 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
929 pNextRect
->left
= r
->left
;
930 pNextRect
->top
= top
;
931 pNextRect
->right
= r
->right
;
932 pNextRect
->bottom
= bottom
;
933 pReg
->rdh
.nCount
+= 1;
941 * Handle an overlapping band for the union operation. Picks the
942 * left-most rectangle each time and merges it into the region.
947 * \note Side Effects:
948 * Rectangles are overwritten in pReg->rects and pReg->numRects will
952 static void FASTCALL
REGION_UnionO (ROSRGNDATA
*pReg
, RECT
*r1
, RECT
*r1End
,
953 RECT
*r2
, RECT
*r2End
, INT top
, INT bottom
)
957 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
959 #define MERGERECT(r) \
960 if ((pReg->rdh.nCount != 0) && \
961 ((pNextRect-1)->top == top) && \
962 ((pNextRect-1)->bottom == bottom) && \
963 ((pNextRect-1)->right >= r->left)) \
965 if ((pNextRect-1)->right < r->right) \
967 (pNextRect-1)->right = r->right; \
972 MEMCHECK(pReg, pNextRect, pReg->Buffer); \
973 pNextRect->top = top; \
974 pNextRect->bottom = bottom; \
975 pNextRect->left = r->left; \
976 pNextRect->right = r->right; \
977 pReg->rdh.nCount += 1; \
982 while ((r1
!= r1End
) && (r2
!= r2End
))
984 if (r1
->left
< r2
->left
)
999 } while (r1
!= r1End
);
1001 else while (r2
!= r2End
)
1008 /***********************************************************************
1009 * REGION_UnionRegion
1011 static void FASTCALL
REGION_UnionRegion(ROSRGNDATA
*newReg
, ROSRGNDATA
*reg1
,
1014 /* checks all the simple cases */
1017 * Region 1 and 2 are the same or region 1 is empty
1019 if (reg1
== reg2
|| 0 == reg1
->rdh
.nCount
||
1020 reg1
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.left
||
1021 reg1
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.top
)
1025 REGION_CopyRegion(newReg
, reg2
);
1031 * if nothing to union (region 2 empty)
1033 if (0 == reg2
->rdh
.nCount
||
1034 reg2
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.left
||
1035 reg2
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.top
)
1039 REGION_CopyRegion(newReg
, reg1
);
1045 * Region 1 completely subsumes region 2
1047 if (1 == reg1
->rdh
.nCount
&&
1048 reg1
->rdh
.rcBound
.left
<= reg2
->rdh
.rcBound
.left
&&
1049 reg1
->rdh
.rcBound
.top
<= reg2
->rdh
.rcBound
.top
&&
1050 reg2
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.right
&&
1051 reg2
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.bottom
)
1055 REGION_CopyRegion(newReg
, reg1
);
1061 * Region 2 completely subsumes region 1
1063 if (1 == reg2
->rdh
.nCount
&&
1064 reg2
->rdh
.rcBound
.left
<= reg1
->rdh
.rcBound
.left
&&
1065 reg2
->rdh
.rcBound
.top
<= reg1
->rdh
.rcBound
.top
&&
1066 reg1
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.right
&&
1067 reg1
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.bottom
)
1071 REGION_CopyRegion(newReg
, reg2
);
1076 REGION_RegionOp(newReg
, reg1
, reg2
, REGION_UnionO
,
1077 REGION_UnionNonO
, REGION_UnionNonO
);
1078 newReg
->rdh
.rcBound
.left
= min(reg1
->rdh
.rcBound
.left
, reg2
->rdh
.rcBound
.left
);
1079 newReg
->rdh
.rcBound
.top
= min(reg1
->rdh
.rcBound
.top
, reg2
->rdh
.rcBound
.top
);
1080 newReg
->rdh
.rcBound
.right
= max(reg1
->rdh
.rcBound
.right
, reg2
->rdh
.rcBound
.right
);
1081 newReg
->rdh
.rcBound
.bottom
= max(reg1
->rdh
.rcBound
.bottom
, reg2
->rdh
.rcBound
.bottom
);
1084 /***********************************************************************
1085 * Region Subtraction
1086 ***********************************************************************/
1089 * Deal with non-overlapping band for subtraction. Any parts from
1090 * region 2 we discard. Anything from region 1 we add to the region.
1095 * \note Side Effects:
1096 * pReg may be affected.
1099 static void FASTCALL
REGION_SubtractNonO1 (ROSRGNDATA
*pReg
, RECT
*r
, RECT
*rEnd
,
1100 INT top
, INT bottom
)
1104 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1108 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1109 pNextRect
->left
= r
->left
;
1110 pNextRect
->top
= top
;
1111 pNextRect
->right
= r
->right
;
1112 pNextRect
->bottom
= bottom
;
1113 pReg
->rdh
.nCount
+= 1;
1122 * Overlapping band subtraction. x1 is the left-most point not yet
1128 * \note Side Effects:
1129 * pReg may have rectangles added to it.
1132 static void FASTCALL
REGION_SubtractO (ROSRGNDATA
*pReg
, RECT
*r1
, RECT
*r1End
,
1133 RECT
*r2
, RECT
*r2End
, INT top
, INT bottom
)
1139 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1141 while ((r1
!= r1End
) && (r2
!= r2End
))
1143 if (r2
->right
<= left
)
1146 * Subtrahend missed the boat: go to next subtrahend.
1150 else if (r2
->left
<= left
)
1153 * Subtrahend preceeds minuend: nuke left edge of minuend.
1156 if (left
>= r1
->right
)
1159 * Minuend completely covered: advance to next minuend and
1160 * reset left fence to edge of new minuend.
1169 * Subtrahend now used up since it doesn't extend beyond
1175 else if (r2
->left
< r1
->right
)
1178 * Left part of subtrahend covers part of minuend: add uncovered
1179 * part of minuend to region and skip to next subtrahend.
1181 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1182 pNextRect
->left
= left
;
1183 pNextRect
->top
= top
;
1184 pNextRect
->right
= r2
->left
;
1185 pNextRect
->bottom
= bottom
;
1186 pReg
->rdh
.nCount
+= 1;
1189 if (left
>= r1
->right
)
1192 * Minuend used up: advance to new...
1201 * Subtrahend used up
1209 * Minuend used up: add any remaining piece before advancing.
1211 if (r1
->right
> left
)
1213 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1214 pNextRect
->left
= left
;
1215 pNextRect
->top
= top
;
1216 pNextRect
->right
= r1
->right
;
1217 pNextRect
->bottom
= bottom
;
1218 pReg
->rdh
.nCount
+= 1;
1227 * Add remaining minuend rectangles to region.
1231 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1232 pNextRect
->left
= left
;
1233 pNextRect
->top
= top
;
1234 pNextRect
->right
= r1
->right
;
1235 pNextRect
->bottom
= bottom
;
1236 pReg
->rdh
.nCount
+= 1;
1248 * Subtract regS from regM and leave the result in regD.
1249 * S stands for subtrahend, M for minuend and D for difference.
1254 * \note Side Effects:
1255 * regD is overwritten.
1258 static void FASTCALL
REGION_SubtractRegion(ROSRGNDATA
*regD
, ROSRGNDATA
*regM
,
1261 /* check for trivial reject */
1262 if ( (!(regM
->rdh
.nCount
)) || (!(regS
->rdh
.nCount
)) ||
1263 (!EXTENTCHECK(®M
->rdh
.rcBound
, ®S
->rdh
.rcBound
)) )
1265 REGION_CopyRegion(regD
, regM
);
1269 REGION_RegionOp (regD
, regM
, regS
, REGION_SubtractO
,
1270 REGION_SubtractNonO1
, NULL
);
1273 * Can't alter newReg's extents before we call miRegionOp because
1274 * it might be one of the source regions and miRegionOp depends
1275 * on the extents of those regions being the unaltered. Besides, this
1276 * way there's no checking against rectangles that will be nuked
1277 * due to coalescing, so we have to examine fewer rectangles.
1279 REGION_SetExtents (regD
);
1282 /***********************************************************************
1285 static void FASTCALL
REGION_XorRegion(ROSRGNDATA
*dr
, ROSRGNDATA
*sra
,
1289 ROSRGNDATA
*tra
, *trb
;
1291 if ((! (htra
= RGNDATA_AllocRgn(sra
->rdh
.nCount
+ 1))) ||
1292 (! (htrb
= RGNDATA_AllocRgn(srb
->rdh
.nCount
+ 1))))
1294 tra
= RGNDATA_LockRgn( htra
);
1296 W32kDeleteObject( htra
);
1297 W32kDeleteObject( htrb
);
1301 trb
= RGNDATA_LockRgn( htrb
);
1303 RGNDATA_UnlockRgn( htra
);
1304 W32kDeleteObject( htra
);
1305 W32kDeleteObject( htrb
);
1309 REGION_SubtractRegion(tra
,sra
,srb
);
1310 REGION_SubtractRegion(trb
,srb
,sra
);
1311 REGION_UnionRegion(dr
,tra
,trb
);
1312 RGNDATA_UnlockRgn( htra
);
1313 RGNDATA_UnlockRgn( htrb
);
1315 W32kDeleteObject( htra
);
1316 W32kDeleteObject( htrb
);
1322 * Adds a rectangle to a REGION
1324 static void FASTCALL
REGION_UnionRectWithRegion(const RECT
*rect
, ROSRGNDATA
*rgn
)
1328 region
.Buffer
= (char*)(&(region
.rdh
.rcBound
));
1329 region
.rdh
.nCount
= 1;
1330 region
.rdh
.nRgnSize
= sizeof( RECT
);
1331 region
.rdh
.rcBound
= *rect
;
1332 REGION_UnionRegion(rgn
, rgn
, ®ion
);
1336 BOOL STDCALL
REGION_LPTODP(HDC hdc
, HRGN hDest
, HRGN hSrc
)
1338 RECT
*pCurRect
, *pEndRect
;
1339 PROSRGNDATA srcObj
= NULL
;
1340 PROSRGNDATA destObj
= NULL
;
1342 DC
* dc
= DC_HandleToPtr(hdc
);
1349 if(dc
->w
.MapMode
== MM_TEXT
) // Requires only a translation
1351 if(W32kCombineRgn(hDest
, hSrc
, 0, RGN_COPY
) == ERROR
)
1354 W32kOffsetRgn(hDest
, dc
->vportOrgX
- dc
->wndOrgX
, dc
->vportOrgY
- dc
->wndOrgY
);
1359 if(!( srcObj
= (PROSRGNDATA
) RGNDATA_LockRgn( hSrc
) ))
1361 if(!( destObj
= (PROSRGNDATA
) RGNDATA_LockRgn( hDest
) ))
1363 RGNDATA_UnlockRgn( hSrc
);
1366 EMPTY_REGION(destObj
);
1368 pEndRect
= (PRECT
)srcObj
->Buffer
+ srcObj
->rdh
.nCount
;
1369 for(pCurRect
= (PRECT
)srcObj
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
1371 tmpRect
= *pCurRect
;
1372 tmpRect
.left
= XLPTODP(dc
, tmpRect
.left
);
1373 tmpRect
.top
= YLPTODP(dc
, tmpRect
.top
);
1374 tmpRect
.right
= XLPTODP(dc
, tmpRect
.right
);
1375 tmpRect
.bottom
= YLPTODP(dc
, tmpRect
.bottom
);
1377 if(tmpRect
.left
> tmpRect
.right
)
1378 { INT tmp
= tmpRect
.left
; tmpRect
.left
= tmpRect
.right
; tmpRect
.right
= tmp
; }
1379 if(tmpRect
.top
> tmpRect
.bottom
)
1380 { INT tmp
= tmpRect
.top
; tmpRect
.top
= tmpRect
.bottom
; tmpRect
.bottom
= tmp
; }
1382 REGION_UnionRectWithRegion(&tmpRect
, destObj
);
1386 RGNDATA_UnlockRgn( hSrc
);
1387 RGNDATA_UnlockRgn( hDest
);
1390 DC_ReleasePtr( hdc
);
1394 HRGN FASTCALL
RGNDATA_AllocRgn(INT n
)
1400 if((hReg
= (HRGN
)GDIOBJ_AllocObj(sizeof(ROSRGNDATA
), GO_REGION_MAGIC
))){
1401 if( (pReg
= GDIOBJ_LockObj( hReg
, GO_REGION_MAGIC
)) ){
1403 if ((pReg
->Buffer
= ExAllocatePool(PagedPool
, n
* sizeof(RECT
)))){
1405 pReg
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
1406 pReg
->rdh
.nCount
= n
;
1407 pReg
->rdh
.nRgnSize
= n
*sizeof(RECT
);
1409 bRet
= GDIOBJ_UnlockObj( hReg
, GO_REGION_MAGIC
);
1417 GDIOBJ_FreeObj( hReg
, GO_REGION_MAGIC
, GDIOBJFLAG_DEFAULT
);
1422 BOOL FASTCALL
RGNDATA_InternalDelete( PROSRGNDATA pRgn
)
1426 ExFreePool(pRgn
->Buffer
);
1430 // W32k Exported Functions
1433 W32kCombineRgn(HRGN hDest
,
1439 GDIMULTILOCK Lock
[3] = {{hDest
, 0, GO_REGION_MAGIC
}, {hSrc1
, 0, GO_REGION_MAGIC
}, {hSrc2
, 0, GO_REGION_MAGIC
}};
1440 PROSRGNDATA destRgn
, src1Rgn
, src2Rgn
;
1442 GDIOBJ_LockMultipleObj(Lock
, 3);
1444 destRgn
= (PROSRGNDATA
) Lock
[0].pObj
;
1445 src1Rgn
= (PROSRGNDATA
) Lock
[1].pObj
;
1446 src2Rgn
= (PROSRGNDATA
) Lock
[2].pObj
;
1450 if (CombineMode
== RGN_COPY
)
1452 if( !REGION_CopyRegion(destRgn
, src1Rgn
) )
1454 result
= destRgn
->rdh
.iType
;
1459 switch (CombineMode
)
1462 REGION_IntersectRegion(destRgn
, src1Rgn
, src2Rgn
);
1465 REGION_UnionRegion(destRgn
, src1Rgn
, src2Rgn
);
1468 REGION_XorRegion(destRgn
, src1Rgn
, src2Rgn
);
1471 REGION_SubtractRegion(destRgn
, src1Rgn
, src2Rgn
);
1474 result
= destRgn
->rdh
.iType
;
1480 DPRINT("W32kCombineRgn: hDest unavailable\n");
1483 GDIOBJ_UnlockMultipleObj(Lock
, 3);
1489 W32kCreateEllipticRgn(INT LeftRect
,
1499 W32kCreateEllipticRgnIndirect(CONST PRECT rc
)
1506 W32kCreatePolygonRgn(CONST PPOINT pt
,
1515 W32kCreatePolyPolygonRgn(CONST PPOINT pt
,
1516 CONST PINT PolyCounts
,
1525 W32kCreateRectRgn(INT LeftRect
,
1531 PROSRGNDATA pRgnData
;
1534 // Allocate region data structure with space for 1 RECT
1535 if( ( hRgn
= RGNDATA_AllocRgn(1) ) ){
1536 if( ( pRgnData
= RGNDATA_LockRgn( hRgn
) ) ){
1537 pRect
= (PRECT
)pRgnData
->Buffer
;
1540 // Fill in the region data header
1541 pRgnData
->rdh
.iType
= SIMPLEREGION
;
1542 W32kSetRect(&(pRgnData
->rdh
.rcBound
), LeftRect
, TopRect
, RightRect
, BottomRect
);
1544 // use W32kCopyRect when implemented
1545 W32kSetRect(pRect
, LeftRect
, TopRect
, RightRect
, BottomRect
);
1546 RGNDATA_UnlockRgn( hRgn
);
1550 W32kDeleteObject( hRgn
);
1552 DPRINT("W32kCreateRectRgn: can't allocate region\n");
1557 W32kCreateRectRgnIndirect(CONST PRECT rc
)
1562 Status
= MmCopyFromCaller(&SafeRc
, rc
, sizeof(RECT
));
1563 if (!NT_SUCCESS(Status
))
1567 return(UnsafeW32kCreateRectRgnIndirect(&SafeRc
));
1571 UnsafeW32kCreateRectRgnIndirect(CONST PRECT rc
)
1573 return(W32kCreateRectRgn(rc
->left
, rc
->top
, rc
->right
, rc
->bottom
));
1578 W32kCreateRoundRectRgn(INT LeftRect
,
1590 W32kEqualRgn(HRGN hSrcRgn1
,
1593 PROSRGNDATA rgn1
, rgn2
;
1594 PRECT tRect1
, tRect2
;
1598 if( !(rgn1
= RGNDATA_LockRgn(hSrcRgn1
)))
1601 if( !(rgn2
= RGNDATA_LockRgn(hSrcRgn2
))){
1602 RGNDATA_UnlockRgn( hSrcRgn1
);
1606 if(rgn1
->rdh
.nCount
!= rgn2
->rdh
.nCount
||
1607 rgn1
->rdh
.nCount
== 0 ||
1608 rgn1
->rdh
.rcBound
.left
!= rgn2
->rdh
.rcBound
.left
||
1609 rgn1
->rdh
.rcBound
.right
!= rgn2
->rdh
.rcBound
.right
||
1610 rgn1
->rdh
.rcBound
.top
!= rgn2
->rdh
.rcBound
.top
||
1611 rgn1
->rdh
.rcBound
.bottom
!= rgn2
->rdh
.rcBound
.bottom
)
1614 tRect1
= (PRECT
)rgn1
->Buffer
;
1615 tRect2
= (PRECT
)rgn2
->Buffer
;
1617 if( !tRect1
|| !tRect2
)
1620 for(i
=0; i
< rgn1
->rdh
.nCount
; i
++)
1622 if(tRect1
[i
].left
!= tRect2
[i
].left
||
1623 tRect1
[i
].right
!= tRect2
[i
].right
||
1624 tRect1
[i
].top
!= tRect2
[i
].top
||
1625 tRect1
[i
].bottom
!= tRect2
[i
].bottom
)
1631 RGNDATA_UnlockRgn( hSrcRgn1
);
1632 RGNDATA_UnlockRgn( hSrcRgn2
);
1638 W32kExtCreateRegion(CONST PXFORM Xform
,
1640 CONST PROSRGNDATA RgnData
)
1644 // FIXME: Apply Xform transformation to the regional data
1654 W32kFillRgn(HDC hDC
, HRGN hRgn
, HBRUSH hBrush
)
1660 if (NULL
== (rgn
= RGNDATA_LockRgn(hRgn
)))
1665 if (NULL
== (oldhBrush
= W32kSelectObject(hDC
, hBrush
)))
1667 RGNDATA_UnlockRgn(hRgn
);
1671 for (r
= (PRECT
) rgn
->Buffer
; r
< ((PRECT
) rgn
->Buffer
) + rgn
->rdh
.nCount
; r
++)
1673 W32kPatBlt(hDC
, r
->left
, r
->top
, r
->right
- r
->left
, r
->bottom
- r
->top
, PATCOPY
);
1676 W32kSelectObject(hDC
, oldhBrush
);
1677 RGNDATA_UnlockRgn( hRgn
);
1684 W32kFrameRgn(HDC hDC
,
1694 UnsafeW32kGetRgnBox(HRGN hRgn
,
1697 PROSRGNDATA rgn
= RGNDATA_LockRgn(hRgn
);
1702 *pRect
= rgn
->rdh
.rcBound
;
1703 ret
= rgn
->rdh
.iType
;
1704 RGNDATA_UnlockRgn( hRgn
);
1708 return 0; //if invalid region return zero
1713 W32kGetRgnBox(HRGN hRgn
,
1716 PROSRGNDATA rgn
= RGNDATA_LockRgn(hRgn
);
1722 SafeRect
.left
= rgn
->rdh
.rcBound
.left
;
1723 SafeRect
.top
= rgn
->rdh
.rcBound
.top
;
1724 SafeRect
.right
= rgn
->rdh
.rcBound
.right
;
1725 SafeRect
.bottom
= rgn
->rdh
.rcBound
.bottom
;
1726 ret
= rgn
->rdh
.iType
;
1727 RGNDATA_UnlockRgn( hRgn
);
1729 if(!NT_SUCCESS(MmCopyToCaller(pRect
, &SafeRect
, sizeof(RECT
))))
1734 return 0; //if invalid region return zero
1739 W32kInvertRgn(HDC hDC
,
1747 W32kOffsetRgn(HRGN hRgn
,
1751 PROSRGNDATA rgn
= RGNDATA_LockRgn(hRgn
);
1754 DPRINT("W32kOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn
, XOffset
, YOffset
, rgn
);
1757 DPRINT("W32kOffsetRgn: hRgn error\n");
1761 if(XOffset
|| YOffset
) {
1762 int nbox
= rgn
->rdh
.nCount
;
1763 PRECT pbox
= (PRECT
)rgn
->Buffer
;
1767 pbox
->left
+= XOffset
;
1768 pbox
->right
+= XOffset
;
1769 pbox
->top
+= YOffset
;
1770 pbox
->bottom
+= YOffset
;
1773 rgn
->rdh
.rcBound
.left
+= XOffset
;
1774 rgn
->rdh
.rcBound
.right
+= XOffset
;
1775 rgn
->rdh
.rcBound
.top
+= YOffset
;
1776 rgn
->rdh
.rcBound
.bottom
+= YOffset
;
1779 ret
= rgn
->rdh
.iType
;
1780 RGNDATA_UnlockRgn( hRgn
);
1786 W32kPaintRgn(HDC hDC
,
1790 HRGN tmpVisRgn
; //, prevVisRgn;
1791 DC
*dc
= DC_HandleToPtr(hDC
);
1793 CLIPOBJ
* ClipRegion
;
1802 if(!(tmpVisRgn
= W32kCreateRectRgn(0, 0, 0, 0))){
1803 DC_ReleasePtr( hDC
);
1808 // Transform region into device co-ords
1809 if(!REGION_LPTODP(hDC, tmpVisRgn, hRgn) || W32kOffsetRgn(tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY) == ERROR) {
1810 W32kDeleteObject( tmpVisRgn );
1811 DC_ReleasePtr( hDC );
1815 /* enable when clipping is implemented
1816 W32kCombineRgn(tmpVisRgn, tmpVisRgn, dc->w.hGCClipRgn, RGN_AND);
1819 //visrgn = RGNDATA_LockRgn(tmpVisRgn);
1820 visrgn
= RGNDATA_LockRgn(hRgn
);
1822 ClipRegion
= IntEngCreateClipRegion( visrgn
->rdh
.nCount
, visrgn
->Buffer
, visrgn
->rdh
.rcBound
);
1823 ASSERT( ClipRegion
);
1824 pBrush
= BRUSHOBJ_LockBrush(dc
->w
.hBrush
);
1826 BrushOrigin
.x
= dc
->w
.brushOrgX
;
1827 BrushOrigin
.y
= dc
->w
.brushOrgY
;
1828 SurfObj
= (SURFOBJ
*)AccessUserObject((ULONG
)dc
->Surface
);
1830 bRet
= IntEngPaint(SurfObj
,
1834 0xFFFF);//FIXME:don't know what to put here
1836 RGNDATA_UnlockRgn( tmpVisRgn
);
1839 DC_ReleasePtr( hDC
);
1845 W32kPtInRegion(HRGN hRgn
,
1852 if( (rgn
= RGNDATA_LockRgn(hRgn
) ) )
1855 if(rgn
->rdh
.nCount
> 0 && INRECT(rgn
->rdh
.rcBound
, X
, Y
)){
1856 for(i
= 0; i
< rgn
->rdh
.nCount
; i
++) {
1857 if(INRECT(*(PRECT
)&rgn
->Buffer
[i
], X
, Y
)){
1858 RGNDATA_UnlockRgn(hRgn
);
1863 RGNDATA_UnlockRgn(hRgn
);
1869 W32kRectInRegion(HRGN hRgn
,
1870 CONST LPRECT unsaferc
)
1873 PRECT pCurRect
, pRectEnd
;
1877 if( !NT_SUCCESS( MmCopyFromCaller( rc
, unsaferc
, sizeof( RECT
) ) ) ){
1878 DPRINT("W32kRectInRegion: bogus rc\n");
1882 if( !( rgn
= RGNDATA_LockRgn(hRgn
) ) )
1885 // this is (just) a useful optimization
1886 if((rgn
->rdh
.nCount
> 0) && EXTENTCHECK(&rgn
->rdh
.rcBound
, rc
))
1888 for (pCurRect
= (PRECT
)rgn
->Buffer
, pRectEnd
= pCurRect
+ rgn
->rdh
.nCount
; pCurRect
< pRectEnd
; pCurRect
++)
1890 if (pCurRect
->bottom
<= rc
->top
) continue; // not far enough down yet
1891 if (pCurRect
->top
>= rc
->bottom
) break; // too far down
1892 if (pCurRect
->right
<= rc
->left
) continue; // not far enough over yet
1893 if (pCurRect
->left
>= rc
->right
) continue;
1898 RGNDATA_UnlockRgn(hRgn
);
1904 W32kSetRectRgn(HRGN hRgn
,
1915 if( !( rgn
= RGNDATA_LockRgn(hRgn
) ) )
1916 return 0; //per documentation
1918 if (LeftRect
> RightRect
) { INT tmp
= LeftRect
; LeftRect
= RightRect
; RightRect
= tmp
; }
1919 if (TopRect
> BottomRect
) { INT tmp
= TopRect
; TopRect
= BottomRect
; BottomRect
= tmp
; }
1921 if((LeftRect
!= RightRect
) && (TopRect
!= BottomRect
))
1923 firstRect
= (PRECT
)rgn
->Buffer
;
1924 ASSERT( firstRect
);
1925 firstRect
->left
= rgn
->rdh
.rcBound
.left
= LeftRect
;
1926 firstRect
->top
= rgn
->rdh
.rcBound
.top
= TopRect
;
1927 firstRect
->right
= rgn
->rdh
.rcBound
.right
= RightRect
;
1928 firstRect
->bottom
= rgn
->rdh
.rcBound
.bottom
= BottomRect
;
1929 rgn
->rdh
.nCount
= 1;
1930 rgn
->rdh
.iType
= SIMPLEREGION
;
1934 RGNDATA_UnlockRgn( hRgn
);
1939 UnsafeW32kUnionRectWithRgn(HRGN hDest
, CONST PRECT Rect
)
1943 pRgn
= RGNDATA_LockRgn(hDest
);
1946 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1950 REGION_UnionRectWithRegion(Rect
, pRgn
);
1951 RGNDATA_UnlockRgn(hDest
);
1957 W32kUnionRectWithRgn(HRGN hDest
, CONST PRECT UnsafeRect
)
1961 if (! NT_SUCCESS(MmCopyFromCaller(&SafeRect
, UnsafeRect
, sizeof(RECT
))))
1963 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1967 return UnsafeW32kUnionRectWithRgn(hDest
, &SafeRect
);
1971 * MSDN: GetRegionData, Return Values:
1973 * "If the function succeeds and dwCount specifies an adequate number of bytes,
1974 * the return value is always dwCount. If dwCount is too small or the function
1975 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
1976 * required number of bytes.
1978 * If the function fails, the return value is zero."
1980 DWORD STDCALL
W32kGetRegionData(HRGN hrgn
, DWORD count
, LPRGNDATA rgndata
)
1983 PROSRGNDATA obj
= RGNDATA_LockRgn( hrgn
);
1988 size
= obj
->rdh
.nCount
* sizeof(RECT
);
1989 if(count
< (size
+ sizeof(RGNDATAHEADER
)) || rgndata
== NULL
)
1991 RGNDATA_UnlockRgn( hrgn
);
1992 if (rgndata
) /* buffer is too small, signal it by return 0 */
1994 else /* user requested buffer size with rgndata NULL */
1995 return size
+ sizeof(RGNDATAHEADER
);
1998 //first we copy the header then we copy buffer
1999 if( !NT_SUCCESS( MmCopyToCaller( rgndata
, obj
, sizeof( RGNDATAHEADER
)))){
2000 RGNDATA_UnlockRgn( hrgn
);
2003 if( !NT_SUCCESS( MmCopyToCaller( (char*)rgndata
+sizeof( RGNDATAHEADER
), obj
->Buffer
, size
))){
2004 RGNDATA_UnlockRgn( hrgn
);
2008 RGNDATA_UnlockRgn( hrgn
);
2009 return size
+ sizeof(RGNDATAHEADER
);